import { AstCreator, Mod, Stmt } from "./ast.ts"; import { Checker } from "./checker.ts"; import { CompoundAssignDesugarer } from "./desugar/compound_assign.ts"; import { StructLiteralDesugarer } from "./desugar/struct_literal.ts"; import { SpecialLoopDesugarer } from "./desugar/special_loop.ts"; import { Reporter } from "./info.ts"; import { Lexer } from "./lexer.ts"; import { Monomorphizer } from "./mono.ts"; import { FnNamesMap, Lowerer } from "./lowerer.ts"; import { Parser } from "./parser.ts"; import { Resolver } from "./resolver.ts"; import { AstVisitor, VisitRes, visitStmts } from "./ast_visitor.ts"; import * as path from "jsr:@std/path"; import { Pos } from "./token.ts"; import { ArrayLiteralDesugarer } from "./desugar/array_literal.ts"; export type CompileResult = { program: number[]; fnNames: FnNamesMap; }; export class Compiler { private astCreator = new AstCreator(); private reporter; public constructor(private startFilePath: string) { this.reporter = new Reporter(this.startFilePath); } public async compile(): Promise { const mod = new ModTree( this.startFilePath, this.astCreator, this.reporter, ).resolve(); new SpecialLoopDesugarer(this.astCreator).desugar(mod.ast); new ArrayLiteralDesugarer(this.astCreator).desugar(mod.ast); new StructLiteralDesugarer(this.astCreator).desugar(mod.ast); new Resolver(this.reporter).resolve(mod.ast); new CompoundAssignDesugarer(this.astCreator).desugar(mod.ast); new Checker(this.reporter).check(mod.ast); if (this.reporter.errorOccured()) { console.error("Errors occurred, stopping compilation."); Deno.exit(1); } const { monoFns, callMap } = new Monomorphizer(mod.ast).monomorphize(); const lastPos = await lastPosInTextFile(this.startFilePath); const lowerer = new Lowerer(monoFns, callMap, lastPos); const { program, fnNames } = lowerer.lower(); //lowerer.printProgram(); return { program, fnNames }; } } export class ModTree implements AstVisitor<[string]> { constructor( private entryFilePath: string, private astCreator: AstCreator, private reporter: Reporter, ) {} public resolve(): Mod { const entryAst = this.parseFile(this.entryFilePath); visitStmts(entryAst, this, this.entryFilePath); return { filePath: this.entryFilePath, ast: entryAst }; } private parseFile(filePath: string): Stmt[] { const text = Deno.readTextFileSync(filePath); const lexer = new Lexer(text, this.reporter); const parser = new Parser(lexer, this.astCreator, this.reporter); const ast = parser.parse(); return ast; } visitModBlockStmt(stmt: Stmt, filePath: string): VisitRes { if (stmt.kind.type !== "mod_block") { throw new Error(); } const { ident, stmts: ast } = stmt.kind; stmt.kind = { type: "mod", ident, mod: { filePath, ast }, }; visitStmts(ast, this, filePath); return "stop"; } visitModFileStmt(stmt: Stmt, filePath: string): VisitRes { if (stmt.kind.type !== "mod_file") { throw new Error(); } const { ident, filePath: modFilePath } = stmt.kind; const ast = this.parseFile( ident === "std" ? path.join( path.dirname(path.fromFileUrl(Deno.mainModule)), "../std/lib.slg", ) : path.join(path.dirname(filePath), modFilePath), ); stmt.kind = { type: "mod", ident, mod: { filePath, ast } }; visitStmts(ast, this, filePath); return "stop"; } } async function lastPosInTextFile(filePath: string): Promise { const text = await Deno.readTextFile(filePath); let index = 0; let line = 1; let col = 1; while (index < text.length) { if (text[index] == "\n") { line += 1; col = 1; } else { col += 1; } index += 1; } return { index, line, col }; }