import {
ReactiveFunction,
ReactiveScopeBlock,
ReactiveStatement,
ReactiveTerminal,
ReactiveTerminalStatement,
} from "../HIR/HIR";
import { assertExhaustive } from "../Utils/utils";
import {
ReactiveFunctionTransform,
Transformed,
visitReactiveFunction,
} from "./visitors";
export function flattenReactiveLoops(fn: ReactiveFunction): void {
visitReactiveFunction(fn, new Transform(), false);
}
class Transform extends ReactiveFunctionTransform<boolean> {
override transformScope(
scope: ReactiveScopeBlock,
isWithinLoop: boolean
): Transformed<ReactiveStatement> {
this.visitScope(scope, isWithinLoop);
if (isWithinLoop) {
return {
kind: "replace",
value: {
kind: "pruned-scope",
scope: scope.scope,
instructions: scope.instructions,
},
};
} else {
return { kind: "keep" };
}
}
override visitTerminal(
stmt: ReactiveTerminalStatement<ReactiveTerminal>,
isWithinLoop: boolean
): void {
switch (stmt.terminal.kind) {
case "do-while":
case "while":
case "for":
case "for-of":
case "for-in": {
this.traverseTerminal(stmt, true);
break;
}
case "try":
case "label":
case "break":
case "continue":
case "if":
case "return":
case "switch":
case "throw": {
this.traverseTerminal(stmt, isWithinLoop);
break;
}
default: {
assertExhaustive(
stmt.terminal,
`Unexpected terminal kind \`${(stmt.terminal as any).kind}\``
);
}
}
}
}