"use strict";
/**
 * Nexus bytecode opcodes and instruction encoding (TypeScript VM).
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.Opcode = void 0;
exports.lookup = lookup;
exports.make = make;
exports.readUint16 = readUint16;
exports.readUint8 = readUint8;
exports.readOperands = readOperands;
exports.concatInstructions = concatInstructions;
var Opcode;
(function (Opcode) {
    Opcode[Opcode["OpConstant"] = 0] = "OpConstant";
    Opcode[Opcode["OpPop"] = 1] = "OpPop";
    Opcode[Opcode["OpAdd"] = 2] = "OpAdd";
    Opcode[Opcode["OpSub"] = 3] = "OpSub";
    Opcode[Opcode["OpMul"] = 4] = "OpMul";
    Opcode[Opcode["OpDiv"] = 5] = "OpDiv";
    Opcode[Opcode["OpMod"] = 6] = "OpMod";
    Opcode[Opcode["OpTrue"] = 7] = "OpTrue";
    Opcode[Opcode["OpFalse"] = 8] = "OpFalse";
    Opcode[Opcode["OpNull"] = 9] = "OpNull";
    Opcode[Opcode["OpEqual"] = 10] = "OpEqual";
    Opcode[Opcode["OpNotEqual"] = 11] = "OpNotEqual";
    Opcode[Opcode["OpGreaterThan"] = 12] = "OpGreaterThan";
    Opcode[Opcode["OpGreaterEqual"] = 13] = "OpGreaterEqual";
    Opcode[Opcode["OpLessThan"] = 14] = "OpLessThan";
    Opcode[Opcode["OpLessEqual"] = 15] = "OpLessEqual";
    Opcode[Opcode["OpMinus"] = 16] = "OpMinus";
    Opcode[Opcode["OpBang"] = 17] = "OpBang";
    Opcode[Opcode["OpJump"] = 18] = "OpJump";
    Opcode[Opcode["OpJumpNotTruthy"] = 19] = "OpJumpNotTruthy";
    Opcode[Opcode["OpGetGlobal"] = 20] = "OpGetGlobal";
    Opcode[Opcode["OpSetGlobal"] = 21] = "OpSetGlobal";
    Opcode[Opcode["OpGetLocal"] = 22] = "OpGetLocal";
    Opcode[Opcode["OpSetLocal"] = 23] = "OpSetLocal";
    Opcode[Opcode["OpGetBuiltin"] = 24] = "OpGetBuiltin";
    Opcode[Opcode["OpArray"] = 25] = "OpArray";
    Opcode[Opcode["OpHash"] = 26] = "OpHash";
    Opcode[Opcode["OpIndex"] = 27] = "OpIndex";
    Opcode[Opcode["OpCall"] = 28] = "OpCall";
    Opcode[Opcode["OpReturnValue"] = 29] = "OpReturnValue";
    Opcode[Opcode["OpReturn"] = 30] = "OpReturn";
    Opcode[Opcode["OpClosure"] = 31] = "OpClosure";
    Opcode[Opcode["OpGetFree"] = 32] = "OpGetFree";
    Opcode[Opcode["OpCurrentClosure"] = 33] = "OpCurrentClosure";
    Opcode[Opcode["OpSetIndex"] = 34] = "OpSetIndex";
    Opcode[Opcode["OpMember"] = 35] = "OpMember";
    Opcode[Opcode["OpAnd"] = 36] = "OpAnd";
    Opcode[Opcode["OpOr"] = 37] = "OpOr";
})(Opcode || (exports.Opcode = Opcode = {}));
const DEFINITIONS = {
    [Opcode.OpConstant]: { name: "OpConstant", operandWidths: [2] },
    [Opcode.OpPop]: { name: "OpPop", operandWidths: [] },
    [Opcode.OpAdd]: { name: "OpAdd", operandWidths: [] },
    [Opcode.OpSub]: { name: "OpSub", operandWidths: [] },
    [Opcode.OpMul]: { name: "OpMul", operandWidths: [] },
    [Opcode.OpDiv]: { name: "OpDiv", operandWidths: [] },
    [Opcode.OpMod]: { name: "OpMod", operandWidths: [] },
    [Opcode.OpTrue]: { name: "OpTrue", operandWidths: [] },
    [Opcode.OpFalse]: { name: "OpFalse", operandWidths: [] },
    [Opcode.OpNull]: { name: "OpNull", operandWidths: [] },
    [Opcode.OpEqual]: { name: "OpEqual", operandWidths: [] },
    [Opcode.OpNotEqual]: { name: "OpNotEqual", operandWidths: [] },
    [Opcode.OpGreaterThan]: { name: "OpGreaterThan", operandWidths: [] },
    [Opcode.OpGreaterEqual]: { name: "OpGreaterEqual", operandWidths: [] },
    [Opcode.OpLessThan]: { name: "OpLessThan", operandWidths: [] },
    [Opcode.OpLessEqual]: { name: "OpLessEqual", operandWidths: [] },
    [Opcode.OpMinus]: { name: "OpMinus", operandWidths: [] },
    [Opcode.OpBang]: { name: "OpBang", operandWidths: [] },
    [Opcode.OpJump]: { name: "OpJump", operandWidths: [2] },
    [Opcode.OpJumpNotTruthy]: { name: "OpJumpNotTruthy", operandWidths: [2] },
    [Opcode.OpGetGlobal]: { name: "OpGetGlobal", operandWidths: [2] },
    [Opcode.OpSetGlobal]: { name: "OpSetGlobal", operandWidths: [2] },
    [Opcode.OpGetLocal]: { name: "OpGetLocal", operandWidths: [1] },
    [Opcode.OpSetLocal]: { name: "OpSetLocal", operandWidths: [1] },
    [Opcode.OpGetBuiltin]: { name: "OpGetBuiltin", operandWidths: [1] },
    [Opcode.OpArray]: { name: "OpArray", operandWidths: [2] },
    [Opcode.OpHash]: { name: "OpHash", operandWidths: [2] },
    [Opcode.OpIndex]: { name: "OpIndex", operandWidths: [] },
    [Opcode.OpCall]: { name: "OpCall", operandWidths: [1] },
    [Opcode.OpReturnValue]: { name: "OpReturnValue", operandWidths: [] },
    [Opcode.OpReturn]: { name: "OpReturn", operandWidths: [] },
    [Opcode.OpClosure]: { name: "OpClosure", operandWidths: [2, 1] },
    [Opcode.OpGetFree]: { name: "OpGetFree", operandWidths: [1] },
    [Opcode.OpCurrentClosure]: { name: "OpCurrentClosure", operandWidths: [] },
    [Opcode.OpSetIndex]: { name: "OpSetIndex", operandWidths: [] },
    [Opcode.OpMember]: { name: "OpMember", operandWidths: [2] },
    [Opcode.OpAnd]: { name: "OpAnd", operandWidths: [] },
    [Opcode.OpOr]: { name: "OpOr", operandWidths: [] },
};
function lookup(op) {
    return DEFINITIONS[op];
}
function make(op, ...operands) {
    const def = DEFINITIONS[op];
    if (!def) {
        return [];
    }
    let instructionLen = 1;
    for (const w of def.operandWidths) {
        instructionLen += w;
    }
    const instruction = new Array(instructionLen);
    instruction[0] = op;
    let offset = 1;
    for (let i = 0; i < operands.length; i++) {
        const width = def.operandWidths[i];
        const o = operands[i];
        if (width === 1) {
            instruction[offset] = o & 0xff;
        }
        else if (width === 2) {
            instruction[offset] = (o >> 8) & 0xff;
            instruction[offset + 1] = o & 0xff;
        }
        offset += width;
    }
    return instruction;
}
function readUint16(ins, offset) {
    return ((ins[offset] & 0xff) << 8) | (ins[offset + 1] & 0xff);
}
function readUint8(ins, offset) {
    return ins[offset] & 0xff;
}
function readOperands(def, ins, start) {
    const operands = [];
    let offset = 0;
    for (const width of def.operandWidths) {
        if (width === 1) {
            operands.push(readUint8(ins, start + offset));
        }
        else if (width === 2) {
            operands.push(readUint16(ins, start + offset));
        }
        offset += width;
    }
    return { operands, bytesRead: offset };
}
function concatInstructions(...parts) {
    const total = parts.reduce((n, p) => n + p.length, 0);
    const out = new Uint8Array(total);
    let offset = 0;
    for (const p of parts) {
        out.set(p, offset);
        offset += p.length;
    }
    return out;
}
//# sourceMappingURL=code.js.map