import type { Sym } from "./ast.ts"; export type SymMap = { [ident: string]: Sym }; type GetRes = { ok: true; sym: Sym } | { ok: false }; export interface Syms { define(ident: string, sym: Sym): void; definedLocally(ident: string): boolean; get(ident: string): GetRes; } export class EntryModSyms implements Syms { private syms: SymMap = {}; public constructor() {} public define(ident: string, sym: Sym) { if (sym.type === "let") { this.define(ident, { ...sym, type: "let_static", }); return; } this.syms[ident] = sym; } public definedLocally(ident: string): boolean { return ident in this.syms; } public get(ident: string): GetRes { if (ident in this.syms) { return { ok: true, sym: this.syms[ident] }; } return { ok: false }; } } export class ModSyms implements Syms { private syms: SymMap = {}; public constructor(private parent: Syms) { this.syms["super"] = { type: "mod", ident: "super", syms: this.parent, }; } public define(ident: string, sym: Sym) { if (sym.type === "let") { this.define(ident, { ...sym, type: "let_static", }); return; } this.syms[ident] = sym; } public definedLocally(ident: string): boolean { return ident in this.syms; } public get(ident: string): GetRes { if (ident in this.syms) { return { ok: true, sym: this.syms[ident] }; } return { ok: false }; } } export class FnSyms implements Syms { private syms: SymMap = {}; public constructor(private parent: Syms) {} public define(ident: string, sym: Sym) { if (sym.type === "let") { this.define(ident, { ...sym, type: "closure", inner: sym, }); return; } this.syms[ident] = sym; } public definedLocally(ident: string): boolean { return ident in this.syms; } public get(ident: string): GetRes { if (ident in this.syms) { return { ok: true, sym: this.syms[ident] }; } return this.parent.get(ident); } } export class LeafSyms implements Syms { private syms: SymMap = {}; public constructor(private parent: Syms) {} public define(ident: string, sym: Sym) { this.syms[ident] = sym; } public definedLocally(ident: string): boolean { return ident in this.syms; } public get(ident: string): GetRes { if (ident in this.syms) { return { ok: true, sym: this.syms[ident] }; } return this.parent.get(ident); } }