@samitouri / QOS-React / commits / be7f98d584
Fork 0

The library for web and native user interfaces.

Scaffolding for rest params

Updates HIR to represent rest element function parameters. We don't construct these yet.

Joe Savona committed Sep 27, 2023 at 14:04 UTC be7f98d5841d16dc553eeb58f372be9cb6e3a05a
10 files changed +92 -26
compiler/packages/babel-plugin-react-forget/src/HIR/HIR.ts
+2 -2
@@ -48,7 +48,7 @@ export type SourceLocation = t.SourceLocation | typeof GeneratedSource;
48 export type ReactiveFunction = {
49 loc: SourceLocation;
50 id: string | null;
51 - params: Array<Place>;
51 + params: Array<Place | SpreadPattern>;
52 generator: boolean;
53 async: boolean;
54 body: ReactiveBlock;
@@ -232,7 +232,7 @@ export type HIRFunction = {
232 loc: SourceLocation;
233 id: string | null;
234 env: Environment;
235 - params: Array<Place>;
235 + params: Array<Place | SpreadPattern>;
236 context: Array<Place>;
237 body: HIR;
238 generator: boolean;
compiler/packages/babel-plugin-react-forget/src/Inference/InferReferenceEffects.ts
+18 -6
@@ -110,13 +110,25 @@ export default function inferReferenceEffects(
110 ? ValueKind.Mutable
111 : ValueKind.Frozen;
112 for (const param of fn.params) {
113 - const value: InstructionValue = {
114 - kind: "Primitive",
115 - loc: param.loc,
116 - value: undefined,
117 - };
113 + let value: InstructionValue;
114 + let place: Place;
115 + if (param.kind === "Identifier") {
116 + place = param;
117 + value = {
118 + kind: "Primitive",
119 + loc: param.loc,
120 + value: undefined,
121 + };
122 + } else {
123 + place = param.place;
124 + value = {
125 + kind: "Primitive",
126 + loc: param.place.loc,
127 + value: undefined,
128 + };
129 + }
130 initialState.initialize(value, paramKind);
119 - initialState.define(param, value);
131 + initialState.define(place, value);
132 }
133
134 // Map of blocks to the last (merged) incoming state that was processed
compiler/packages/babel-plugin-react-forget/src/ReactiveScopes/CodegenReactiveFunction.ts
+16 -2
@@ -54,10 +54,14 @@ export function codegenReactiveFunction(
54 ): Result<CodegenFunction, CompilerError> {
55 const cx = new Context(fn.env, fn.id ?? "[[ anonymous ]]");
56 for (const param of fn.params) {
57 - cx.temp.set(param.identifier.id, null);
57 + if (param.kind === "Identifier") {
58 + cx.temp.set(param.identifier.id, null);
59 + } else {
60 + cx.temp.set(param.place.identifier.id, null);
61 + }
62 }
63
60 - const params = fn.params.map((param) => convertIdentifier(param.identifier));
64 + const params = fn.params.map((param) => convertParameter(param));
65 const body = codegenBlock(cx, fn.body);
66 const statements = body.body;
67 if (statements.length !== 0) {
@@ -97,6 +101,16 @@ export function codegenReactiveFunction(
101 });
102 }
103
104 +function convertParameter(
105 + param: Place | SpreadPattern
106 +): t.Identifier | t.RestElement {
107 + if (param.kind === "Identifier") {
108 + return convertIdentifier(param.identifier);
109 + } else {
110 + return t.restElement(convertIdentifier(param.place.identifier));
111 + }
112 +}
113 +
114 class Context {
115 env: Environment;
116 fnName: string;
compiler/packages/babel-plugin-react-forget/src/ReactiveScopes/InferReactiveIdentifiers.ts
+5 -1
@@ -188,7 +188,11 @@ export function inferReactiveIdentifiers(
188 const visitor = new Visitor();
189 const state = new State(fn.env);
190 for (const param of fn.params) {
191 - state.reactivityMap.set(param.identifier.id, true);
191 + if (param.kind === "Identifier") {
192 + state.reactivityMap.set(param.identifier.id, true);
193 + } else {
194 + state.reactivityMap.set(param.place.identifier.id, true);
195 + }
196 }
197 visitReactiveFunction(fn, visitor, state);
198
compiler/packages/babel-plugin-react-forget/src/ReactiveScopes/PrintReactiveFunction.ts
+5 -1
@@ -27,7 +27,11 @@ export function printReactiveFunction(fn: ReactiveFunction): string {
27 writer.writeLine(`function ${fn.id !== null ? fn.id : "<unknown>"}(`);
28 writer.indented(() => {
29 for (const param of fn.params) {
30 - writer.writeLine(`${printPlace(param)},`);
30 + if (param.kind === "Identifier") {
31 + writer.writeLine(`${printPlace(param)},`);
32 + } else {
33 + writer.writeLine(`...${printPlace(param.place)},`);
34 + }
35 }
36 });
37 writer.writeLine(") {");
compiler/packages/babel-plugin-react-forget/src/ReactiveScopes/PropagateScopeDependencies.ts
+11 -4
@@ -50,10 +50,17 @@ export function propagateScopeDependencies(fn: ReactiveFunction): void {
50
51 const context = new Context(escapingTemporaries.usedOutsideDeclaringScope);
52 for (const param of fn.params) {
53 - context.declare(param.identifier, {
54 - id: makeInstructionId(0),
55 - scope: empty(),
56 - });
53 + if (param.kind === "Identifier") {
54 + context.declare(param.identifier, {
55 + id: makeInstructionId(0),
56 + scope: empty(),
57 + });
58 + } else {
59 + context.declare(param.place.identifier, {
60 + id: makeInstructionId(0),
61 + scope: empty(),
62 + });
63 + }
64 }
65 visitReactiveFunction(fn, new PropagationVisitor(), context);
66 }
compiler/packages/babel-plugin-react-forget/src/ReactiveScopes/PruneNonEscapingScopes.ts
+5 -1
@@ -117,7 +117,11 @@ export function pruneNonEscapingScopes(
117 // and which values are returned.
118 const state = new State(fn.env);
119 for (const param of fn.params) {
120 - state.declare(param.identifier.id);
120 + if (param.kind === "Identifier") {
121 + state.declare(param.identifier.id);
122 + } else {
123 + state.declare(param.place.identifier.id);
124 + }
125 }
126 visitReactiveFunction(
127 fn,
compiler/packages/babel-plugin-react-forget/src/ReactiveScopes/RenameVariables.ts
+5 -1
@@ -34,7 +34,11 @@ export function renameVariables(fn: ReactiveFunction): void {
34 const scopes = new Scopes();
35 scopes.enter(() => {
36 for (const param of fn.params) {
37 - scopes.visit(param.identifier);
37 + if (param.kind === "Identifier") {
38 + scopes.visit(param.identifier);
39 + } else {
40 + scopes.visit(param.place.identifier);
41 + }
42 }
43 visitReactiveFunction(fn, new Visitor(), scopes);
44 });
compiler/packages/babel-plugin-react-forget/src/SSA/EnterSSA.ts
+20 -4
@@ -259,7 +259,16 @@ function enterSSAImpl(
259 loc: func.loc,
260 suggestions: null,
261 });
262 - func.params = func.params.map((p) => builder.definePlace(p));
262 + func.params = func.params.map((param) => {
263 + if (param.kind === "Identifier") {
264 + return builder.definePlace(param);
265 + } else {
266 + return {
267 + kind: "Spread",
268 + place: builder.definePlace(param.place),
269 + };
270 + }
271 + });
272 }
273
274 for (const instr of block.instructions) {
@@ -282,9 +291,16 @@ function enterSSAImpl(
291 loweredFunc.context = loweredFunc.context.map((p) =>
292 builder.getPlace(p)
293 );
285 - loweredFunc.params = loweredFunc.params.map((p) =>
286 - builder.definePlace(p)
287 - );
294 + loweredFunc.params = loweredFunc.params.map((param) => {
295 + if (param.kind === "Identifier") {
296 + return builder.definePlace(param);
297 + } else {
298 + return {
299 + kind: "Spread",
300 + place: builder.definePlace(param.place),
301 + };
302 + }
303 + });
304 enterSSAImpl(loweredFunc, builder, rootEntry);
305 });
306 entry.preds.clear();
compiler/packages/babel-plugin-react-forget/src/SSA/LeaveSSA.ts
+5 -4
@@ -100,13 +100,14 @@ export function leaveSSA(fn: HIRFunction): void {
100 > = new Map();
101
102 for (const param of fn.params) {
103 - if (param.identifier.name !== null) {
104 - declarations.set(param.identifier.name, {
103 + let place: Place = param.kind === "Identifier" ? param : param.place;
104 + if (place.identifier.name !== null) {
105 + declarations.set(place.identifier.name, {
106 lvalue: {
107 kind: InstructionKind.Let,
107 - place: param,
108 + place,
109 },
109 - place: param,
110 + place,
111 });
112 }
113 }