649
const stmt = stmtPath as NodePath<t.ExpressionStatement>;
650
const expression = stmt.get("expression");
651
const value = lowerExpression(builder, expression);
652
- if (expression.isAssignmentExpression()) {
653
- // instruction already emitted via lowerExpression()
652
+ if (expression.isAssignmentExpression() && value.kind === "Identifier") {
653
+ // already lowered to a place
654
return;
655
}
656
+ const place = buildTemporaryPlace(
657
+ builder,
658
+ stmt.node.loc ?? GeneratedSource
659
+ );
660
builder.push({
661
id: makeInstructionId(0),
658
- lvalue: null,
662
+ lvalue: { kind: InstructionKind.Const, place },
663
value,
664
loc: stmt.node.loc ?? GeneratedSource,
665
});
889
// tmp != null ? tmp : <right>
890
const left = lowerExpressionToPlace(builder, leftPath);
891
888
- const nullPlace: Place = {
889
- kind: "Identifier",
890
- identifier: builder.makeTemporary(),
891
- memberPath: null,
892
- effect: Effect.Unknown,
893
- loc: left.loc,
894
- };
892
+ const nullPlace: Place = buildTemporaryPlace(builder, left.loc);
893
builder.push({
894
id: makeInstructionId(0),
895
value: {
901
lvalue: { place: { ...nullPlace }, kind: InstructionKind.Const },
902
});
903
906
- const condPlace: Place = {
907
- kind: "Identifier",
908
- identifier: builder.makeTemporary(),
909
- memberPath: null,
910
- effect: Effect.Unknown,
911
- loc: left.loc,
912
- };
904
+ const condPlace: Place = buildTemporaryPlace(builder, left.loc);
905
builder.push({
906
id: makeInstructionId(0),
907
lvalue: {
952
}
953
case "MemberExpression": {
954
const leftExpr = left as NodePath<t.MemberExpression>;
963
- const object = lowerExpressionToPlace(
964
- builder,
965
- leftExpr.get("object")
966
- );
955
const property = leftExpr.get("property");
956
invariant(
957
property.isIdentifier(),
958
"Assignment expression to dynamic properties is not yet supported"
959
);
960
const right = lowerExpressionToPlace(builder, expr.get("right"));
973
- const place: Place = {
974
- kind: "Identifier",
975
- identifier: builder.makeTemporary(),
976
- memberPath: null,
977
- effect: Effect.Read,
978
- loc: exprLoc,
961
+ const object = lowerExpressionToPlace(
962
+ builder,
963
+ leftExpr.get("object")
964
+ );
965
+ return {
966
+ kind: "PropertyStore",
967
+ object,
968
+ property: property.node.name,
969
+ value: right,
970
+ loc: leftNode.loc ?? GeneratedSource,
971
};
980
- builder.push({
981
- id: makeInstructionId(0),
982
- lvalue: { place: { ...place }, kind: InstructionKind.Const },
983
- value: {
984
- kind: "PropertyStore",
985
- object,
986
- property: property.node.name,
987
- value: right,
988
- loc: leftNode.loc ?? GeneratedSource,
989
- },
990
- loc: exprLoc,
991
- });
992
- return place;
972
}
973
default: {
974
todoInvariant(
1035
"Assignment expression to dynamic properties is not yet supported"
1036
);
1037
// Store the previous value to a temporary
1059
- const previousValuePlace: Place = {
1060
- kind: "Identifier",
1061
- identifier: builder.makeTemporary(),
1062
- memberPath: null,
1063
- effect: Effect.Read,
1064
- loc: exprLoc,
1065
- };
1038
+ const previousValuePlace: Place = buildTemporaryPlace(
1039
+ builder,
1040
+ exprLoc
1041
+ );
1042
builder.push({
1043
id: makeInstructionId(0),
1044
lvalue: {
1054
loc: leftExpr.node.loc ?? GeneratedSource,
1055
});
1056
// Store the new value to a temporary
1081
- const newValuePlace: Place = {
1082
- kind: "Identifier",
1083
- identifier: builder.makeTemporary(),
1084
- memberPath: null,
1085
- effect: Effect.Read,
1086
- loc: exprLoc,
1087
- };
1057
+ const newValuePlace: Place = buildTemporaryPlace(builder, exprLoc);
1058
builder.push({
1059
id: makeInstructionId(0),
1060
lvalue: {
1072
});
1073
1074
// Save the result back to the property
1105
- const place: Place = {
1106
- kind: "Identifier",
1107
- identifier: builder.makeTemporary(),
1108
- memberPath: null,
1109
- effect: Effect.Read,
1110
- loc: exprLoc,
1111
- };
1112
- builder.push({
1113
- id: makeInstructionId(0),
1114
- lvalue: {
1115
- place: { ...place },
1116
- kind: InstructionKind.Const,
1117
- },
1118
- value: {
1119
- kind: "PropertyStore",
1120
- object: { ...object },
1121
- property: property.node.name,
1122
- value: { ...newValuePlace },
1123
- loc: leftExpr.node.loc ?? GeneratedSource,
1124
- },
1075
+ return {
1076
+ kind: "PropertyStore",
1077
+ object: { ...object },
1078
+ property: property.node.name,
1079
+ value: { ...newValuePlace },
1080
loc: leftExpr.node.loc ?? GeneratedSource,
1126
- });
1127
- return place;
1081
+ };
1082
}
1083
default: {
1084
invariant(
1103
property: property.node.name,
1104
loc: exprLoc,
1105
};
1152
- const place: Place = {
1153
- kind: "Identifier",
1154
- identifier: builder.makeTemporary(),
1155
- memberPath: null,
1156
- effect: Effect.Read,
1157
- loc: exprLoc,
1158
- };
1106
+ const place: Place = buildTemporaryPlace(builder, exprLoc);
1107
builder.push({
1108
id: makeInstructionId(0),
1109
lvalue: { place: { ...place }, kind: InstructionKind.Const },
1179
consequent: () => InstructionValue,
1180
alternate: () => InstructionValue
1181
): Place {
1234
- const place: Place = {
1235
- kind: "Identifier",
1236
- identifier: builder.makeTemporary(),
1237
- memberPath: null,
1238
- effect: Effect.Read,
1239
- loc,
1240
- };
1182
+ const place: Place = buildTemporaryPlace(builder, loc);
1183
// Block for code following the if
1184
const continuationBlock = builder.reserve();
1185
// Block for the consequent (if the test is truthy)
1253
};
1254
return place;
1255
} else {
1314
- const place: Place = {
1315
- kind: "Identifier",
1316
- identifier: builder.makeTemporary(),
1317
- memberPath: null,
1318
- effect: Effect.Unknown,
1319
- loc: exprLoc,
1320
- };
1256
+ const place: Place = buildTemporaryPlace(builder, exprLoc);
1257
builder.push({
1258
id: makeInstructionId(0),
1259
value: {
1287
todoInvariant(expression.isExpression(), "handle empty expressions");
1288
return lowerExpressionToPlace(builder, expression);
1289
} else if (exprPath.isJSXText()) {
1354
- const place: Place = {
1355
- kind: "Identifier",
1356
- identifier: builder.makeTemporary(),
1357
- memberPath: null,
1358
- effect: Effect.Unknown,
1359
- loc: exprLoc,
1360
- };
1290
+ const place: Place = buildTemporaryPlace(builder, exprLoc);
1291
builder.push({
1292
id: makeInstructionId(0),
1293
value: {
1304
t.isJSXFragment(exprNode) || t.isJSXSpreadChild(exprNode),
1305
"Expected refinement to work"
1306
);
1377
- const place: Place = {
1378
- kind: "Identifier",
1379
- identifier: builder.makeTemporary(),
1380
- memberPath: null,
1381
- effect: Effect.Unknown,
1382
- loc: exprLoc,
1383
- };
1307
+ const place: Place = buildTemporaryPlace(builder, exprLoc);
1308
builder.push({
1309
id: makeInstructionId(0),
1310
value: {
1328
return instr;
1329
}
1330
const exprLoc = exprPath.node.loc ?? GeneratedSource;
1407
- const place: Place = {
1408
- kind: "Identifier",
1409
- identifier: builder.makeTemporary(),
1410
- memberPath: null,
1411
- effect: Effect.Unknown,
1412
- loc: exprLoc,
1413
- };
1331
+ const place: Place = buildTemporaryPlace(builder, exprLoc);
1332
builder.push({
1333
id: makeInstructionId(0),
1334
value: instr,
1414
}
1415
}
1416
1417
+/**
1418
+ * Creates a temporary Identifier and Place referencing that identifier.
1419
+ */
1420
+function buildTemporaryPlace(builder: HIRBuilder, loc: SourceLocation): Place {
1421
+ const place: Place = {
1422
+ kind: "Identifier",
1423
+ identifier: builder.makeTemporary(),
1424
+ memberPath: null,
1425
+ effect: Effect.Unknown,
1426
+ loc,
1427
+ };
1428
+ return place;
1429
+}
1430
+
1431
function lowerAssignment(
1432
builder: HIRBuilder,
1433
loc: SourceLocation,