mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
[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:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user