diff --git a/compiler/forget/src/HIR/BuildHIR.ts b/compiler/forget/src/HIR/BuildHIR.ts index 282bd15d68..7538415039 100644 --- a/compiler/forget/src/HIR/BuildHIR.ts +++ b/compiler/forget/src/HIR/BuildHIR.ts @@ -901,13 +901,50 @@ function lowerExpression( case "AssignmentExpression": { const expr = exprPath as NodePath; const left = lowerLVal(builder, expr.get("left")); - const right = lowerExpression(builder, expr.get("right")); const operator = expr.node.operator; - todoInvariant(operator === "=", "todo: support non-simple assignment"); + + if (operator === "=") { + const right = lowerExpression(builder, expr.get("right")); + builder.push({ + id: 0, + lvalue: { place: left, kind: InstructionKind.Reassign }, + value: right, + loc: exprLoc, + }); + return left; + } + + const operators: { [key: string]: t.BinaryExpression["operator"] } = { + "+=": "+", + "-=": "-", + "/=": "/", + "%=": "%", + "*=": "*", + "**=": "**", + "&=": "&", + "|=": "|", + ">>=": ">>", + ">>>=": ">>>", + "<<=": "<<", + "^=": "^", + }; + const binaryOperator = operators[operator]; + invariant( + binaryOperator != null, + `Unhandled assignment operator '${operator}'` + ); + + const right = lowerExpressionToPlace(builder, expr.get("right")); builder.push({ id: 0, lvalue: { place: left, kind: InstructionKind.Reassign }, - value: right, + value: { + kind: "BinaryExpression", + operator: binaryOperator, + left, + right, + loc: exprLoc, + }, loc: exprLoc, }); return left; diff --git a/compiler/forget/src/__tests__/fixtures/hir/assignment-variations.expect.md b/compiler/forget/src/__tests__/fixtures/hir/assignment-variations.expect.md new file mode 100644 index 0000000000..2817fd9b69 --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/assignment-variations.expect.md @@ -0,0 +1,107 @@ + +## Input + +```javascript +function f() { + let x = 1; + x = x + 1; + x += 1; + x >>>= 1; +} + +function g(a) { + a.b.c = a.b.c + 1; + a.b.c *= 2; +} + +``` + +## HIR + +``` +bb0: + [1] Let mutate x$5 = 1 + [2] Const mutate $6 = 1 + [3] Reassign mutate x$7 = Binary read x$5 + read $6 + [4] Const mutate $8 = 1 + [5] Reassign mutate x$9 = Binary read x$7 + read $8 + [6] Const mutate $10 = 1 + [7] Reassign mutate x$11 = Binary read x$9 >>> read $10 + Return +``` + +### CFG + +```mermaid +flowchart TB + %% Basic Blocks + subgraph bb0 + bb0_instrs[" + [1] Let mutate x$5 = 1 + [2] Const mutate $6 = 1 + [3] Reassign mutate x$7 = Binary read x$5 + read $6 + [4] Const mutate $8 = 1 + [5] Reassign mutate x$9 = Binary read x$7 + read $8 + [6] Const mutate $10 = 1 + [7] Reassign mutate x$11 = Binary read x$9 >>> read $10 + "] + bb0_instrs --> bb0_terminal(["Return"]) + end + + %% Jumps + %% empty +``` + +## Code + +```javascript +function f$0() { + let x$5 = 1; + x$7 = x$5 + 1; + x$9 = x$7 + 1; + x$11 = x$9 >>> 1; + return; +} + +``` +## HIR + +``` +bb0: + [1] Const mutate $5 = 1 + [2] Reassign mutate a$4.b.c[0:4] = Binary read a$4.b.c + read $5 + [3] Const mutate $6 = 2 + [4] Reassign mutate a$4.b.c[0:4] = Binary read a$4.b.c * read $6 + Return +``` + +### CFG + +```mermaid +flowchart TB + %% Basic Blocks + subgraph bb0 + bb0_instrs[" + [1] Const mutate $5 = 1 + [2] Reassign mutate a$4.b.c[0:4] = Binary read a$4.b.c + read $5 + [3] Const mutate $6 = 2 + [4] Reassign mutate a$4.b.c[0:4] = Binary read a$4.b.c * read $6 + "] + bb0_instrs --> bb0_terminal(["Return"]) + end + + %% Jumps + %% empty +``` + +## Code + +```javascript +function g$0(a$4) { + a$4 = a$4.b.c + 1; + a$4 = a$4.b.c * 2; + return; +} + +``` + \ No newline at end of file diff --git a/compiler/forget/src/__tests__/fixtures/hir/assignment-variations.js b/compiler/forget/src/__tests__/fixtures/hir/assignment-variations.js new file mode 100644 index 0000000000..a5385a78e1 --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/hir/assignment-variations.js @@ -0,0 +1,11 @@ +function f() { + let x = 1; + x = x + 1; + x += 1; + x >>>= 1; +} + +function g(a) { + a.b.c = a.b.c + 1; + a.b.c *= 2; +}