/*
 * Copyright (c) 2023 Ross Cunniff
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

namespace oadlmach {

// OADL opcodes
const
    // Miscellaneous group
    OP_NOP              = 0x00, // Do nothing
    OP_POP              = 0x01, // val pop
    OP_DUP              = 0x02, // val dup => val val
    OP_EXCH             = 0x03, // v1 v2 exch => v2 v1
    OP_DUPN             = 0x04, // v0 v1 ... vn n dupn => v0 v1 ... vn v0
    OP_INC              = 0x05, // v0 => v0 + 1 (without promotion)
    OP_DEC              = 0x06, // v0 => v0 - 1 (without promotion)
    // Unused: 0x07

    // Arithmetic
    OP_ADD              = 0x08, // op1 op2 add => (op1 + op2)
    OP_SUB              = 0x09, // op1 op2 sub => (op1 - op2)
    OP_MUL              = 0x0A, // op1 op2 mul => (op1 * op2)
    OP_DIV              = 0x0B, // op1 op2 div => (op1 / op2)
    OP_MOD              = 0x0C, // op1 op2 mod => (op1 % op2)
    OP_NEG              = 0x0D, // op1 neg => (-op1)
    OP_POW              = 0x0E, // op1 op2 pow => (op1 ** op2)
    // Unused: 0x0F

    // Boolean
    OP_AND              = 0x10, // op1 op2 and => (op1 & op2)
    OP_OR               = 0x11, // op1 op2 or => (op1 | op2)
    OP_XOR              = 0x12, // op1 op2 xor => (op1 ^ op2)
    OP_NOT              = 0x13, // op1 not => (~op1)
    OP_LOGNOT           = 0x14, // op1 lognot => (~op1)
    OP_LSHIFT           = 0x15, // op1 op2 lshift => (op1 << op2)
    OP_RSHIFT           = 0x16, // op1 op2 rshift => (op1 >> op2)
    // Unused: 0x17

    // Comparison
    OP_LT               = 0x18, // op1 op2 lt => (op1 < op2)
    OP_GT               = 0x19, // op1 op2 gt => (op1 > op2)
    OP_LE               = 0x1A, // op1 op2 le => (op1 <= op2)
    OP_GE               = 0x1B, // op1 op2 ge => (op1 >= op2)
    // Unused: 0x1C - 0x1F

    // Equivalence
    OP_EQ               = 0x20, // op1 op2 eq => (op1 == op2)
    OP_NE               = 0x21, // op1 op2 ne => (op1 != op2)
    OP_ARR_EQ           = 0x22, // op1 op2 arreq => (op1 #= op2)
    // Unused: 0x23 - 0x27

    // String matching
    OP_MATCH            = 0x28, // str patt comp MATCH => new match env
    OP_ENDMATCH         = 0x29, // ENDMATCH => pop match env
    OP_NMATCH           = 0x2A, // NMATCH => # of matches
    OP_MATCHN           = 0x2B, // N MATCHN => (match #N)
    // Unused: 0x2C - 0x2F

    // Execution flow
    OP_CALL             = 0x30, // arg1 arg2 ... argN N addr call
    OP_RET              = 0x31, // retval ret
    OP_MCALL            = 0x32, // arg1 arg2 ... argN N obj public mcall
    OP_JMP              = 0x33, // addr jmp
    OP_JMPZ             = 0x34, // val addr jmpz
    OP_LOCALS           = 0x35, // Allocate locals on the stack
    OP_TRY              = 0x36, // addr try
    OP_ENDTRY           = 0x37, // endtry
    OP_THROW            = 0x38, // excepnum throw
    OP_PROC             = 0x39, // PROC => current executing proc
    OP_ARR_CALL         = 0x3A, // arr addr arrcall
    OP_ARR_MCALL        = 0x3B, // arr obj public arrmcall
    // Unused: 0x3C - 0x3F

    // Get/set global, local, arg, index
    OP_GETG             = 0x40, // global getg => (*global)
    OP_SETG             = 0x41, // global val setg
    OP_SETG_TC          = 0x42, // type global val setg_tc
    OP_GETL             = 0x43, // local getl => (*local)
    OP_SETL             = 0x44, // local val setl
    OP_SETL_TC          = 0x45, // type local val setl_tc
    OP_GETA             = 0x46, // arg geta => (*arg)
    OP_SETA             = 0x47, // arg val seta
    OP_SETA_TC          = 0x48, // type arg val seta_tc
    OP_GETP             = 0x49, // prop getp => (self.prop)
    OP_SETP             = 0x4A, // prop val setp
    OP_SETP_TC          = 0x4B, // type prop val setp_tc
    OP_GETPK            = 0x4C, // prop getpk => prop (self.prop)
    OP_GETI             = 0x4D, // arr index geti => (arr[index])
    OP_GETI_M           = 0x4E, // arr i0 i1 ... n geti_m => arr[i0,i1,...]
    OP_SETI             = 0x4F, // arr index val seti
    OP_SETI_M           = 0x50, // arr i0 i1 ... n val seti_m
    OP_GETIK            = 0x51, // arr index getik => arr index arr[index]
    OP_GETIK_M          = 0x52, // arr i0 i1 ... n getik_m => arr i0 ... a[i]
    OP_GETPUB           = 0x53, // obj pub getpub => obj.pub
    OP_SETPUB           = 0x54, // obj pub val setpub
    OP_GETPUBK          = 0x55, // obj pub getpubk => obj pub obj.pub
    OP_SELF             = 0x56, // self => self
    OP_LOOPINIT         = 0x57, // vbase expr num ishash loopinit => stop?
    OP_LOOPINCR         = 0x58, // vbase num ishash loopincr => stop?
    OP_GETI_X           = 0x59, // arr index geti_x => arr#[index]
    OP_GETI_XK          = 0x5A, // arr index geti_xk => arr index arr#[index]
    OP_SETI_X           = 0x5B, // arr index val seti_x
    OP_SETSUBR          = 0x5C, // arr s0 e0 s1 e1 ... n val setsubr
    OP_GETSUB_K         = 0x5D, // arr s0 e0 ... n getsub_k arr s0 .. arr[..]
    // Unused: 0x5E - 0x5F

    // Debugging ops
    OP_BREAKPOINT       = 0x60, // Break and exec
    OP_DEBUG_POP        = 0x61, // Pop debug name stack
    OP_LINE             = 0x62, // linenum line
    OP_DEBUG_PRINT      = 0x63, // var DEBUG_PRINT
    OP_BREAK_HALT       = 0x64, // Break and halt
    // Unused: 0x64 - 0x6F

    // Push instructions - 0 extra bytes
    OP_NIL              = 0x70, // Push nil - 0xFFFFFFFF
    OP_FLT_0            = 0x71, // Push 0.0
    OP_INT_0            = 0x72, // Push 0
    OP_DBL_0            = 0x73, // Push 0.d (only OADL64)
    OP_I64_0            = 0x74, // Push 0L (only OADL64)
    OP_WCH_0            = 0x75, // Push '\x0'L
    OP_F16_0            = 0x76, // Push 0.0h
    OP_U16_0            = 0x77, // Push 0us
    OP_I16_0            = 0x78, // Push 0s
    OP_U8_0             = 0x79, // Push 0ub
    OP_I8_0             = 0x7A, // Push 0b
    OP_CHR_0            = 0x7B, // Push '\x0'
    OP_FALSE            = 0x7C, // Push false
    OP_TRUE             = 0x7D, // Push true
    OP_ARG_0            = 0x7E, // Push address of arg 0
    // Unused: 0x7F

    // Unused: 0x80 - 0x8F

    // Push instructions - 1 extra byte
    OP_INT_8            = 0x90, // Push -128 to 127
    OP_I64_8            = 0x91, // Push -128l to 127l (OADL64)
    OP_WCH_8            = 0x92, // Push '\x0'L to '\xFF'L
    OP_U16_8            = 0x93, // Push 0us to 255us
    OP_I16_8            = 0x94, // Push -128s to 127s
    OP_U8_8             = 0x95, // Push 0ub to 255ub
    OP_I8_8             = 0x96, // Push -128b to 127b
    OP_CHR_8            = 0x97, // Push Char
    OP_TYP_8            = 0x98, // Push 8-bit Type
    OP_EXCP_8           = 0x99, // Push 8-bit Exception
    OP_LOCAL_8          = 0x9A, // next byte is local var offs
    OP_ARG_8            = 0x9B, // next byte is arg offs
    OP_BUILTIN          = 0x9C, // next byte is builtin number from builtin.h
    OP_FILE_8           = 0x9D, // Push 8-bit File
    // Unused: 0x9E - 0x9F

    // Multibyte instructions - 2 extra bytes
    OP_INT_16           = 0xA0, // Push -32768 to 32767
    OP_FLT_16           = 0xA1, // next 2 bytes are upper bits of float
    OP_I64_16           = 0xA2, // Push -32768l to 32767l (OADL64)
    OP_DBL_16           = 0xA3, // next 2 bytes are upper bits of dbl (OADL64)
    OP_WCH_16           = 0xA4, // Push '\x0800'L to '\xFFFF'L
    OP_F16_16           = 0xA5, // Push Half
    OP_U16_16           = 0xA6, // Push 0us to 65535us
    OP_I16_16           = 0xA7, // Push -32768s to 32767s
    OP_LOCAL_16         = 0xA8, // next 2 bytes are local var offs
    OP_ARG_16           = 0xA9, // next 2 bytes are arg offs
    OP_DEBUG_PUSH       = 0xAA, // next 2 bytes are unique ID
    // Unused: 0xAB - 0xAF

    // Multibyte instructions - various extra bytes
    OP_FLT_24           = 0xB0, // next 3 bytes are upper 3 of float
    OP_DBL_24           = 0xB1, // next 3 bytes are upper 3 of dbl (OADL64)
    OP_WCH_24           = 0xB2, // Push '\x080000'L to '\xFFFFFF'L
    OP_ADDRESS          = 0xB3, // next 3 bytes are code address offset
    // Unused: 0xB4 - 0xB7      // next 3 bytes...
    OP_PARENT           = 0xB8, // next 4 bytes are parent object
    OP_DBL_32           = 0xB9, // next 4 bytes are upper 4 of Double (OADL64)
    OP_I64_32           = 0xBA, // next 4 bytes are lower 4 of Long (OADL64)
    OP_DEBUG_VAR        = 0xBB, // next 4 bytes are name for debugging
    OP_FILE             = 0xBC, // next 4 bytes are array ID of filename
    OP_DEBUG_PUSH_NS    = 0xBD, // next 4 bytes are namespace name ID
    // Unused: 0xBE             // next 4 bytes...
    OP_VAR_64           = 0xBF, // next 8 bytes are 64-bit Var (OADL64 only)

    // Multibyte instructions - 4 extra bytes
    OP_PUSH_32          = 0xC0; // Lower 6 bits of opcode are type.
                                // Next 4 bytes are value.

// Builtins
const
    // Procedure argument builtins
    BI_ARG = 0x00,      // arg(n) => argument #n
    BI_NARGS = 0x01,    // nargs() => number of arguments
    BI_ARGVEC = 0x02,   // argvec() => array of arguments
    BI_GETLOCAL = 0x03, // getlocal(offs) => local at stack[offs]
    BI_SETLOCAL = 0x04, // setlocal(offs,val) => stack[offs] = val
    // Unused: 0x05 - 0x0F

    // Type utilities
    BI_TYPEOF = 0x10,   // typeof(v) => type of v
    BI_TYPECHECK = 0x11,// typecheck(v,typ) => NIL (raise $TYPECHECK if fail)
    BI_IS_A = 0x12,     // is_a(a,b) - true iff b is a parent of a
    BI_ISARRAY = 0x13,  // isarray(v) => true iff a is an array
    BI_ISINT = 0x14,    // a.isint() = true iff a has an integral type
    BI_ISFLOAT = 0x15,  // a.isfloat() = true iff a has a floating pt type
    BI_ISCHAR = 0x16,   // a.ischar() = true iff a has a character type
    BI_ISSTRING = 0x17, // a.isstring() = true iff is a string or lstring
    BI_ARRBASE = 0x18,  // a.arrbase() => base tyhpe of a, or Array if het
    BI_ISNUMERIC = 0x19,// a.isnumeric() = true iff a has a numeric type
    BI_PROMOTE = 0x1A,  // a.promote(b) => promoted type of a op b
    BI_PACKTYPE = 0x1B, // a.packtype(opt-rank) => packed arr type of base a
    // Unused: 0x1C - 0x1F

    // Memory management utilities
    BI_COPY = 0x20,     // copy(v) => copy of (possibly read-only) v
    BI_PERM = 0x21,     // perm(a) => permanent copy of a
    BI_GC = 0x22,       // gc() => nil - collect garbage
    BI_PROTECT = 0x23,  // protect(a) => write-protected version of a
    BI_DEEP_COPY = 0x24,// deepcopy(v) => recursive copy of v
    BI_READONLY = 0x25, // readonly(a) or readonly(a,b) => true iff so
    BI_TRANSIENT = 0x26,// transient(a) => true iff array a can go away
    // Unused: 0x27 - 0x2F

    // Control flow
    BI_SETJMP = 0x30,   // setjmp(a) => nil on set, lonjump v on jump
    BI_LONGJMP = 0x31,  // longjmp(a,v) => does not return
    BI_HALT = 0x32,     // halt() - does not return (halts current thread)
    BI_SAVE = 0x33,     // save(v) - returns true/false/nil dep on restore
    BI_RESTORE = 0x34,  // restore(v) - does not return if successful
    BI_RESTART = 0x35,  // restart() - does not return if successful
    // Unused: 0x36 - 0x3F

    // Misc numerics
    BI_FIX2FLT = 0x40,  // fix2flt(a,typ) => (a / (tmax(typeof(a)))) => typ
    BI_FLT2FIX = 0x41,  // flt2fix(a,typ) => (a * tmax(typ)) => typ
    BI_MIN = 0x42,      // min(a,b) => (a < b) ? a : b
    BI_MAX = 0x43,      // max(a,b) => (a > b) ? a : b
    BI_CLAMP = 0x44,    // clamp(a,mn,mx) => (a<mn) ? mn : ((a>mx) : mx : a)
    BI_LERP = 0x45,     // lerp(a,mn,mx) => (1-a)*mn + a*mx (a clamped 0..1)
    BI_SATADD = 0x46,   // satadd(a,b,mn,mx) => clamp(a+b,mn,mx)
    BI_SATSUB = 0x47,   // satsub(a,b,mn,mx) => clamp(a-b,mn,mx)
    BI_ABS = 0x48,      // abs(a) => absolute value of a
    BI_SIGNUM = 0x49,   // signum(a) => signum of a (-1, 0, 1)
    // Unused: 0x4A - 0x4F

    // Internal variables
    // Unused 0x50
    // Unused 0x51
    BI_INTR_PUSH = 0x52,// intrpush() - returns depth of intrinsic stack
    BI_INTR_POP = 0x53, // intrpop() - pops the intrinsic stack
    BI_INTR_EXIT = 0x54,// intrexit() - resets the intrinsic stack
    // Unused: 0x55 - 0x5F

    // Array / dict handling
    BI_ARRAY = 0x60,    // array(shape) => n-element array
    BI_PACKED = 0x61,   // packed(type,shape) => shaped packed array of type
    BI_STRING = 0x62,   // string(n) => n-element string
    BI_LSTRING = 0x63,  // lstring(n) => n-element wide string
    BI_PACK = 0x64,     // pack(a) => packed version of array a
    BI_UNPACK = 0x65,   // unpack(a) => generic array version of packed a
    BI_LENGTH = 0x66,   // length(a) => length of array a (elem 0 of shape)
    BI_SHAPE = 0x67,    // shape(a) => shape of array a
    BI_RANK = 0x68,     // rank(a) => shape of array a
    BI_CONCAT = 0x69,   // concat(a,b) => a ## b
    BI_SUBR = 0x6A,     // subr(val,i1,i2,...,in) => val[i1:i2,...,in-1,in]
    BI_ITERATE = 0x6B,  // iterate(shape) => {0,1,2,3,...,n-1}
    BI_RESHAPE = 0x6C,  // reshape(v,shape) => reshaped copy of v
    BI_DICT = 0x6D,     // dict(n) => dictionary of size n
    BI_SIZEOF = 0x6E,   // sizeof(arr) => total # of elements of arr
    // Unused: 0x6F

    // More array operations
    BI_REDUCE = 0x70,   // arr.reduce(op,ax)
    BI_ACCUM = 0x71,    // arr.accum(op,ax)
    BI_INNER = 0x72,    // arr1.inner(op,arr2)
    BI_ENCLOSE = 0x73,  // arr.enclose(ax)
    BI_OUTER = 0x74,    // arr1.outer(op1,op2,arr2)
    BI_REPLICATE = 0x75,// arr1.replicate(vec,ax)
    // Unused 0x76
    BI_REVERSE = 0x77,  // arr.reverse(ax)
    BI_ROTATE = 0x78,   // arr.rotate(ax)
    BI_TRANSPOSE = 0x79,// arr.transpose(ax)
    BI_TAKE = 0x7A,     // arr.take(num,ax)
    BI_DROP = 0x7B,     // arr.drop(num,ax)
    BI_UNRAVEL = 0x7C,  // arr.unravel(ax)
    BI_LAMINATE = 0x7D, // arr1.laminate(arr2,ax)
    BI_MEMBER = 0x7E,   // arr1.member(arr2)
    BI_POSITION = 0x7F, // arr1.position(arr2)

    // Even more array operations
    BI_ENCODE = 0x80,   // arr1.encode(arr2)
    BI_DECODE = 0x81,   // arr1.decode(arr2)
    BI_SORT = 0x82,
    BI_UNIQUE = 0x83,   // arr.unique()
    BI_UNION = 0x84,    // arr1.union(arr2)
    BI_INTERSECT = 0x85,// arr1.intersect(arr2)
    BI_WITHOUT = 0x86,  // arr1.without(arr2)
    BI_INCREMENT = 0x87,// arr1.increment(arr2) - odometer function
    BI_STRIDE = 0x88,   // arr.stride() - return the array stride
    // Unused 0x89
    BI_GETIDX = 0x8A,
    BI_SETIDX = 0x8B,
    BI_ARRCMP = 0x8C,
    BI_FLATTEN = 0x8D,
    // Unused: 0x8E - 0xCF

    // I/O builtins
    BI_SAY = 0xD0,      // say(a,b,c,...) or f.say(a,b,c,...)
    BI_CLOSE = 0xD1,    // f.close()
    BI_READSTR = 0xD2,  // a = readstr() or a = f.readstr()
    BI_PRINT = 0xD3,    // print(fmt,a,b,c,...) or f..print(fmt,a,b,c,...)
    BI_READ = 0xD4,     // arr = f.read(fmt,t,...) or arr = f.read(t,...)
    BI_WRITE = 0xD5,    // f.write(a,b,c,...)
    BI_FORMAT = 0xD6,   // a = format(fmt, a, b, c)
    BI_REWIND = 0xD7,   // f.rewind()
    BI_FSEEK = 0xD8,    // f.fseek(pos)
    BI_GETCHAR = 0xD9,  // c = f.getchar()
    BI_PUTCHAR = 0xDA,  // f.putchar(c)
    BI_FFLUSH = 0xDB,   // f.fflush()
    // Unused: 0xDC - 0xDF

    BI_FERROR = 0xE0,   // err = f.ferror()
    BI_FEOF = 0xE1,     // tf = f.feof()
    BI_FTELL = 0xE2,    // pos = f.ftell()
    BI_BINARY = 0xE3,   // tf = f.binary()
    BI_ISPIPE = 0xE4,   // tf = f.ispipe()
    BI_GETSWAB = 0xE5,  // tf = f.getswab()
    BI_SETSWAB = 0xE6,  // f.setswab(tf)
    BI_CLEARERR = 0xE7, // f.clearerr()

    // Other attribute builtins
    BI_MINVAL = 0xE8,   // typ.minval() => minimum value of typ
    BI_MAXVAL = 0xE9,   // typ.maxval() => maximum value of typ
    // Unused: 0xEA - 0xEF

    // Pseudo-builtins - not directly callable with procedure syntax
    BI_NEW = 0xF0,      // new(cls,obj) - create object with given class
    BI_TYPECONV = 0xF1, // typeconv(val,typ) => (val => typ)
    BI_ASSERT = 0xF2,   // assert(expr) => nil (throws $ASSERT$ if false)
    BI_MKLIST = 0xF3,   // mklist(v0,v1,...,vn) =>  {v0,v1,...,vn}
    BI_MKDICT = 0xF4,   // mkdict(v0,v1,...,v2n+1) => <<<v0,v1,...,v2n+1>>>
    BI_MKARR = 0xF5,    // mkarr(rank,s0,..,v0,...) => [[v0,...],[...],...]
    BI_MIN_N = 0xF6,    // min(a,b,...,z) => minimum value of elements
    BI_MAX_N = 0xF7,    // max(a,b,...,z) => maximum value of elements
    BI_CONCAT_N = 0xF8, // concat(a,b,...,z) => a ## b ## ... ## z
    BI_ITERATOR = 0xF9, // [a:b:c] => a b c iterator
    BI_MKSUBARR = 0xFA, // var num mksubarr => num-dimensioned array
    BI_OBJPROP = 0xFB,  // obj offs objprop => obj[objprop] - for debugger
    BI_SETOBJPROP = 0xFC; // obj offs val setobjprop - for debugger
    // Unused: 0xFD - 0xFF


#if(#defined(OADLMACH_DEFINE_EXTERNS)) // [
var OADL_OpcodeSizes = [
    1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b,  // 0x00
    1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b,  // 0x10
    1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b,  // 0x20
    1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b,  // 0x30
    1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b,  // 0x40
    1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b,  // 0x50
    1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b,  // 0x60
    1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b,  // 0x70
    1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b, 1b,  // 0x80
    2b, 2b, 2b, 2b, 2b, 2b, 2b, 2b, 2b, 2b, 2b, 2b, 2b, 2b, 2b, 2b,  // 0x90
    3b, 3b, 3b, 3b, 3b, 3b, 3b, 3b, 3b, 3b, 3b, 3b, 3b, 3b, 3b, 3b,  // 0xA0
    4b, 4b, 4b, 4b, 4b, 4b, 4b, 4b, 5b, 5b, 5b, 5b, 5b, 5b, 5b, 9b,  // 0xB0
    5b, 5b, 5b, 5b, 5b, 5b, 5b, 5b, 5b, 5b, 5b, 5b, 5b, 5b, 5b, 5b,  // 0xC0
    5b, 5b, 5b, 5b, 5b, 5b, 5b, 5b, 5b, 5b, 5b, 5b, 5b, 5b, 5b, 5b,  // 0xD0
    5b, 5b, 5b, 5b, 5b, 5b, 5b, 5b, 5b, 5b, 5b, 5b, 5b, 5b, 5b, 5b,  // 0xE0
    5b, 5b, 5b, 5b, 5b, 5b, 5b, 5b, 5b, 5b, 5b, 5b, 5b, 5b, 5b, 5b   // 0xF0
];
var OADL_op0types = <<<
     0, "Null",
     1, "Float",
     2, "Int",
     3, "Double",
     4, "Long",
     5, "WideChar",
     6, "Half",
     7, "Ushort",
     8, "Short",
     9, "Ubyte",
    10, "Byte",
    11, "Char",
    12, "Bool",
    13, "Bool",
    14, "$ARG$"
>>>;
var OADL_op8types = <<<
     0, "Int",
     1, "Long",
     2, "WideChar",
     3, "Ushort",
     4, "Short",
     5, "Ubyte",
     6, "Byte",
     7, "Char",
     8, "Type",
     9, "Except",
    10, "$LOCAL$",
    11, "$ARG$",
    12, "$INTR$",
    13, "File"
>>>;
var OADL_op16types = <<<
     0, "Int",
     1, "Float",
     2, "Long",
     3, "Double",
     4, "WideChar",
     5, "Half",
     6, "Ushort",
     7, "Short",
     8, "$LOCAL$",
     9, "$ARG$"
>>>;

proc OADL_InstrCount(op)
{
    return Int(OADL_OpcodeSizes[op]);
}


proc OADL_Decode(ip, o, op, args : PackUint)
{
    var size;

    args[0] = 0;
    args[1] = 0;
    size = OADL_InstrCount(op);

    switch (size) {
    case 2 :
        args[0] =                                                 ip[o+1];
    case 3 :
        args[0] =                                  (ip[o+2]<<8) | ip[o+1];
    case 4 :
        args[0] =                  (ip[o+3]<<16) | (ip[o+2]<<8) | ip[o+1];
    case 5 :
        args[0] = (ip[o+4]<<24u) | (ip[o+3]<<16) | (ip[o+2]<<8) | ip[o+1];
    case 9 :
        args[0] = (ip[o+4]<<24u) | (ip[o+3]<<16) | (ip[o+2]<<8) | ip[o+1];
        args[1] = (ip[o+8]<<24u) | (ip[o+7]<<16) | (ip[o+6]<<8) | ip[o+5];
    }

    return size;
}

var opcodeTab = <<<
    OP_NOP, "NOP",
    OP_POP, "POP",
    OP_DUP, "DUP",
    OP_EXCH, "EXCH",
    OP_DUPN, "DUPN",
    OP_INC, "INC",
    OP_DEC, "DEC",

    OP_ADD, "ADD",
    OP_SUB, "SUB",
    OP_MUL, "MUL",
    OP_DIV, "DIV",
    OP_MOD, "MOD",
    OP_NEG, "NEG",
    OP_POW, "POW",

    OP_AND, "AND",
    OP_OR, "OR",
    OP_XOR, "XOR",
    OP_NOT, "NOT",
    OP_LOGNOT, "LOGNOT",
    OP_LSHIFT, "LSHIFT",
    OP_RSHIFT, "RSHIFT",

    OP_LT, "LT",
    OP_GT, "GT",
    OP_LE, "LE",
    OP_GE, "GE",

    OP_EQ, "EQ",
    OP_NE, "NE",
    OP_ARR_EQ, "ARR_EQ",

    OP_MATCH, "MATCH",
    OP_ENDMATCH, "ENDMATCH",
    OP_NMATCH, "NMATCH",
    OP_MATCHN, "MATCHN",

    OP_CALL, "CALL",
    OP_RET, "RET",
    OP_MCALL, "MCALL",
    OP_JMP, "JMP",
    OP_JMPZ, "JMPZ",
    OP_LOCALS, "LOCALS",
    OP_TRY, "TRY",
    OP_ENDTRY, "ENDTRY",
    OP_THROW, "THROW",
    OP_PROC, "PROC",
    OP_ARR_CALL, "ARR_CALL",
    OP_ARR_MCALL, "ARR_MCALL",

    OP_GETG, "GETG",
    OP_SETG, "SETG",
    OP_SETG_TC, "SETG_TC",
    OP_GETL, "GETL",
    OP_SETL, "SETL",
    OP_SETL_TC, "SETL_TC",
    OP_GETA, "GETA",
    OP_SETA, "SETA",
    OP_SETA_TC, "SETA_TC",
    OP_GETP, "GETP",
    OP_SETP, "SETP",
    OP_SETP_TC, "SETP_TC",
    OP_GETPK, "GETPK",
    OP_GETI, "GETI",
    OP_GETI_M, "GETI_M",
    OP_SETI, "SETI",
    OP_SETI_M, "SETI_M",
    OP_GETIK, "GETIK",
    OP_GETIK_M, "GETIK_M",
    OP_GETPUB, "GETPUB",
    OP_SETPUB, "SETPUB",
    OP_GETPUBK, "GETPUBK",
    OP_SELF, "SELF",
    OP_LOOPINIT, "LOOPINIT",
    OP_LOOPINCR, "LOOPINCR",
    OP_GETI_X, "GETI_X",
    OP_GETI_XK, "GETI_XK",
    OP_SETI_X, "SETI_X",

    OP_BREAKPOINT, "BREAKPOINT",
    OP_DEBUG_POP, "DEBUG_POP",
    OP_LINE, "LINE",
    OP_DEBUG_PRINT, "DEBUG_PRINT",
    OP_BREAK_HALT, "BREAK_HALT",

    OP_NIL, "NIL",
    OP_FLT_0, "FLT_0",
    OP_INT_0, "INT_0",
    OP_DBL_0, "DBL_0",
    OP_I64_0, "I64_0",
    OP_WCH_0, "WCH_0",
    OP_F16_0, "F16_0",
    OP_U16_0, "U16_0",
    OP_I16_0, "I16_0",
    OP_U8_0, "U8_0",
    OP_I8_0, "I8_0",
    OP_CHR_0, "CHR_0",
    OP_FALSE, "FALSE",
    OP_TRUE, "TRUE",
    OP_ARG_0, "ARG_0",

    OP_INT_8, "INT_8",
    OP_I64_8, "I64_8",
    OP_WCH_8, "WCH_8",
    OP_U16_8, "U16_8",
    OP_I16_8, "I16_8",
    OP_U8_8, "U8_8",
    OP_I8_8, "I8_8",
    OP_CHR_8, "CHR_8",
    OP_TYP_8, "TYP_8",
    OP_EXCP_8, "EXCP_8",
    OP_LOCAL_8, "LOCAL_8",
    OP_ARG_8, "ARG_8",
    OP_BUILTIN, "BUILTIN",
    OP_FILE_8, "FILE_8",

    OP_INT_16, "INT_16",
    OP_FLT_16, "FLT_16",
    OP_I64_16, "I64_16",
    OP_DBL_16, "DBL_16",
    OP_WCH_16, "WCH_16",
    OP_F16_16, "F16_16",
    OP_U16_16, "U16_16",
    OP_I16_16, "I16_16",
    OP_LOCAL_16, "LOCAL_16",
    OP_ARG_16, "ARG_16",
    OP_DEBUG_PUSH, "DEBUG_PUSH",

    OP_FLT_24, "FLT_24",
    OP_DBL_24, "DBL_24",
    OP_WCH_24, "WCH_24",
    OP_ADDRESS, "ADDRESS",

    OP_PARENT, "PARENT",
    OP_DBL_32, "DBL_32",
    OP_I64_32, "I64_32",
    OP_DEBUG_VAR, "DEBUG_VAR",
    OP_FILE, "FILE",
    OP_DEBUG_PUSH_NS, "DEBUG_PUSH_NS",

    OP_VAR_64, "VAR_64"
>>>;

var typeTab = <<<
#if(oadl::MAXINT <= 0x1FFFFFFF)
    // 32-bit
     0, "Float",
     1, "Int",
     2, "Double",
     3, "Long",
#else
    // 64-bit
     0, "Double",
     1, "Long",
     2, "Float",
     3, "Int",
#endif
     4, "Ulong",
     5, "Uint",
     6, "Array",
     7, "Object",

    16, "Pointer",
    17, "Dict",
    18, "Proc",
    19, "Extern",
    20, "Public",
    21, "Except",
    22, "File",
    23, "ArrayType",

    32, "$GLOBAL$",
    33, "$LOCAL$",
    34, "$ARG$",
    35, "$PROP$",
    36, "$INTR$",

    54, "WideChar",
    55, "Half",
    56, "Ushort",
    57, "Short",
    58, "Ubyte",
    59, "Byte",
    60, "Char",
    61, "Type",
    62, "Bool",
    63, "Null"
>>>;

var builtinTab = <<<
    BI_ARG, "ARG",
    BI_NARGS, "NARGS",
    BI_ARGVEC, "ARGVEC",
    BI_GETLOCAL, "GETLOCAL",
    BI_SETLOCAL, "SETLOCAL",

    BI_TYPEOF, "TYPEOF",
    BI_TYPECHECK, "TYPECHECK",
    BI_IS_A, "IS_A",
    BI_ISARRAY, "ISARRAY",
    BI_ISINT, "ISINT",
    BI_ISFLOAT, "ISFLOAT",
    BI_ISCHAR, "ISCHAR",
    BI_ISSTRING, "ISSTRING",

    BI_COPY, "COPY",
    BI_PERM, "PERM",
    BI_GC, "GC",
    BI_PROTECT, "PROTECT",
    BI_DEEP_COPY, "DEEP_COPY",
    BI_READONLY, "READONLY",
    BI_TRANSIENT, "TRANSIENT",

    BI_SETJMP, "SETJMP",
    BI_LONGJMP, "LONGJMP",
    BI_HALT, "HALT",
    BI_SAVE, "SAVE",
    BI_RESTORE, "RESTORE",
    BI_RESTART, "RESTART",

    BI_FIX2FLT, "FIX2FLT",
    BI_FLT2FIX, "FLT2FIX",
    BI_MIN, "MIN",
    BI_MAX, "MAX",
    BI_CLAMP, "CLAMP",
    BI_LERP, "LERP",
    BI_SATADD, "SATADD",
    BI_SATSUB, "SATSUB",
    BI_ABS, "ABS",
    BI_SIGNUM, "SIGNUM",

    BI_INTR_PUSH, "INTR_PUSH",
    BI_INTR_POP, "INTR_POP",
    BI_INTR_EXIT, "INTR_EXIT",

    BI_ARRAY, "ARRAY",
    BI_PACKED, "PACKED",
    BI_STRING, "STRING",
    BI_LSTRING, "LSTRING",
    BI_PACK, "PACK",
    BI_UNPACK, "UNPACK",
    BI_ISARRAY, "ISARRAY",
    BI_LENGTH, "LENGTH",
    BI_SHAPE, "SHAPE",
    BI_RANK, "RANK",
    BI_CONCAT, "CONCAT",
    BI_SUBR, "SUBR",
    BI_ITERATE, "ITERATE",
    BI_RESHAPE, "RESHAPE",
    BI_DICT, "DICT",
    BI_SIZEOF, "SIZEOF",

    BI_REDUCE, "REDUCE",
    BI_ACCUM, "ACCUM",
    BI_INNER, "INNER",
    BI_ENCLOSE, "ENCLOSE",
    BI_OUTER, "OUTER",
    BI_REPLICATE, "REPLICATE",
    BI_REVERSE, "REVERSE",
    BI_ROTATE, "ROTATE",
    BI_TRANSPOSE, "TRANSPOSE",
    BI_TAKE, "TAKE",
    BI_DROP, "DROP",
    BI_UNRAVEL, "UNRAVEL",
    BI_LAMINATE, "LAMINATE",
    BI_MEMBER, "MEMBER",
    BI_POSITION, "POSITION",

    BI_ENCODE, "ENCODE",
    BI_DECODE, "DECODE",
    BI_SORT, "SORT",
    BI_UNIQUE, "UNIQUE",
    BI_UNION, "UNION",
    BI_INTERSECT, "INTERSECT",
    BI_WITHOUT, "WITHOUT",
    BI_INCREMENT, "INCREMENT",
    BI_STRIDE, "STRIDE",
    BI_GETIDX, "GETIDX",
    BI_SETIDX, "SETIDX",
    BI_ARRCMP, "ARRCMP",
    BI_FLATTEN, "FLATTEN",

    BI_SAY, "SAY",
    BI_CLOSE, "CLOSE",
    BI_READSTR, "READSTR",
    BI_PRINT, "PRINT",
    BI_READ, "READ",
    BI_WRITE, "WRITE",
    BI_FORMAT, "FORMAT",
    BI_REWIND, "REWIND",
    BI_FSEEK, "FSEEK",
    BI_GETCHAR, "GETCHAR",
    BI_PUTCHAR, "PUTCHAR",
    BI_FFLUSH, "FFLUSH",

    BI_FERROR, "FERROR",
    BI_FEOF, "FEOF",
    BI_FTELL, "FTELL",
    BI_BINARY, "BINARY",
    BI_ISPIPE, "ISPIPE",
    BI_GETSWAB, "GETSWAB",
    BI_SETSWAB, "SETSWAB",
    BI_CLEARERR, "CLEARERR",

    BI_NEW, "NEW",
    BI_TYPECONV, "TYPECONV",
    BI_ASSERT, "ASSERT",
    BI_MKLIST, "MKLIST",
    BI_MKDICT, "MKDICT",
    BI_MKARR, "MKARR",
    BI_MIN_N, "MIN_N",
    BI_MAX_N, "MAX_N",
    BI_CONCAT_N, "CONCAT_N",
    BI_ITERATOR, "ITERATOR",
    BI_MKSUBARR, "MKSUBARR"
>>>;

#else // ] [

var OADL_OpcodeSizes;
var OADL_op0types, OADL_op8types, OADL_op16types;
proc OADL_InstrCount, OADL_Decode;
var opcodeTab, typeTab, builtinTab;

#endif // ]

}