support for compiling reporters (experimental)

currently “hidden” behind shift-click in the settings menu
upd4.2
Jens Mönig 2018-02-15 15:03:40 +01:00
rodzic dad8875afd
commit 07ce8493b4
7 zmienionych plików z 142 dodań i 58 usunięć

Wyświetl plik

@ -148,7 +148,7 @@ CustomCommandBlockMorph, SymbolMorph, ToggleButtonMorph, DialMorph*/
// Global stuff ////////////////////////////////////////////////////////
modules.blocks = '2018-January-25';
modules.blocks = '2018-February-15';
var SyntaxElementMorph;
var BlockMorph;
@ -5873,6 +5873,7 @@ RingMorph.prototype.vanishForSimilar = function () {
if (block.selector === 'reportGetVar' ||
block.selector === 'reportJSFunction' ||
block.selector == 'reportAttributeOf' ||
block.selector == 'reportCompiled' ||
(block instanceof RingMorph)
) {
this.parent.silentReplaceInput(this, block);

16
gui.js
Wyświetl plik

@ -75,7 +75,7 @@ isRetinaSupported, SliderMorph, Animation, BoxMorph, MediaRecorder*/
// Global stuff ////////////////////////////////////////////////////////
modules.gui = '2018-February-09';
modules.gui = '2018-February-15';
// Declarations
@ -2970,6 +2970,20 @@ IDE_Morph.prototype.settingsMenu = function () {
'EXPERIMENTAL! check to enable\n live custom control structures',
true
);
addPreference(
'JIT compiler support',
function () {
Process.prototype.enableCompiling =
!Process.prototype.enableCompiling;
myself.currentSprite.blocksCache.operators = null;
myself.currentSprite.paletteCache.operators = null;
myself.refreshPalette();
},
Process.prototype.enableCompiling,
'EXPERIMENTAL! uncheck to disable live\nsupport for compiling',
'EXPERIMENTAL! check to enable\nsupport for compiling',
true
);
menu.addLine(); // everything below this line is stored in the project
addPreference(
'Thread safe scripts',

Wyświetl plik

@ -3952,12 +3952,18 @@ Translation Updates:
* Threads: Allow JS-functions for invoke()
* Threads, Objects: Small compilation experiment
180215
------
* Threads, Blocks, Objects: experimental JIT compiler
=== v4.1.2 features ===
v4.1.2 New Features:
* experimental JIT compiler (in progress)
Notable Changes:
* new cloud backend
Notable Fixes:

Wyświetl plik

@ -185,7 +185,7 @@ SnapTranslator.dict.de = {
'translator_e-mail':
'jens@moenig.org', // optional
'last_changed':
'2018-01-25', // this, too, will appear in the Translators tab
'2018-02-15', // this, too, will appear in the Translators tab
// GUI
// control bar:
@ -628,6 +628,8 @@ SnapTranslator.dict.de = {
'ist %s identisch mit %s ?',
'JavaScript function ( %mult%s ) { %code }':
'JavaScript Funktion ( %mult%s ) { %code }',
'compile %repRing':
'kompiliere %repRing',
'type of %s':
'Typ von %s',

Wyświetl plik

@ -42,7 +42,7 @@
/*global modules, contains*/
modules.locale = '2018-February-9';
modules.locale = '2018-February-15';
// Global stuff
@ -160,7 +160,7 @@ SnapTranslator.dict.de = {
'translator_e-mail':
'jens@moenig.org',
'last_changed':
'2018-01-25'
'2018-02-15'
};
SnapTranslator.dict.it = {

Wyświetl plik

@ -81,9 +81,9 @@ modules, IDE_Morph, VariableDialogMorph, HTMLCanvasElement, Context, List,
SpeechBubbleMorph, RingMorph, isNil, FileReader, TableDialogMorph,
BlockEditorMorph, BlockDialogMorph, PrototypeHatBlockMorph, localize,
TableMorph, TableFrameMorph, normalizeCanvas, BooleanSlotMorph, HandleMorph,
AlignmentMorph*/
AlignmentMorph, Process*/
modules.objects = '2018-February-13';
modules.objects = '2018-February-15';
var SpriteMorph;
var StageMorph;
@ -1079,8 +1079,7 @@ SpriteMorph.prototype.initBlocks = function () {
spec: '%txtfun of %s',
defaults: [null, "Abelson & Sussman"]
},
reportCompiled: { // only in dev mode - experimental
dev: true,
reportCompiled: { // experimental
type: 'reporter',
category: 'operators',
spec: 'compile %repRing'
@ -2134,6 +2133,9 @@ SpriteMorph.prototype.blockTemplates = function (category) {
if (true) { // (Process.prototype.enableJS) {
blocks.push('-');
blocks.push(block('reportJSFunction'));
if (Process.prototype.enableCompiling) {
blocks.push(block('reportCompiled'));
}
}
// for debugging: ///////////////
@ -2149,7 +2151,6 @@ SpriteMorph.prototype.blockTemplates = function (category) {
blocks.push('-');
blocks.push(block('reportTypeOf'));
blocks.push(block('reportTextFunction'));
blocks.push(block('reportCompiled'));
}
/////////////////////////////////
@ -7268,6 +7269,9 @@ StageMorph.prototype.blockTemplates = function (category) {
if (true) { // (Process.prototype.enableJS) {
blocks.push('-');
blocks.push(block('reportJSFunction'));
if (Process.prototype.enableCompiling) {
blocks.push(block('reportCompiled'));
}
}
// for debugging: ///////////////
@ -7283,7 +7287,6 @@ StageMorph.prototype.blockTemplates = function (category) {
blocks.push('-');
blocks.push(block('reportTypeOf'));
blocks.push(block('reportTextFunction'));
blocks.push(block('reportCompiled'));
}
//////////////////////////////////

Wyświetl plik

@ -61,7 +61,7 @@ StageMorph, SpriteMorph, StagePrompterMorph, Note, modules, isString, copy,
isNil, WatcherMorph, List, ListWatcherMorph, alert, console, TableMorph,
TableFrameMorph, ColorSlotMorph, isSnapObject*/
modules.threads = '2018-February-13';
modules.threads = '2018-February-15';
var ThreadManager;
var Process;
@ -527,6 +527,7 @@ Process.prototype.timeout = 500; // msecs after which to force yield
Process.prototype.isCatchingErrors = true;
Process.prototype.enableLiveCoding = false; // experimental
Process.prototype.enableSingleStepping = false; // experimental
Process.prototype.enableCompiling = false; // experimental
Process.prototype.flashTime = 0; // experimental
// Process.prototype.enableJS = false;
@ -740,64 +741,121 @@ Process.prototype.evaluateBlock = function (block, argCount) {
// ** highly experimental and heavily under construction **
Process.prototype.reportCompiled = function (context) {
this.assertType(context, 'reporter');
this.assertType(context, ['reporter', 'predicate']);
return this.compileFunction(context.expression, context.inputs);
};
Process.prototype.compileFunction = function (block, parameters) {
// private
return this.compileExpression(block);
// parameter binding is commented out for now
/*
var selector = block.selector,
args = this.compileInputs(block),
body = 'return Cfunc.apply(null, [' + args.toString() + ']);',
method = this[selector] ||
(this.context.receiver || this.receiver)[selector];
// global!
Cfunc = function () {return method.apply(null, arguments); };
return Function.apply(null, parameters.concat([body]));
*/
// first test for unbound variables
block.allChildren().forEach(function (morph) {
if (morph.selector === 'reportGetVar' &&
!contains(parameters, morph.blockSpec)
) {
throw new Error(
'compiling does not yet support\n' +
'variables that are not\nformal parameters'
);
}
});
return Function.apply(
null,
parameters.concat(['return ' + this.compileExpression(block)])
);
};
Process.prototype.compileExpression = function (block) {
// private
var selector = block.selector,
args = this.compileInputs(block),
method = this[selector] ||
(this.context.receiver || this.receiver)[selector];
inputs = block.inputs(),
src,
rcvr,
args;
function evalArg(value) {
return value instanceof Function ? value() : value;
}
return function () {return method.apply(null, args.map(evalArg)); };
// first check for special forms and infix operators
switch (selector) {
case 'reportOr':
return this.compileInfix('||', inputs);
case 'reportAnd':
return this.compileInfix('&&', inputs);
case 'evaluateCustomBlock':
throw new Error(
'compiling does not yet support\n' +
'custom blocks'
);
default:
src = this[selector] ? this : (this.context.receiver || this.receiver);
rcvr = src.constructor.name + '.prototype';
args = this.compileInputs(inputs);
return rcvr + '.' + selector + '.apply('+ rcvr + ', [' + args +'])';
}
};
Process.prototype.compileInputs = function (block) {
var args = [],
myself = this;
block.inputs().forEach(function (inp) {
if (inp.isEmptySlot && inp.isEmptySlot()) {
// implicit parameter
} else if (inp instanceof ArgMorph) {
// literal - evaluate inline
args.push(inp.evaluate());
} else if (inp instanceof BlockMorph) {
if (inp.selector === 'reportGetVar') {
args.push(inp.blockSpec);
} else {
// recurse
args.push(myself.compileExpression(inp));
}
} else {
// raise error about unsupported slot
}
Process.prototype.compileInfix = function (operator, inputs) {
return '(' + this.compileInput(inputs[0]) + ' ' + operator + ' ' +
this.compileInput(inputs[1]) +')';
};
Process.prototype.compileInputs = function (array) {
var args = '',
myself = this;
array.forEach(function (inp) {
if (args.length) {
args += ', ';
}
args += myself.compileInput(inp);
});
return args;
return args;
};
Process.prototype.compileInput = function (inp) {
var value, type;
if (inp.isEmptySlot && inp.isEmptySlot()) {
// implicit parameter - unsupported for now
throw new Error(
'compiling does not yet support\n' +
'implicit parameters\n(empty input slots)'
);
} else if (inp instanceof MultiArgMorph) {
if (inp.isStatic) {
return 'new List([' + this.compileInputs(inp.inputs()) + '])';
} else {
return '' + this.compileInputs(inp.inputs());
}
} else if (inp instanceof ArgMorph) {
// literal - evaluate inline
value = inp.evaluate();
type = this.reportTypeOf(value);
switch (type) {
case 'number':
case 'Boolean':
return '' + value;
case 'text':
// enclose in double quotes
return '"' + value + '"';
case 'list':
return 'new List([' + this.compileInputs(value) + '])';
default:
throw new Error(
'compiling does not yet support\n' +
'inputs of type\n' +
type
);
}
} else if (inp instanceof BlockMorph) {
if (inp.selector === 'reportGetVar') {
// un-quoted string:
return inp.blockSpec;
} else {
return this.compileExpression(inp);
}
} else {
throw new Error(
'compiling does not yet support\n' +
'input slots of type\n' +
inp.constructor.name
);
}
};
// Process: Special Forms Blocks Primitives