[hir syntax] Handle TemplateLiteral syntax

This commit is contained in:
Mofei Zhang
2023-02-03 15:44:37 -05:00
parent 34595b84c8
commit e30a9e9258
9 changed files with 131 additions and 1 deletions
+34
View File
@@ -1420,6 +1420,40 @@ function lowerExpression(
loc: exprLoc,
};
}
case "TemplateLiteral": {
const expr = exprPath as NodePath<t.TemplateLiteral>;
const subexprs = expr.get("expressions");
const quasis = expr.get("quasis");
if (subexprs.length !== quasis.length - 1) {
builder.errors.push({
reason: `(BuildHIR::lowerAssignment) Unexpected quasi and subexpression lengths in TemplateLiteral.`,
severity: ErrorSeverity.InvalidInput,
nodePath: exprPath,
});
return { kind: "UnsupportedNode", node: exprNode, loc: exprLoc };
}
if (subexprs.some((e) => !e.isExpression())) {
builder.errors.push({
reason: `(BuildHIR::lowerAssignment) Handle TSType in TemplateLiteral.`,
severity: ErrorSeverity.Todo,
nodePath: exprPath,
});
return { kind: "UnsupportedNode", node: exprNode, loc: exprLoc };
}
const subexprPlaces = subexprs.map((e) =>
lowerExpressionToPlace(builder, e as NodePath<t.Expression>)
);
return {
kind: "TemplateLiteral",
subexprs: subexprPlaces,
quasis: expr.get("quasis").map((q) => q.node.value),
loc: exprLoc,
};
}
case "UnaryExpression": {
let expr = exprPath as NodePath<t.UnaryExpression>;
return {
+5 -1
View File
@@ -446,7 +446,11 @@ export type InstructionData =
tag: Place;
value: { raw: string; cooked?: string };
}
| {
kind: "TemplateLiteral";
subexprs: Array<Place>;
quasis: Array<{ raw: string; cooked?: string }>;
}
/**
* Catch-all for statements such as type imports, nested class declarations, etc
* which are not directly represented, but included for completeness and to allow
+14
View File
@@ -6,6 +6,7 @@
*/
import generate from "@babel/generator";
import invariant from "invariant";
import DisjointSet from "../Utils/DisjointSet";
import { assertExhaustive } from "../Utils/utils";
import {
@@ -370,6 +371,19 @@ export function printInstructionValue(instrValue: ReactiveValue): string {
)} : ${printInstructionValue(instrValue.alternate)}`;
break;
}
case "TemplateLiteral": {
value = "`";
invariant(
instrValue.subexprs.length === instrValue.quasis.length - 1,
"Bad assumption about quasi length."
);
for (let i = 0; i < instrValue.subexprs.length; i++) {
value += instrValue.quasis[i].raw;
value += `\${${printPlace(instrValue.subexprs[i])}}`;
}
value += instrValue.quasis.at(-1)!.raw + "`";
break;
}
default: {
assertExhaustive(
instrValue,
+8
View File
@@ -127,6 +127,10 @@ export function* eachInstructionValueOperand(
yield instrValue.value;
break;
}
case "TemplateLiteral": {
yield* instrValue.subexprs;
break;
}
case "UnsupportedNode":
case "Primitive":
case "JSXText": {
@@ -251,6 +255,10 @@ export function mapInstructionOperands(
instrValue.value = fn(instrValue.value);
break;
}
case "TemplateLiteral": {
instrValue.subexprs = instrValue.subexprs.map(fn);
break;
}
case "UnsupportedNode":
case "Primitive":
case "JSXText": {
@@ -599,6 +599,13 @@ function inferBlock(env: Environment, block: BasicBlock) {
effectKind = Effect.Mutate;
break;
}
case "TemplateLiteral": {
// template literal (with no tag function) always produces
// an immutable string
valueKind = ValueKind.Immutable;
effectKind = Effect.Read;
break;
}
case "JSXText":
case "Primitive": {
valueKind = ValueKind.Immutable;
@@ -415,6 +415,7 @@ const createTaggedTemplateExpression = withLoc(t.taggedTemplateExpression);
const createLogicalExpression = withLoc(t.logicalExpression);
const createSequenceExpression = withLoc(t.sequenceExpression);
const createConditionalExpression = withLoc(t.conditionalExpression);
const createTemplateLiteral = withLoc(t.templateLiteral);
type Temporaries = Map<IdentifierId, t.Expression>;
@@ -751,6 +752,14 @@ function codegenInstructionValue(
}
break;
}
case "TemplateLiteral": {
value = createTemplateLiteral(
instrValue.loc,
instrValue.quasis.map((q) => t.templateElement(q)),
instrValue.subexprs.map((p) => codegenPlace(cx, p))
);
break;
}
default: {
assertExhaustive(
instrValue,
@@ -174,6 +174,7 @@ function mayAllocate(value: InstructionValue): boolean {
case "ComputedLoad":
case "JSXText":
case "UnaryExpression":
case "TemplateLiteral":
case "Primitive": {
return false;
}
@@ -0,0 +1,43 @@
## Input
```javascript
function componentA(props) {
let t = `hello ${props.a}, ${props.b}!`;
t += ``;
return t;
}
function componentB(props) {
let x = useFoo(`hello ${props.a}`);
return x;
}
```
## Code
```javascript
function componentA(props) {
const t = `hello ${props.a}, ${props.b}!`;
const t$0 = t + ``;
return t$0;
}
function componentB(props) {
const $ = React.useMemoCache();
const t0 = `hello ${props.a}`;
const c_0 = $[0] !== t0;
let x;
if (c_0) {
x = useFoo(t0);
$[0] = t0;
$[1] = x;
} else {
x = $[1];
}
return x;
}
```
@@ -0,0 +1,10 @@
function componentA(props) {
let t = `hello ${props.a}, ${props.b}!`;
t += ``;
return t;
}
function componentB(props) {
let x = useFoo(`hello ${props.a}`);
return x;
}