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): Sym; definedLocally(ident: string): boolean; get(ident: string): GetRes; getPub(ident: string): GetRes; rootMod(): Sym; pathString(): string; } export class EntryModSyms implements Syms { private syms: SymMap = {}; public constructor(private modName: string) {} public define(ident: string, sym: Sym): Sym { if (sym.type === "let") { return this.define(ident, { ...sym, type: "let_static", }); } this.syms[ident] = sym; return 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 }; } public getPub(ident: string): GetRes { if (ident in this.syms) { return { ok: true, sym: this.syms[ident] }; } return { ok: false }; } public rootMod(): Sym { return { type: "mod", ident: this.modName, fullPath: this.modName, syms: this, }; } public pathString(): string { return this.modName; } } export class ModSyms implements Syms { private syms: SymMap = {}; public constructor(private parent: Syms, private modName: string) { this.syms["super"] = { type: "mod", ident: "super", fullPath: this.pathString(), syms: this.parent, }; } public define(ident: string, sym: Sym): Sym { if (sym.type === "let") { return 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 }; } public getPub(ident: string): GetRes { if (ident in this.syms) { return { ok: true, sym: this.syms[ident] }; } return { ok: false }; } public rootMod(): Sym { return this.parent.rootMod(); } public pathString(): string { return `${this.parent.pathString()}::${this.modName}`; } } export class FnSyms implements Syms { private syms: SymMap = {}; public constructor(private parent: Syms) {} public define(ident: string, sym: Sym): Sym { if (sym.type === "let") { return this.define(ident, { ...sym, type: "closure", inner: sym, }); } this.syms[ident] = sym; return 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); } public getPub(ident: string): GetRes { if (ident in this.syms) { return { ok: true, sym: this.syms[ident] }; } return { ok: false }; } public rootMod(): Sym { return this.parent.rootMod(); } public pathString(): string { return this.parent.pathString(); } } export class LeafSyms implements Syms { private syms: SymMap = {}; public constructor(private parent: Syms) {} public define(ident: string, sym: Sym): Sym { this.syms[ident] = sym; return 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); } public getPub(ident: string): GetRes { if (ident in this.syms) { return { ok: true, sym: this.syms[ident] }; } return { ok: false }; } public rootMod(): Sym { return this.parent.rootMod(); } public pathString(): string { return this.parent.pathString(); } }