import { AstCreator } from "./ast.ts";
import { Checker } from "./checker.ts";
import { CompoundAssignDesugarer } from "./desugar/compound_assign.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";

export type CompiledFile = {
    filepath: string;
    program: number[];
};

export type CompileResult = {
    program: number[];
    fnNames: FnNamesMap;
};

export class Compiler {
    private astCreator = new AstCreator();
    private reporter = new Reporter();

    public constructor(private startFilePath: string) {}

    public async compile(): Promise<CompileResult> {
        const text = await Deno.readTextFile(this.startFilePath);

        const lexer = new Lexer(text, this.reporter);

        const parser = new Parser(lexer, this.astCreator, this.reporter);
        const ast = parser.parse();

        new SpecialLoopDesugarer(this.astCreator).desugar(ast);

        new Resolver(this.reporter).resolve(ast);

        new CompoundAssignDesugarer(this.astCreator).desugar(ast);

        new Checker(this.reporter).check(ast);

        if (this.reporter.errorOccured()) {
            console.error("Errors occurred, stopping compilation.");
            Deno.exit(1);
        }

        const { monoFns, callMap } = new Monomorphizer(ast).monomorphize();

        const lowerer = new Lowerer(monoFns, callMap, lexer.currentPos());
        const { program, fnNames } = lowerer.lower();
        lowerer.printProgram();

        return { program, fnNames };
    }
}
