Partial support for update expressions

Adds limited support for UpdateExpressions (`x++`). We now support the postfix 
form (`x++` ok, `++x` is a todo) and only when the argument is an identifier. We 
can relax these restrictions with more work, but this PR should be sufficient 
for the examples we've seen so far.
This commit is contained in:
Joe Savona
2023-02-02 07:53:24 -08:00
parent 7a92b2fe5d
commit de929fcc40
7 changed files with 142 additions and 4 deletions
+49
View File
@@ -1405,6 +1405,55 @@ function lowerExpression(
loc: exprLoc,
};
}
case "UpdateExpression": {
let expr = exprPath as NodePath<t.UpdateExpression>;
const argument = expr.get("argument");
if (!argument.isIdentifier()) {
builder.errors.push({
reason: `(BuildHIR::lowerExpression) Handle UpdateExpression with ${argument.type} argument`,
severity: ErrorSeverity.Todo,
nodePath: exprPath,
});
return { kind: "UnsupportedNode", node: exprNode, loc: exprLoc };
}
if (expr.node.prefix) {
builder.errors.push({
reason: `(BuildHIR::lowerExpression) Handle prefix UpdateExpression`,
severity: ErrorSeverity.Todo,
nodePath: exprPath,
});
return { kind: "UnsupportedNode", node: exprNode, loc: exprLoc };
}
const temp = buildTemporaryPlace(
builder,
expr.node.loc ?? GeneratedSource
);
builder.push({
id: makeInstructionId(0),
lvalue: { place: { ...temp }, kind: InstructionKind.Const },
value: {
kind: "Primitive",
value: 1,
loc: expr.node.loc ?? GeneratedSource,
},
loc: expr.node.loc ?? GeneratedSource,
});
const identifier = argument as NodePath<t.Identifier>;
const place = lowerExpressionToPlace(builder, identifier);
builder.push({
id: makeInstructionId(0),
lvalue: { place: { ...place }, kind: InstructionKind.Reassign },
value: {
kind: "BinaryExpression",
operator: expr.node.operator === "++" ? "+" : "-",
left: { ...place },
right: { ...temp },
loc: exprLoc,
},
loc: exprLoc,
});
return place;
}
default: {
builder.errors.push({
reason: `(BuildHIR::lowerExpression) Handle ${exprPath.type} expressions`,
@@ -52,6 +52,12 @@ function foo([a, b], { c, d, e = "e" }, f = "f", ...args) {
}
do {} while (i < 3);
let updateIdentifier = 0;
--updateIdentifier;
++updateIdentifier;
updateIdentifier.y++;
updateIdentifier.y--;
}
```
@@ -327,8 +333,44 @@ function foo([a, b], { c, d, e = "e" }, f = "f", ...args) {
49 |
> 50 | do {} while (i < 3);
| ^^^^^^^^^^^^^^^^^^^^
51 | }
52 |
51 |
52 | let updateIdentifier = 0;
53 | --updateIdentifier;
[ReactForget] TodoError: (BuildHIR::lowerExpression) Handle prefix UpdateExpression
51 |
52 | let updateIdentifier = 0;
> 53 | --updateIdentifier;
| ^^^^^^^^^^^^^^^^^^
54 | ++updateIdentifier;
55 | updateIdentifier.y++;
56 | updateIdentifier.y--;
[ReactForget] TodoError: (BuildHIR::lowerExpression) Handle prefix UpdateExpression
52 | let updateIdentifier = 0;
53 | --updateIdentifier;
> 54 | ++updateIdentifier;
| ^^^^^^^^^^^^^^^^^^
55 | updateIdentifier.y++;
56 | updateIdentifier.y--;
57 | }
[ReactForget] TodoError: (BuildHIR::lowerExpression) Handle UpdateExpression with MemberExpression argument
53 | --updateIdentifier;
54 | ++updateIdentifier;
> 55 | updateIdentifier.y++;
| ^^^^^^^^^^^^^^^^^^^^
56 | updateIdentifier.y--;
57 | }
58 |
[ReactForget] TodoError: (BuildHIR::lowerExpression) Handle UpdateExpression with MemberExpression argument
54 | ++updateIdentifier;
55 | updateIdentifier.y++;
> 56 | updateIdentifier.y--;
| ^^^^^^^^^^^^^^^^^^^^
57 | }
58 |
```
@@ -48,4 +48,10 @@ function foo([a, b], { c, d, e = "e" }, f = "f", ...args) {
}
do {} while (i < 3);
let updateIdentifier = 0;
--updateIdentifier;
++updateIdentifier;
updateIdentifier.y++;
updateIdentifier.y--;
}
@@ -4,7 +4,7 @@
```javascript
function foo() {
let x = 1;
for (let i = 0; i < 10; i += 1) {
for (let i = 0; i < 10; i++) {
x += 1;
}
return x;
@@ -1,6 +1,6 @@
function foo() {
let x = 1;
for (let i = 0; i < 10; i += 1) {
for (let i = 0; i < 10; i++) {
x += 1;
}
return x;
@@ -0,0 +1,35 @@
## Input
```javascript
function foo(props) {
let x = props.x;
let y = x++;
let z = x--;
return { x, y, z };
}
```
## Code
```javascript
function foo(props) {
const $ = React.useMemoCache();
const x = props.x;
const x$0 = x + 1;
const y = x$0;
const x$1 = x$0 - 1;
const z = x$1;
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t0 = { x: x$1, y: y, z: z };
$[0] = t0;
} else {
t0 = $[0];
}
return t0;
}
```
@@ -0,0 +1,6 @@
function foo(props) {
let x = props.x;
let y = x++;
let z = x--;
return { x, y, z };
}