kopia lustrzana https://github.com/backface/turtlestitch
rodzic
4be96bb240
commit
75849a59a2
|
@ -2342,7 +2342,7 @@ ______
|
||||||
-------
|
-------
|
||||||
* Threads: Fix “stop this block” primitive for tail-call-elimination
|
* Threads: Fix “stop this block” primitive for tail-call-elimination
|
||||||
|
|
||||||
1411214
|
1411224
|
||||||
-------
|
-------
|
||||||
* Threads: Fixed #318
|
* Threads: Fixed #318
|
||||||
* Objects: Fixed #416
|
* Objects: Fixed #416
|
||||||
|
@ -2353,3 +2353,7 @@ ______
|
||||||
* snap.html, favicon.ico: new Favicon, thanks, Michael!
|
* snap.html, favicon.ico: new Favicon, thanks, Michael!
|
||||||
* Threads: improved whitespace detection for “split” primitive, thanks, Michael!
|
* Threads: improved whitespace detection for “split” primitive, thanks, Michael!
|
||||||
* Threads: tail-call-elimination for reporters experiment (commented out, under construction)
|
* Threads: tail-call-elimination for reporters experiment (commented out, under construction)
|
||||||
|
|
||||||
|
1411225
|
||||||
|
-------
|
||||||
|
* Threads: Evaluator optimizations (reducing the stack size for reporters)
|
||||||
|
|
127
threads.js
127
threads.js
|
@ -83,7 +83,7 @@ ArgLabelMorph, localize, XML_Element, hex_sha512*/
|
||||||
|
|
||||||
// Global stuff ////////////////////////////////////////////////////////
|
// Global stuff ////////////////////////////////////////////////////////
|
||||||
|
|
||||||
modules.threads = '2014-November-24';
|
modules.threads = '2014-November-25';
|
||||||
|
|
||||||
var ThreadManager;
|
var ThreadManager;
|
||||||
var Process;
|
var Process;
|
||||||
|
@ -218,11 +218,10 @@ ThreadManager.prototype.resumeAll = function (stage) {
|
||||||
};
|
};
|
||||||
|
|
||||||
ThreadManager.prototype.step = function () {
|
ThreadManager.prototype.step = function () {
|
||||||
/*
|
// run each process until it gives up control, skipping processes
|
||||||
run each process until it gives up control, skipping processes
|
// for sprites that are currently picked up, then filter out any
|
||||||
for sprites that are currently picked up, then filter out any
|
// processes that have been terminated
|
||||||
processes that have been terminated
|
|
||||||
*/
|
|
||||||
this.processes.forEach(function (proc) {
|
this.processes.forEach(function (proc) {
|
||||||
if (!proc.homeContext.receiver.isPickedUp() && !proc.isDead) {
|
if (!proc.homeContext.receiver.isPickedUp() && !proc.isDead) {
|
||||||
proc.runStep();
|
proc.runStep();
|
||||||
|
@ -384,13 +383,13 @@ Process.prototype.isRunning = function () {
|
||||||
// Process entry points
|
// Process entry points
|
||||||
|
|
||||||
Process.prototype.runStep = function () {
|
Process.prototype.runStep = function () {
|
||||||
/*
|
// a step is an an uninterruptable 'atom', it can consist
|
||||||
a step is an an uninterruptable 'atom', it can consist
|
// of several contexts, even of several blocks
|
||||||
of several contexts, even of several blocks
|
|
||||||
*/
|
|
||||||
if (this.isPaused) { // allow pausing in between atomic steps:
|
if (this.isPaused) { // allow pausing in between atomic steps:
|
||||||
return this.pauseStep();
|
return this.pauseStep();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.readyToYield = false;
|
this.readyToYield = false;
|
||||||
while (!this.readyToYield
|
while (!this.readyToYield
|
||||||
&& this.context
|
&& this.context
|
||||||
|
@ -459,6 +458,9 @@ Process.prototype.pauseStep = function () {
|
||||||
Process.prototype.evaluateContext = function () {
|
Process.prototype.evaluateContext = function () {
|
||||||
var exp = this.context.expression;
|
var exp = this.context.expression;
|
||||||
this.frameCount += 1;
|
this.frameCount += 1;
|
||||||
|
if (this.context.tag === 'exit') {
|
||||||
|
this.expectReport();
|
||||||
|
}
|
||||||
if (exp instanceof Array) {
|
if (exp instanceof Array) {
|
||||||
return this.evaluateSequence(exp);
|
return this.evaluateSequence(exp);
|
||||||
}
|
}
|
||||||
|
@ -482,7 +484,7 @@ Process.prototype.evaluateContext = function () {
|
||||||
|
|
||||||
Process.prototype.evaluateBlock = function (block, argCount) {
|
Process.prototype.evaluateBlock = function (block, argCount) {
|
||||||
// check for special forms
|
// check for special forms
|
||||||
if (contains(['reportOr', 'reportAnd'], block.selector)) {
|
if (contains(['reportOr', 'reportAnd', 'doReport'], block.selector)) {
|
||||||
return this[block.selector](block);
|
return this[block.selector](block);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -548,33 +550,29 @@ Process.prototype.reportAnd = function (block) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
tail-call-elimination for reporters
|
|
||||||
-----------------------------------
|
|
||||||
currently under construction, commented out for now
|
|
||||||
to activate add 'doReport' to the list of special forms
|
|
||||||
selectors in evaluateBlock() and comment out / remove
|
|
||||||
the current 'doReport' primitive in the "return"
|
|
||||||
section of the code
|
|
||||||
|
|
||||||
Process.prototype.doReport = function (block) {
|
Process.prototype.doReport = function (block) {
|
||||||
|
if (this.context.expression.partOfCustomCommand) {
|
||||||
// if (this.context.expression.partOfCustomCommand) {
|
this.doStopCustomBlock();
|
||||||
// return this.doStopCustomBlock();
|
this.popContext();
|
||||||
// }
|
return;
|
||||||
|
}
|
||||||
var outer = this.context.outerContext;
|
var outer = this.context.outerContext;
|
||||||
while (this.context && this.context.expression !== 'exitReporter') {
|
while (this.context && this.context.tag !== 'exit') {
|
||||||
if (this.context.expression === 'doStopWarping') {
|
if (this.context.expression === 'doStopWarping') {
|
||||||
this.doStopWarping();
|
this.doStopWarping();
|
||||||
} else {
|
} else {
|
||||||
this.popContext();
|
this.popContext();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.popContext();
|
if (this.context.expression === 'expectReport') {
|
||||||
|
// pop off inserted top-level exit context
|
||||||
|
this.popContext();
|
||||||
|
} else {
|
||||||
|
// un-tag and preserve original caller
|
||||||
|
this.context.tag = null;
|
||||||
|
}
|
||||||
this.pushContext(block.inputs()[0], outer);
|
this.pushContext(block.inputs()[0], outer);
|
||||||
};
|
};
|
||||||
*/
|
|
||||||
|
|
||||||
// Process: Non-Block evaluation
|
// Process: Non-Block evaluation
|
||||||
|
|
||||||
|
@ -724,9 +722,8 @@ Process.prototype.doYield = function () {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Process.prototype.exitReporter = function () {
|
Process.prototype.expectReport = function () {
|
||||||
// catch-tag for REPORT and STOP BLOCK primitives
|
this.handleError(new Error("reporter didn't report"));
|
||||||
this.handleError(new Error("missing 'report' statement in reporter"));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Process Exception Handling
|
// Process Exception Handling
|
||||||
|
@ -831,9 +828,10 @@ Process.prototype.evaluate = function (
|
||||||
}
|
}
|
||||||
|
|
||||||
var outer = new Context(null, null, context.outerContext),
|
var outer = new Context(null, null, context.outerContext),
|
||||||
|
caller = this.context.parentContext,
|
||||||
|
exit,
|
||||||
runnable,
|
runnable,
|
||||||
extra,
|
extra,
|
||||||
exit,
|
|
||||||
parms = args.asArray(),
|
parms = args.asArray(),
|
||||||
i,
|
i,
|
||||||
value;
|
value;
|
||||||
|
@ -904,17 +902,22 @@ Process.prototype.evaluate = function (
|
||||||
|
|
||||||
if (runnable.expression instanceof CommandBlockMorph) {
|
if (runnable.expression instanceof CommandBlockMorph) {
|
||||||
runnable.expression = runnable.expression.blockSequence();
|
runnable.expression = runnable.expression.blockSequence();
|
||||||
|
|
||||||
// insert a reporter exit tag for the
|
|
||||||
// CALL SCRIPT primitive variant
|
|
||||||
if (!isCommand) {
|
if (!isCommand) {
|
||||||
exit = new Context(
|
if (caller) {
|
||||||
runnable.parentContext,
|
// tag caller, so "report" can catch it later
|
||||||
'exitReporter',
|
caller.tag = 'exit';
|
||||||
outer,
|
} else {
|
||||||
outer.receiver
|
// top-level context, insert a tagged exit context
|
||||||
);
|
// which "report" can catch later
|
||||||
runnable.parentContext = exit;
|
exit = new Context(
|
||||||
|
runnable.parentContext,
|
||||||
|
'expectReport',
|
||||||
|
outer,
|
||||||
|
outer.receiver
|
||||||
|
);
|
||||||
|
exit.tag = 'exit';
|
||||||
|
runnable.parentContext = exit;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -993,21 +996,7 @@ Process.prototype.fork = function (context, args) {
|
||||||
stage.threads.processes.push(proc);
|
stage.threads.processes.push(proc);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Process "return" primitives
|
// Process stopping blocks primitives
|
||||||
|
|
||||||
Process.prototype.doReport = function (value) {
|
|
||||||
if (this.context.expression.partOfCustomCommand) {
|
|
||||||
return this.doStopCustomBlock();
|
|
||||||
}
|
|
||||||
while (this.context && this.context.expression !== 'exitReporter') {
|
|
||||||
if (this.context.expression === 'doStopWarping') {
|
|
||||||
this.doStopWarping();
|
|
||||||
} else {
|
|
||||||
this.popContext();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
};
|
|
||||||
|
|
||||||
Process.prototype.doStopBlock = function () {
|
Process.prototype.doStopBlock = function () {
|
||||||
var target = this.context.expression.exitTag;
|
var target = this.context.expression.exitTag;
|
||||||
|
@ -1119,13 +1108,21 @@ Process.prototype.evaluateCustomBlock = function () {
|
||||||
// insert a reporter exit tag for the
|
// insert a reporter exit tag for the
|
||||||
// CALL SCRIPT primitive variant
|
// CALL SCRIPT primitive variant
|
||||||
if (this.context.expression.definition.type !== 'command') {
|
if (this.context.expression.definition.type !== 'command') {
|
||||||
exit = new Context(
|
if (caller) {
|
||||||
runnable.parentContext,
|
// tag caller, so "report" can catch it later
|
||||||
'exitReporter',
|
caller.tag = 'exit';
|
||||||
outer,
|
} else {
|
||||||
outer.receiver
|
// top-level context, insert a tagged exit context
|
||||||
);
|
// which "report" can catch later
|
||||||
runnable.parentContext = exit;
|
exit = new Context(
|
||||||
|
runnable.parentContext,
|
||||||
|
'expectReport',
|
||||||
|
outer,
|
||||||
|
outer.receiver
|
||||||
|
);
|
||||||
|
exit.tag = 'exit';
|
||||||
|
runnable.parentContext = exit;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// tag all "stop this block" blocks with the current
|
// tag all "stop this block" blocks with the current
|
||||||
// procedureCount as exitTag, and mark all "report" blocks
|
// procedureCount as exitTag, and mark all "report" blocks
|
||||||
|
@ -2925,7 +2922,7 @@ Context.prototype.continuation = function () {
|
||||||
} else {
|
} else {
|
||||||
return new Context(null, 'doStop');
|
return new Context(null, 'doStop');
|
||||||
}
|
}
|
||||||
if (cont.expression === 'exitReporter') {
|
if (cont.expression === 'expectReport') {
|
||||||
return cont.continuation();
|
return cont.continuation();
|
||||||
}
|
}
|
||||||
cont = cont.copyForContinuation();
|
cont = cont.copyForContinuation();
|
||||||
|
|
Ładowanie…
Reference in New Issue