@samitouri / QOS-React-2 / commits / ce7cab4eee

[hir] Parse and codegen FunctionExpression

Sathya Gunasekaran committed Jan 9, 2023 at 18:22 UTC ce7cab4eeeae907d9cac4af10792272a63b01336
10 files changed +85
compiler/forget/src/HIR/BuildHIR.ts
+16
@@ -1148,6 +1148,22 @@ function lowerExpression(
1148 loc: exprLoc,
1149 };
1150 }
1151 + case "FunctionExpression": {
1152 + const expr = exprPath as NodePath<t.FunctionExpression>;
1153 + const name: string | null = expr.get("id")?.node?.name ?? null;
1154 + const body = expr.get("body").node;
1155 + const params: Array<string> = expr.get("params").map((p) => {
1156 + todoInvariant(p.isIdentifier(), "handle non identifier params");
1157 + return p.node.name;
1158 + });
1159 + return {
1160 + kind: "FunctionExpression",
1161 + name,
1162 + body,
1163 + params,
1164 + loc: exprLoc,
1165 + };
1166 + }
1167 default: {
1168 todo(`lowerExpression(${exprNode.type})`);
1169 // assertExhaustive(
compiler/forget/src/HIR/Codegen.ts
+7
@@ -498,6 +498,13 @@ export function codegenInstructionValue(
498 value = codegenPlace(temp, instrValue);
499 break;
500 }
501 + case "FunctionExpression": {
502 + const id =
503 + instrValue.name !== null ? t.identifier(instrValue.name) : null;
504 + const params = instrValue.params.map((p) => t.identifier(p));
505 + value = t.functionExpression(id, params, instrValue.body);
506 + break;
507 + }
508 default: {
509 assertExhaustive(
510 instrValue,
compiler/forget/src/HIR/HIR.ts
+6
@@ -309,6 +309,12 @@ export type InstructionData =
309 | { kind: "ComputedStore"; object: Place; property: Place; value: Place }
310 // load `object[index]` - like PropertyLoad but with a dynamic property
311 | { kind: "ComputedLoad"; object: Place; property: Place }
312 + | {
313 + kind: "FunctionExpression";
314 + name: string | null;
315 + params: Array<string>;
316 + body: t.BlockStatement;
317 + }
318
319 /**
320 * Catch-all for statements such as type imports, nested class declarations, etc
compiler/forget/src/HIR/PrintHIR.ts
+6
@@ -290,6 +290,12 @@ export function printInstructionValue(instrValue: InstructionValue): string {
290 )}] = ${printPlace(instrValue.value)}`;
291 break;
292 }
293 + case "FunctionExpression": {
294 + const params = instrValue.params.join(",");
295 + const body = generate(instrValue.body).code;
296 + value = `Function ${instrValue.name}(${params}){${body}}`;
297 + break;
298 + }
299 default: {
300 assertExhaustive(
301 instrValue,
compiler/forget/src/HIR/visitors.ts
+2
@@ -89,6 +89,7 @@ export function* eachInstructionValueOperand(
89 }
90 case "OtherStatement":
91 case "Primitive":
92 + case "FunctionExpression":
93 case "JSXText": {
94 break;
95 }
@@ -175,6 +176,7 @@ export function mapInstructionOperands(
176 }
177 case "OtherStatement":
178 case "Primitive":
179 + case "FunctionExpression":
180 case "JSXText": {
181 break;
182 }
compiler/forget/src/Inference/InferReferenceEffects.ts
+6
@@ -551,6 +551,12 @@ function inferBlock(env: Environment, block: BasicBlock) {
551 lvalueEffect = Effect.Store;
552 break;
553 }
554 + case "FunctionExpression": {
555 + valueKind = ValueKind.Mutable;
556 + effectKind = Effect.Read;
557 + lvalueEffect = Effect.Store;
558 + break;
559 + }
560 case "UnaryExpression": {
561 // TODO check that value must be a primitive, or make conditional based on the operator
562 valueKind = ValueKind.Immutable;
compiler/forget/src/ReactiveScopes/InferReactiveScopeVariables.ts
+1
@@ -173,6 +173,7 @@ function mayAllocate(value: InstructionValue): boolean {
173 case "NewExpression":
174 case "ObjectExpression":
175 case "OtherStatement":
176 + case "FunctionExpression":
177 case "UnaryExpression": {
178 return true;
179 }
compiler/forget/src/ReactiveScopes/PropagateScopeDependencies.ts
+1
@@ -313,6 +313,7 @@ function valueKind(value: InstructionValue): DeclKind {
313 case "JsxFragment":
314 case "NewExpression":
315 case "ObjectExpression":
316 + case "FunctionExpression":
317 case "OtherStatement":
318 case "UnaryExpression": {
319 return DeclKind.Dynamic;
compiler/forget/src/__tests__/fixtures/hir/simple-function-1.expect.md new
+34
@@ -0,0 +1,34 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function component() {
6 + let x = function (a) {
7 + a.foo();
8 + };
9 + return x;
10 +}
11 +
12 +```
13 +
14 +## Code
15 +
16 +```javascript
17 +function component() {
18 + const $ = React.useMemoCache();
19 + let x;
20 + if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
21 + x = function (a) {
22 + a.foo();
23 + };
24 +
25 + $[0] = x;
26 + } else {
27 + x = $[0];
28 + }
29 +
30 + return x;
31 +}
32 +
33 +```
34 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/simple-function-1.js new
+6
@@ -0,0 +1,6 @@
1 +function component() {
2 + let x = function (a) {
3 + a.foo();
4 + };
5 + return x;
6 +}