kopia lustrzana https://github.com/backface/turtlestitch
moved reporterizing infix expressions to search-blocks field
thanks, @bromagosa, for the brilliant idea!pull/29/head
rodzic
955aabfc93
commit
41e55064a2
140
blocks.js
140
blocks.js
|
@ -12330,8 +12330,7 @@ CommentMorph.prototype.fixLayout = function () {
|
||||||
|
|
||||||
CommentMorph.prototype.userMenu = function () {
|
CommentMorph.prototype.userMenu = function () {
|
||||||
var menu = new MenuMorph(this),
|
var menu = new MenuMorph(this),
|
||||||
myself = this,
|
myself = this;
|
||||||
block = this.blockify();
|
|
||||||
|
|
||||||
menu.addItem(
|
menu.addItem(
|
||||||
"duplicate",
|
"duplicate",
|
||||||
|
@ -12354,24 +12353,6 @@ CommentMorph.prototype.userMenu = function () {
|
||||||
},
|
},
|
||||||
'open a new window\nwith a picture of this comment'
|
'open a new window\nwith a picture of this comment'
|
||||||
);
|
);
|
||||||
if (block) {
|
|
||||||
menu.addLine();
|
|
||||||
menu.addItem(
|
|
||||||
block,
|
|
||||||
function () {
|
|
||||||
var world = myself.world(),
|
|
||||||
ide = myself.parentThatIsA(IDE_Morph);
|
|
||||||
block.pickUp(world);
|
|
||||||
if (ide) {
|
|
||||||
world.hand.grabOrigin = {
|
|
||||||
origin: ide.palette,
|
|
||||||
position: ide.palette.center()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'blockify this expression'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return menu;
|
return menu;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -12508,125 +12489,6 @@ CommentMorph.prototype.stackHeight = function () {
|
||||||
return this.height();
|
return this.height();
|
||||||
};
|
};
|
||||||
|
|
||||||
// CommentMorph parsing simple arithmetic expressions to reporters
|
|
||||||
|
|
||||||
CommentMorph.prototype.blockify = function () {
|
|
||||||
// highly experimental Christmas Easter Egg 2016 :-)
|
|
||||||
var ast;
|
|
||||||
|
|
||||||
function parseInfix(expression, operator, already) {
|
|
||||||
// very basic binary infix parser for arithmetic expressions
|
|
||||||
// with strict left-to-right operator precedence (like in Smalltalk)
|
|
||||||
// which can be overriden by - nested - parentheses.
|
|
||||||
// assumes well-formed expressions, no graceful error handling yet.
|
|
||||||
|
|
||||||
var inputs = ['', ''],
|
|
||||||
idx = 0,
|
|
||||||
ch;
|
|
||||||
|
|
||||||
function format(value) {
|
|
||||||
return value instanceof Array || isNaN(+value) ? value : +value;
|
|
||||||
}
|
|
||||||
|
|
||||||
function nested() {
|
|
||||||
var level = 1,
|
|
||||||
expr = '';
|
|
||||||
while (idx < expression.length) {
|
|
||||||
ch = expression[idx];
|
|
||||||
idx += 1;
|
|
||||||
switch (ch) {
|
|
||||||
case '(':
|
|
||||||
level += 1;
|
|
||||||
break;
|
|
||||||
case ')':
|
|
||||||
level -= 1;
|
|
||||||
if (!level) {
|
|
||||||
return expr;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
expr += ch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (idx < expression.length) {
|
|
||||||
ch = expression[idx];
|
|
||||||
idx += 1;
|
|
||||||
switch (ch) {
|
|
||||||
case ' ':
|
|
||||||
break;
|
|
||||||
case '(':
|
|
||||||
inputs[operator ? 1 : 0] = parseInfix(nested());
|
|
||||||
break;
|
|
||||||
case '-':
|
|
||||||
case '+':
|
|
||||||
case '*':
|
|
||||||
case '/':
|
|
||||||
if (!operator && !inputs[0].length) {
|
|
||||||
inputs[0] += ch;
|
|
||||||
} else if (operator) {
|
|
||||||
return parseInfix(
|
|
||||||
expression.slice(idx),
|
|
||||||
ch,
|
|
||||||
[operator, already, format(inputs[1])]
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
operator = ch;
|
|
||||||
already = format(inputs[0]);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
inputs[operator ? 1 : 0] += ch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (operator) {
|
|
||||||
return [operator, already, format(inputs[1])];
|
|
||||||
}
|
|
||||||
return format(inputs[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function blockFromAST(ast) {
|
|
||||||
var block, selectors, i, inps;
|
|
||||||
selectors = {
|
|
||||||
'+': 'reportSum',
|
|
||||||
'-': 'reportDifference',
|
|
||||||
'*': 'reportProduct',
|
|
||||||
'/': 'reportQuotient'
|
|
||||||
};
|
|
||||||
block = SpriteMorph.prototype.blockForSelector(selectors[ast[0]], true);
|
|
||||||
block.isDraggable = true;
|
|
||||||
inps = block.inputs();
|
|
||||||
for (i = 1; i < 3; i += 1) {
|
|
||||||
if (ast[i] instanceof Array) {
|
|
||||||
block.silentReplaceInput(inps[i - 1], blockFromAST(ast[i]));
|
|
||||||
} else if (isString(ast[i])) {
|
|
||||||
block.silentReplaceInput(
|
|
||||||
inps[i - 1],
|
|
||||||
SpriteMorph.prototype.variableBlock(ast[i])
|
|
||||||
);
|
|
||||||
} else { // number
|
|
||||||
inps[i - 1].setContents(ast[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
block.fixLayout();
|
|
||||||
block.fixBlockColor(null, true);
|
|
||||||
return block;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.contents.text.length > 100) {return null; }
|
|
||||||
if (Process.prototype.isCatchingErrors) {
|
|
||||||
try {
|
|
||||||
ast = parseInfix(this.contents.text);
|
|
||||||
return ast instanceof Array ? blockFromAST(ast) : null;
|
|
||||||
} catch (error) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ast = parseInfix(this.contents.text);
|
|
||||||
return ast instanceof Array ? blockFromAST(ast) : null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// ScriptFocusMorph //////////////////////////////////////////////////////////
|
// ScriptFocusMorph //////////////////////////////////////////////////////////
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -3196,7 +3196,7 @@ http://snap.berkeley.edu/run#cloud:Username=jens&ProjectName=rotation
|
||||||
161219
|
161219
|
||||||
------
|
------
|
||||||
* GUI: new url-switch: &noExitWarning
|
* GUI: new url-switch: &noExitWarning
|
||||||
* Blocks: highly experimental infix-expression-to-reporter parser
|
* Blocks, Objects: highly experimental infix-expression-to-reporter parser
|
||||||
|
|
||||||
|
|
||||||
== v4.10 === (in development)
|
== v4.10 === (in development)
|
||||||
|
@ -3211,7 +3211,7 @@ Features:
|
||||||
* new url option switch: &noExitWarning
|
* new url option switch: &noExitWarning
|
||||||
* svg support for images from the web (svg files have been supported for a long time)
|
* svg support for images from the web (svg files have been supported for a long time)
|
||||||
* use media dialog for browsing and importing sounds
|
* use media dialog for browsing and importing sounds
|
||||||
* highly experimental infix-expression-to-reporter parser
|
* highly experimental infix-expression-to-reporter parser. Thanks, Bernat, for the brilliant idea to add it to the search-blocks field!
|
||||||
|
|
||||||
Fixes:
|
Fixes:
|
||||||
* Music (play note) to work again in new and recent browser versions (Chrome 55)
|
* Music (play note) to work again in new and recent browser versions (Chrome 55)
|
||||||
|
|
129
objects.js
129
objects.js
|
@ -82,7 +82,7 @@ SpeechBubbleMorph, RingMorph, isNil, FileReader, TableDialogMorph,
|
||||||
BlockEditorMorph, BlockDialogMorph, PrototypeHatBlockMorph, localize,
|
BlockEditorMorph, BlockDialogMorph, PrototypeHatBlockMorph, localize,
|
||||||
TableMorph, TableFrameMorph, normalizeCanvas, BooleanSlotMorph*/
|
TableMorph, TableFrameMorph, normalizeCanvas, BooleanSlotMorph*/
|
||||||
|
|
||||||
modules.objects = '2016-December-09';
|
modules.objects = '2016-December-19';
|
||||||
|
|
||||||
var SpriteMorph;
|
var SpriteMorph;
|
||||||
var StageMorph;
|
var StageMorph;
|
||||||
|
@ -2425,7 +2425,8 @@ SpriteMorph.prototype.blocksMatching = function (
|
||||||
blocksDict,
|
blocksDict,
|
||||||
myself = this,
|
myself = this,
|
||||||
search = searchString.toLowerCase(),
|
search = searchString.toLowerCase(),
|
||||||
stage = this.parentThatIsA(StageMorph);
|
stage = this.parentThatIsA(StageMorph),
|
||||||
|
reporterized;
|
||||||
|
|
||||||
if (!types || !types.length) {
|
if (!types || !types.length) {
|
||||||
types = ['hat', 'command', 'reporter', 'predicate', 'ring'];
|
types = ['hat', 'command', 'reporter', 'predicate', 'ring'];
|
||||||
|
@ -2498,6 +2499,15 @@ SpriteMorph.prototype.blocksMatching = function (
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
// infix arithmetic expression
|
||||||
|
if (contains(types, 'reporter')) {
|
||||||
|
reporterized = this.reporterize(searchString);
|
||||||
|
if (reporterized) {
|
||||||
|
// reporterized.isTemplate = true;
|
||||||
|
// reporterized.isDraggable = false;
|
||||||
|
blocks.push([reporterized, '']);
|
||||||
|
}
|
||||||
|
}
|
||||||
blocks.sort(function (x, y) {return x[1] < y[1] ? -1 : 1; });
|
blocks.sort(function (x, y) {return x[1] < y[1] ? -1 : 1; });
|
||||||
return blocks.map(function (each) {return each[0]; });
|
return blocks.map(function (each) {return each[0]; });
|
||||||
};
|
};
|
||||||
|
@ -2624,6 +2634,121 @@ SpriteMorph.prototype.searchBlocks = function (
|
||||||
if (searchString) {searchPane.reactToKeystroke(); }
|
if (searchString) {searchPane.reactToKeystroke(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// SpritMorph parsing simple arithmetic expressions to reporter blocks
|
||||||
|
|
||||||
|
SpriteMorph.prototype.reporterize = function (expressionString) {
|
||||||
|
// highly experimental Christmas Easter Egg 2016 :-)
|
||||||
|
var ast,
|
||||||
|
myself = this;
|
||||||
|
|
||||||
|
function parseInfix(expression, operator, already) {
|
||||||
|
// very basic binary infix parser for arithmetic expressions
|
||||||
|
// with strict left-to-right operator precedence (like in Smalltalk)
|
||||||
|
// which can be overriden by - nested - parentheses.
|
||||||
|
// assumes well-formed expressions, no graceful error handling yet.
|
||||||
|
|
||||||
|
var inputs = ['', ''],
|
||||||
|
idx = 0,
|
||||||
|
ch;
|
||||||
|
|
||||||
|
function format(value) {
|
||||||
|
return value instanceof Array || isNaN(+value) ? value : +value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function nested() {
|
||||||
|
var level = 1,
|
||||||
|
expr = '';
|
||||||
|
while (idx < expression.length) {
|
||||||
|
ch = expression[idx];
|
||||||
|
idx += 1;
|
||||||
|
switch (ch) {
|
||||||
|
case '(':
|
||||||
|
level += 1;
|
||||||
|
break;
|
||||||
|
case ')':
|
||||||
|
level -= 1;
|
||||||
|
if (!level) {
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
expr += ch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (idx < expression.length) {
|
||||||
|
ch = expression[idx];
|
||||||
|
idx += 1;
|
||||||
|
switch (ch) {
|
||||||
|
case ' ':
|
||||||
|
break;
|
||||||
|
case '(':
|
||||||
|
inputs[operator ? 1 : 0] = parseInfix(nested());
|
||||||
|
break;
|
||||||
|
case '-':
|
||||||
|
case '+':
|
||||||
|
case '*':
|
||||||
|
case '/':
|
||||||
|
if (!operator && !inputs[0].length) {
|
||||||
|
inputs[0] += ch;
|
||||||
|
} else if (operator) {
|
||||||
|
return parseInfix(
|
||||||
|
expression.slice(idx),
|
||||||
|
ch,
|
||||||
|
[operator, already, format(inputs[1])]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
operator = ch;
|
||||||
|
already = format(inputs[0]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
inputs[operator ? 1 : 0] += ch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (operator) {
|
||||||
|
return [operator, already, format(inputs[1])];
|
||||||
|
}
|
||||||
|
return format(inputs[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function blockFromAST(ast) {
|
||||||
|
var block, selectors, i, inps;
|
||||||
|
selectors = {
|
||||||
|
'+': 'reportSum',
|
||||||
|
'-': 'reportDifference',
|
||||||
|
'*': 'reportProduct',
|
||||||
|
'/': 'reportQuotient'
|
||||||
|
};
|
||||||
|
block = myself.blockForSelector(selectors[ast[0]], true);
|
||||||
|
block.isDraggable = true;
|
||||||
|
inps = block.inputs();
|
||||||
|
for (i = 1; i < 3; i += 1) {
|
||||||
|
if (ast[i] instanceof Array) {
|
||||||
|
block.silentReplaceInput(inps[i - 1], blockFromAST(ast[i]));
|
||||||
|
} else if (isString(ast[i])) {
|
||||||
|
block.silentReplaceInput(
|
||||||
|
inps[i - 1],
|
||||||
|
myself.variableBlock(ast[i])
|
||||||
|
);
|
||||||
|
} else { // number
|
||||||
|
inps[i - 1].setContents(ast[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
block.fixLayout();
|
||||||
|
block.fixBlockColor(null, true);
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expressionString > 100) {return null; }
|
||||||
|
try {
|
||||||
|
ast = parseInfix(expressionString);
|
||||||
|
return ast instanceof Array ? blockFromAST(ast) : null;
|
||||||
|
} catch (error) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// SpriteMorph variable management
|
// SpriteMorph variable management
|
||||||
|
|
||||||
SpriteMorph.prototype.addVariable = function (name, isGlobal) {
|
SpriteMorph.prototype.addVariable = function (name, isGlobal) {
|
||||||
|
|
Ładowanie…
Reference in New Issue