diff --git a/compiler/forget/src/HIR/HIR.ts b/compiler/forget/src/HIR/HIR.ts index 037c8934d4..0e2165b531 100644 --- a/compiler/forget/src/HIR/HIR.ts +++ b/compiler/forget/src/HIR/HIR.ts @@ -165,7 +165,7 @@ export type ReactiveSwitchTerminal = { }; export type ReactiveWhileTerminal = { kind: "while"; - test: ReactiveValueBlock; + test: ReactiveValue; loop: ReactiveBlock; id: InstructionId; }; diff --git a/compiler/forget/src/ReactiveScopes/BuildReactiveFunction.ts b/compiler/forget/src/ReactiveScopes/BuildReactiveFunction.ts index 389098197d..009731a29b 100644 --- a/compiler/forget/src/ReactiveScopes/BuildReactiveFunction.ts +++ b/compiler/forget/src/ReactiveScopes/BuildReactiveFunction.ts @@ -253,16 +253,11 @@ class Driver { ); scheduleIds.push(scheduleId); - const testBlock = this.cx.ir.blocks.get(terminal.test)!; - const testTerminal = testBlock.terminal; - invariant( - testTerminal.kind === "branch", - "Expected while loop test block to end in an if" - ); - const testValue = this.visitValueBlock(blockValue, testBlock, { - value: testTerminal.test, - id: testTerminal.id, - }); + const testValue = this.visitValueBlockNew( + terminal.test, + terminal.loc + ).value; + let loopBody: ReactiveBlock; if (loopId) { loopBody = this.traverseBlock(this.cx.ir.blocks.get(loopId)!); diff --git a/compiler/forget/src/ReactiveScopes/CodegenReactiveFunction.ts b/compiler/forget/src/ReactiveScopes/CodegenReactiveFunction.ts index d341fc23ee..c130a35944 100644 --- a/compiler/forget/src/ReactiveScopes/CodegenReactiveFunction.ts +++ b/compiler/forget/src/ReactiveScopes/CodegenReactiveFunction.ts @@ -299,7 +299,7 @@ function codegenTerminal( return t.throwStatement(codegenPlace(cx, terminal.value)); } case "while": { - const test = codegenValueBlock(cx, terminal.test); + const test = codegenInstructionValue(cx, terminal.test); return t.whileStatement(test, codegenBlock(cx, terminal.loop)); } default: { diff --git a/compiler/forget/src/ReactiveScopes/PrintReactiveFunction.ts b/compiler/forget/src/ReactiveScopes/PrintReactiveFunction.ts index 32e3991b22..6820883987 100644 --- a/compiler/forget/src/ReactiveScopes/PrintReactiveFunction.ts +++ b/compiler/forget/src/ReactiveScopes/PrintReactiveFunction.ts @@ -192,7 +192,7 @@ function printTerminal(writer: Writer, terminal: ReactiveTerminal): void { } case "while": { writer.writeLine(`[${terminal.id}] while (`); - printValueBlock(writer, terminal.test); + printReactiveValue(writer, terminal.test); writer.writeLine(") {"); printReactiveInstructions(writer, terminal.loop); writer.writeLine("}"); diff --git a/compiler/forget/src/ReactiveScopes/PropagateScopeDependencies.ts b/compiler/forget/src/ReactiveScopes/PropagateScopeDependencies.ts index 6c9400fbe1..8cac6ff45b 100644 --- a/compiler/forget/src/ReactiveScopes/PropagateScopeDependencies.ts +++ b/compiler/forget/src/ReactiveScopes/PropagateScopeDependencies.ts @@ -21,6 +21,7 @@ import { ReactiveValue, ReactiveValueBlock, } from "../HIR/HIR"; +import { eachInstructionValueOperand } from "../HIR/visitors"; import { assertExhaustive } from "../Utils/utils"; import { eachReactiveValueOperand } from "./visitors"; @@ -101,6 +102,20 @@ class Context { this.visitDependency({ place, path: null }); } + visitProperty(object: Place, property: string): void { + const objectDependency = this.#properties.get(object.identifier); + let nextDependency: ReactiveScopeDependency; + if (objectDependency === undefined) { + nextDependency = { place: object, path: [property] }; + } else { + nextDependency = { + place: objectDependency.place, + path: [...(objectDependency.path ?? []), property], + }; + } + this.visitDependency(nextDependency); + } + visitDependency(dependency: ReactiveScopeDependency): void { let maybeDependency: ReactiveScopeDependency; if (dependency.path !== null) { @@ -222,7 +237,7 @@ function visit(context: Context, block: ReactiveBlock): void { break; } case "while": { - visitValueBlock(context, terminal.test); + visitReactiveValue(context, terminal.test); visit(context, terminal.loop); break; } @@ -266,17 +281,49 @@ function visitValueBlock(context: Context, block: ReactiveValueBlock): void { } } if (block.last !== null) { - visitReactiveValue(context, block.last.value, null); + visitInstructionValue(context, block.last.value, null); } } -function visitReactiveValue( +function visitReactiveValue(context: Context, value: ReactiveValue): void { + switch (value.kind) { + case "LogicalExpression": { + visitReactiveValue(context, value.left); + visitReactiveValue(context, value.right); + break; + } + case "ConditionalExpression": { + visitReactiveValue(context, value.test); + visitReactiveValue(context, value.consequent); + visitReactiveValue(context, value.alternate); + break; + } + case "SequenceExpression": { + for (const instr of value.instructions) { + visitInstruction(context, instr); + } + visitInstructionValue(context, value.value, null); + break; + } + default: { + for (const operand of eachInstructionValueOperand(value)) { + context.visitOperand(operand); + } + } + } +} + +function visitInstructionValue( context: Context, value: ReactiveValue, lvalue: LValue | null ): void { - if (value.kind === "PropertyLoad" && lvalue !== null) { - context.declareProperty(lvalue.place, value.object, value.property); + if (value.kind === "PropertyLoad") { + if (lvalue !== null) { + context.declareProperty(lvalue.place, value.object, value.property); + } else { + context.visitProperty(value.object, value.property); + } } else { for (const operand of eachReactiveValueOperand(value)) { context.visitOperand(operand); @@ -286,7 +333,7 @@ function visitReactiveValue( function visitInstruction(context: Context, instr: ReactiveInstruction): void { const { lvalue } = instr; - visitReactiveValue(context, instr.value, lvalue); + visitInstructionValue(context, instr.value, lvalue); if (lvalue !== null && lvalue.kind !== InstructionKind.Reassign) { const range = lvalue.place.identifier.mutableRange; // TODO: only assign Const if the value is never reassigned diff --git a/compiler/forget/src/ReactiveScopes/visitors.ts b/compiler/forget/src/ReactiveScopes/visitors.ts index c859930ffe..0bddd3f294 100644 --- a/compiler/forget/src/ReactiveScopes/visitors.ts +++ b/compiler/forget/src/ReactiveScopes/visitors.ts @@ -40,8 +40,30 @@ export class ReactiveFunctionVisitor { this.traverseValue(id, value, state); } traverseValue(id: InstructionId, value: ReactiveValue, state: TState): void { - for (const place of eachReactiveValueOperand(value)) { - this.visitPlace(id, place, state); + switch (value.kind) { + case "LogicalExpression": { + this.visitValue(id, value.left, state); + this.visitValue(id, value.right, state); + break; + } + case "ConditionalExpression": { + this.visitValue(id, value.test, state); + this.visitValue(id, value.consequent, state); + this.visitValue(id, value.alternate, state); + break; + } + case "SequenceExpression": { + for (const instr of value.instructions) { + this.visitInstruction(instr, state); + } + this.visitValue(id, value.value, state); + break; + } + default: { + for (const place of eachReactiveValueOperand(value)) { + this.visitPlace(id, place, state); + } + } } } @@ -87,7 +109,7 @@ export class ReactiveFunctionVisitor { break; } case "while": { - this.visitValueBlock(terminal.test, state); + this.visitValue(terminal.id, terminal.test, state); this.visitBlock(terminal.loop, state); break; } @@ -318,7 +340,8 @@ export function eachTerminalBlock( break; } case "while": { - visitValueBlock(terminal.test); + // TODO + // visitValueBlock(terminal.test); visitBlock(terminal.loop); break; } diff --git a/compiler/forget/src/__tests__/fixtures/hir/error.while-with-assignment-in-test.expect.md b/compiler/forget/src/__tests__/fixtures/hir/error.while-with-assignment-in-test.expect.md index 5dc68ff63f..70ac4bf9a0 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/error.while-with-assignment-in-test.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/error.while-with-assignment-in-test.expect.md @@ -19,7 +19,7 @@ function f(reader) { ## Error ``` -TODO: Handle conversion of VariableDeclaration to expression +TODO: Cannot declare variables in a value block, tried to declare 'value$0' ``` \ No newline at end of file diff --git a/compiler/forget/src/__tests__/fixtures/hir/ternary-expression.expect.md b/compiler/forget/src/__tests__/fixtures/hir/ternary-expression.expect.md index c10d292ccc..ffd55cfbfd 100644 --- a/compiler/forget/src/__tests__/fixtures/hir/ternary-expression.expect.md +++ b/compiler/forget/src/__tests__/fixtures/hir/ternary-expression.expect.md @@ -39,7 +39,7 @@ function ternary(props) { const c_5 = $[5] !== b; let t6; if (c_4 || c_5) { - t6 = a ? b : null; + t6 = a ? b : (null, null); $[4] = a; $[5] = b; $[6] = t6;