"use strict";
/**
 * Multi-tier compiler engine: tree-walk eval, bytecode VM, WASM / LLVM codegen.
 */
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateLlvm = exports.generateWasm = exports.CodeGenerator = exports.defaultEngine = exports.CompilerEngine = void 0;
exports.compile = compile;
exports.evaluate = evaluate;
exports.compileToWasm = compileToWasm;
exports.compileToLlvm = compileToLlvm;
exports.compileToNative = compileToNative;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const lexer_1 = require("../language/lexer");
const parser_1 = require("../language/parser");
const macro_1 = require("../language/macro");
const checker_1 = require("../language/checker");
const evaluator_1 = require("../language/evaluator");
const syntax_1 = require("../language/syntax");
const reflection_1 = require("../language/reflection");
const regions_1 = require("../language/regions");
const effects_1 = require("../language/effects");
const codegen_1 = require("./codegen");
Object.defineProperty(exports, "CodeGenerator", { enumerable: true, get: function () { return codegen_1.CodeGenerator; } });
Object.defineProperty(exports, "generateLlvm", { enumerable: true, get: function () { return codegen_1.generateLlvm; } });
Object.defineProperty(exports, "generateWasm", { enumerable: true, get: function () { return codegen_1.generateWasm; } });
const memory_1 = require("../runtime/memory");
const std_1 = require("../std");
const modules_1 = require("../runtime/modules");
const vm_1 = require("../vm");
const values_1 = require("../language/values");
/**
 * Multi-tier high-performance compiler engine.
 * Fast path: tree-walking evaluator. Second tier: bytecode VM.
 * Slow path: WASM / LLVM codegen.
 */
