export interface Locals { reserveId(id: number): void; allocSym(ident: string): void; symId(ident: string): number; } export class LocalsFnRoot implements Locals { private localsAmount = 0; private localIdCounter = 0; private symLocalMap: { [key: string]: number } = {}; constructor(private parent?: Locals) { } public reserveId(id: number): void { this.localsAmount = Math.max(id + 1, this.localsAmount); } public allocSym(ident: string) { this.symLocalMap[ident] = this.localIdCounter; this.localIdCounter++; this.reserveId(this.localIdCounter); } public symId(ident: string): number { if (ident in this.symLocalMap) { return this.symLocalMap[ident]; } if (this.parent) { return this.parent.symId(ident); } throw new Error(`undefined symbol '${ident}'`); } } export class LocalLeaf implements Locals { private localIdCounter = 0; private symLocalMap: { [key: string]: number } = {}; constructor(private parent: Locals) { } public reserveId(id: number): void { this.parent.reserveId(id); } public allocSym(ident: string) { this.symLocalMap[ident] = this.localIdCounter; this.localIdCounter++; this.reserveId(this.localIdCounter); } public symId(ident: string): number { if (ident in this.symLocalMap) { return this.symLocalMap[ident]; } return this.parent.symId(ident); } }