Scaffolding for rest params

Updates HIR to represent rest element function parameters. We don't construct 
these yet.
This commit is contained in:
Joe Savona
2023-09-27 14:04:02 -04:00
parent 687ad02e43
commit be7f98d584
10 changed files with 92 additions and 26 deletions
@@ -48,7 +48,7 @@ export type SourceLocation = t.SourceLocation | typeof GeneratedSource;
export type ReactiveFunction = {
loc: SourceLocation;
id: string | null;
params: Array<Place>;
params: Array<Place | SpreadPattern>;
generator: boolean;
async: boolean;
body: ReactiveBlock;
@@ -232,7 +232,7 @@ export type HIRFunction = {
loc: SourceLocation;
id: string | null;
env: Environment;
params: Array<Place>;
params: Array<Place | SpreadPattern>;
context: Array<Place>;
body: HIR;
generator: boolean;
@@ -110,13 +110,25 @@ export default function inferReferenceEffects(
? ValueKind.Mutable
: ValueKind.Frozen;
for (const param of fn.params) {
const value: InstructionValue = {
kind: "Primitive",
loc: param.loc,
value: undefined,
};
let value: InstructionValue;
let place: Place;
if (param.kind === "Identifier") {
place = param;
value = {
kind: "Primitive",
loc: param.loc,
value: undefined,
};
} else {
place = param.place;
value = {
kind: "Primitive",
loc: param.place.loc,
value: undefined,
};
}
initialState.initialize(value, paramKind);
initialState.define(param, value);
initialState.define(place, value);
}
// Map of blocks to the last (merged) incoming state that was processed
@@ -54,10 +54,14 @@ export function codegenReactiveFunction(
): Result<CodegenFunction, CompilerError> {
const cx = new Context(fn.env, fn.id ?? "[[ anonymous ]]");
for (const param of fn.params) {
cx.temp.set(param.identifier.id, null);
if (param.kind === "Identifier") {
cx.temp.set(param.identifier.id, null);
} else {
cx.temp.set(param.place.identifier.id, null);
}
}
const params = fn.params.map((param) => convertIdentifier(param.identifier));
const params = fn.params.map((param) => convertParameter(param));
const body = codegenBlock(cx, fn.body);
const statements = body.body;
if (statements.length !== 0) {
@@ -97,6 +101,16 @@ export function codegenReactiveFunction(
});
}
function convertParameter(
param: Place | SpreadPattern
): t.Identifier | t.RestElement {
if (param.kind === "Identifier") {
return convertIdentifier(param.identifier);
} else {
return t.restElement(convertIdentifier(param.place.identifier));
}
}
class Context {
env: Environment;
fnName: string;
@@ -188,7 +188,11 @@ export function inferReactiveIdentifiers(
const visitor = new Visitor();
const state = new State(fn.env);
for (const param of fn.params) {
state.reactivityMap.set(param.identifier.id, true);
if (param.kind === "Identifier") {
state.reactivityMap.set(param.identifier.id, true);
} else {
state.reactivityMap.set(param.place.identifier.id, true);
}
}
visitReactiveFunction(fn, visitor, state);
@@ -27,7 +27,11 @@ export function printReactiveFunction(fn: ReactiveFunction): string {
writer.writeLine(`function ${fn.id !== null ? fn.id : "<unknown>"}(`);
writer.indented(() => {
for (const param of fn.params) {
writer.writeLine(`${printPlace(param)},`);
if (param.kind === "Identifier") {
writer.writeLine(`${printPlace(param)},`);
} else {
writer.writeLine(`...${printPlace(param.place)},`);
}
}
});
writer.writeLine(") {");
@@ -50,10 +50,17 @@ export function propagateScopeDependencies(fn: ReactiveFunction): void {
const context = new Context(escapingTemporaries.usedOutsideDeclaringScope);
for (const param of fn.params) {
context.declare(param.identifier, {
id: makeInstructionId(0),
scope: empty(),
});
if (param.kind === "Identifier") {
context.declare(param.identifier, {
id: makeInstructionId(0),
scope: empty(),
});
} else {
context.declare(param.place.identifier, {
id: makeInstructionId(0),
scope: empty(),
});
}
}
visitReactiveFunction(fn, new PropagationVisitor(), context);
}
@@ -117,7 +117,11 @@ export function pruneNonEscapingScopes(
// and which values are returned.
const state = new State(fn.env);
for (const param of fn.params) {
state.declare(param.identifier.id);
if (param.kind === "Identifier") {
state.declare(param.identifier.id);
} else {
state.declare(param.place.identifier.id);
}
}
visitReactiveFunction(
fn,
@@ -34,7 +34,11 @@ export function renameVariables(fn: ReactiveFunction): void {
const scopes = new Scopes();
scopes.enter(() => {
for (const param of fn.params) {
scopes.visit(param.identifier);
if (param.kind === "Identifier") {
scopes.visit(param.identifier);
} else {
scopes.visit(param.place.identifier);
}
}
visitReactiveFunction(fn, new Visitor(), scopes);
});
@@ -259,7 +259,16 @@ function enterSSAImpl(
loc: func.loc,
suggestions: null,
});
func.params = func.params.map((p) => builder.definePlace(p));
func.params = func.params.map((param) => {
if (param.kind === "Identifier") {
return builder.definePlace(param);
} else {
return {
kind: "Spread",
place: builder.definePlace(param.place),
};
}
});
}
for (const instr of block.instructions) {
@@ -282,9 +291,16 @@ function enterSSAImpl(
loweredFunc.context = loweredFunc.context.map((p) =>
builder.getPlace(p)
);
loweredFunc.params = loweredFunc.params.map((p) =>
builder.definePlace(p)
);
loweredFunc.params = loweredFunc.params.map((param) => {
if (param.kind === "Identifier") {
return builder.definePlace(param);
} else {
return {
kind: "Spread",
place: builder.definePlace(param.place),
};
}
});
enterSSAImpl(loweredFunc, builder, rootEntry);
});
entry.preds.clear();
@@ -100,13 +100,14 @@ export function leaveSSA(fn: HIRFunction): void {
> = new Map();
for (const param of fn.params) {
if (param.identifier.name !== null) {
declarations.set(param.identifier.name, {
let place: Place = param.kind === "Identifier" ? param : param.place;
if (place.identifier.name !== null) {
declarations.set(place.identifier.name, {
lvalue: {
kind: InstructionKind.Let,
place: param,
place,
},
place: param,
place,
});
}
}