import * as ast from "./ast/mod.ts"; import { Pos, prettyPrintReport, printStackTrace, Report, Span, } from "./diagnostics.ts"; import * as hir from "./middle/hir.ts"; import { Mod } from "./middle/res.ts"; export class Ctx { private fileIds = new Ids(); private files = new Map, FileInfo>(); private reports: Report[] = []; public fileHasChildWithIdent(file: File, childIdent: string): boolean { return this.files.get(idKey(file))! .subFiles.has(childIdent); } public addFile( ident: string, absPath: string, relPath: string, superFile: File | undefined, text: string, ): File { const file = this.fileIds.nextThenStep(); this.files.set(idKey(file), { ident, absPath, relPath, superFile, subFiles: new Map(), text, }); if (superFile) { this.files.get(idKey(superFile))! .subFiles.set(ident, file); } return file; } public addFileAst(file: File, ast: ast.File) { this.files.get(idKey(file))!.ast = ast; } public fileInfo(file: File): FileInfo { return this.files.get(idKey(file))!; } public entryFile(): File { return keyId(0); } public iterFiles(): Iterator { return this.files.keys() .map((key) => keyId(key)); } // private identIds = new Ids(); private identStringToId = new Map(); private identIdToString = new Map, string>(); public internIdent(ident: string): IdentId { if (this.identStringToId.has(ident)) { return this.identStringToId.get(ident)!; } const id = this.identIds.nextThenStep(); this.identStringToId.set(ident, id); this.identIdToString.set(idKey(id), ident); return id; } public identText(ident: IdentId): string { return this.identIdToString.get(idKey(ident))!; } // private hirIds = new Ids(); private stmts = new Map, hir.Stmt>(); /// don't intern the same thing twice public internStmt(kind: hir.StmtKind, span: Span): hir.Stmt { const id = this.hirIds.nextThenStep(); const v: hir.Stmt = { id, kind, span }; this.stmts.set(idKey(id), v); return v; } private exprs = new Map, hir.Expr>(); /// don't intern the same thing twice public internExpr(kind: hir.ExprKind, span: Span): hir.Expr { const id = this.hirIds.nextThenStep(); const v: hir.Expr = { id, kind, span }; this.exprs.set(idKey(id), v); return v; } private pats = new Map, hir.Pat>(); /// don't intern the same thing twice public internPat(kind: hir.PatKind, span: Span): hir.Pat { const id = this.hirIds.nextThenStep(); const v: hir.Pat = { id, kind, span }; this.pats.set(idKey(id), v); return v; } private tys = new Map, hir.Ty>(); /// don't intern the same thing twice public internTy(kind: hir.TyKind, span: Span): hir.Ty { const id = this.hirIds.nextThenStep(); const v: hir.Ty = { id, kind, span }; this.tys.set(idKey(id), v); return v; } private blocks = new Map, hir.Block>(); /// don't intern the same thing twice public internBlock(block: Omit): hir.Block { const id = this.hirIds.nextThenStep(); const v: hir.Block = { id, ...block }; this.blocks.set(idKey(id), v); return v; } // private defIds = new Ids(); private defs = new Map, HirId>(); public addHirIdDef(hirId: HirId): DefId { const id = this.defIds.nextThenStep(); this.defs.set(idKey(id), hirId); return id; } public defHirId(id: DefId): HirId { return this.defs.get(idKey(id))!; } private modDefs = new Map, Mod>(); private modItemMaps = new Map, Map, DefId>>(); public modDef(id: DefId): Mod { return this.modDefs.get(idKey(id))!; } public mod(id: DefId, ident: IdentId): DefId | undefined { return this.modItemMaps.get(idKey(id))!.get(idKey(ident)); } // public filePosLineText(file: File, pos: Pos): string { const fileTextLines = this.fileInfo(file).text.split("\n"); return fileTextLines[pos.line - 1]; } public fileSpanText(file: File, span: Span): string { let result = ""; const fileTextLines = this.fileInfo(file).text.split("\n"); for (let i = 0; i < fileTextLines.length; i++) { if (i > span.end.line - 1) { break; } if (i >= span.begin.line - 1) { result += fileTextLines[i] + "\n"; } } return result; } public report(rep: Report) { this.reports.push(rep); this.reportImmediately(rep); } public enableReportImmediately = false; public enableStacktrace = false; private reportImmediately(rep: Report) { if (this.enableReportImmediately) { prettyPrintReport(this, rep); if (this.enableStacktrace) { printStackTrace(); } } } public printAsts() { for (const [_, info] of this.files) { console.log(`${info.absPath}:`); console.log(JSON.stringify(info.ast!, null, 2)); } } } export type File = IdBase & { readonly _: unique symbol }; export type FileInfo = { ident: string; absPath: string; relPath: string; superFile?: File; subFiles: Map; text: string; ast?: ast.File; }; export type IdentId = IdBase & { readonly _: unique symbol }; export type HirId = IdBase & { readonly _: unique symbol }; export type DefId = IdBase & { readonly _: unique symbol }; export type IdBase = { key: number }; export type Key = IdType["key"]; export const idKey = (id: IdType): Key => id.key; export const keyId = ( key: Key, ): IdType => ({ key } as IdType); export class Ids { private next = 0; public nextThenStep(): IdType { const key = this.next; this.next += 1; return { key } as IdType; } }