import {
BlockId,
ReactiveFunction,
ReactiveStatement,
ReactiveTerminalStatement,
} from "../HIR/HIR";
import {
ReactiveFunctionTransform,
Transformed,
visitReactiveFunction,
} from "./visitors";
export function pruneUnusedLabels(fn: ReactiveFunction): void {
const labels: Labels = new Set();
visitReactiveFunction(fn, new Transform(), labels);
}
type Labels = Set<BlockId>;
class Transform extends ReactiveFunctionTransform<Labels> {
override transformTerminal(
stmt: ReactiveTerminalStatement,
state: Labels
): Transformed<ReactiveStatement> {
this.traverseTerminal(stmt, state);
const { terminal } = stmt;
if (
(terminal.kind === "break" || terminal.kind === "continue") &&
terminal.targetKind === "labeled"
) {
state.add(terminal.target);
}
const isReachableLabel = stmt.label !== null && state.has(stmt.label.id);
if (stmt.terminal.kind === "label" && !isReachableLabel) {
const block = [...stmt.terminal.block];
const last = block.at(-1);
if (
last !== undefined &&
last.kind === "terminal" &&
last.terminal.kind === "break" &&
last.terminal.target === null
) {
block.pop();
}
return { kind: "replace-many", value: block };
} else {
if (!isReachableLabel && stmt.label != null) {
stmt.label.implicit = true;
}
return { kind: "keep" };
}
}
}