127
const terminal: ReturnTerminal = {
128
kind: "return",
129
loc: GeneratedSource,
130
- value: lowerExpressionToPlace(builder, body),
130
+ value: lowerExpressionToTemporary(builder, body),
131
id: makeInstructionId(0),
132
};
133
builder.terminateWithContinuation(terminal, fallthrough);
169
switch (stmtNode.type) {
170
case "ThrowStatement": {
171
const stmt = stmtPath as NodePath<t.ThrowStatement>;
172
- const value = lowerExpressionToPlace(builder, stmt.get("argument"));
172
+ const value = lowerExpressionToTemporary(builder, stmt.get("argument"));
173
const terminal: ThrowTerminal = {
174
kind: "throw",
175
value,
183
const argument = stmt.get("argument");
184
const value =
185
argument.node != null
186
- ? lowerExpressionToPlace(builder, argument as NodePath<t.Expression>)
186
+ ? lowerExpressionToTemporary(
187
+ builder,
188
+ argument as NodePath<t.Expression>
189
+ )
190
: null;
191
const terminal: ReturnTerminal = {
192
kind: "return",
228
// If there is no else clause, use the continuation directly
229
alternateBlock = continuationBlock.id;
230
}
228
- const test = lowerExpressionToPlace(builder, stmt.get("test"));
231
+ const test = lowerExpressionToTemporary(builder, stmt.get("test"));
232
const terminal: IfTerminal = {
233
kind: "if",
234
test,
356
builder.terminateWithContinuation(
357
{
358
kind: "branch",
356
- test: lowerExpressionToPlace(
359
+ test: lowerExpressionToTemporary(
360
builder,
361
test as NodePath<t.Expression>
362
),
412
* The conditional block is empty and exists solely as conditional for
413
* (re)entering or exiting the loop
414
*/
412
- const test = lowerExpressionToPlace(builder, stmt.get("test"));
415
+ const test = lowerExpressionToTemporary(builder, stmt.get("test"));
416
const terminal: BranchTerminal = {
417
kind: "branch",
418
test,
528
});
529
}
530
}
528
- test = lowerExpressionToPlace(
531
+ test = lowerExpressionToTemporary(
532
builder,
533
testExpr as NodePath<t.Expression>
534
);
552
cases.push({ test: null, block: continuationBlock.id });
553
}
554
552
- const test = lowerExpressionToPlace(builder, stmt.get("discriminant"));
555
+ const test = lowerExpressionToTemporary(
556
+ builder,
557
+ stmt.get("discriminant")
558
+ );
559
builder.terminateWithContinuation(
560
{
561
kind: "switch",
778
hasError = true;
779
continue;
780
}
775
- const value = lowerExpressionToPlace(builder, valuePath);
781
+ const value = lowerExpressionToTemporary(builder, valuePath);
782
properties.set(key.name, value);
783
}
784
return hasError
804
continue;
805
}
806
elements.push(
801
- lowerExpressionToPlace(builder, element as NodePath<t.Expression>)
807
+ lowerExpressionToTemporary(builder, element as NodePath<t.Expression>)
808
);
809
}
810
return hasError
826
});
827
return { kind: "UnsupportedNode", node: exprNode, loc: exprLoc };
828
}
823
- const callee = lowerExpressionToPlace(builder, calleePath);
829
+ const callee = lowerExpressionToTemporary(builder, calleePath);
830
let args: Place[] = [];
831
let hasError = false;
832
for (const argPath of expr.get("arguments")) {
839
hasError = true;
840
continue;
841
}
836
- args.push(lowerExpressionToPlace(builder, argPath));
842
+ args.push(lowerExpressionToTemporary(builder, argPath));
843
}
844
845
return hasError
879
hasError = true;
880
continue;
881
}
876
- args.push(lowerExpressionToPlace(builder, argPath));
882
+ args.push(lowerExpressionToTemporary(builder, argPath));
883
}
884
if (typeof property === "string") {
885
return {
899
};
900
}
901
} else {
896
- const callee = lowerExpressionToPlace(builder, calleePath);
902
+ const callee = lowerExpressionToTemporary(builder, calleePath);
903
let args: Place[] = [];
904
for (const argPath of expr.get("arguments")) {
905
if (!argPath.isExpression()) {
911
hasError = true;
912
continue;
913
}
908
- args.push(lowerExpressionToPlace(builder, argPath));
914
+ args.push(lowerExpressionToTemporary(builder, argPath));
915
}
916
return hasError
917
? { kind: "UnsupportedNode", node: exprNode, loc: exprLoc }
934
});
935
return { kind: "UnsupportedNode", node: exprNode, loc: exprLoc };
936
}
931
- const left = lowerExpressionToPlace(builder, leftPath);
932
- const right = lowerExpressionToPlace(builder, expr.get("right"));
937
+ const left = lowerExpressionToTemporary(builder, leftPath);
938
+ const right = lowerExpressionToTemporary(builder, expr.get("right"));
939
const operator = expr.node.operator;
940
return {
941
kind: "BinaryExpression",
951
952
let last: Place | null = null;
953
for (const item of expr.get("expressions")) {
948
- last = lowerExpressionToPlace(builder, item);
954
+ last = lowerExpressionToTemporary(builder, item);
955
}
956
if (last === null) {
957
builder.errors.push({
977
builder.push({
978
id: makeInstructionId(0),
979
lvalue: { kind: InstructionKind.Reassign, place: { ...place } },
974
- value: lowerExpressionToPlace(builder, expr.get("consequent")),
980
+ value: lowerExpressionToTemporary(builder, expr.get("consequent")),
981
loc: exprLoc,
982
});
983
return {
992
builder.push({
993
id: makeInstructionId(0),
994
lvalue: { kind: InstructionKind.Reassign, place: { ...place } },
989
- value: lowerExpressionToPlace(builder, expr.get("alternate")),
995
+ value: lowerExpressionToTemporary(builder, expr.get("alternate")),
996
loc: exprLoc,
997
});
998
return {
1013
},
1014
testBlock
1015
);
1010
- const testPlace = lowerExpressionToPlace(builder, expr.get("test"));
1016
+ const testPlace = lowerExpressionToTemporary(builder, expr.get("test"));
1017
builder.terminateWithContinuation(
1018
{
1019
kind: "branch",
1054
builder.push({
1055
id: makeInstructionId(0),
1056
lvalue: { kind: InstructionKind.Reassign, place: { ...place } },
1051
- value: lowerExpressionToPlace(builder, expr.get("right")),
1057
+ value: lowerExpressionToTemporary(builder, expr.get("right")),
1058
loc: exprLoc,
1059
});
1060
return {
1078
builder.push({
1079
id: makeInstructionId(0),
1080
lvalue: { kind: InstructionKind.Reassign, place: { ...leftPlace } },
1075
- value: lowerExpressionToPlace(builder, expr.get("left")),
1081
+ value: lowerExpressionToTemporary(builder, expr.get("left")),
1082
loc: exprLoc,
1083
});
1084
builder.terminateWithContinuation(
1099
1100
if (builder.currentBlockKind() === "value") {
1101
// try lowering the RHS in case it also contains errors
1096
- lowerExpressionToPlace(builder, expr.get("right"));
1102
+ lowerExpressionToTemporary(builder, expr.get("right"));
1103
builder.errors.push({
1104
reason: `(BuildHIR::lowerExpression) Handle AssignmentExpression within a LogicalExpression or ConditionalExpression`,
1105
severity: ErrorSeverity.Todo,
1115
left.node.loc ?? GeneratedSource,
1116
InstructionKind.Reassign,
1117
left,
1112
- lowerExpression(builder, expr.get("right"))
1118
+ // NOTE: it's okay not to lower to a temporary here because this is the entire RHS value, not a single operand
1119
+ lowerExpressionToPlace(builder, expr.get("right"))
1120
);
1121
}
1122
1137
const binaryOperator = operators[operator];
1138
if (binaryOperator == null) {
1139
builder.errors.push({
1133
- reason: `(BuildHIR::lowerExpression) Handle ${operator} operaators in AssignmentExpression`,
1140
+ reason: `(BuildHIR::lowerExpression) Handle ${operator} operators in AssignmentExpression`,
1141
severity: ErrorSeverity.Todo,
1142
nodePath: expr.get("operator"),
1143
});
1148
switch (leftNode.type) {
1149
case "Identifier": {
1150
const leftExpr = left as NodePath<t.Identifier>;
1144
- const place = lowerExpressionToPlace(builder, leftExpr);
1145
- const right = lowerExpressionToPlace(builder, expr.get("right"));
1151
+ const place = lowerIdentifier(builder, leftExpr);
1152
+ const right = lowerExpressionToTemporary(builder, expr.get("right"));
1153
builder.push({
1154
id: makeInstructionId(0),
1155
lvalue: { place: { ...place }, kind: InstructionKind.Reassign },
1198
kind: "BinaryExpression",
1199
operator: binaryOperator,
1200
left: { ...previousValuePlace },
1194
- right: lowerExpressionToPlace(builder, expr.get("right")),
1201
+ right: lowerExpressionToTemporary(builder, expr.get("right")),
1202
loc: leftExpr.node.loc ?? GeneratedSource,
1203
},
1204
loc: leftExpr.node.loc ?? GeneratedSource,
1259
let hasError = false;
1260
for (const attribute of opening.get("attributes")) {
1261
if (attribute.isJSXSpreadAttribute()) {
1255
- const argument = lowerExpressionToPlace(
1262
+ const argument = lowerExpressionToTemporary(
1263
builder,
1264
attribute.get("argument")
1265
);
1288
const valueExpr = attribute.get("value");
1289
let value;
1290
if (valueExpr.isJSXElement() || valueExpr.isStringLiteral()) {
1284
- value = lowerExpressionToPlace(builder, valueExpr);
1291
+ value = lowerExpressionToTemporary(builder, valueExpr);
1292
} else {
1293
if (!valueExpr.isJSXExpressionContainer()) {
1294
builder.errors.push({
1309
hasError = true;
1310
continue;
1311
}
1305
- value = lowerExpressionToPlace(builder, expression);
1312
+ value = lowerExpressionToTemporary(builder, expression);
1313
}
1314
const prop: string = name.node.name;
1315
props.push({ kind: "JsxAttribute", name: prop, place: value });
1409
1410
return {
1411
kind: "TaggedTemplateExpression",
1405
- tag: lowerExpressionToPlace(builder, expr.get("tag")),
1412
+ tag: lowerExpressionToTemporary(builder, expr.get("tag")),
1413
value,
1414
loc: exprLoc,
1415
};
1438
}
1439
1440
const subexprPlaces = subexprs.map((e) =>
1434
- lowerExpressionToPlace(builder, e as NodePath<t.Expression>)
1441
+ lowerExpressionToTemporary(builder, e as NodePath<t.Expression>)
1442
);
1443
1444
return {
1453
return {
1454
kind: "UnaryExpression",
1455
operator: expr.node.operator,
1449
- value: lowerExpressionToPlace(builder, expr.get("argument")),
1456
+ value: lowerExpressionToTemporary(builder, expr.get("argument")),
1457
loc: exprLoc,
1458
};
1459
}
1461
let expr = exprPath as NodePath<t.TypeCastExpression>;
1462
return {
1463
kind: "TypeCastExpression",
1457
- value: lowerExpressionToPlace(builder, expr.get("expression")),
1464
+ value: lowerExpressionToTemporary(builder, expr.get("expression")),
1465
type: expr.get("typeAnnotation").node,
1466
loc: exprLoc,
1467
};
1500
loc: expr.node.loc ?? GeneratedSource,
1501
});
1502
const identifier = argument as NodePath<t.Identifier>;
1496
- const place = lowerExpressionToPlace(builder, identifier);
1503
+ const place = lowerIdentifier(builder, identifier);
1504
builder.push({
1505
id: makeInstructionId(0),
1506
lvalue: { place: { ...place }, kind: InstructionKind.Reassign },
1532
): { object: Place; property: Place | string; value: InstructionValue } {
1533
const exprNode = expr.node;
1534
const exprLoc = exprNode.loc ?? GeneratedSource;
1528
- const object = lowerExpressionToPlace(builder, expr.get("object"));
1535
+ const object = lowerExpressionToTemporary(builder, expr.get("object"));
1536
const property = expr.get("property");
1537
if (!expr.node.computed) {
1538
if (!property.isIdentifier()) {
1572
},
1573
};
1574
}
1568
- const propertyPlace = lowerExpressionToPlace(builder, property);
1575
+ const propertyPlace = lowerExpressionToTemporary(builder, property);
1576
const value: InstructionValue = {
1577
kind: "ComputedLoad",
1578
object: { ...object },
1642
const exprNode = exprPath.node;
1643
const exprLoc = exprNode.loc ?? GeneratedSource;
1644
if (exprPath.isJSXElement() || exprPath.isJSXFragment()) {
1638
- return lowerExpressionToPlace(builder, exprPath);
1645
+ return lowerExpressionToTemporary(builder, exprPath);
1646
} else if (exprPath.isJSXExpressionContainer()) {
1647
const expression = exprPath.get("expression");
1648
if (!expression.isExpression()) {
1664
});
1665
return { ...place };
1666
}
1660
- return lowerExpressionToPlace(builder, expression);
1667
+ return lowerExpressionToTemporary(builder, expression);
1668
} else if (exprPath.isJSXText()) {
1669
const place: Place = buildTemporaryPlace(builder, exprLoc);
1670
builder.push({
1701
}
1702
}
1703
1704
+function lowerExpressionToTemporary(
1705
+ builder: HIRBuilder,
1706
+ exprPath: NodePath<t.Expression>
1707
+): Place {
1708
+ const value = lowerExpression(builder, exprPath);
1709
+ if (value.kind === "Identifier" && value.identifier.name === null) {
1710
+ return value;
1711
+ }
1712
+ const exprLoc = exprPath.node.loc ?? GeneratedSource;
1713
+ const place: Place = buildTemporaryPlace(builder, exprLoc);
1714
+ builder.push({
1715
+ id: makeInstructionId(0),
1716
+ value: value,
1717
+ loc: exprLoc,
1718
+ lvalue: { place: { ...place }, kind: InstructionKind.Const },
1719
+ });
1720
+ return place;
1721
+}
1722
+
1723
function lowerExpressionToPlace(
1724
builder: HIRBuilder,
1725
exprPath: NodePath<t.Expression>
1726
): Place {
1701
- const instr = lowerExpression(builder, exprPath);
1702
- if (instr.kind === "Identifier") {
1703
- return instr;
1727
+ const value = lowerExpression(builder, exprPath);
1728
+ if (value.kind === "Identifier") {
1729
+ return value;
1730
}
1731
const exprLoc = exprPath.node.loc ?? GeneratedSource;
1732
const place: Place = buildTemporaryPlace(builder, exprLoc);
1733
builder.push({
1734
id: makeInstructionId(0),
1709
- value: instr,
1735
+ value: value,
1736
loc: exprLoc,
1737
lvalue: { place: { ...place }, kind: InstructionKind.Const },
1738
});
1863
case "MemberExpression": {
1864
const lvalue = lvaluePath as NodePath<t.MemberExpression>;
1865
const property = lvalue.get("property");
1840
- const object = lowerExpressionToPlace(builder, lvalue.get("object"));
1866
+ const object = lowerExpressionToTemporary(builder, lvalue.get("object"));
1867
let valuePlace: Place;
1868
if (value.kind === "Identifier") {
1869
valuePlace = value;
1902
});
1903
return { kind: "UnsupportedNode", node: lvalueNode, loc };
1904
}
1879
- const propertyPlace = lowerExpressionToPlace(builder, property);
1905
+ const propertyPlace = lowerExpressionToTemporary(builder, property);
1906
return {
1907
kind: "ComputedStore",
1908
object,
2082
2083
path.skip();
2084
capturedIds.add(binding.identifier);
2059
- capturedRefs.add(lowerExpressionToPlace(builder, path));
2085
+ capturedRefs.add(lowerExpressionToTemporary(builder, path));
2086
},
2087
});
2088