mirror of
https://github.com/scratchfoundation/scratch-vm.git
synced 2025-08-28 22:30:40 -04:00
Add single-frame yield mode
This commit is contained in:
parent
5876681bc7
commit
de6ba08866
4 changed files with 39 additions and 11 deletions
|
@ -37,7 +37,13 @@ Scratch3ControlBlocks.prototype.repeat = function(args, util) {
|
|||
};
|
||||
|
||||
Scratch3ControlBlocks.prototype.forever = function(args, util) {
|
||||
util.startSubstack();
|
||||
if (!util.stackFrame.executed) {
|
||||
util.stackFrame.executed = true;
|
||||
util.startSubstack();
|
||||
} else {
|
||||
util.stackFrame.executed = false;
|
||||
util.yieldFrame();
|
||||
}
|
||||
};
|
||||
|
||||
Scratch3ControlBlocks.prototype.wait = function(args) {
|
||||
|
|
|
@ -63,8 +63,14 @@ var execute = function (sequencer, thread) {
|
|||
|
||||
var primitiveReportedValue = null;
|
||||
primitiveReportedValue = blockFunction(argValues, {
|
||||
yield: thread.yield.bind(thread),
|
||||
yield: function() {
|
||||
thread.setStatus(Thread.STATUS_YIELD);
|
||||
},
|
||||
yieldFrame: function() {
|
||||
thread.setStatus(Thread.STATUS_YIELD_FRAME);
|
||||
},
|
||||
done: function() {
|
||||
thread.setStatus(Thread.STATUS_RUNNING);
|
||||
sequencer.proceedThread(thread);
|
||||
},
|
||||
stackFrame: currentStackFrame.executionContext,
|
||||
|
@ -84,17 +90,19 @@ var execute = function (sequencer, thread) {
|
|||
if (isPromise) {
|
||||
if (thread.status === Thread.STATUS_RUNNING) {
|
||||
// Primitive returned a promise; automatically yield thread.
|
||||
thread.status = Thread.STATUS_YIELD;
|
||||
thread.setStatus(Thread.STATUS_YIELD);
|
||||
}
|
||||
// Promise handlers
|
||||
primitiveReportedValue.then(function(resolvedValue) {
|
||||
// Promise resolved: the primitive reported a value.
|
||||
thread.pushReportedValue(resolvedValue);
|
||||
thread.setStatus(Thread.STATUS_RUNNING);
|
||||
sequencer.proceedThread(thread);
|
||||
}, function(rejectionReason) {
|
||||
// Promise rejected: the primitive had some error.
|
||||
// Log it and proceed.
|
||||
console.warn('Primitive rejected promise: ', rejectionReason);
|
||||
thread.setStatus(Thread.STATUS_RUNNING);
|
||||
sequencer.proceedThread(thread);
|
||||
});
|
||||
} else if (thread.status === Thread.STATUS_RUNNING) {
|
||||
|
|
|
@ -36,6 +36,13 @@ Sequencer.prototype.stepThreads = function (threads) {
|
|||
var inactiveThreads = [];
|
||||
// If all of the threads are yielding, we should yield.
|
||||
var numYieldingThreads = 0;
|
||||
// Clear all yield statuses that were for the previous frame.
|
||||
for (var t = 0; t < threads.length; t++) {
|
||||
if (threads[t].status === Thread.STATUS_YIELD_FRAME) {
|
||||
threads[t].setStatus(Thread.STATUS_RUNNING);
|
||||
}
|
||||
}
|
||||
|
||||
// While there are still threads to run and we are within WORK_TIME,
|
||||
// continue executing threads.
|
||||
while (threads.length > 0 &&
|
||||
|
@ -51,8 +58,10 @@ Sequencer.prototype.stepThreads = function (threads) {
|
|||
if (activeThread.status === Thread.STATUS_RUNNING) {
|
||||
// Normal-mode thread: step.
|
||||
this.startThread(activeThread);
|
||||
} else if (activeThread.status === Thread.STATUS_YIELD) {
|
||||
} else if (activeThread.status === Thread.STATUS_YIELD ||
|
||||
activeThread.status === Thread.STATUS_YIELD_FRAME) {
|
||||
// Yielding thread: do nothing for this step.
|
||||
numYieldingThreads++;
|
||||
continue;
|
||||
}
|
||||
if (activeThread.stack.length === 0 &&
|
||||
|
@ -148,8 +157,6 @@ Sequencer.prototype.proceedThread = function (thread) {
|
|||
var currentBlockId = thread.peekStack();
|
||||
// Mark the status as done and proceed to the next block.
|
||||
this.runtime.glowBlock(currentBlockId, false);
|
||||
// If the block was yielding, move back to running state.
|
||||
thread.status = Thread.STATUS_RUNNING;
|
||||
// Pop from the stack - finished this level of execution.
|
||||
thread.popStack();
|
||||
// Push next connected block, if there is one.
|
||||
|
@ -164,7 +171,7 @@ Sequencer.prototype.proceedThread = function (thread) {
|
|||
}
|
||||
// If we still can't find a next block to run, mark the thread as done.
|
||||
if (thread.peekStack() === null) {
|
||||
thread.status = Thread.STATUS_DONE;
|
||||
thread.setStatus(Thread.STATUS_DONE);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -46,12 +46,18 @@ Thread.STATUS_RUNNING = 0;
|
|||
*/
|
||||
Thread.STATUS_YIELD = 1;
|
||||
|
||||
/**
|
||||
* Thread status for a single-frame yield.
|
||||
* @const
|
||||
*/
|
||||
Thread.STATUS_YIELD_FRAME = 2;
|
||||
|
||||
/**
|
||||
* Thread status for a finished/done thread.
|
||||
* Thread is in this state when there are no more blocks to execute.
|
||||
* @const
|
||||
*/
|
||||
Thread.STATUS_DONE = 2;
|
||||
Thread.STATUS_DONE = 3;
|
||||
|
||||
/**
|
||||
* Push stack and update stack frames appropriately.
|
||||
|
@ -118,10 +124,11 @@ Thread.prototype.pushReportedValue = function (value) {
|
|||
};
|
||||
|
||||
/**
|
||||
* Yields the thread.
|
||||
* Set thread status.
|
||||
* @param {number} status Enum representing thread status.
|
||||
*/
|
||||
Thread.prototype.yield = function () {
|
||||
this.status = Thread.STATUS_YIELD;
|
||||
Thread.prototype.setStatus = function (status) {
|
||||
this.status = status;
|
||||
};
|
||||
|
||||
module.exports = Thread;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue