import { Expr, Stmt, Sym } from "./ast.ts"; import { Pos } from "./Token.ts"; type Ident = string type SymMap = { [ident: string]: Sym } class 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] }; if (this.parent) return this.parent.get(ident); return { ok: false }; } } // Chapter 7 is generally fucked, remember to give feedback to Simon class Resolver { private root = new Syms(); private resolveIdentExpr(expr: Expr, syms: Syms) { if (expr.kind.type !== "ident") throw new Error("expected ident"); const ident = expr.kind; const symResult = syms.get(ident.value); if (!symResult.ok) { this.reportUseOfUndefined(ident.value, expr.pos, syms); return; } const sym = symResult.sym expr.kind = { type: "sym", ident: ident.value, defType: sym.type, }; if (sym.stmt) expr.kind.stmt = sym.stmt; if (sym.param) expr.kind.param = sym.param; } private resolveExpr(expr: Expr, syms: Syms) { if (expr.kind.type === "error") { return; } if (expr.kind.type === "ident") { this.resolveIdentexpr(expr, syms); return; } // ... if (expr.kind.type === "binary") { this.resolveExpr(expr.kind.left, syms); this.resolveExpr(expr.kind.right, syms); return; } // ... if (expr.kind.type === "block") { const childSyms = new Syms(syms); for (const stmt of expr.kind.stmts) { this.resolveStmt(stmt, childSyms); } if (expr.kind.expr) { this.resolveExpr(expr.kind.expr, childSyms); } return; } // ... throw new Error(`unknown expression ${expr.kind.type}`); } private resolveIdentexpr(expr: Expr, syms: Syms) { } private resolveStmt(stmt: Stmt, syms: Syms) { if (stmt.kind.type === "error") { return; } if (stmt.kind.type === "let") { this.resolveLetStmt(stmt, syms); return; } if (stmt.kind.type === "fn") { this.resolveFnStmt(stmt, syms); return; } if (stmt.kind.type === "return") { if (stmt.kind.expr) this.resolveExpr(stmt.kind.expr, syms); return; } // ... throw new Error(`unknown statement ${stmt.kind.type}`); } private resolveLetStmt(stmt: Stmt, syms: Syms) { } private resolveFnStmt(stmt: Stmt, syms: Syms) { } private reportUseOfUndefined(ident: Ident, pos: Pos, syms: Syms) { console.error(`use of undefined symbol '${ident}' at ${pos.line}${pos.col}`); } private reportAlreadyDefined(ident: Ident, pos: Pos, syms: Syms) { console.error(`symbol already defined '${ident}', at ${pos.line}${pos.col}`); const prev = syms.get(ident); if (!prev.ok) throw new Error("expected to be defined"); if (!prev.sym.pos) return; const { line: prevLine, col: prevCol } = prev.sym.pos; console.error(`previous definition of '${ident}' at ${prevLine}:${prevCol}`); } }