Support spread patterns in object literals

Support ObjectExpression with spread items, eg `const x = {...y}`.
This commit is contained in:
Joe Savona
2023-03-06 15:24:43 -08:00
parent 7893a6c403
commit 93cca54aba
6 changed files with 93 additions and 39 deletions
+42 -31
View File
@@ -33,6 +33,7 @@ import {
Place,
ReturnTerminal,
SourceLocation,
SpreadPattern,
ThrowTerminal,
} from "./HIR";
import HIRBuilder from "./HIRBuilder";
@@ -799,9 +800,48 @@ function lowerExpression(
case "ObjectExpression": {
const expr = exprPath as NodePath<t.ObjectExpression>;
const propertyPaths = expr.get("properties");
const properties: Array<ObjectProperty> = [];
const properties: Array<ObjectProperty | SpreadPattern> = [];
for (const propertyPath of propertyPaths) {
if (!propertyPath.isObjectProperty()) {
if (propertyPath.isObjectProperty()) {
const key = propertyPath.node.key;
let keyName: string;
if (key.type === "Identifier") {
keyName = key.name;
} else if (key.type === "StringLiteral") {
keyName = key.value;
} else {
builder.errors.push({
reason: `(BuildHIR::lowerExpression) Expected Identifier, got ${key.type} key in ObjectExpression`,
severity: ErrorSeverity.InvalidInput,
nodePath: propertyPath,
});
continue;
}
const valuePath = propertyPath.get("value");
if (!valuePath.isExpression()) {
builder.errors.push({
reason: `(BuildHIR::lowerExpression) Handle ${valuePath.type} values in ObjectExpression`,
severity: ErrorSeverity.Todo,
nodePath: valuePath,
});
continue;
}
const value = lowerExpressionToTemporary(builder, valuePath);
properties.push({
kind: "ObjectProperty",
name: keyName,
place: value,
});
} else if (propertyPath.isSpreadElement()) {
const place = lowerExpressionToTemporary(
builder,
propertyPath.get("argument")
);
properties.push({
kind: "Spread",
place,
});
} else {
builder.errors.push({
reason: `(BuildHIR::lowerExpression) Handle ${propertyPath.type} properties in ObjectExpression`,
severity: ErrorSeverity.Todo,
@@ -809,35 +849,6 @@ function lowerExpression(
});
continue;
}
const key = propertyPath.node.key;
let keyName: string;
if (key.type === "Identifier") {
keyName = key.name;
} else if (key.type === "StringLiteral") {
keyName = key.value;
} else {
builder.errors.push({
reason: `(BuildHIR::lowerExpression) Expected Identifier, got ${key.type} key in ObjectExpression`,
severity: ErrorSeverity.InvalidInput,
nodePath: propertyPath,
});
continue;
}
const valuePath = propertyPath.get("value");
if (!valuePath.isExpression()) {
builder.errors.push({
reason: `(BuildHIR::lowerExpression) Handle ${valuePath.type} values in ObjectExpression`,
severity: ErrorSeverity.Todo,
nodePath: valuePath,
});
continue;
}
const value = lowerExpressionToTemporary(builder, valuePath);
properties.push({
kind: "ObjectProperty",
name: keyName,
place: value,
});
}
return {
kind: "ObjectExpression",
+1 -1
View File
@@ -518,7 +518,7 @@ export type InstructionValue =
}
| {
kind: "ObjectExpression";
properties: Array<ObjectProperty>; // null === empty object
properties: Array<ObjectProperty | SpreadPattern>;
loc: SourceLocation;
}
| { kind: "ArrayExpression"; elements: Array<Place>; loc: SourceLocation }
+5 -1
View File
@@ -230,7 +230,11 @@ export function printInstructionValue(instrValue: ReactiveValue): string {
const properties = [];
if (instrValue.properties !== null) {
for (const property of instrValue.properties) {
properties.push(`${property.name}: ${printPlace(property.place)}`);
if (property.kind === "ObjectProperty") {
properties.push(`${property.name}: ${printPlace(property.place)}`);
} else {
properties.push(`...${printPlace(property.place)}`);
}
}
}
value = `Object { ${properties.join(", ")} }`;
@@ -586,12 +586,16 @@ function codegenInstructionValue(
case "ObjectExpression": {
const properties = [];
for (const property of instrValue.properties) {
properties.push(
t.objectProperty(
t.stringLiteral(property.name),
codegenPlace(cx, property.place)
)
);
if (property.kind === "ObjectProperty") {
properties.push(
t.objectProperty(
t.stringLiteral(property.name),
codegenPlace(cx, property.place)
)
);
} else {
properties.push(t.spreadElement(codegenPlace(cx, property.place)));
}
}
value = t.objectExpression(properties);
break;
@@ -0,0 +1,31 @@
## Input
```javascript
function Component(props) {
const x = { ...props.foo };
return x;
}
```
## Code
```javascript
function Component(props) {
const $ = React.unstable_useMemoCache(2);
const c_0 = $[0] !== props.foo;
let t0;
if (c_0) {
t0 = { ...props.foo };
$[0] = props.foo;
$[1] = t0;
} else {
t0 = $[1];
}
const x = t0;
return x;
}
```
@@ -0,0 +1,4 @@
function Component(props) {
const x = { ...props.foo };
return x;
}