[hir] Parse and codegen FunctionExpression

This commit is contained in:
Sathya Gunasekaran
2023-01-09 18:22:32 +00:00
parent 57ea3b7e8a
commit ce7cab4eee
10 changed files with 85 additions and 0 deletions
+16
View File
@@ -1148,6 +1148,22 @@ function lowerExpression(
loc: exprLoc,
};
}
case "FunctionExpression": {
const expr = exprPath as NodePath<t.FunctionExpression>;
const name: string | null = expr.get("id")?.node?.name ?? null;
const body = expr.get("body").node;
const params: Array<string> = expr.get("params").map((p) => {
todoInvariant(p.isIdentifier(), "handle non identifier params");
return p.node.name;
});
return {
kind: "FunctionExpression",
name,
body,
params,
loc: exprLoc,
};
}
default: {
todo(`lowerExpression(${exprNode.type})`);
// assertExhaustive(
+7
View File
@@ -498,6 +498,13 @@ export function codegenInstructionValue(
value = codegenPlace(temp, instrValue);
break;
}
case "FunctionExpression": {
const id =
instrValue.name !== null ? t.identifier(instrValue.name) : null;
const params = instrValue.params.map((p) => t.identifier(p));
value = t.functionExpression(id, params, instrValue.body);
break;
}
default: {
assertExhaustive(
instrValue,
+6
View File
@@ -309,6 +309,12 @@ export type InstructionData =
| { kind: "ComputedStore"; object: Place; property: Place; value: Place }
// load `object[index]` - like PropertyLoad but with a dynamic property
| { kind: "ComputedLoad"; object: Place; property: Place }
| {
kind: "FunctionExpression";
name: string | null;
params: Array<string>;
body: t.BlockStatement;
}
/**
* Catch-all for statements such as type imports, nested class declarations, etc
+6
View File
@@ -290,6 +290,12 @@ export function printInstructionValue(instrValue: InstructionValue): string {
)}] = ${printPlace(instrValue.value)}`;
break;
}
case "FunctionExpression": {
const params = instrValue.params.join(",");
const body = generate(instrValue.body).code;
value = `Function ${instrValue.name}(${params}){${body}}`;
break;
}
default: {
assertExhaustive(
instrValue,
+2
View File
@@ -89,6 +89,7 @@ export function* eachInstructionValueOperand(
}
case "OtherStatement":
case "Primitive":
case "FunctionExpression":
case "JSXText": {
break;
}
@@ -175,6 +176,7 @@ export function mapInstructionOperands(
}
case "OtherStatement":
case "Primitive":
case "FunctionExpression":
case "JSXText": {
break;
}
@@ -551,6 +551,12 @@ function inferBlock(env: Environment, block: BasicBlock) {
lvalueEffect = Effect.Store;
break;
}
case "FunctionExpression": {
valueKind = ValueKind.Mutable;
effectKind = Effect.Read;
lvalueEffect = Effect.Store;
break;
}
case "UnaryExpression": {
// TODO check that value must be a primitive, or make conditional based on the operator
valueKind = ValueKind.Immutable;
@@ -173,6 +173,7 @@ function mayAllocate(value: InstructionValue): boolean {
case "NewExpression":
case "ObjectExpression":
case "OtherStatement":
case "FunctionExpression":
case "UnaryExpression": {
return true;
}
@@ -313,6 +313,7 @@ function valueKind(value: InstructionValue): DeclKind {
case "JsxFragment":
case "NewExpression":
case "ObjectExpression":
case "FunctionExpression":
case "OtherStatement":
case "UnaryExpression": {
return DeclKind.Dynamic;
@@ -0,0 +1,34 @@
## Input
```javascript
function component() {
let x = function (a) {
a.foo();
};
return x;
}
```
## Code
```javascript
function component() {
const $ = React.useMemoCache();
let x;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
x = function (a) {
a.foo();
};
$[0] = x;
} else {
x = $[0];
}
return x;
}
```
@@ -0,0 +1,6 @@
function component() {
let x = function (a) {
a.foo();
};
return x;
}