import * as ast from "./ast.ts";
import { selectFnInstructions } from "./codegen/x86_64/isel.ts";
import { Reporter } from "./diagnostics.ts";
import * as front from "./front/mod.ts";
import * as middle from "./middle.ts";
import * as mir from "./mir.ts";
import { FnInterpreter } from "./mir_interpreter.ts";
import * as stringify from "./stringify.ts";

const reporter = new Reporter();

const filename = Deno.args[0];
const text = await Deno.readTextFile(filename);

const fileRep = reporter.ofFile({ filename, text });

const fileAst = front.parse(text, fileRep);
const syms = front.resolve(fileAst, fileRep);

let mainFn: ast.NodeWithKind<"FnStmt"> | null = null;

fileAst.visit({
    visit(node) {
        if (node.kind.tag === "FnStmt" && node.kind.ident === "main") {
            if (mainFn) {
                console.error("error: multiple 'main' functions");
                Deno.exit(1);
            }

            ast.assertNodeWithKind(node, "FnStmt");
            mainFn = node;
        }
    },
});

if (!mainFn) {
    console.error("error: no 'main' function");
    Deno.exit(1);
}

const checker = new front.Checker(syms, fileRep);
const fnTys = checker.checkFn(mainFn);

const m = new middle.MiddleLowerer(syms, checker);
const mainMiddleFn = m.lowerFn(mainFn);

if (Deno.args.includes("--print-mir")) {
    for (const fn of m.allFns()) {
        stringify.printWithConsoleColors(fn.pretty(stringify.consoleColors));
    }
}

const result = selectFnInstructions(mainMiddleFn);
stringify.printWithConsoleColors(
    stringify.x86_64FnPretty(result, stringify.consoleColors),
);
// console.log(JSON.stringify(result, null, 4));

if (!reporter.ok()) {
    reporter.printAll();
    Deno.exit(1);
}

new FnInterpreter(mainMiddleFn, []).eval();
