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

Make CompilerPipeline a generator

Turns CompilerPipeline into two functions: * `run()` is a generator and yields values that are a disjoint union of either AST/HIR/ReactiveFunction along with a name for that step. The idea is to use this in the playground so that it always matches the exact steps for compilation. I'll update playground in a follow-up. * `compile()` is ast in, ast out, and uses `run()` under the hood.

Joe Savona committed Jan 10, 2023 at 10:15 UTC 77512024334e0cb12836b441b7c853d165abaa95
4 files changed +110 -54
compiler/forget/src/Babel/BabelPlugin.ts
+2 -4
@@ -10,8 +10,7 @@
10 import type * as BabelCore from "@babel/core";
11 import type { PluginObj } from "@babel/core";
12 import jsx from "@babel/plugin-syntax-jsx";
13 -import Pipeline from "../CompilerPipeline";
14 -import { invariant } from "../Utils/CompilerError";
13 +import { compile } from "../CompilerPipeline";
14
15 /**
16 * The React Forget Babel Plugin
@@ -25,8 +24,7 @@ export default function (babel: typeof BabelCore): PluginObj {
24 visitor: {
25 FunctionDeclaration: {
26 enter(fn, pass) {
28 - const { ast } = Pipeline(fn);
29 - invariant(ast !== null, "Expected ast to be present");
27 + const ast = compile(fn);
28 fn.replaceWith(ast);
29 },
30 },
compiler/forget/src/CompilerPipeline.ts
+97 -42
@@ -30,77 +30,132 @@ import {
30 import { eliminateRedundantPhi, enterSSA, leaveSSA } from "./SSA";
31 import { inferTypes } from "./TypeInference";
32 import { logHIRFunction, logReactiveFunction } from "./Utils/logger";
33 +import { assertExhaustive } from "./Utils/utils";
34
34 -export type CompilerResult = {
35 - ast: t.Function;
36 - ir: HIRFunction;
37 - reactiveFunction: ReactiveFunction;
38 -};
35 +export type CompilerPipelineValue =
36 + | { kind: "ast"; name: string; value: t.Function }
37 + | { kind: "hir"; name: string; value: HIRFunction }
38 + | { kind: "reactive"; name: string; value: ReactiveFunction };
39
40 -export default function (
40 +export function* run(
41 func: NodePath<t.FunctionDeclaration>
42 -): CompilerResult {
42 +): Iterator<CompilerPipelineValue, t.Function> {
43 const env = new Environment();
44
45 - const ir = lower(func, env);
46 - logHIRFunction("HIR", ir);
45 + const hir = lower(func, env);
46 + yield log({ kind: "hir", name: "HIR", value: hir });
47
48 - mergeConsecutiveBlocks(ir);
49 - logHIRFunction("mergeConsecutiveBlocks", ir);
48 + mergeConsecutiveBlocks(hir);
49 + yield log({ kind: "hir", name: "MergeConsecutiveBlocks", value: hir });
50
51 - enterSSA(ir, env);
52 - logHIRFunction("SSA", ir);
51 + enterSSA(hir, env);
52 + yield log({ kind: "hir", name: "SSA", value: hir });
53
54 - eliminateRedundantPhi(ir);
55 - logHIRFunction("eliminateRedundantPhi", ir);
54 + eliminateRedundantPhi(hir);
55 + yield log({ kind: "hir", name: "EliminateRedundantPhi", value: hir });
56
57 - constantPropagation(ir);
58 - logHIRFunction("constantPropagation", ir);
57 + constantPropagation(hir);
58 + yield log({ kind: "hir", name: "ConstantPropagation", value: hir });
59
60 - inferTypes(ir);
61 - logHIRFunction("inferTypes", ir);
60 + inferTypes(hir);
61 + yield log({ kind: "hir", name: "InferTypes", value: hir });
62
63 - inferReferenceEffects(ir);
64 - logHIRFunction("inferReferenceEffects", ir);
63 + inferReferenceEffects(hir);
64 + yield log({ kind: "hir", name: "InferReferenceEffects", value: hir });
65
66 - inferMutableRanges(ir);
67 - logHIRFunction("inferMutableRanges", ir);
66 + inferMutableRanges(hir);
67 + yield log({ kind: "hir", name: "InferMutableRanges", value: hir });
68
69 - leaveSSA(ir);
70 - logHIRFunction("leaveSSA", ir);
69 + leaveSSA(hir);
70 + yield log({ kind: "hir", name: "LeaveSSA", value: hir });
71
72 - inferReactiveScopeVariables(ir);
73 - logHIRFunction("inferReactiveScopeVariables", ir);
72 + inferReactiveScopeVariables(hir);
73 + yield log({ kind: "hir", name: "InferReactiveScopeVariables", value: hir });
74
75 - inferReactiveScopes(ir);
76 - logHIRFunction("inferReactiveScopes", ir);
75 + inferReactiveScopes(hir);
76 + yield log({ kind: "hir", name: "InferReactiveScopes", value: hir });
77
78 - const reactiveFunction = buildReactiveFunction(ir);
79 - logReactiveFunction("buildReactiveFunction", reactiveFunction);
78 + const reactiveFunction = buildReactiveFunction(hir);
79 + yield log({
80 + kind: "reactive",
81 + name: "BuildReactiveFunction",
82 + value: reactiveFunction,
83 + });
84
85 pruneUnusedLabels(reactiveFunction);
82 - logReactiveFunction("pruneUnusedLabels", reactiveFunction);
86 + yield log({
87 + kind: "reactive",
88 + name: "PruneUnusedLabels",
89 + value: reactiveFunction,
90 + });
91
92 flattenReactiveLoops(reactiveFunction);
85 - logReactiveFunction("flattenReactiveLoops", reactiveFunction);
93 + yield log({
94 + kind: "reactive",
95 + name: "FlattenReactiveLoops",
96 + value: reactiveFunction,
97 + });
98
99 propagateScopeDependencies(reactiveFunction);
88 - logReactiveFunction("propagateScopeDependencies", reactiveFunction);
100 + yield log({
101 + kind: "reactive",
102 + name: "PropagateScopeDependencies",
103 + value: reactiveFunction,
104 + });
105
106 pruneUnusedScopes(reactiveFunction);
91 - logReactiveFunction("pruneUnusedScopes", reactiveFunction);
107 + yield log({
108 + kind: "reactive",
109 + name: "PruneUnusedScopes",
110 + value: reactiveFunction,
111 + });
112
113 pruneUnusedLValues(reactiveFunction);
94 - logReactiveFunction("pruneUnusedLValues", reactiveFunction);
114 + yield log({
115 + kind: "reactive",
116 + name: "PruneUnusedLValues",
117 + value: reactiveFunction,
118 + });
119
120 renameVariables(reactiveFunction);
97 - logReactiveFunction("renameVariables", reactiveFunction);
121 + yield log({
122 + kind: "reactive",
123 + name: "RenameVariables",
124 + value: reactiveFunction,
125 + });
126
127 const ast = codegenReactiveFunction(reactiveFunction);
128 + yield log({ kind: "ast", name: "Codegen", value: ast });
129
101 - return {
102 - ast,
103 - ir,
104 - reactiveFunction,
105 - };
130 + return ast;
131 +}
132 +
133 +export function compile(func: NodePath<t.FunctionDeclaration>): t.Function {
134 + let generator = run(func);
135 + while (true) {
136 + const next = generator.next();
137 + if (next.done) {
138 + return next.value;
139 + }
140 + }
141 +}
142 +
143 +function log(value: CompilerPipelineValue): CompilerPipelineValue {
144 + switch (value.kind) {
145 + case "ast": {
146 + break;
147 + }
148 + case "hir": {
149 + logHIRFunction(value.name, value.value);
150 + break;
151 + }
152 + case "reactive": {
153 + logReactiveFunction(value.name, value.value);
154 + break;
155 + }
156 + default: {
157 + assertExhaustive(value, "Unexpected compilation kind");
158 + }
159 + }
160 + return value;
161 }
compiler/forget/src/__tests__/hir-test.ts
+2 -2
@@ -13,7 +13,7 @@ import traverse from "@babel/traverse";
13 import { wasmFolder } from "@hpcc-js/wasm";
14 import path from "path";
15 import prettier from "prettier";
16 -import run from "../CompilerPipeline";
16 +import { compile } from "../CompilerPipeline";
17 import { toggleLogging } from "../Utils/logger";
18 import generateTestsFromFixtures from "./test-utils/generateTestsFromFixtures";
19
@@ -121,7 +121,7 @@ function transform(text: string, file: string): Array<TestOutput> {
121 traverse(ast, {
122 FunctionDeclaration: {
123 enter(nodePath) {
124 - const { ast } = run(nodePath);
124 + const ast = compile(nodePath);
125
126 const text = prettier.format(generate(ast).code.replace("\n\n", "\n"), {
127 semi: true,
compiler/forget/src/index.ts
+9 -6
@@ -14,12 +14,12 @@ declare global {
14 import { parse } from "@babel/parser";
15 import traverse, { NodePath } from "@babel/traverse";
16 import * as t from "@babel/types";
17 +import { compile, run } from "./CompilerPipeline";
18 import { lower } from "./HIR/BuildHIR";
19 import codegen from "./HIR/Codegen";
20 import { Environment } from "./HIR/HIRBuilder";
20 -import { inferMutableRanges, inferReferenceEffects } from "./Inference";
21 -import { inferTypes } from "./TypeInference";
21 import printHIR, { printFunction } from "./HIR/PrintHIR";
22 +import { inferMutableRanges, inferReferenceEffects } from "./Inference";
23 import { buildReactiveFunction } from "./ReactiveScopes/BuildReactiveFunction";
24 import { codegenReactiveFunction } from "./ReactiveScopes/CodegenReactiveFunction";
25 import { flattenReactiveLoops } from "./ReactiveScopes/FlattenReactiveLoops";
@@ -32,6 +32,7 @@ import { pruneUnusedScopes } from "./ReactiveScopes/PruneUnusedScopes";
32 import { eliminateRedundantPhi } from "./SSA/EliminateRedundantPhi";
33 import enterSSA from "./SSA/EnterSSA";
34 import { leaveSSA } from "./SSA/LeaveSSA";
35 +import { inferTypes } from "./TypeInference";
36
37 function parseFunctions(
38 source: string
@@ -55,27 +56,29 @@ function parseFunctions(
56 }
57
58 export const HIR = {
58 - codegenReactiveFunction,
59 - flattenReactiveLoops,
60 - propagateScopeDependencies,
59 buildReactiveFunction,
60 codegen,
61 + codegenReactiveFunction,
62 + compile,
63 eliminateRedundantPhi,
64 enterSSA,
65 Environment,
66 - inferTypes,
66 + flattenReactiveLoops,
67 inferMutableRanges,
68 inferReactiveScopes,
69 inferReactiveScopeVariables,
70 inferReferenceEffects,
71 + inferTypes,
72 leaveSSA,
73 lower,
74 parseFunctions,
75 printFunction,
76 printHIR,
77 printReactiveFunction,
78 + propagateScopeDependencies,
79 pruneUnusedLabels,
80 pruneUnusedScopes,
81 + run,
82 };
83
84 export default BabelPlugin;