slige-mirror/compiler/ctx.ts
2025-01-28 15:15:30 +01:00

164 lines
4.3 KiB
TypeScript

import * as ast from "./ast/mod.ts";
import {
Pos,
prettyPrintReport,
printStackTrace,
Report,
Span,
} from "./diagnostics.ts";
import * as hir from "./middle/hir.ts";
export class Ctx {
private fileIds = new Ids<File>();
private files = new Map<Key<File>, 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<File> {
return this.files.keys()
.map((key) => keyId(key));
}
private identIds = new Ids<IdentId>();
private identStringToId = new Map<string, IdentId>();
private identIdToString = new Map<Key<IdentId>, 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 stmtIds = new Ids<hir.StmtId>();
private stmts = new Map<Key<hir.StmtId>, hir.Stmt>();
public internStmt(kind: hir.StmtKind, span: Span): hir.StmtId {
const id = this.stmtIds.nextThenStep();
this.stmts.set(idKey(id), { kind, span });
return id;
}
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<string, File>;
text: string;
ast?: ast.File;
};
export type IdentId = IdBase & { readonly _: unique symbol };
export type DefId = IdBase & { readonly _: unique symbol };
export type IdBase = { key: number };
export type Key<IdType extends IdBase> = IdType["key"];
export const idKey = <IdType extends IdBase>(id: IdType): Key<IdType> => id.key;
export const keyId = <IdType extends IdBase>(
key: Key<IdType>,
): IdType => ({ key } as IdType);
export class Ids<IdType extends IdBase> {
private next = 0;
public nextThenStep(): IdType {
const key = this.next;
this.next += 1;
return { key } as IdType;
}
}