[valueblocks] While.test is a proper value block

Changes ReactiveWhileTerminal’s test to use the new value block representation. 
This means logical and condition expressions will work as while test values now.
This commit is contained in:
Joe Savona
2023-01-31 13:39:38 -08:00
parent 50f300bc92
commit 90e1265442
8 changed files with 90 additions and 25 deletions
+1 -1
View File
@@ -165,7 +165,7 @@ export type ReactiveSwitchTerminal = {
};
export type ReactiveWhileTerminal = {
kind: "while";
test: ReactiveValueBlock;
test: ReactiveValue;
loop: ReactiveBlock;
id: InstructionId;
};
@@ -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)!);
@@ -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: {
@@ -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("}");
@@ -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
+27 -4
View File
@@ -40,8 +40,30 @@ export class ReactiveFunctionVisitor<TState = void> {
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<TState = void> {
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;
}
@@ -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'
```
@@ -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;