import * as ast from "../ast/mod.ts"; import { IdBase, IdentId, IdMap } from "../ids.ts"; import { Res } from "../util.ts"; export interface Syms { getVal(ident: ast.Ident): Resolve; getTy(ident: ast.Ident): Resolve; defVal(ident: ast.Ident, kind: ResolveKind): Res; defTy(ident: ast.Ident, kind: ResolveKind): Res; } export type Resolve = { ident: ast.Ident; kind: ResolveKind; }; export type LocalId = IdBase & { readonly _: unique symbol }; export type ResolveKind = | { tag: "error" } | { tag: "fn"; item: ast.Item; kind: ast.FnItem } | { tag: "local"; id: LocalId }; export const ResolveError = (ident: ast.Ident): Resolve => ({ ident, kind: { tag: "error" }, }); export type Redef = { ident: ast.Ident; }; export class SymsOneNsTab { private defs = new IdMap(); public get(ident: ast.Ident): Resolve | undefined { return this.defs.get(ident.id)!; } public def(ident: ast.Ident, kind: ResolveKind): Res { if (this.defs.has(ident.id)) { return Res.Err({ ident: this.defs.get(ident.id)!.ident }); } this.defs.set(ident.id, { ident, kind }); return Res.Ok(undefined); } } export class SymsNsTab { private vals = new SymsOneNsTab(); private tys = new SymsOneNsTab(); public getVal(ident: ast.Ident): Resolve | undefined { return this.vals.get(ident); } public getTy(ident: ast.Ident): Resolve | undefined { return this.tys.get(ident); } public defVal(ident: ast.Ident, kind: ResolveKind): Res { return this.vals.def(ident, kind); } public defTy(ident: ast.Ident, kind: ResolveKind): Res { return this.tys.def(ident, kind); } } export class RootSyms implements Syms { private syms = new SymsNsTab(); getVal(ident: ast.Ident): Resolve { return this.syms.getVal(ident) || ResolveError(ident); } getTy(ident: ast.Ident): Resolve { return this.syms.getTy(ident) || ResolveError(ident); } defVal(ident: ast.Ident, kind: ResolveKind): Res { return this.syms.defVal(ident, kind); } defTy(ident: ast.Ident, kind: ResolveKind): Res { return this.syms.defTy(ident, kind); } } export class FnSyms implements Syms { private syms = new SymsNsTab(); public constructor( private parent: Syms, ) {} getVal(ident: ast.Ident): Resolve { const res = this.syms.getVal(ident) || this.parent.getVal(ident); if (res.kind.tag === "local") { return ResolveError(ident); } return res; } getTy(ident: ast.Ident): Resolve { return this.syms.getTy(ident) || this.parent.getTy(ident); } defVal(ident: ast.Ident, kind: ResolveKind): Res { return this.syms.defVal(ident, kind); } defTy(ident: ast.Ident, kind: ResolveKind): Res { return this.syms.defTy(ident, kind); } } export class LocalSyms implements Syms { private syms = new SymsNsTab(); public constructor( private parent: Syms, ) {} getVal(ident: ast.Ident): Resolve { return this.syms.getVal(ident) || this.parent.getVal(ident); } getTy(ident: ast.Ident): Resolve { return this.syms.getTy(ident) || this.parent.getTy(ident); } defVal(ident: ast.Ident, kind: ResolveKind): Res { return this.syms.defVal(ident, kind); } defTy(ident: ast.Ident, kind: ResolveKind): Res { return this.syms.defTy(ident, kind); } }