import { Sym } from "./ast.ts"; export type SymMap = { [ident: string]: Sym }; export interface Syms { define(ident: string, sym: Sym): void; definedLocally(ident: string): boolean; get(ident: string): { ok: true; sym: Sym } | { ok: false }; } export class GlobalSyms 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): { ok: true; sym: Sym } | { ok: false } { if (ident in this.syms) { return { ok: true, sym: this.syms[ident] }; } return { ok: false }; } } export class StaticSyms implements Syms { private syms: SymMap = {}; public constructor(private parent: GlobalSyms) {} 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): { ok: true; sym: Sym } | { ok: false } { if (ident in this.syms) { return { ok: true, sym: this.syms[ident] }; } return this.parent.get(ident); } } 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): { ok: true; sym: Sym } | { ok: false } { 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): { ok: true; sym: Sym } | { ok: false } { if (ident in this.syms) { return { ok: true, sym: this.syms[ident] }; } return this.parent.get(ident); } }