[hir] implement assignment expressions
Implements assignment expressions with operators other than `=` (such as `+=`) by lowering to an assignment. I think this isn't fully correct for something like `a.b.c += 1`, but it seems like there's more gaps in object accesses.
Jan Kassens committed
Nov 14, 2022 at 10:58 UTC
99181160d56ac573b7dc5cfb7291dfb3634c94db
3 files changed
+158
-3
compiler/forget/src/HIR/BuildHIR.ts
+40
-3
@@ -901,13 +901,50 @@ function lowerExpression(
901
case "AssignmentExpression": {
902
const expr = exprPath as NodePath<t.AssignmentExpression>;
903
const left = lowerLVal(builder, expr.get("left"));
904
- const right = lowerExpression(builder, expr.get("right"));
904
const operator = expr.node.operator;
906
- todoInvariant(operator === "=", "todo: support non-simple assignment");
905
+
906
+ if (operator === "=") {
907
+ const right = lowerExpression(builder, expr.get("right"));
908
+ builder.push({
909
+ id: 0,
910
+ lvalue: { place: left, kind: InstructionKind.Reassign },
911
+ value: right,
912
+ loc: exprLoc,
913
+ });
914
+ return left;
915
+ }
916
+
917
+ const operators: { [key: string]: t.BinaryExpression["operator"] } = {
918
+ "+=": "+",
919
+ "-=": "-",
920
+ "/=": "/",
921
+ "%=": "%",
922
+ "*=": "*",
923
+ "**=": "**",
924
+ "&=": "&",
925
+ "|=": "|",
926
+ ">>=": ">>",
927
+ ">>>=": ">>>",
928
+ "<<=": "<<",
929
+ "^=": "^",
930
+ };
931
+ const binaryOperator = operators[operator];
932
+ invariant(
933
+ binaryOperator != null,
934
+ `Unhandled assignment operator '${operator}'`
935
+ );
936
+
937
+ const right = lowerExpressionToPlace(builder, expr.get("right"));
938
builder.push({
939
id: 0,
940
lvalue: { place: left, kind: InstructionKind.Reassign },
910
- value: right,
941
+ value: {
942
+ kind: "BinaryExpression",
943
+ operator: binaryOperator,
944
+ left,
945
+ right,
946
+ loc: exprLoc,
947
+ },
948
loc: exprLoc,
949
});
950
return left;
compiler/forget/src/__tests__/fixtures/hir/assignment-variations.expect.md
new
+107
@@ -0,0 +1,107 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function f() {
6
+ let x = 1;
7
+ x = x + 1;
8
+ x += 1;
9
+ x >>>= 1;
10
+}
11
+
12
+function g(a) {
13
+ a.b.c = a.b.c + 1;
14
+ a.b.c *= 2;
15
+}
16
+
17
+```
18
+
19
+## HIR
20
+
21
+```
22
+bb0:
23
+ [1] Let mutate x$5 = 1
24
+ [2] Const mutate $6 = 1
25
+ [3] Reassign mutate x$7 = Binary read x$5 + read $6
26
+ [4] Const mutate $8 = 1
27
+ [5] Reassign mutate x$9 = Binary read x$7 + read $8
28
+ [6] Const mutate $10 = 1
29
+ [7] Reassign mutate x$11 = Binary read x$9 >>> read $10
30
+ Return
31
+```
32
+
33
+### CFG
34
+
35
+```mermaid
36
+flowchart TB
37
+ %% Basic Blocks
38
+ subgraph bb0
39
+ bb0_instrs["
40
+ [1] Let mutate x$5 = 1
41
+ [2] Const mutate $6 = 1
42
+ [3] Reassign mutate x$7 = Binary read x$5 + read $6
43
+ [4] Const mutate $8 = 1
44
+ [5] Reassign mutate x$9 = Binary read x$7 + read $8
45
+ [6] Const mutate $10 = 1
46
+ [7] Reassign mutate x$11 = Binary read x$9 >>> read $10
47
+ "]
48
+ bb0_instrs --> bb0_terminal(["Return"])
49
+ end
50
+
51
+ %% Jumps
52
+ %% empty
53
+```
54
+
55
+## Code
56
+
57
+```javascript
58
+function f$0() {
59
+ let x$5 = 1;
60
+ x$7 = x$5 + 1;
61
+ x$9 = x$7 + 1;
62
+ x$11 = x$9 >>> 1;
63
+ return;
64
+}
65
+
66
+```
67
+## HIR
68
+
69
+```
70
+bb0:
71
+ [1] Const mutate $5 = 1
72
+ [2] Reassign mutate a$4.b.c[0:4] = Binary read a$4.b.c + read $5
73
+ [3] Const mutate $6 = 2
74
+ [4] Reassign mutate a$4.b.c[0:4] = Binary read a$4.b.c * read $6
75
+ Return
76
+```
77
+
78
+### CFG
79
+
80
+```mermaid
81
+flowchart TB
82
+ %% Basic Blocks
83
+ subgraph bb0
84
+ bb0_instrs["
85
+ [1] Const mutate $5 = 1
86
+ [2] Reassign mutate a$4.b.c[0:4] = Binary read a$4.b.c + read $5
87
+ [3] Const mutate $6 = 2
88
+ [4] Reassign mutate a$4.b.c[0:4] = Binary read a$4.b.c * read $6
89
+ "]
90
+ bb0_instrs --> bb0_terminal(["Return"])
91
+ end
92
+
93
+ %% Jumps
94
+ %% empty
95
+```
96
+
97
+## Code
98
+
99
+```javascript
100
+function g$0(a$4) {
101
+ a$4 = a$4.b.c + 1;
102
+ a$4 = a$4.b.c * 2;
103
+ return;
104
+}
105
+
106
+```
107
+
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/assignment-variations.js
new
+11
@@ -0,0 +1,11 @@
1
+function f() {
2
+ let x = 1;
3
+ x = x + 1;
4
+ x += 1;
5
+ x >>>= 1;
6
+}
7
+
8
+function g(a) {
9
+ a.b.c = a.b.c + 1;
10
+ a.b.c *= 2;
11
+}