kopia lustrzana https://github.com/backface/turtlestitch
added @xBZZZZ's JSCompiler fixes (was #3009)
rodzic
af04d1a4fb
commit
d42d01f9e0
|
|
@ -23,6 +23,9 @@
|
|||
* **Translation Updates:**
|
||||
* German
|
||||
|
||||
### 2022-03-25
|
||||
* threads: added @xBZZZZ's JSCompiler fixes (was #3009)
|
||||
|
||||
### 2022-03-24
|
||||
* German translation update for "costume name"
|
||||
* threads, extension: decodeURI XHR requests
|
||||
|
|
|
|||
135
src/threads.js
135
src/threads.js
|
|
@ -7507,9 +7507,10 @@ VariableFrame.prototype.allNames = function (upTo, includeHidden) {
|
|||
function JSCompiler(aProcess) {
|
||||
this.process = aProcess;
|
||||
this.source = null; // a context
|
||||
this.gensyms = null; // temp dictionary for parameter substitutions
|
||||
this.gensyms = new Map(); // temp dictionary for parameter substitutions
|
||||
this.implicitParams = null;
|
||||
this.paramCount = null;
|
||||
this.scriptVarCounter = null;
|
||||
}
|
||||
|
||||
JSCompiler.prototype.toString = function () {
|
||||
|
|
@ -7519,12 +7520,19 @@ JSCompiler.prototype.toString = function () {
|
|||
JSCompiler.prototype.compileFunction = function (aContext, implicitParamCount) {
|
||||
var block = aContext.expression,
|
||||
parameters = aContext.inputs,
|
||||
parms = [],
|
||||
hasEmptySlots = false,
|
||||
i;
|
||||
plength = 0;
|
||||
|
||||
this.source = aContext;
|
||||
this.implicitParams = implicitParamCount || 1;
|
||||
if (implicitParamCount == null || implicitParamCount === '') {
|
||||
this.implicitParams = 1;
|
||||
} else {
|
||||
this.implicitParams = implicitParamCount >> 0;
|
||||
if (this.implicitParams < 0) {
|
||||
// use 1 if implicitParamCount doesn't make sense
|
||||
this.implicitParams = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// scan for empty input slots
|
||||
hasEmptySlots = !isNil(detect(
|
||||
|
|
@ -7533,7 +7541,7 @@ JSCompiler.prototype.compileFunction = function (aContext, implicitParamCount) {
|
|||
));
|
||||
|
||||
// translate formal parameters into gensyms
|
||||
this.gensyms = new Map();
|
||||
this.gensyms.clear();
|
||||
this.paramCount = 0;
|
||||
if (parameters.length) {
|
||||
// test for conflicts
|
||||
|
|
@ -7546,33 +7554,34 @@ JSCompiler.prototype.compileFunction = function (aContext, implicitParamCount) {
|
|||
}
|
||||
// map explicit formal parameters
|
||||
parameters.forEach((pName, idx) => {
|
||||
var pn = 'p' + idx;
|
||||
parms.push(pn);
|
||||
this.gensyms.set(pName, pn);
|
||||
this.gensyms.set(pName, 'p[' + idx + ']');
|
||||
});
|
||||
plength = parameters.length;
|
||||
} else if (hasEmptySlots) {
|
||||
if (this.implicitParams > 1) {
|
||||
for (i = 0; i < this.implicitParams; i += 1) {
|
||||
parms.push('p' + i);
|
||||
}
|
||||
} else {
|
||||
// allow for a single implicit formal parameter
|
||||
parms = ['p0'];
|
||||
}
|
||||
plength = this.implicitParams;
|
||||
}
|
||||
|
||||
// compile using gensyms
|
||||
|
||||
if (block instanceof CommandBlockMorph) {
|
||||
return Function.apply(
|
||||
null,
|
||||
parms.concat([this.compileSequence(block)])
|
||||
);
|
||||
this.scriptVarCounter = 0;
|
||||
var code = 'proc=p.pop();\n';
|
||||
if (plength) {
|
||||
// fill missing parameters with empty string
|
||||
code += 'while(' + plength + '>p.length)p.push("");\n';
|
||||
}
|
||||
return Function.apply(
|
||||
null,
|
||||
parms.concat(['return ' + this.compileExpression(block)])
|
||||
);
|
||||
if (block instanceof CommandBlockMorph) {
|
||||
code += this.compileSequence(block) + 'return ""';
|
||||
} else {
|
||||
code += 'return ' + this.compileExpression(block);
|
||||
}
|
||||
block = 'var ';
|
||||
this.gensyms.forEach(function (value) {
|
||||
if (value.charAt(0) === 's') {
|
||||
// declare script variable
|
||||
block += value + '=0,';
|
||||
}
|
||||
});
|
||||
return Function('...p', block + code);
|
||||
};
|
||||
|
||||
JSCompiler.prototype.compileExpression = function (block) {
|
||||
|
|
@ -7607,21 +7616,49 @@ JSCompiler.prototype.compileExpression = function (block) {
|
|||
case 'evaluate':
|
||||
return 'invoke(' +
|
||||
this.compileInput(inputs[0]) +
|
||||
',' +
|
||||
', ' +
|
||||
this.compileInput(inputs[1]) +
|
||||
')';
|
||||
|
||||
// special command forms
|
||||
case 'doSetVar': // redirect var to process
|
||||
return 'arguments[arguments.length - 1].setVarNamed(' +
|
||||
case 'doDeclareVariables':
|
||||
block = '';
|
||||
inputs[0].inputs().forEach(({children: {0: {blockSpec: name}}}) => {
|
||||
if (gensym = this.gensyms.get(name)) {
|
||||
// we already have that script variable, just set it to 0
|
||||
block += gensym + '=';
|
||||
return;
|
||||
}
|
||||
var gensym = 's' + this.scriptVarCounter++;
|
||||
block += gensym + '=';
|
||||
this.gensyms.set(name, gensym);
|
||||
});
|
||||
return block + '0';
|
||||
case 'reportGetVar':
|
||||
return this.gensyms.get(block.blockSpec) || ('proc.getVarNamed("' +
|
||||
this.escape(block.blockSpec) +
|
||||
'")');
|
||||
case 'doSetVar':
|
||||
if (inputs[0] instanceof ArgMorph && (target = this.gensyms.get(inputs[0].evaluate()))) {
|
||||
// setting gensym (script or argument) variable
|
||||
return target + ' = ' + this.compileInput(inputs[1]);
|
||||
}
|
||||
// redirect var to process
|
||||
return 'proc.setVarNamed(' +
|
||||
this.compileInput(inputs[0]) +
|
||||
',' +
|
||||
', ' +
|
||||
this.compileInput(inputs[1]) +
|
||||
')';
|
||||
case 'doChangeVar': // redirect var to process
|
||||
return 'arguments[arguments.length - 1].incrementVarNamed(' +
|
||||
case 'doChangeVar':
|
||||
if (inputs[0] instanceof ArgMorph && (target = this.gensyms.get(inputs[0].evaluate()))) {
|
||||
return '{const d=' + this.compileInput(inputs[1]) +
|
||||
',v=parseFloat(' + target + ');' +
|
||||
target + '=isNaN(v)?d:v+parseFloat(d)}';
|
||||
}
|
||||
// redirect var to process
|
||||
return 'proc.incrementVarNamed(' +
|
||||
this.compileInput(inputs[0]) +
|
||||
',' +
|
||||
', ' +
|
||||
this.compileInput(inputs[1]) +
|
||||
')';
|
||||
case 'doReport':
|
||||
|
|
@ -7640,7 +7677,9 @@ JSCompiler.prototype.compileExpression = function (block) {
|
|||
'} else {\n' +
|
||||
this.compileSequence(inputs[2].evaluate()) +
|
||||
'}';
|
||||
|
||||
case 'reportBoolean':
|
||||
case 'reportNewList':
|
||||
return this.compileInput(inputs[0]);
|
||||
default:
|
||||
target = this.process[selector] ? this.process
|
||||
: (this.source.receiver || this.process.receiver);
|
||||
|
|
@ -7649,13 +7688,11 @@ JSCompiler.prototype.compileExpression = function (block) {
|
|||
if (isSnapObject(target)) {
|
||||
if (rcvr === 'SpriteMorph.prototype') {
|
||||
// fix for blocks like (x position)
|
||||
rcvr = 'arguments[arguments.length - 1].blockReceiver()';
|
||||
}
|
||||
return rcvr + '.' + selector + '(' + args +')';
|
||||
rcvr = 'proc.blockReceiver()';
|
||||
}
|
||||
return rcvr + '.' + selector + '(' + args + ')';
|
||||
} else {
|
||||
return 'arguments[arguments.length - 1].' +
|
||||
selector +
|
||||
'(' + args + ')';
|
||||
return 'proc.' + selector + '(' + args + ')';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -7670,13 +7707,13 @@ JSCompiler.prototype.compileSequence = function (commandBlock) {
|
|||
|
||||
JSCompiler.prototype.compileInfix = function (operator, inputs) {
|
||||
return '(' + this.compileInput(inputs[0]) + ' ' + operator + ' ' +
|
||||
this.compileInput(inputs[1]) +')';
|
||||
this.compileInput(inputs[1]) + ')';
|
||||
};
|
||||
|
||||
JSCompiler.prototype.compileInputs = function (array) {
|
||||
var args = '';
|
||||
array.forEach(inp => {
|
||||
if (args.length) {
|
||||
if (args) {
|
||||
args += ', ';
|
||||
}
|
||||
args += this.compileInput(inp);
|
||||
|
|
@ -7692,7 +7729,7 @@ JSCompiler.prototype.compileInput = function (inp) {
|
|||
if (this.implicitParams > 1) {
|
||||
if (this.paramCount < this.implicitParams) {
|
||||
this.paramCount += 1;
|
||||
return 'p' + (this.paramCount - 1);
|
||||
return 'p[' + (this.paramCount - 1) + ']';
|
||||
}
|
||||
throw new Error(
|
||||
localize('expecting') + ' ' + this.implicitParams + ' '
|
||||
|
|
@ -7700,7 +7737,7 @@ JSCompiler.prototype.compileInput = function (inp) {
|
|||
+ this.paramCount
|
||||
);
|
||||
}
|
||||
return 'p0';
|
||||
return 'p[0]';
|
||||
} else if (inp instanceof MultiArgMorph) {
|
||||
return 'new List([' + this.compileInputs(inp.inputs()) + '])';
|
||||
} else if (inp instanceof ArgLabelMorph) {
|
||||
|
|
@ -7729,16 +7766,6 @@ JSCompiler.prototype.compileInput = function (inp) {
|
|||
);
|
||||
}
|
||||
} else if (inp instanceof BlockMorph) {
|
||||
if (inp.selector === 'reportGetVar') {
|
||||
if (this.gensyms.has(inp.blockSpec)) {
|
||||
// un-quoted gensym:
|
||||
return this.gensyms.get(inp.blockSpec);
|
||||
}
|
||||
// redirect var query to process
|
||||
return 'arguments[arguments.length - 1].getVarNamed("' +
|
||||
this.escape(inp.blockSpec) +
|
||||
'")';
|
||||
}
|
||||
return this.compileExpression(inp);
|
||||
} else {
|
||||
throw new Error(
|
||||
|
|
@ -7752,7 +7779,7 @@ JSCompiler.prototype.compileInput = function (inp) {
|
|||
JSCompiler.prototype.escape = function(string) {
|
||||
// make sure string is a string
|
||||
string += '';
|
||||
var len = string.length, i = 0, char, escaped = '', safe_chars =
|
||||
var len = string.length, i = 0, char, escaped = '', safe_chars =
|
||||
' abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$' +
|
||||
"%&'()*+,-./:;<=>?@[]^_`{|}~";
|
||||
while (len > i) {
|
||||
|
|
|
|||
Ładowanie…
Reference in New Issue