mirror of
https://github.com/scratchfoundation/scratch-vm.git
synced 2025-01-10 15:02:06 -05:00
fix: initialize stack frame params for all procedures
A previous change fixed compatibility with Scratch 2 removing 3's unintentional scope leaking. This furthers that change so that procedures with no parameters will also not accidentally use values in other procedure stacks.
This commit is contained in:
parent
532e63da15
commit
20ff75b776
5 changed files with 38 additions and 21 deletions
|
@ -38,6 +38,7 @@ class Scratch3ProcedureBlocks {
|
||||||
|
|
||||||
const [paramNames, paramIds, paramDefaults] = paramNamesIdsAndDefaults;
|
const [paramNames, paramIds, paramDefaults] = paramNamesIdsAndDefaults;
|
||||||
|
|
||||||
|
util.initParams();
|
||||||
for (let i = 0; i < paramIds.length; i++) {
|
for (let i = 0; i < paramIds.length; i++) {
|
||||||
if (args.hasOwnProperty(paramIds[i])) {
|
if (args.hasOwnProperty(paramIds[i])) {
|
||||||
util.pushParam(paramNames[i], args[paramIds[i]]);
|
util.pushParam(paramNames[i], args[paramIds[i]]);
|
||||||
|
|
|
@ -170,6 +170,13 @@ class BlockUtility {
|
||||||
return this.thread.target.blocks.getProcedureParamNamesIdsAndDefaults(procedureCode);
|
return this.thread.target.blocks.getProcedureParamNamesIdsAndDefaults(procedureCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize procedure parameters in the thread before pushing parameters.
|
||||||
|
*/
|
||||||
|
initParams () {
|
||||||
|
this.thread.initParams();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Store a procedure parameter value by its name.
|
* Store a procedure parameter value by its name.
|
||||||
* @param {string} paramName The procedure's parameter name.
|
* @param {string} paramName The procedure's parameter name.
|
||||||
|
|
|
@ -321,6 +321,16 @@ class Thread {
|
||||||
this.justReported = typeof value === 'undefined' ? null : value;
|
this.justReported = typeof value === 'undefined' ? null : value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize procedure parameters on this stack frame.
|
||||||
|
*/
|
||||||
|
initParams () {
|
||||||
|
const stackFrame = this.peekStackFrame();
|
||||||
|
if (stackFrame.params === null) {
|
||||||
|
stackFrame.params = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a parameter to the stack frame.
|
* Add a parameter to the stack frame.
|
||||||
* Use when calling a procedure with parameter values.
|
* Use when calling a procedure with parameter values.
|
||||||
|
@ -329,9 +339,6 @@ class Thread {
|
||||||
*/
|
*/
|
||||||
pushParam (paramName, value) {
|
pushParam (paramName, value) {
|
||||||
const stackFrame = this.peekStackFrame();
|
const stackFrame = this.peekStackFrame();
|
||||||
if (stackFrame.params === null) {
|
|
||||||
stackFrame.params = {};
|
|
||||||
}
|
|
||||||
stackFrame.params[paramName] = value;
|
stackFrame.params[paramName] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
BIN
test/fixtures/execute/procedures-nested-missing-no-param.sb2
vendored
Normal file
BIN
test/fixtures/execute/procedures-nested-missing-no-param.sb2
vendored
Normal file
Binary file not shown.
|
@ -5,7 +5,7 @@ const Sprite = require('../../src/sprites/sprite');
|
||||||
|
|
||||||
test('spec', t => {
|
test('spec', t => {
|
||||||
t.type(Thread, 'function');
|
t.type(Thread, 'function');
|
||||||
|
|
||||||
const th = new Thread('arbitraryString');
|
const th = new Thread('arbitraryString');
|
||||||
t.type(th, 'object');
|
t.type(th, 'object');
|
||||||
t.ok(th instanceof Thread);
|
t.ok(th instanceof Thread);
|
||||||
|
@ -17,20 +17,21 @@ test('spec', t => {
|
||||||
t.type(th.peekStackFrame, 'function');
|
t.type(th.peekStackFrame, 'function');
|
||||||
t.type(th.peekParentStackFrame, 'function');
|
t.type(th.peekParentStackFrame, 'function');
|
||||||
t.type(th.pushReportedValue, 'function');
|
t.type(th.pushReportedValue, 'function');
|
||||||
|
t.type(th.initParams, 'function');
|
||||||
t.type(th.pushParam, 'function');
|
t.type(th.pushParam, 'function');
|
||||||
t.type(th.peekStack, 'function');
|
t.type(th.peekStack, 'function');
|
||||||
t.type(th.getParam, 'function');
|
t.type(th.getParam, 'function');
|
||||||
t.type(th.atStackTop, 'function');
|
t.type(th.atStackTop, 'function');
|
||||||
t.type(th.goToNextBlock, 'function');
|
t.type(th.goToNextBlock, 'function');
|
||||||
t.type(th.isRecursiveCall, 'function');
|
t.type(th.isRecursiveCall, 'function');
|
||||||
|
|
||||||
t.end();
|
t.end();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('pushStack', t => {
|
test('pushStack', t => {
|
||||||
const th = new Thread('arbitraryString');
|
const th = new Thread('arbitraryString');
|
||||||
th.pushStack('arbitraryString');
|
th.pushStack('arbitraryString');
|
||||||
|
|
||||||
t.end();
|
t.end();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -39,7 +40,7 @@ test('popStack', t => {
|
||||||
th.pushStack('arbitraryString');
|
th.pushStack('arbitraryString');
|
||||||
t.strictEquals(th.popStack(), 'arbitraryString');
|
t.strictEquals(th.popStack(), 'arbitraryString');
|
||||||
t.strictEquals(th.popStack(), undefined);
|
t.strictEquals(th.popStack(), undefined);
|
||||||
|
|
||||||
t.end();
|
t.end();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -50,7 +51,7 @@ test('atStackTop', t => {
|
||||||
t.strictEquals(th.atStackTop(), false);
|
t.strictEquals(th.atStackTop(), false);
|
||||||
th.popStack();
|
th.popStack();
|
||||||
t.strictEquals(th.atStackTop(), true);
|
t.strictEquals(th.atStackTop(), true);
|
||||||
|
|
||||||
t.end();
|
t.end();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -59,7 +60,7 @@ test('reuseStackForNextBlock', t => {
|
||||||
th.pushStack('arbitraryString');
|
th.pushStack('arbitraryString');
|
||||||
th.reuseStackForNextBlock('secondString');
|
th.reuseStackForNextBlock('secondString');
|
||||||
t.strictEquals(th.popStack(), 'secondString');
|
t.strictEquals(th.popStack(), 'secondString');
|
||||||
|
|
||||||
t.end();
|
t.end();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -69,7 +70,7 @@ test('peekStackFrame', t => {
|
||||||
t.strictEquals(th.peekStackFrame().warpMode, false);
|
t.strictEquals(th.peekStackFrame().warpMode, false);
|
||||||
th.popStack();
|
th.popStack();
|
||||||
t.strictEquals(th.peekStackFrame(), null);
|
t.strictEquals(th.peekStackFrame(), null);
|
||||||
|
|
||||||
t.end();
|
t.end();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -80,7 +81,7 @@ test('peekParentStackFrame', t => {
|
||||||
t.strictEquals(th.peekParentStackFrame(), null);
|
t.strictEquals(th.peekParentStackFrame(), null);
|
||||||
th.pushStack('secondString');
|
th.pushStack('secondString');
|
||||||
t.strictEquals(th.peekParentStackFrame().warpMode, true);
|
t.strictEquals(th.peekParentStackFrame().warpMode, true);
|
||||||
|
|
||||||
t.end();
|
t.end();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -100,13 +101,14 @@ test('peekStack', t => {
|
||||||
t.strictEquals(th.peekStack(), 'arbitraryString');
|
t.strictEquals(th.peekStack(), 'arbitraryString');
|
||||||
th.popStack();
|
th.popStack();
|
||||||
t.strictEquals(th.peekStack(), null);
|
t.strictEquals(th.peekStack(), null);
|
||||||
|
|
||||||
t.end();
|
t.end();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('PushGetParam', t => {
|
test('PushGetParam', t => {
|
||||||
const th = new Thread('arbitraryString');
|
const th = new Thread('arbitraryString');
|
||||||
th.pushStack('arbitraryString');
|
th.pushStack('arbitraryString');
|
||||||
|
th.initParams();
|
||||||
th.pushParam('testParam', 'testValue');
|
th.pushParam('testParam', 'testValue');
|
||||||
t.strictEquals(th.peekStackFrame().params.testParam, 'testValue');
|
t.strictEquals(th.peekStackFrame().params.testParam, 'testValue');
|
||||||
t.strictEquals(th.getParam('testParam'), 'testValue');
|
t.strictEquals(th.getParam('testParam'), 'testValue');
|
||||||
|
@ -149,12 +151,12 @@ test('goToNextBlock', t => {
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0
|
y: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
rt.blocks.createBlock(block1);
|
rt.blocks.createBlock(block1);
|
||||||
rt.blocks.createBlock(block2);
|
rt.blocks.createBlock(block2);
|
||||||
rt.blocks.createBlock(block2);
|
rt.blocks.createBlock(block2);
|
||||||
th.target = rt;
|
th.target = rt;
|
||||||
|
|
||||||
t.strictEquals(th.peekStack(), null);
|
t.strictEquals(th.peekStack(), null);
|
||||||
th.pushStack('secondString');
|
th.pushStack('secondString');
|
||||||
t.strictEquals(th.peekStack(), 'secondString');
|
t.strictEquals(th.peekStack(), 'secondString');
|
||||||
|
@ -167,7 +169,7 @@ test('goToNextBlock', t => {
|
||||||
t.strictEquals(th.peekStack(), 'secondString');
|
t.strictEquals(th.peekStack(), 'secondString');
|
||||||
th.goToNextBlock();
|
th.goToNextBlock();
|
||||||
t.strictEquals(th.peekStack(), null);
|
t.strictEquals(th.peekStack(), null);
|
||||||
|
|
||||||
t.end();
|
t.end();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -204,11 +206,11 @@ test('stopThisScript', t => {
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0
|
y: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
rt.blocks.createBlock(block1);
|
rt.blocks.createBlock(block1);
|
||||||
rt.blocks.createBlock(block2);
|
rt.blocks.createBlock(block2);
|
||||||
th.target = rt;
|
th.target = rt;
|
||||||
|
|
||||||
th.stopThisScript();
|
th.stopThisScript();
|
||||||
t.strictEquals(th.peekStack(), null);
|
t.strictEquals(th.peekStack(), null);
|
||||||
th.pushStack('arbitraryString');
|
th.pushStack('arbitraryString');
|
||||||
|
@ -219,7 +221,7 @@ test('stopThisScript', t => {
|
||||||
th.pushStack('secondString');
|
th.pushStack('secondString');
|
||||||
th.stopThisScript();
|
th.stopThisScript();
|
||||||
t.strictEquals(th.peekStack(), 'secondString');
|
t.strictEquals(th.peekStack(), 'secondString');
|
||||||
|
|
||||||
t.end();
|
t.end();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -256,11 +258,11 @@ test('isRecursiveCall', t => {
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0
|
y: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
rt.blocks.createBlock(block1);
|
rt.blocks.createBlock(block1);
|
||||||
rt.blocks.createBlock(block2);
|
rt.blocks.createBlock(block2);
|
||||||
th.target = rt;
|
th.target = rt;
|
||||||
|
|
||||||
t.strictEquals(th.isRecursiveCall('fakeCode'), false);
|
t.strictEquals(th.isRecursiveCall('fakeCode'), false);
|
||||||
th.pushStack('secondString');
|
th.pushStack('secondString');
|
||||||
t.strictEquals(th.isRecursiveCall('fakeCode'), false);
|
t.strictEquals(th.isRecursiveCall('fakeCode'), false);
|
||||||
|
@ -274,6 +276,6 @@ test('isRecursiveCall', t => {
|
||||||
t.strictEquals(th.isRecursiveCall('fakeCode'), false);
|
t.strictEquals(th.isRecursiveCall('fakeCode'), false);
|
||||||
th.popStack();
|
th.popStack();
|
||||||
t.strictEquals(th.isRecursiveCall('fakeCode'), false);
|
t.strictEquals(th.isRecursiveCall('fakeCode'), false);
|
||||||
|
|
||||||
t.end();
|
t.end();
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue