diff --git a/src/common/Spine.ts b/src/common/Spine.ts index 19b50d3c..7fefd105 100644 --- a/src/common/Spine.ts +++ b/src/common/Spine.ts @@ -1,4 +1,4 @@ -import { type IR, isOp, op } from "../IR"; +import { type IR, isOp, op, isOfKind, block } from "../IR"; import { type CompilationContext } from "./compile"; import { getChild, getChildFragments, type PathFragment } from "./fragments"; import { replaceAtIndex } from "./arrays"; @@ -70,26 +70,29 @@ export class Spine { if (this.parent === null || this.pathFragment === null) { return new Spine(newNode, null, null); } - if (newNode.kind === "Block" && this.parent.node.kind === "Block") { - throw new Error( - `Programming error: attempt to insert a Block into a Block`, - ); - } const parentNode = this.parent.node; const parent = canonizeAndReturnRoot && - isOp()(parentNode) && + isOfKind("Op", "Block")(parentNode) && typeof this.pathFragment === "object" ? this.parent.replacedWith( { - ...op( - parentNode.op, - ...replaceAtIndex( - parentNode.args, - this.pathFragment.index, - newNode, - ), - ), + ...(isOp()(parentNode) + ? op( + parentNode.op, + ...replaceAtIndex( + parentNode.args, + this.pathFragment.index, + newNode, + ), + ) + : block( + replaceAtIndex( + parentNode.children, + this.pathFragment.index, + newNode, + ), + )), targetType: parentNode.targetType, }, true, @@ -144,8 +147,8 @@ export class Spine { // eslint-disable-next-line @typescript-eslint/no-this-alias let curr = this as Spine; // recurse on children - if (isOp()(this.node)) { - // Create canonical Op instead of just replacing the chidren + if (isOfKind("Op", "Block")(this.node)) { + // Create canonical Op / block instead of just replacing the chidren const newChildren: IR.Node[] = []; let someChildrenIsNew = false; for (const child of this.getChildSpines()) { @@ -155,7 +158,9 @@ export class Spine { } if (someChildrenIsNew) curr = curr.replacedWith({ - ...op(this.node.op, ...newChildren), + ...(isOp()(this.node) + ? op(this.node.op, ...newChildren) + : block(newChildren)), targetType: this.node.targetType, }); } else { diff --git a/src/plugins/loops.test.md b/src/plugins/loops.test.md index 219349e1..50790c2f 100644 --- a/src/plugins/loops.test.md +++ b/src/plugins/loops.test.md @@ -28,6 +28,30 @@ for_c_like ($i <- 0) ($i < 10) ($i <- (1 + $i)) ( ); ``` +## For range to while, inside a block + +```polygolf +for $i 0 10 { + print_int $x; +}; +for $j 1 11 { + print_int $y; +}; +``` + +```polygolf loops.forRangeToWhile +$i <- 0; +while ($i < 10) { + print_int $x; + $i <- (1 + $i); +}; +$j <- 1; +while ($j < 11) { + print_int $y; + $j <- (1 + $j); +}; +``` + ## For each ```polygolf