kopia lustrzana https://github.com/backface/turtlestitch
Merge branch 'master' into cat5d
commit
45c5794fcb
20
HISTORY.md
20
HISTORY.md
|
@ -25,6 +25,8 @@
|
|||
* new "get graphic effect" reporter
|
||||
* new "get pen attribute" reporter
|
||||
* new "write" command in pen category (used to be "label" in tools)
|
||||
* new "map","keep", "combine" and "for each" primitives in list category
|
||||
* new "for" loop and "if then else" reporter primitives in the Control category
|
||||
* added "neg", "lg" (log2) and "2^" selectors to monadic function reporter in Operators
|
||||
* added "^" reporter (power of) in the Operators category
|
||||
* added "width" and "height" as attribute selectors of the OF primitive for the stage
|
||||
|
@ -67,8 +69,26 @@
|
|||
* German
|
||||
* French
|
||||
|
||||
### 2019-04-24
|
||||
* updated German translation (for new HOF prims)
|
||||
|
||||
### 2019-04-24
|
||||
* Threads, Objects: new "combine" primitive in list category
|
||||
* Threads: added type-assertions for the new HOF prims
|
||||
* Threads, Objects: new "for" loop primitive in Control category
|
||||
* Threads, Objects: new "if then else" reporter primitive in Control category
|
||||
|
||||
### 2019-04-23
|
||||
* Threads: fixed JS stack overflow issue for MAP primitive
|
||||
* Threads: new "map" and "for each" primitives in list category
|
||||
* Threads: new "keep" primitive in list category
|
||||
|
||||
### 2019-04-22
|
||||
* Threads: fixed variable binding for "arguments", turned dictionary key into a Symbol
|
||||
|
||||
### 2019-04-15
|
||||
* Catalan translation update
|
||||
|
||||
### 2019-04-12
|
||||
* Objects: enabled text-variables as inputs for graphic effects / pen attributes
|
||||
* updated amination library with graphic effects and audio attributes
|
||||
|
|
|
@ -185,7 +185,7 @@ SnapTranslator.dict.de = {
|
|||
'translator_e-mail':
|
||||
'jens@moenig.org, jadga.huegle@sap.com', // optional
|
||||
'last_changed':
|
||||
'2019-04-11', // this, too, will appear in the Translators tab
|
||||
'2019-04-25', // this, too, will appear in the Translators tab
|
||||
|
||||
// GUI
|
||||
// control bar:
|
||||
|
@ -529,10 +529,14 @@ SnapTranslator.dict.de = {
|
|||
'wiederhole %n mal %loop',
|
||||
'repeat until %b %loop':
|
||||
'wiederhole bis %b %loop',
|
||||
'for %upvar = %n to %n %cla':
|
||||
'für %upvar = %n bis %n %cla',
|
||||
'if %b %c':
|
||||
'falls %b %c',
|
||||
'if %b %c else %c':
|
||||
'falls %b %c sonst %c',
|
||||
'if %b then %s else %s':
|
||||
'falls %b dann %s sonst %s',
|
||||
'report %s':
|
||||
'berichte %s',
|
||||
'stop %stopChoices':
|
||||
|
@ -763,6 +767,16 @@ SnapTranslator.dict.de = {
|
|||
'%l enth\u00e4lt %s',
|
||||
'thing':
|
||||
'etwas',
|
||||
'for each %upvar in %l %cla':
|
||||
'für jedes %upvar von %l %cla',
|
||||
'item':
|
||||
'Element',
|
||||
'map %repRing over %l':
|
||||
'wende %repRing an auf %l',
|
||||
'keep items such that %predRing from %l':
|
||||
'behalte Elemente, die %predRing aus %l',
|
||||
'combine with %repRing items of %l':
|
||||
'kombiniere mit %repRing die Elemente von %l',
|
||||
'add %s to %l':
|
||||
'f\u00fcge %s zu %l hinzu',
|
||||
'delete %ida of %l':
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
<script type="text/javascript" src="src/morphic.js?version=2019-02-07"></script>
|
||||
<script type="text/javascript" src="src/widgets.js?version=2019-04-05"></script>
|
||||
<script type="text/javascript" src="src/blocks.js?version=2019-04-11"></script>
|
||||
<script type="text/javascript" src="src/threads.js?version=2019-04-11"></script>
|
||||
<script type="text/javascript" src="src/objects.js?version=2019-04-12"></script>
|
||||
<script type="text/javascript" src="src/threads.js?version=2019-04-24"></script>
|
||||
<script type="text/javascript" src="src/objects.js?version=2019-04-24"></script>
|
||||
<script type="text/javascript" src="src/gui.js?version=2019-04-10"></script>
|
||||
<script type="text/javascript" src="src/paint.js?version=2019-02-22"></script>
|
||||
<script type="text/javascript" src="src/lists.js?version=2019-02-07"></script>
|
||||
|
@ -18,7 +18,7 @@
|
|||
<script type="text/javascript" src="src/sketch.js?version=2019-02-22"></script>
|
||||
<script type="text/javascript" src="src/xml.js?version=2018-11-12"></script>
|
||||
<script type="text/javascript" src="src/store.js?version=2019-04-04"></script>
|
||||
<script type="text/javascript" src="src/locale.js?version=2019-04-11"></script>
|
||||
<script type="text/javascript" src="src/locale.js?version=2019-04-25"></script>
|
||||
<script type="text/javascript" src="src/cloud.js?version=2019-03-25"></script>
|
||||
<script type="text/javascript" src="src/sha512.js?version=2018-10-02"></script>
|
||||
<script type="text/javascript" src="src/FileSaver.min.js?version=2018-10-02"></script>
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
|
||||
/*global modules, contains*/
|
||||
|
||||
modules.locale = '2019-April-15';
|
||||
modules.locale = '2019-April-25';
|
||||
|
||||
// Global stuff
|
||||
|
||||
|
@ -160,7 +160,7 @@ SnapTranslator.dict.de = {
|
|||
'translator_e-mail':
|
||||
'jens@moenig.org, jadga.huegle@sap.com',
|
||||
'last_changed':
|
||||
'2019-04-11'
|
||||
'2019-04-25'
|
||||
};
|
||||
|
||||
SnapTranslator.dict.it = {
|
||||
|
|
|
@ -84,7 +84,7 @@ BlockEditorMorph, BlockDialogMorph, PrototypeHatBlockMorph, localize,
|
|||
TableMorph, TableFrameMorph, normalizeCanvas, BooleanSlotMorph, HandleMorph,
|
||||
AlignmentMorph, Process, XML_Element, VectorPaintEditorMorph*/
|
||||
|
||||
modules.objects = '2019-April-12';
|
||||
modules.objects = '2019-April-24';
|
||||
|
||||
var SpriteMorph;
|
||||
var StageMorph;
|
||||
|
@ -736,6 +736,12 @@ SpriteMorph.prototype.initBlocks = function () {
|
|||
category: 'control',
|
||||
spec: 'repeat until %b %loop'
|
||||
},
|
||||
doFor: {
|
||||
type: 'command',
|
||||
category: 'control',
|
||||
spec: 'for %upvar = %n to %n %cla',
|
||||
defaults: ['i', 1, 10]
|
||||
},
|
||||
doIf: {
|
||||
type: 'command',
|
||||
category: 'control',
|
||||
|
@ -746,6 +752,11 @@ SpriteMorph.prototype.initBlocks = function () {
|
|||
category: 'control',
|
||||
spec: 'if %b %c else %c'
|
||||
},
|
||||
reportIfElse: {
|
||||
type: 'reporter',
|
||||
category: 'control',
|
||||
spec: 'if %b then %s else %s'
|
||||
},
|
||||
doStopThis: {
|
||||
type: 'command',
|
||||
category: 'control',
|
||||
|
@ -1270,6 +1281,16 @@ SpriteMorph.prototype.initBlocks = function () {
|
|||
category: 'lists',
|
||||
spec: 'map %repRing over %l'
|
||||
},
|
||||
reportKeep: {
|
||||
type: 'reporter',
|
||||
category: 'lists',
|
||||
spec: 'keep items such that %predRing from %l'
|
||||
},
|
||||
reportCombine: {
|
||||
type: 'reporter',
|
||||
category: 'lists',
|
||||
spec: 'combine with %repRing items of %l'
|
||||
},
|
||||
doForEach: {
|
||||
type: 'command',
|
||||
category: 'lists',
|
||||
|
@ -2162,9 +2183,11 @@ SpriteMorph.prototype.blockTemplates = function (category) {
|
|||
blocks.push(block('doForever'));
|
||||
blocks.push(block('doRepeat'));
|
||||
blocks.push(block('doUntil'));
|
||||
blocks.push(block('doFor'));
|
||||
blocks.push('-');
|
||||
blocks.push(block('doIf'));
|
||||
blocks.push(block('doIfElse'));
|
||||
blocks.push(block('reportIfElse'));
|
||||
blocks.push('-');
|
||||
blocks.push(block('doReport'));
|
||||
blocks.push(block('doStopThis'));
|
||||
|
@ -2409,6 +2432,11 @@ SpriteMorph.prototype.blockTemplates = function (category) {
|
|||
blocks.push(block('reportListLength'));
|
||||
blocks.push(block('reportListContainsItem'));
|
||||
blocks.push('-');
|
||||
blocks.push(block('doForEach'));
|
||||
blocks.push(block('reportMap'));
|
||||
blocks.push(block('reportKeep'));
|
||||
blocks.push(block('reportCombine'));
|
||||
blocks.push('-');
|
||||
blocks.push(block('doAddToList'));
|
||||
blocks.push(block('doDeleteFromList'));
|
||||
blocks.push(block('doInsertInList'));
|
||||
|
@ -2425,9 +2453,6 @@ SpriteMorph.prototype.blockTemplates = function (category) {
|
|||
txt.setColor(this.paletteTextColor);
|
||||
blocks.push(txt);
|
||||
blocks.push('-');
|
||||
blocks.push(block('doForEach'));
|
||||
blocks.push(block('reportMap'));
|
||||
blocks.push('-');
|
||||
blocks.push(block('doShowTable'));
|
||||
}
|
||||
|
||||
|
@ -2590,8 +2615,10 @@ SpriteMorph.prototype.freshPalette = function (category) {
|
|||
'reportCDR',
|
||||
'reportListLength',
|
||||
'reportListContainsItem',
|
||||
// 'doForEach',
|
||||
// 'reportMap',
|
||||
'doForEach',
|
||||
'reportMap',
|
||||
'reportKeep',
|
||||
'reportCombine',
|
||||
'doAddToList',
|
||||
'doDeleteFromList',
|
||||
'doInsertInList',
|
||||
|
@ -7733,9 +7760,11 @@ StageMorph.prototype.blockTemplates = function (category) {
|
|||
blocks.push(block('doForever'));
|
||||
blocks.push(block('doRepeat'));
|
||||
blocks.push(block('doUntil'));
|
||||
blocks.push(block('doFor'));
|
||||
blocks.push('-');
|
||||
blocks.push(block('doIf'));
|
||||
blocks.push(block('doIfElse'));
|
||||
blocks.push(block('reportIfElse'));
|
||||
blocks.push('-');
|
||||
blocks.push(block('doReport'));
|
||||
blocks.push(block('doStopThis'));
|
||||
|
@ -7956,6 +7985,11 @@ StageMorph.prototype.blockTemplates = function (category) {
|
|||
blocks.push(block('reportListLength'));
|
||||
blocks.push(block('reportListContainsItem'));
|
||||
blocks.push('-');
|
||||
blocks.push(block('doForEach'));
|
||||
blocks.push(block('reportMap'));
|
||||
blocks.push(block('reportKeep'));
|
||||
blocks.push(block('reportCombine'));
|
||||
blocks.push('-');
|
||||
blocks.push(block('doAddToList'));
|
||||
blocks.push(block('doDeleteFromList'));
|
||||
blocks.push(block('doInsertInList'));
|
||||
|
@ -7972,9 +8006,6 @@ StageMorph.prototype.blockTemplates = function (category) {
|
|||
txt.setColor(this.paletteTextColor);
|
||||
blocks.push(txt);
|
||||
blocks.push('-');
|
||||
blocks.push(block('doForEach'));
|
||||
blocks.push(block('reportMap'));
|
||||
blocks.push('-');
|
||||
blocks.push(block('doShowTable'));
|
||||
}
|
||||
|
||||
|
|
321
src/threads.js
321
src/threads.js
|
@ -60,9 +60,9 @@ degrees, detect, nop, radians, ReporterSlotMorph, CSlotMorph, RingMorph, Sound,
|
|||
IDE_Morph, ArgLabelMorph, localize, XML_Element, hex_sha512, TableDialogMorph,
|
||||
StageMorph, SpriteMorph, StagePrompterMorph, Note, modules, isString, copy,
|
||||
isNil, WatcherMorph, List, ListWatcherMorph, alert, console, TableMorph, Color,
|
||||
TableFrameMorph, ColorSlotMorph, isSnapObject, Map, newCanvas*/
|
||||
TableFrameMorph, ColorSlotMorph, isSnapObject, Map, newCanvas, Symbol*/
|
||||
|
||||
modules.threads = '2019-April-11';
|
||||
modules.threads = '2019-April-24';
|
||||
|
||||
var ThreadManager;
|
||||
var Process;
|
||||
|
@ -716,6 +716,7 @@ Process.prototype.evaluateBlock = function (block, argCount) {
|
|||
// check for special forms
|
||||
if (selector === 'reportOr' ||
|
||||
selector === 'reportAnd' ||
|
||||
selector === 'reportIfElse' ||
|
||||
selector === 'doReport') {
|
||||
return this[selector](block);
|
||||
}
|
||||
|
@ -1018,7 +1019,7 @@ Process.prototype.reify = function (topBlock, parameterNames, isCustomBlock) {
|
|||
context.expression.allEmptySlots().forEach(function (slot) {
|
||||
i += 1;
|
||||
if (slot instanceof MultiArgMorph) {
|
||||
slot.bindingID = ['arguments'];
|
||||
slot.bindingID = Symbol.for('arguments');
|
||||
} else {
|
||||
slot.bindingID = i;
|
||||
}
|
||||
|
@ -1075,11 +1076,9 @@ Process.prototype.evaluate = function (
|
|||
) {
|
||||
if (!context) {return null; }
|
||||
if (context instanceof Function) {
|
||||
/*
|
||||
if (!this.enableJS) {
|
||||
throw new Error('JavaScript is not enabled');
|
||||
}
|
||||
*/
|
||||
// if (!this.enableJS) {
|
||||
// throw new Error('JavaScript is not enabled');
|
||||
// }
|
||||
return context.apply(
|
||||
this.blockReceiver(),
|
||||
args.asArray().concat([this])
|
||||
|
@ -1120,8 +1119,8 @@ Process.prototype.evaluate = function (
|
|||
// assign arguments to parameters
|
||||
|
||||
// assign the actual arguments list to the special
|
||||
// parameter ID ['arguments'], to be used for variadic inputs
|
||||
outer.variables.addVar(['arguments'], args);
|
||||
// parameter ID Symbol.for('arguments'), to be used for variadic inputs
|
||||
outer.variables.addVar(Symbol.for('arguments'), args);
|
||||
|
||||
// assign arguments that are actually passed
|
||||
if (parms.length > 0) {
|
||||
|
@ -1220,8 +1219,8 @@ Process.prototype.initializeFor = function (context, args) {
|
|||
// assign arguments to parameters
|
||||
|
||||
// assign the actual arguments list to the special
|
||||
// parameter ID ['arguments'], to be used for variadic inputs
|
||||
outer.variables.addVar(['arguments'], args);
|
||||
// parameter ID Symbol.for('arguments'), to be used for variadic inputs
|
||||
outer.variables.addVar(Symbol.for('arguments'), args);
|
||||
|
||||
// assign arguments that are actually passed
|
||||
if (parms.length > 0) {
|
||||
|
@ -1839,6 +1838,23 @@ Process.prototype.doIfElse = function () {
|
|||
this.pushContext();
|
||||
};
|
||||
|
||||
Process.prototype.reportIfElse = function (block) {
|
||||
var inputs = this.context.inputs;
|
||||
|
||||
if (inputs.length < 1) {
|
||||
this.evaluateNextInput(block);
|
||||
} else if (inputs.length > 1) {
|
||||
if (this.flashContext()) {return; }
|
||||
this.returnValueToParentContext(inputs.pop());
|
||||
this.popContext();
|
||||
} else if (inputs[0]) {
|
||||
this.evaluateNextInput(block);
|
||||
} else {
|
||||
inputs.push(null);
|
||||
this.evaluateNextInput(block);
|
||||
}
|
||||
};
|
||||
|
||||
// Process process related primitives
|
||||
|
||||
Process.prototype.doStop = function () {
|
||||
|
@ -2067,63 +2083,16 @@ Process.prototype.doWaitUntil = function (goalCondition) {
|
|||
this.pushContext();
|
||||
};
|
||||
|
||||
Process.prototype.reportMap = function (reporter, list) {
|
||||
// answer a new list containing the results of the reporter applied
|
||||
// to each value of the given list. Distinguish between linked and
|
||||
// arrayed lists.
|
||||
// Note: This method utilizes the current context's inputs array to
|
||||
// manage temporary variables, whose allocation to which slot are
|
||||
// documented in each of the variants' code (linked or arrayed) below
|
||||
// Process interpolated iteration primitives
|
||||
|
||||
var next;
|
||||
if (list.isLinked) {
|
||||
// this.context.inputs:
|
||||
// [0] - reporter
|
||||
// [1] - list (original source)
|
||||
// -----------------------------
|
||||
// [2] - result list (target)
|
||||
// [3] - currently last element of result list
|
||||
// [4] - current source list (what's left to map)
|
||||
// [5] - current value of last function call
|
||||
|
||||
if (this.context.inputs.length < 3) {
|
||||
this.context.addInput(new List());
|
||||
this.context.inputs[2].isLinked = true;
|
||||
this.context.addInput(this.context.inputs[2]);
|
||||
this.context.addInput(list);
|
||||
}
|
||||
if (this.context.inputs[4].length() === 0) {
|
||||
this.context.inputs[3].rest = list.cons(this.context.inputs[5]);
|
||||
this.returnValueToParentContext(this.context.inputs[2].cdr());
|
||||
return;
|
||||
}
|
||||
if (this.context.inputs.length > 5) {
|
||||
this.context.inputs[3].rest = list.cons(this.context.inputs[5]);
|
||||
this.context.inputs[3] = this.context.inputs[3].rest;
|
||||
this.context.inputs.splice(5);
|
||||
}
|
||||
next = this.context.inputs[4].at(1);
|
||||
this.context.inputs[4] = this.context.inputs[4].cdr();
|
||||
this.pushContext();
|
||||
this.evaluate(reporter, new List([next]));
|
||||
} else { // arrayed
|
||||
// this.context.inputs:
|
||||
// [0] - reporter
|
||||
// [1] - list (original source)
|
||||
// -----------------------------
|
||||
// [2..n] - result values (target)
|
||||
|
||||
if (this.context.inputs.length - 2 === list.length()) {
|
||||
this.returnValueToParentContext(
|
||||
new List(this.context.inputs.slice(2))
|
||||
);
|
||||
return;
|
||||
}
|
||||
next = list.at(this.context.inputs.length - 1);
|
||||
this.pushContext();
|
||||
this.evaluate(reporter, new List([next]));
|
||||
}
|
||||
};
|
||||
/*
|
||||
these primitives can be - for the most part easily - written as
|
||||
custom blocks by users themselves. They are, or used to be, in
|
||||
libraries that could be loaded additionally. Making them available
|
||||
as primitives has the benefit of getting novices acquainted to
|
||||
using HOFs plus some performance advantages, however at the cost
|
||||
of losing the ability to inspect how they're written.
|
||||
*/
|
||||
|
||||
Process.prototype.doForEach = function (upvar, list, script) {
|
||||
// perform a script for each element of a list, assigning the
|
||||
|
@ -2132,13 +2101,11 @@ Process.prototype.doForEach = function (upvar, list, script) {
|
|||
// within the script. Uses the context's - unused - fourth
|
||||
// element as temporary storage for the current list index
|
||||
|
||||
this.assertType(list, 'list');
|
||||
if (isNil(this.context.inputs[3])) {this.context.inputs[3] = 1; }
|
||||
var index = this.context.inputs[3];
|
||||
this.context.outerContext.variables.addVar(upvar);
|
||||
this.context.outerContext.variables.setVar(
|
||||
upvar,
|
||||
list.at(index)
|
||||
);
|
||||
this.context.outerContext.variables.setVar(upvar, list.at(index));
|
||||
if (index > list.length()) {return; }
|
||||
this.context.inputs[3] += 1;
|
||||
this.pushContext('doYield');
|
||||
|
@ -2146,6 +2113,214 @@ Process.prototype.doForEach = function (upvar, list, script) {
|
|||
this.evaluate(script, new List(), true);
|
||||
};
|
||||
|
||||
Process.prototype.doFor = function (upvar, start, end, script) {
|
||||
// perform a script for every integer step between start and stop,
|
||||
// assigning the current iteration index to a variable with the
|
||||
// name specified in the "upvar" parameter, so it can be referenced
|
||||
// within the script.
|
||||
|
||||
var dta;
|
||||
if (this.context.aggregation === null) {
|
||||
this.context.aggregation = {
|
||||
idx : Math.floor(start),
|
||||
test : start < end ?
|
||||
function () {return this.idx > end; }
|
||||
: function () {return this.idx < end; },
|
||||
step : start < end ? 1 : -1,
|
||||
parms : new List() // empty parameters, reusable to avoid GC
|
||||
};
|
||||
}
|
||||
dta = this.context.aggregation;
|
||||
this.context.outerContext.variables.addVar(upvar);
|
||||
this.context.outerContext.variables.setVar(upvar, dta.idx);
|
||||
if (dta.test()) {return; }
|
||||
dta.idx += dta.step;
|
||||
this.pushContext('doYield');
|
||||
this.pushContext();
|
||||
this.evaluate(script, dta.parms, true);
|
||||
};
|
||||
|
||||
// Process interpolated HOF primitives
|
||||
|
||||
/*
|
||||
this.context.inputs:
|
||||
[0] - reporter
|
||||
[1] - list (original source)
|
||||
-----------------------------
|
||||
[2] - last reporter evaluation result
|
||||
|
||||
these primitives used to store the aggregated data in the unused parts
|
||||
of the context's input-array. For reasons obscure to me this led to
|
||||
JS stack overflows when used on large lists (> 150 k items). As a remedy
|
||||
aggregations are now accumulated in the "aggregation" property slot
|
||||
of Context. Why this speeds up execution by orders of magnitude while
|
||||
"fixing" the stack-overflow issue eludes me. -Jens
|
||||
*/
|
||||
|
||||
Process.prototype.reportMap = function (reporter, list) {
|
||||
// answer a new list containing the results of the reporter applied
|
||||
// to each value of the given list. Distinguish between linked and
|
||||
// arrayed lists.
|
||||
|
||||
var next;
|
||||
this.assertType(list, 'list');
|
||||
if (list.isLinked) {
|
||||
if (this.context.aggregation === null) {
|
||||
this.context.aggregation = {
|
||||
source : list,
|
||||
target : new List(),
|
||||
end : null,
|
||||
remaining : list.length()
|
||||
};
|
||||
this.context.aggregation.target.isLinked = true;
|
||||
this.context.aggregation.end = this.context.aggregation.target;
|
||||
} else if (this.context.inputs.length > 2) {
|
||||
this.context.aggregation.end.rest = list.cons(
|
||||
this.context.inputs.pop()
|
||||
);
|
||||
this.context.aggregation.end = this.context.aggregation.end.rest;
|
||||
this.context.aggregation.remaining -= 1;
|
||||
}
|
||||
if (this.context.aggregation.remaining === 0) {
|
||||
this.context.aggregation.end.rest = list.cons(
|
||||
this.context.inputs[2]
|
||||
).cdr();
|
||||
this.returnValueToParentContext(
|
||||
this.context.aggregation.target.cdr()
|
||||
);
|
||||
return;
|
||||
}
|
||||
next = this.context.aggregation.source.at(1);
|
||||
this.context.aggregation.source = this.context.aggregation.source.cdr();
|
||||
} else { // arrayed
|
||||
if (this.context.aggregation === null) {
|
||||
this.context.aggregation = [];
|
||||
} else if (this.context.inputs.length > 2) {
|
||||
this.context.aggregation.push(this.context.inputs.pop());
|
||||
}
|
||||
if (this.context.aggregation.length === list.length()) {
|
||||
this.returnValueToParentContext(
|
||||
new List(this.context.aggregation)
|
||||
);
|
||||
return;
|
||||
}
|
||||
next = list.at(this.context.aggregation.length + 1);
|
||||
}
|
||||
this.pushContext();
|
||||
this.evaluate(reporter, new List([next]));
|
||||
};
|
||||
|
||||
Process.prototype.reportKeep = function (predicate, list) {
|
||||
// Filter - answer a new list containing the items of the list for which
|
||||
// the predicate evaluates TRUE.
|
||||
// Distinguish between linked and arrayed lists.
|
||||
|
||||
var next;
|
||||
this.assertType(list, 'list');
|
||||
if (list.isLinked) {
|
||||
if (this.context.aggregation === null) {
|
||||
this.context.aggregation = {
|
||||
source : list,
|
||||
target : new List(),
|
||||
end : null,
|
||||
remaining : list.length()
|
||||
};
|
||||
this.context.aggregation.target.isLinked = true;
|
||||
this.context.aggregation.end = this.context.aggregation.target;
|
||||
} else if (this.context.inputs.length > 2) {
|
||||
if (this.context.inputs.pop() === true) {
|
||||
this.context.aggregation.end.rest = list.cons(
|
||||
this.context.aggregation.source.at(1)
|
||||
);
|
||||
this.context.aggregation.end =
|
||||
this.context.aggregation.end.rest;
|
||||
}
|
||||
this.context.aggregation.remaining -= 1;
|
||||
this.context.aggregation.source =
|
||||
this.context.aggregation.source.cdr();
|
||||
}
|
||||
if (this.context.aggregation.remaining === 0) {
|
||||
this.returnValueToParentContext(
|
||||
this.context.aggregation.target.cdr()
|
||||
);
|
||||
return;
|
||||
}
|
||||
next = this.context.aggregation.source.at(1);
|
||||
} else { // arrayed
|
||||
if (this.context.aggregation === null) {
|
||||
this.context.aggregation = {
|
||||
idx : 0,
|
||||
target : []
|
||||
};
|
||||
} else if (this.context.inputs.length > 2) {
|
||||
if (this.context.inputs.pop() === true) {
|
||||
this.context.aggregation.target.push(
|
||||
list.at(this.context.aggregation.idx)
|
||||
);
|
||||
}
|
||||
}
|
||||
if (this.context.aggregation.idx === list.length()) {
|
||||
this.returnValueToParentContext(
|
||||
new List(this.context.aggregation.target)
|
||||
);
|
||||
return;
|
||||
}
|
||||
this.context.aggregation.idx += 1;
|
||||
next = list.at(this.context.aggregation.idx);
|
||||
}
|
||||
this.pushContext();
|
||||
this.evaluate(predicate, new List([next]));
|
||||
};
|
||||
|
||||
Process.prototype.reportCombine = function (reporter, list) {
|
||||
// Fold - answer an aggregation of all list items from "left to right"
|
||||
// Distinguish between linked and arrayed lists.
|
||||
|
||||
var next, current;
|
||||
this.assertType(list, 'list');
|
||||
if (list.length() < 2) {
|
||||
this.returnValueToParentContext(list.length() ? list.at(1) : 0);
|
||||
return;
|
||||
}
|
||||
if (list.isLinked) {
|
||||
if (this.context.aggregation === null) {
|
||||
this.context.aggregation = {
|
||||
source : list.cdr(),
|
||||
target : list.at(1),
|
||||
remaining : list.length() - 1
|
||||
};
|
||||
} else if (this.context.inputs.length > 2) {
|
||||
this.context.aggregation.target = this.context.inputs.pop();
|
||||
this.context.aggregation.remaining -= 1;
|
||||
this.context.aggregation.source =
|
||||
this.context.aggregation.source.cdr();
|
||||
}
|
||||
if (this.context.aggregation.remaining === 0) {
|
||||
this.returnValueToParentContext(this.context.aggregation.target);
|
||||
return;
|
||||
}
|
||||
next = this.context.aggregation.source.at(1);
|
||||
} else { // arrayed
|
||||
if (this.context.aggregation === null) {
|
||||
this.context.aggregation = {
|
||||
idx : 1,
|
||||
target : list.at(1)
|
||||
};
|
||||
} else if (this.context.inputs.length > 2) {
|
||||
this.context.aggregation.target = this.context.inputs.pop();
|
||||
}
|
||||
if (this.context.aggregation.idx === list.length()) {
|
||||
this.returnValueToParentContext(this.context.aggregation.target);
|
||||
return;
|
||||
}
|
||||
this.context.aggregation.idx += 1;
|
||||
next = list.at(this.context.aggregation.idx);
|
||||
}
|
||||
current = this.context.aggregation.target;
|
||||
this.pushContext();
|
||||
this.evaluate(reporter, new List([current, next]));
|
||||
};
|
||||
|
||||
// Process interpolated primitives
|
||||
|
||||
Process.prototype.doWait = function (secs) {
|
||||
|
@ -4819,6 +4994,7 @@ Process.prototype.reportAtomicGroup = function (list, reporter) {
|
|||
tag string or number to optionally identify the Context,
|
||||
as a "return" target (for the "stop block" primitive)
|
||||
isFlashing flag for single-stepping
|
||||
aggregation slot for collecting data from reentrant visits
|
||||
*/
|
||||
|
||||
function Context(
|
||||
|
@ -4849,6 +5025,7 @@ function Context(
|
|||
this.emptySlots = 0; // used for block reification
|
||||
this.tag = null; // lexical catch-tag for custom blocks
|
||||
this.isFlashing = false; // for single-stepping
|
||||
this.aggregation = null;
|
||||
}
|
||||
|
||||
Context.prototype.toString = function () {
|
||||
|
|
Ładowanie…
Reference in New Issue