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'};
}
}
}