diff --git a/HISTORY.md b/HISTORY.md index b2ec2383..f8b9f699 100755 --- a/HISTORY.md +++ b/HISTORY.md @@ -69,6 +69,9 @@ * Chinese, thanks, Simon! * Brazilian Portuguese, thank you, Cassiano D'Andrea! +### 2021-12-08 +* blocks: refactored syntax trees + ### 2021-12-07 * objects: backwards-compatibility fix for key-event hat blocks * store, objects: load category-less custom blocks into "other" diff --git a/snap.html b/snap.html index 41c7d3f1..eda60868 100755 --- a/snap.html +++ b/snap.html @@ -16,7 +16,7 @@ - + diff --git a/src/blocks.js b/src/blocks.js index ef8975c8..00e2159c 100644 --- a/src/blocks.js +++ b/src/blocks.js @@ -160,7 +160,7 @@ CustomCommandBlockMorph, ToggleButtonMorph, DialMorph, SnapExtensions*/ // Global stuff //////////////////////////////////////////////////////// -modules.blocks = '2021-December-06'; +modules.blocks = '2021-December-08'; var SyntaxElementMorph; var BlockMorph; @@ -3721,8 +3721,72 @@ BlockMorph.prototype.exportResultPic = function () { // BlockMorph components - EXPERIMENTAL -BlockMorph.prototype.components = function () { - throw new Error('subclass responsility'); +BlockMorph.prototype.components = function (parameterNames = []) { + if (this instanceof ReporterBlockMorph) { + return this.syntaxTree(parameterNames); + } + var seq = new List(this.blockSequence()).map((block, i) => + block.syntaxTree(i < 1 ? parameterNames : []) + ); + return seq.length() === 1 ? seq.at(1) : seq; +}; + +BlockMorph.prototype.syntaxTree = function (parameterNames) { + var expr = this.fullCopy(), + nb = expr.nextBlock ? expr.nextBlock() : null, + inputs, parts; + if (nb) { + nb.destroy(); + } + expr.fixBlockColor(null, true); + inputs = expr.inputs(); + parts = new List([expr.reify()]); + inputs.forEach(inp => { + var val; + if (inp instanceof BlockMorph) { + if (inp instanceof RingMorph && inp.isEmptySlot()) { + parts.add(); + return; + } + parts.add(inp.components()); + expr.revertToDefaultInput(inp, true); + } else if (inp.isEmptySlot()) { + if (!inp.isStatic) { + parts.add(); + expr.revertToDefaultInput(inp, true); + } + } else if (inp instanceof MultiArgMorph) { + inp.inputs().forEach((slot, i) => { + var entry; + if (slot instanceof BlockMorph) { + if (slot instanceof RingMorph && slot.isEmptySlot()) { + parts.add(); + return; + } + parts.add(slot.components()); + } else if (slot.isEmptySlot()) { + parts.add(); + } else { + entry = slot.evaluate(); + parts.add(entry instanceof BlockMorph ? + entry.components() : entry); + } + if (!(slot instanceof TemplateSlotMorph)) { + inp.revertToDefaultInput(slot, true); + } + }); + } else if (inp instanceof ArgLabelMorph) { + parts.add(inp.argMorph().components()); + expr.revertToDefaultInput(inp, true).collapseAll(); + } else { + val = inp.evaluate(); + parts.add(val instanceof BlockMorph ? val.components() : val); + expr.revertToDefaultInput(inp, true); + } + }); + parts.at(1).updateEmptySlots(); + parameterNames.forEach(name => parts.add(name)); + return parts; }; BlockMorph.prototype.equalTo = function (other) { @@ -3815,6 +3879,19 @@ BlockMorph.prototype.copyWithInputs = function (inputs) { return cpy.reify(dta.slice(count)); }; +BlockMorph.prototype.copyWithNext = function (next, parameterNames) { + var expr = this.fullCopy(), + top; + if (this instanceof ReporterBlockMorph) { + return expr.reify(); + } + top = next.fullCopy().topBlock(); + if (top instanceof CommandBlockMorph) { + expr.bottomBlock().nextBlock(top); + } + return expr.reify(parameterNames); +}; + BlockMorph.prototype.reify = function (inputNames) { // private - assumes that I've already been deep copied var context = new Context(); @@ -5558,80 +5635,6 @@ CommandBlockMorph.prototype.extract = function () { } }; -// CommandBlockMorph components - EXPERIMENTAL - -CommandBlockMorph.prototype.components = function (parameterNames = []) { - var seq = new List(this.blockSequence()).map(block => { - var expr = block.fullCopy(), - nb = expr.nextBlock(), - inputs, parts; - if (nb) { - nb.destroy(); - } - expr.fixBlockColor(null, true); - inputs = expr.inputs(); - parts = new List([expr.reify()]); - inputs.forEach(inp => { - var val; - if (inp instanceof BlockMorph) { - if (inp instanceof RingMorph && inp.isEmptySlot()) { - parts.add(); - return; - } - parts.add(inp.components()); - expr.revertToDefaultInput(inp, true); - } else if (inp.isEmptySlot()) { - if (!inp.isStatic) { - parts.add(); - expr.revertToDefaultInput(inp, true); - } - } else if (inp instanceof MultiArgMorph) { - inp.inputs().forEach((slot, i) => { - var entry; - if (slot instanceof BlockMorph) { - if (slot instanceof RingMorph && slot.isEmptySlot()) { - parts.add(); - return; - } - parts.add(slot.components()); - } else if (slot.isEmptySlot()) { - parts.add(); - } else { - entry = slot.evaluate(); - parts.add(entry instanceof BlockMorph ? - entry.components() : entry); - } - if (!(slot instanceof TemplateSlotMorph)) { - inp.revertToDefaultInput(slot, true); - } - }); - } else if (inp instanceof ArgLabelMorph) { - parts.add(inp.argMorph().components()); - expr.revertToDefaultInput(inp, true).collapseAll(); - } else { - val = inp.evaluate(); - parts.add(val instanceof BlockMorph ? val.components() : val); - expr.revertToDefaultInput(inp, true); - } - }); - parts.at(1).updateEmptySlots(); - parameterNames.forEach(name => parts.add(name)); - return parts; - }); - return seq.length() === 1 ? seq.at(1) : seq; -}; - -CommandBlockMorph.prototype.copyWithNext = function (next, parameterNames) { - var exp = this.fullCopy(), - bottom = exp.bottomBlock(), - top = next.fullCopy().topBlock(); - - if (top instanceof CommandBlockMorph) { - bottom.nextBlock(top); - } - return exp.reify(parameterNames); -}; - // CommandBlockMorph drawing: CommandBlockMorph.prototype.outlinePath = function(ctx, inset) { @@ -6406,66 +6409,6 @@ ReporterBlockMorph.prototype.userDestroy = function () { this.destroy(); }; -// ReporterBlockMorph components - EXPERIMENTAL - -ReporterBlockMorph.prototype.components = function (parameterNames = []) { - var expr = this.fullCopy(), - inputs = expr.inputs(), - parts; - expr.fixBlockColor(null, true); - parts = new List([expr.reify()]); - inputs.forEach(inp => { - var val; - if (inp instanceof BlockMorph) { - if (inp instanceof RingMorph && inp.isEmptySlot()) { - parts.add(); - return; - } - parts.add(inp.components()); - expr.revertToDefaultInput(inp, true); - } else if (inp.isEmptySlot()) { - if (!inp.isStatic) { - parts.add(); - expr.revertToDefaultInput(inp, true); - } - } else if (inp instanceof MultiArgMorph) { - inp.inputs().forEach((slot, i) => { - var entry; - if (slot instanceof BlockMorph) { - if (slot instanceof RingMorph && slot.isEmptySlot()) { - parts.add(); - return; - } - parts.add(slot.components()); - } else if (slot.isEmptySlot()) { - parts.add(); - } else { - entry = slot.evaluate(); - parts.add(entry instanceof BlockMorph ? - entry.components() : entry); - } - if (!(slot instanceof TemplateSlotMorph)) { - inp.revertToDefaultInput(slot, true); - } - }); - } else if (inp instanceof ArgLabelMorph) { - parts.add(inp.argMorph().components()); - expr.revertToDefaultInput(inp, true).collapseAll(); - } else { - val = inp.evaluate(); - parts.add(val instanceof BlockMorph ? val.components() : val); - expr.revertToDefaultInput(inp, true); - } - }); - parameterNames.forEach(name => parts.add(name)); - parts.at(1).updateEmptySlots(); - return parts; -}; - -ReporterBlockMorph.prototype.copyWithNext = function (next) { - return this.fullCopy().reify(); -}; - // ReporterBlockMorph drawing: ReporterBlockMorph.prototype.outlinePath = function (ctx, inset) {