mirror of
https://github.com/scratchfoundation/scratch-vm.git
synced 2024-12-23 14:32:59 -05:00
Merge pull request #1335 from mzgoddard/fix-execute
fix asynchronous block execution
This commit is contained in:
commit
b33d9ba4e0
2 changed files with 63 additions and 17 deletions
|
@ -102,7 +102,7 @@ const handleReport = function (resolvedValue, sequencer, thread, blockCached) {
|
|||
}
|
||||
};
|
||||
|
||||
const handlePromise = (primitiveReportedValue, sequencer, thread, blockCached) => {
|
||||
const handlePromise = (primitiveReportedValue, sequencer, thread, blockCached, lastOperation) => {
|
||||
if (thread.status === Thread.STATUS_RUNNING) {
|
||||
// Primitive returned a promise; automatically yield thread.
|
||||
thread.status = Thread.STATUS_PROMISE_WAIT;
|
||||
|
@ -110,7 +110,8 @@ const handlePromise = (primitiveReportedValue, sequencer, thread, blockCached) =
|
|||
// Promise handlers
|
||||
primitiveReportedValue.then(resolvedValue => {
|
||||
handleReport(resolvedValue, sequencer, thread, blockCached);
|
||||
if (typeof resolvedValue === 'undefined') {
|
||||
// If its a command block.
|
||||
if (lastOperation && typeof resolvedValue === 'undefined') {
|
||||
let stackFrame;
|
||||
let nextBlockId;
|
||||
do {
|
||||
|
@ -131,8 +132,6 @@ const handlePromise = (primitiveReportedValue, sequencer, thread, blockCached) =
|
|||
} while (stackFrame !== null && !stackFrame.isLoop);
|
||||
|
||||
thread.pushStack(nextBlockId);
|
||||
} else {
|
||||
thread.popStack();
|
||||
}
|
||||
}, rejectionReason => {
|
||||
// Promise rejected: the primitive had some error.
|
||||
|
@ -407,7 +406,44 @@ const execute = function (sequencer, thread) {
|
|||
const reported = currentStackFrame.reported;
|
||||
// Reinstate all the previous values.
|
||||
for (; i < reported.length; i++) {
|
||||
const {opCached, inputValue} = reported[i];
|
||||
const {opCached: oldOpCached, inputValue} = reported[i];
|
||||
|
||||
const opCached = ops.find(op => op.id === oldOpCached);
|
||||
|
||||
if (opCached) {
|
||||
const inputName = opCached._parentKey;
|
||||
const argValues = opCached._parentValues;
|
||||
|
||||
if (inputName === 'BROADCAST_INPUT') {
|
||||
// Something is plugged into the broadcast input.
|
||||
// Cast it to a string. We don't need an id here.
|
||||
argValues.BROADCAST_OPTION.id = null;
|
||||
argValues.BROADCAST_OPTION.name = cast.toString(inputValue);
|
||||
} else {
|
||||
argValues[inputName] = inputValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find the last reported block that is still in the set of operations.
|
||||
// This way if the last operation was removed, we'll find the next
|
||||
// candidate. If an earlier block that was performed was removed then
|
||||
// we'll find the index where the last operation is now.
|
||||
if (reported.length > 0) {
|
||||
const lastExisting = reported.reverse().find(report => ops.find(op => op.id === report.opCached));
|
||||
if (lastExisting) {
|
||||
i = ops.findIndex(opCached => opCached.id === lastExisting.opCached) + 1;
|
||||
} else {
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// The reporting block must exist and must be the next one in the sequence of operations.
|
||||
if (thread.justReported !== null && ops[i] && ops[i].id === currentStackFrame.reporting) {
|
||||
const opCached = ops[i];
|
||||
const inputValue = thread.justReported;
|
||||
|
||||
thread.justReported = null;
|
||||
|
||||
const inputName = opCached._parentKey;
|
||||
const argValues = opCached._parentValues;
|
||||
|
@ -420,17 +456,11 @@ const execute = function (sequencer, thread) {
|
|||
} else {
|
||||
argValues[inputName] = inputValue;
|
||||
}
|
||||
|
||||
i += 1;
|
||||
}
|
||||
|
||||
// Find the last reported block that is still in the set of operations.
|
||||
// This way if the last operation was removed, we'll find the next
|
||||
// candidate. If an earlier block that was performed was removed then
|
||||
// we'll find the index where the last operation is now.
|
||||
if (reported.length > 0) {
|
||||
const lastExisting = reported.reverse().find(report => ops.find(op => op.id === report[0].id));
|
||||
i = ops.findIndex(opCached => opCached.id === lastExisting.id) + 1;
|
||||
}
|
||||
|
||||
currentStackFrame.reporting = null;
|
||||
currentStackFrame.reported = null;
|
||||
}
|
||||
|
||||
|
@ -471,23 +501,33 @@ const execute = function (sequencer, thread) {
|
|||
|
||||
// If it's a promise, wait until promise resolves.
|
||||
if (isPromise(primitiveReportedValue)) {
|
||||
handlePromise(primitiveReportedValue, sequencer, thread, opCached);
|
||||
handlePromise(primitiveReportedValue, sequencer, thread, opCached, last);
|
||||
|
||||
// Store the already reported values. They will be thawed into the
|
||||
// future versions of the same operations by block id. The reporting
|
||||
// operation if it is promise waiting will set its parent value at
|
||||
// that time.
|
||||
thread.justReported = null;
|
||||
currentStackFrame.reporting = ops[i].id;
|
||||
currentStackFrame.reported = ops.slice(0, i).map(reportedCached => {
|
||||
const inputName = reportedCached._parentKey;
|
||||
const reportedValues = reportedCached._parentValues;
|
||||
|
||||
if (inputName === 'BROADCAST_INPUT') {
|
||||
return {
|
||||
opCached: reportedCached,
|
||||
opCached: reportedCached.id,
|
||||
inputValue: reportedValues[inputName].BROADCAST_OPTION.name
|
||||
};
|
||||
}
|
||||
return {
|
||||
opCached: reportedCached,
|
||||
opCached: reportedCached.id,
|
||||
inputValue: reportedValues[inputName]
|
||||
};
|
||||
});
|
||||
|
||||
// We are waiting for a promise. Stop running this set of operations
|
||||
// and continue them later after thawing the reported values.
|
||||
break;
|
||||
} else if (thread.status === Thread.STATUS_RUNNING) {
|
||||
if (last) {
|
||||
if (typeof primitiveReportedValue === 'undefined') {
|
||||
|
|
|
@ -32,6 +32,12 @@ class _StackFrame {
|
|||
*/
|
||||
this.justReported = null;
|
||||
|
||||
/**
|
||||
* The active block that is waiting on a promise.
|
||||
* @type {string}
|
||||
*/
|
||||
this.reporting = '';
|
||||
|
||||
/**
|
||||
* Persists reported inputs during async block.
|
||||
* @type {Object}
|
||||
|
|
Loading…
Reference in a new issue