export type Program = Ins[];
export type Ins = Ops | number;

// NOTICE: keep up to date with runtime/arch.hpp

export type Ops = typeof Ops;
export const Ops = {
    Nop: 0x00,
    PushNull: 0x01,
    PushInt: 0x02,
    PushBool: 0x03,
    PushString: 0x04,
    PushPtr: 0x05,
    Pop: 0x06,
    ReserveStatic: 0x07,
    LoadStatic: 0x08,
    StoreStatic: 0x09,
    LoadLocal: 0x0a,
    StoreLocal: 0x0b,
    Call: 0x0c,
    Return: 0x0d,
    Jump: 0x0e,
    JumpIfTrue: 0x0f,
    Builtin: 0x10,
    Add: 0x20,
    Subtract: 0x21,
    Multiply: 0x22,
    Divide: 0x23,
    Remainder: 0x24,
    Equal: 0x25,
    LessThan: 0x26,
    And: 0x27,
    Or: 0x28,
    Xor: 0x29,
    Not: 0x2a,
    SourceMap: 0x30,
} as const;

export type Builtins = typeof Builtins;
export const Builtins = {
    IntToString: 0x00,
    StringConcat: 0x10,
    StringEqual: 0x11,
    StringCharAt: 0x12,
    StringLength: 0x13,
    StringPushChar: 0x14,
    StringToInt: 0x15,
    ArrayNew: 0x20,
    ArraySet: 0x21,
    ArrayPush: 0x22,
    ArrayAt: 0x23,
    ArrayLength: 0x24,
    StructSet: 0x30,
    Print: 0x40,
    FileOpen: 0x41,
    FileClose: 0x42,
    FileWriteString: 0x43,
    FileReadChar: 0x44,
    FileReadToString: 0x45,
    FileFlush: 0x46,
    FileEof: 0x47,
} as const;

export function opToString(op: number): string {
    return Object.entries(Ops)
        .find(([_key, value]) => value === op)
        ?.[0] ?? `<unknown Op ${op}>`;
}

export function builtinToString(builtin: number): string {
    return Object.entries(Builtins)
        .find(([_key, value]) => value === builtin)
        ?.[0] ?? `<unknown Builtin ${builtin}>`;
}