Support JsxMemberExpression

This commit is contained in:
Joe Savona
2023-03-17 16:18:07 -07:00
parent 0c8f11e13f
commit a7ac20973f
5 changed files with 127 additions and 37 deletions
+53 -16
View File
@@ -1760,7 +1760,27 @@ function lowerJsxElementName(
): Place {
const exprNode = exprPath.node;
const exprLoc = exprNode.loc ?? GeneratedSource;
if (!exprPath.isJSXIdentifier()) {
if (exprPath.isJSXIdentifier()) {
const tag: string = exprPath.node.name;
if (tag.match(/^[A-Z]/)) {
return lowerIdentifier(builder, exprPath);
} else {
const place: Place = buildTemporaryPlace(builder, exprLoc);
builder.push({
id: makeInstructionId(0),
value: {
kind: "Primitive",
value: tag,
loc: exprLoc,
},
loc: exprLoc,
lvalue: { ...place },
});
return place;
}
} else if (exprPath.isJSXMemberExpression()) {
return lowerJsxMemberExpression(builder, exprPath);
} else {
builder.errors.push({
reason: `(BuildHIR::lowerJsxElementName) Handle ${exprPath.type} tags`,
severity: ErrorSeverity.Todo,
@@ -1779,23 +1799,40 @@ function lowerJsxElementName(
});
return { ...place };
}
const tag: string = exprPath.node.name;
if (tag.match(/^[A-Z]/)) {
return lowerIdentifier(builder, exprPath);
}
function lowerJsxMemberExpression(
builder: HIRBuilder,
exprPath: NodePath<t.JSXMemberExpression>
): Place {
const loc = exprPath.node.loc ?? GeneratedSource;
const object = exprPath.get("object");
let objectPlace: Place;
if (object.isJSXMemberExpression()) {
objectPlace = lowerJsxMemberExpression(builder, object);
} else {
const place: Place = buildTemporaryPlace(builder, exprLoc);
builder.push({
id: makeInstructionId(0),
value: {
kind: "Primitive",
value: tag,
loc: exprLoc,
},
loc: exprLoc,
lvalue: { ...place },
});
return place;
invariant(
object.isJSXIdentifier(),
"TypeScript refinement fail: expected 'JsxIdentifier', got '%s'",
object.node.type
);
objectPlace = lowerIdentifier(builder, object);
}
const place = buildTemporaryPlace(builder, loc);
const property = exprPath.get("property").node.name;
builder.push({
id: makeInstructionId(0),
lvalue: { ...place },
value: {
kind: "PropertyLoad",
object: objectPlace,
property,
optional: false,
loc,
},
loc,
});
return place;
}
function lowerJsxElement(
@@ -651,29 +651,26 @@ function codegenInstructionValue(
}
}
let tagValue = codegenPlace(cx, instrValue.tag);
let tag: string;
let tag: t.JSXIdentifier | t.JSXMemberExpression;
if (tagValue.type === "Identifier") {
tag = tagValue.name;
tag = t.jsxIdentifier(tagValue.name);
} else if (tagValue.type === "MemberExpression") {
tag = convertMemberExpressionToJsx(tagValue);
} else {
invariant(
tagValue.type === "StringLiteral",
"Expected JSX tag to be an identifier or string"
"Expected JSX tag to be an identifier or string, got '%s'",
tagValue.type
);
tag = tagValue.value;
tag = t.jsxIdentifier(tagValue.value);
}
const children =
instrValue.children !== null
? instrValue.children.map((child) => codegenJsxElement(cx, child))
: [];
value = t.jsxElement(
t.jsxOpeningElement(
t.jsxIdentifier(tag),
attributes,
instrValue.children === null
),
instrValue.children !== null
? t.jsxClosingElement(t.jsxIdentifier(tag))
: null,
t.jsxOpeningElement(tag, attributes, instrValue.children === null),
instrValue.children !== null ? t.jsxClosingElement(tag) : null,
children,
instrValue.children === null
);
@@ -896,6 +893,26 @@ function codegenJsxElement(
}
}
function convertMemberExpressionToJsx(
expr: t.MemberExpression
): t.JSXMemberExpression {
invariant(
expr.property.type === "Identifier",
"Expected JSX member expression property to be a string"
);
const property = t.jsxIdentifier(expr.property.name);
if (expr.object.type === "Identifier") {
return t.jsxMemberExpression(t.jsxIdentifier(expr.object.name), property);
} else {
invariant(
expr.object.type === "MemberExpression",
"Expected JSX member expression to be an identifier or nested member expression"
);
const object = convertMemberExpressionToJsx(expr.object);
return t.jsxMemberExpression(object, property);
}
}
function codegenLValue(
pattern: Pattern | Place | SpreadPattern
): t.ArrayPattern | t.ObjectPattern | t.RestElement | t.Identifier {
@@ -166,15 +166,6 @@ let moduleLocal = false;
20 |
21 | const j = function bar([quz, qux], ...args) {};
[ReactForget] TodoError: (BuildHIR::lowerJsxElementName) Handle JSXMemberExpression tags
17 | <Button haha={1}></Button>;
18 | <Button>{/** empty */}</Button>;
> 19 | <DesignSystem.Button />;
| ^^^^^^^^^^^^^^^^^^^
20 |
21 | const j = function bar([quz, qux], ...args) {};
22 |
[ReactForget] TodoError: (BuildHIR::lower) Handle RestElement params
19 | <DesignSystem.Button />;
20 |
@@ -0,0 +1,38 @@
## Input
```javascript
function Component(props) {
return (
<Sathya.Codes.Forget>
<Foo.Bar.Baz />
</Sathya.Codes.Forget>
);
}
```
## Code
```javascript
function Component(props) {
const $ = React.unstable_useMemoCache(2);
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t0 = <Foo.Bar.Baz></Foo.Bar.Baz>;
$[0] = t0;
} else {
t0 = $[0];
}
let t1;
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
t1 = <Sathya.Codes.Forget>{t0}</Sathya.Codes.Forget>;
$[1] = t1;
} else {
t1 = $[1];
}
return t1;
}
```
@@ -0,0 +1,7 @@
function Component(props) {
return (
<Sathya.Codes.Forget>
<Foo.Bar.Baz />
</Sathya.Codes.Forget>
);
}