class CompilerEngine {
    compile(source, options = {}) {
        const diagnostics = [];
        const checkOwnership = options.checkOwnership !== false;
        const lowered = (0, syntax_1.lowerSyntax)(source);
        const lexer = new lexer_1.Lexer(lowered);
        const parser = new parser_1.Parser(lexer);
        let program = parser.parseProgram();
        for (const err of parser.getErrors()) {
            diagnostics.push({ message: err, phase: "parse" });
        }
        const macro = new macro_1.MacroExpander().expand(program);
        program = macro.program;
        for (const err of macro.errors) {
            diagnostics.push({ message: err, phase: "macro" });
        }
        if (options.enableReflection !== false) {
            const reflected = (0, reflection_1.expandReflection)(program);
            program = reflected.program;
            for (const err of reflected.errors) {
                diagnostics.push({ message: err, phase: "reflection" });
            }
        }
        let regions = [];
        if (options.enableRegions !== false) {
            const regionResult = (0, regions_1.inferRegions)(program);
            regions = regionResult.regions;
            program = regionResult.program;
            for (const err of regionResult.errors) {
                diagnostics.push({ message: err, phase: "region" });
            }
        }
        if (checkOwnership) {
            const checker = new checker_1.OwnershipChecker();
            const ownershipErrors = checker.check(program);
            for (const d of ownershipErrors) {
                diagnostics.push(checkToPipeline(d, "ownership"));
            }
        }
        if (options.enableEffects !== false) {
            const effectDiags = (0, effects_1.checkEffects)(program);
            for (const d of effectDiags) {
                diagnostics.push({
                    message: d.message,
                    line: d.line,
                    column: d.column,
                    phase: "effects",
                });
            }
        }
        const artifact = {
            program,
            diagnostics,
            regions,
        };
        const tier = options.tier ?? "eval";
        if (tier === "wasm" || tier === "native") {
            artifact.codegen = (0, codegen_1.generateWasm)(program);
            if (options.outputDir) {
                artifact.outputPath = writeCodegen(artifact.codegen, options.outputDir, options.fileName ?? "main", "wat");
            }
        }
        else if (tier === "llvm") {
            artifact.codegen = (0, codegen_1.generateLlvm)(program);
            if (options.outputDir) {
                artifact.outputPath = writeCodegen(artifact.codegen, options.outputDir, options.fileName ?? "main", "ll");
            }
        }
        return artifact;
    }
    async evaluate(source, options = {}) {
        (0, memory_1.resetMemoryEngine)();
        const tier = options.tier ?? "eval";
        const artifact = this.compile(source, {
            ...options,
            tier: tier === "vm" ? "eval" : tier,
        });
        const hardErrors = artifact.diagnostics.filter((d) => d.phase === "parse" ||
            d.phase === "macro" ||
            d.phase === "ownership" ||
            d.phase === "effects");
        if (hardErrors.some((d) => d.phase === "parse" || d.phase === "ownership")) {
            return {
                value: new values_1.ErrorObj(hardErrors.map((d) => d.message).join("\n")),
                output: [],
                diagnostics: artifact.diagnostics,
            };
        }
        const rootDir = options.rootDir ?? process.cwd();
        const modulesDir = options.modulesDir ?? path.join(rootDir, modules_1.MODULES_DIRNAME);
        const stdlibDir = options.stdlibDir !== undefined
            ? options.stdlibDir
            : (0, modules_1.findStdlibDir)(rootDir);
        if (tier === "vm") {
            const compiled = (0, vm_1.compileProgram)(artifact.program);
            if (compiled.error || !compiled.bytecode) {
                return {
                    value: new values_1.ErrorObj(compiled.error ?? "vm compile failed"),
                    output: [],
                    diagnostics: [
                        ...artifact.diagnostics,
                        {
                            message: compiled.error ?? "vm compile failed",
                            phase: "vm",
                        },
                    ],
                };
            }
            const result = (0, vm_1.runBytecode)(compiled.bytecode);
            return {
                value: result.value,
                output: result.output,
                diagnostics: result.error
                    ? [
                        ...artifact.diagnostics,
                        { message: result.error, phase: "vm" },
                    ]
                    : artifact.diagnostics,
            };
        }
        const env = new evaluator_1.Environment();
        (0, std_1.installStdlib)(env);
        if (options.bindings) {
            for (const [name, value] of Object.entries(options.bindings)) {
                env.set(name, value);
            }
        }
        void (0, memory_1.getMemoryEngine)();
        const result = await (0, evaluator_1.runSourceAsync)(source, env, artifact.program, {
            rootDir,
            modulesDir,
            stdlibDir,
            filePath: options.filePath,
            onReady: options.webHost
                ? ({ env: e, evaluator }) => {
                    options.webHost.install(e, (fn, args) => evaluator.applyFunction(fn, args));
                }
                : undefined,
        });
        return { ...result, diagnostics: artifact.diagnostics };
    }
    compileToWasm(source, outputDir, fileName = "main") {
        return this.compile(source, { tier: "wasm", outputDir, fileName });
    }
    compileToLlvm(source, outputDir, fileName = "main") {
        return this.compile(source, { tier: "llvm", outputDir, fileName });
    }
    compileNative(source, outputDir, fileName = "main") {
        const artifact = this.compile(source, { tier: "native", outputDir, fileName });
        if (artifact.codegen && outputDir) {
            const note = path.join(outputDir, "NATIVE.md");
            fs.writeFileSync(note, `# Nexus native compile path

Generated WebAssembly text at: ${artifact.outputPath ?? "(in-memory)"}

To produce a binary module:
  wat2wasm main.wat -o main.wasm

To go via LLVM (alternative artifact):
  Use the Nexus: Compile to LLVM command, then:
  llc main.ll -o main.s
  clang main.s -o main
`, "utf8");
        }
        return artifact;
    }
}
exports.CompilerEngine = CompilerEngine;
function checkToPipeline(d, phase) {
    return {
        message: d.message,
        line: d.line,
        column: d.column,
        phase,
    };
}
function writeCodegen(codegen, outputDir, fileName, ext) {
    fs.mkdirSync(outputDir, { recursive: true });
    const outPath = path.join(outputDir, `${fileName}.${ext}`);
    fs.writeFileSync(outPath, codegen.source, "utf8");
    return outPath;
}
exports.defaultEngine = new CompilerEngine();
function compile(source, options) {
    return exports.defaultEngine.compile(source, options);
}
async function evaluate(source, options) {
    return exports.defaultEngine.evaluate(source, options);
}
function compileToWasm(source, outputDir) {
    return exports.defaultEngine.compileToWasm(source, outputDir);
}
function compileToLlvm(source, outputDir) {
    return exports.defaultEngine.compileToLlvm(source, outputDir);
}
function compileToNative(source, outputDir) {
    return exports.defaultEngine.compileNative(source, outputDir);
}
//# sourceMappingURL=engine.js.map