/*
 * Copyright (c) 2024 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.
 */

/* Note that the order of this enumeration is architected, and embedded
 * in generated code.  Changing the order breaks backward compatibility.
 */
typedef enum {
    /* Procedure argument / local variable builtins */
    BI_ARG = 0x00,      /* arg(n) => argument #n */
    BI_NARGS,           /* nargs() => number of arguments */
    BI_ARGVEC,          /* argvec() => array of arguments */
    BI_GETLOCAL,        /* getlocal(offs) => local at stack[offs] */
    BI_SETLOCAL,        /* setlocal(offs,val) => stack[offs] = val */
    BI_MATCHVEC,        /* matchvec() => the match vector */
    BI_SETGLOBAL,       /* setglobal(offs,val) => globs[offs] = val */
    BI_SETPROP,         /* setprop(offs,val) => self[offs] = val */
    /* Unused: 0x08 - 0x0F */

    /* Type utilities */
    BI_TYPEOF = 0x10,   /* typeof(v) => type of v */
    BI_TYPECHECK,       /* typecheck(v,typ) => NIL (raise $TYPECHECK if fail) */
    BI_IS_A,            /* is_a(a,b) - true iff b is a parent of a */
    BI_ISARRAY,         /* isarray(a) => true iff a is an array */
    BI_ISINTEGER,       /* a.isinter() => true iff a has an integral type */
    BI_ISFLOAT,         /* a.isfloat() => true iff a has a floating pt type */
    BI_ISCHAR,          /* a.ischar() => true iff a has a character type */
    BI_ISSTRING,        /* a.isstring() => true iff a is a string or lstr */
    BI_ARRBASE,         /* a.arrbase() => base type of a, or Array if het. */
    BI_ISNUMERIC,       /* a.isnumeric() => true iff a is a numeric type */
    BI_PROMOTE,         /* a.promote(b) => promoted type of a op b */
    BI_PACKTYPE,        /* 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,            /* perm(a) => permanent copy of a */
    BI_GC,              /* gc() => nil - collect garbage */
    BI_PROTECT,         /* protect(a) => write-protected version of a */
    BI_DEEP_COPY,       /* deepcopy(v) => recursive copy of v */
    BI_READONLY,        /* readonly(a) or readonly(a,b) */
    BI_TRANSIENT,       /* transient(a) => true iff array a can go away */
    BI_DELETED,         /* deleted(obj) => true iff the object is a zombie */
    /* Unused: 0x28 - 0x2F */

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

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

    /* Internal variables */
    BI_ERR_50 = 0x50,   /* Unused for now */
    BI_ERR_51,          /* Unused for now */
    BI_INTR_PUSH,       /* intrpush() - returns depth of intrinsic stack */
    BI_INTR_POP,        /* intrpop() - pops the intrinsic stack */
    BI_INTR_EXIT,       /* intrexit() - resets the intrinsic stack */
    /* Unused: 0x55 - 0x5F */

    /* Array / dict handling */
    BI_ARRAY = 0x60,    /* array(shape) => n-element array */
    BI_PACKED,          /* packed(type,shape) => shaped packed array of type */
    BI_STRING,          /* string(n) => n-element string */
    BI_LSTRING,         /* lstring(n) => n-element wide string */
    BI_PACK,            /* pack(a) => packed version of array a */
    BI_UNPACK,          /* unpack(a) => generic array version of packed a */
    BI_LENGTH,          /* length(a) => length of array a (elem 0 of shape) */
    BI_SHAPE,           /* shape(a) => shape of array a */
    BI_RANK,            /* rank(a) => shape of array a */
    BI_CONCAT,          /* concat(a,b) => a ## b */
    BI_SUBR,            /* subr(val,i1,i2,...,in) => val[i1:i2,...,in-1,in] */
    BI_ITERATE,         /* iterate(shape) => {0,1,2,3,...,n-1} */
    BI_RESHAPE,         /* reshape(v,shape) => reshaped copy of v */
    BI_DICT,            /* dict(n) => dictionary of size n */
    BI_SIZEOF,          /* sizeof(arr) => total # of elements of arr */
    BI_WIDTH,           /* width(arr) => length of last axis of arr */

    /* More array operations */
    BI_REDUCE = 0x70,   /* arr.reduce(op,ax) */
    BI_ACCUM,           /* arr.accum(op,ax) */
    BI_INNER,           /* arr1.inner(op,arr2) */
    BI_ENCLOSE,         /* arr.enclose(ax) */
    BI_OUTER,           /* arr1.outer(op1,op2,arr2) */
    BI_REPLICATE,       /* arr.replicate(vec,ax) */
    BI_DISCLOSE,        /* encl.disclose() */
    BI_REVERSE,         /* arr.reverse(ax) */
    BI_ROTATE,          /* arr.rotate(ax) */
    BI_TRANSPOSE,       /* arr.transpose(ax) */
    BI_TAKE,            /* arr.take(vec,ax) */
    BI_DROP,            /* arr.drop(vec,ax) */
    BI_RAVEL,           /* arr.ravel(ax) */
    BI_LAMINATE,        /* arr1.laminate(arr2,ax) */
    BI_MEMBER,          /* arr1.member(arr2) */
    BI_POSITION,        /* arr1.position(vec) */

    /* Even more array operations */
    BI_ENCODE = 0x80,   /* arr.encode(vec) */
    BI_DECODE,          /* arr1.decode(arr2) */
    BI_SORT,            /* arr.sort() */
    BI_UNIQUE,          /* vec.unique() */
    BI_UNION,           /* vec.union(arr) */
    BI_INTERSECT,       /* vec.intersect(arr) */
    BI_WITHOUT,         /* vec.without(arr) */
    BI_INCREMENT,       /* idx.increment(shp) - odometer function */
    BI_STRIDE,          /* arr.stride() - return the array stride */
    BI_UNUSED_0x89,     /* Unused */
    BI_GETIDX,          /* arr.getidx#(idxarr) */
    BI_SETIDX,          /* arr.setidx#(idxarr ## val) */
    BI_ARRCMP,          /* arr1.arrcmp(vec2) - like strcmp but generalized */
    BI_FLATTEN,         /* arr.flatten() - returns a vector with no nesting */
    /* Unused: 0x8E - 0xCF */

    /* I/O builtins */
    BI_SAY = 0xD0,      /* say(a,b,c,...) or f.say(a,b,c,...) */
    BI_CLOSE,           /* f.close() */
    BI_READSTR,         /* a = readstr() or a = f.readstr() */
    BI_PRINT,           /* print(fmt,a,b,c,...) or f.print(fmt,a,b,c,...) */
    BI_READ,            /* arr = f.read(fmt,t,...) or arr = f.read(t,...) */
    BI_WRITE,           /* f.write(a,b,c,...) */
    BI_FORMAT,          /* a = format(fmt, a, b, c) */
    BI_REWIND,          /* f.rewind() */
    BI_FSEEK,           /* f.fseek(pos) */
    BI_GETCHAR,         /* c = f.getchar() */
    BI_PUTCHAR,         /* f.putchar(c) */
    BI_FFLUSH,          /* f.fflush() */
    BI_UNGETC,          /* f.ungetc(c) */
    /* Unused: 0xDD - 0xDF */

    /* I/O attribute builtins */
    BI_FERROR = 0xE0,   /* err = f.ferror() */
    BI_FEOF,            /* tf = f.feof() */
    BI_FTELL,           /* pos = f.ftell() */
    BI_BINARY,          /* tf = f.binary() */
    BI_ISPIPE,          /* tf = f.ispipe() */
    BI_GETSWAB,         /* tf = f.getswab() */
    BI_SETSWAB,         /* f.setswab(tf) */
    BI_CLEARERR,        /* f.clearerr() */

    /* Other attribute builtins */
    BI_MINVAL = 0xE8,   /* typ.minval() */
    BI_MAXVAL = 0xE9,   /* typ.maxval() */

    /* #LIST / #EDIT builtins */
    BI_X_LIST = 0xEA,   /* f.list(val,name) */
    BI_X_EDIT,          /* f.edit(name) */
    /* Unused: 0xEC - 0xEF */

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

typedef enum {
    PUB_PARENT = 0,
    PUB_CREATE = 1,
    PUB_DESTROY = 2,
    PUB_ASSIGN = 3,

    /* operators for overloading */
    PUB_OP_COMPLETE,
    PUB_OP_OR,
    PUB_OP_XOR,
    PUB_OP_AND,
    PUB_OP_LT,
    PUB_OP_GT,
    PUB_OP_PLUS,
    PUB_OP_MINUS,
    PUB_OP_MUL,
    PUB_OP_DIV,
    PUB_OP_MOD,
    PUB_OP_NOT,
    PUB_OP_BANG,
    PUB_OP_EQEQ,
    PUB_OP_ARR_EQ,
    PUB_OP_NE,
    PUB_OP_LE,
    PUB_OP_GE,
    PUB_OP_LSHIFT,
    PUB_OP_RSHIFT,
    PUB_OP_CALL,
    PUB_OP_INDEX,
    PUB_OP_INDEX_ASSIGN,
    PUB_OP_EQGT,
    PUB_OP_MATCHES,
    PUB_OP_POW,
    PUB_OP_HASH_IDX,
    PUB_OP_HASH_IDX_ASSIGN,
    PUB_OP_INC,
    PUB_OP_DEC,
    PUB_OP_NEGATIVE,

    /* Right-arg versions of overloaded operators */
    PUB_OP_OR_R,
    PUB_OP_XOR_R,
    PUB_OP_AND_R,
    PUB_OP_LT_R,
    PUB_OP_GT_R,
    PUB_OP_PLUS_R,
    PUB_OP_MINUS_R,
    PUB_OP_MUL_R,
    PUB_OP_DIV_R,
    PUB_OP_MOD_R,
    PUB_OP_EQEQ_R,
    PUB_OP_ARR_EQ_R,
    PUB_OP_NE_R,
    PUB_OP_LE_R,
    PUB_OP_GE_R,
    PUB_OP_LSHIFT_R,
    PUB_OP_RSHIFT_R,
    PUB_OP_EQGT_R,
    PUB_OP_MATCHES_R,
    PUB_OP_POW_R,

    // Public versions of builtins - overloadable
    PUB_ISARRAY,        // val.isarray()
    PUB_ISINTEGER,      // val.isinteger()
    PUB_ISFLOAT,        // val.isfloat()
    PUB_ISCHAR,         // val.ischar()
    PUB_ISSTRING,       // val.isstring()
    PUB_ARRBASE,        // val.arrbase()
    PUB_ISNUMERIC,      // val.isnumeric()
    PUB_PROMOTE,        // val.promote(other)
    PUB_PACKTYPE,       // val.packtype(opt-rank)
    PUB_PACK,           // arr.pack()
    PUB_UNPACK,         // arr.unpack()
    PUB_LENGTH,         // arr.length()
    PUB_WIDTH,          // arr.width()
    PUB_SHAPE,          // arr.shape()
    PUB_RANK,           // arr.rank()
    PUB_CONCAT,         // arr.concat(other)
    PUB_SUBR,           // arr.subr(args)
    PUB_ITERATE,        // arr.iterate()
    PUB_RESHAPE,        // arr.reshape(args)
    PUB_SIZEOF,         // val.sizeof()
    PUB_COPY,           // val.copy()
    PUB_DEEP_COPY,      // val.deepcopy()
    PUB_FIX2FLT,        // val.fix2flt(typ)
    PUB_FLT2FIX,        // val.flt2fix(typ)
    PUB_MIN,            // val.min(other)
    PUB_MAX,            // val.max(other)
    PUB_CLAMP,          // val.clamp(min,max)
    PUB_LERP,           // val.lerp(min,max)
    PUB_SATADD,         // val.satadd(other)
    PUB_SATSUB,         // val.satsub(other)
    PUB_ABS,            // val.abs()
    PUB_SIGNUM,         // val.signum()
    PUB_REDUCE,         // val.reduce(op)
    PUB_ACCUM,          // val.accum(op)
    PUB_INNER,          // val.inner(op,other)
    PUB_ENCLOSE,        // val.enclose(ax)
    PUB_OUTER,          // val.outer(op1,op2,other)
    PUB_REPLICATE,      // val.replicate(other,ax)
    PUB_DISCLOSE,       // val.disclose()
    PUB_REVERSE,        // val.reverse(ax)
    PUB_ROTATE,         // val.rotate(ax)
    PUB_TRANSPOSE,      // val.transpose(ax)
    PUB_TAKE,           // val.take(num,ax)
    PUB_DROP,           // val.drop(num,ax)
    PUB_RAVEL,          // val.ravel(ax)
    PUB_LAMINATE,       // val.laminate(other,ax)
    PUB_MEMBER,         // val.member(other)
    PUB_POSITION,       // val.position(other)
    PUB_ENCODE,         // val.encode(other)
    PUB_DECODE,         // val.decode(other)
    PUB_SORT,           // val.sort()
    PUB_UNIQUE,         // val.unique()
    PUB_UNION,          // val.union(other)
    PUB_INTERSECT,      // val.intersect(other)
    PUB_WITHOUT,        // val.without(other)
    PUB_INCREMENT,      // arr.increment(shape)
    PUB_STRIDE,         // arr.stride()
    PUB_ARRCMP,         // arr.arrcmp(otharr)
    PUB_FLATTEN,        // arr.flatten()

    PUB_READONLY,       // arr.readonly()
    PUB_TRANSIENT,      // arr.transient()
    PUB_SAY,            // f.say(a,b,c,...)
    PUB_CLOSE,          // f.close()
    PUB_READSTR,        // f.readstr()
    PUB_PRINT,          // f.print(fmt,a,b,c,...)
    PUB_READ,           // f.read()
    PUB_WRITE,          // f.write()
    PUB_REWIND,         // f.rewind()
    PUB_FSEEK,          // f.fseek()
    PUB_GETCHAR,        // f.getchar()
    PUB_PUTCHAR,        // f.putchar()
    PUB_FFLUSH,         // f.fflush()
    PUB_UNGETC,         // f.ungetc(c)
    PUB_FERROR,         // f.ferror()
    PUB_FEOF,           // f.feof()
    PUB_FTELL,          // f.ftell()
    PUB_BINARY,         // f.binary()
    PUB_ISPIPE,         // f.ispipe()
    PUB_GETSWAB,        // f.getswab()
    PUB_SETSWAB,        // f.setswab()
    PUB_CLEARERR,       // f.clearerr()

    PUB_MINVAL,         // typ.minval()
    PUB_MAXVAL,         // typ.maxval()

    PUB_NUM_PUBLICS     // Always keep as the last public!
} PredefPublics;

#define V_PARENT   OadlVar(OADL_VT_PUBLIC, PUB_PARENT)
#define V_CREATE   OadlVar(OADL_VT_PUBLIC, PUB_CREATE)
#define V_DESTROY  OadlVar(OADL_VT_PUBLIC, PUB_DESTROY)
#define V_COMPLETE OadlVar(OADL_VT_PUBLIC, PUB_OP_COMPLETE)

typedef enum {
    GLOB_TYPE_PROMOTE,  // Type promotion
    GLOB_FIELD_WIDTH,   // Printing field width
    GLOB_NUM_DIGITS,    // Printing num digits
    GLOB_NUM_EXPONENT,  // Printing num exponent digits
    GLOB_INT_RADIX,     // Radix for printing ints
    GLOB_FLT_FORMAT_CHAR, // Float format char
    GLOB_INT_FORMAT_CHAR, // Int format char
    GLOB_FORMAT_FLAGS,  // Printing flags
    GLOB_MONETARY_FILL, // Monetary fill char
    GLOB_CALC_PROMPT1,  // First-level prompt for calculator
    GLOB_CALC_PROMPT2,  // Second-level prompt for calculator
    GLOB_ITER_OPTIM,    // Optimize iterators?
    GLOB_ARGVEC,        // Argument vector
    GLOB_TERM_ROWS,     // $ROWS
    GLOB_TERM_COLUMNS,  // $COLUMNS
    GLOB_EDITOR,        // $EDITOR

    GLOB_NUM_GLOBALS    // Always  keep as last global!
} PredefGlobals;

extern const char *OADL_BuiltinNames[256];
extern const char OADL_BuiltinKinds[256];

#if defined(OADL_DEFINE_BUILTIN_TABLE) // [

const char *OADL_BuiltinNames[256] = {
    "arg",      "nargs",        "argvec",       "getlocal",     // 00
    "setlocal", "matchvec",     "setglobal",    "setprop",      // 04
    0,          0,              0,              0,              // 08
    0,          0,              0,              0,              // 0C

    "typeof",   "typecheck",    "is_a",         "isarray",      // 10
    "isinteger", "isfloat",     "ischar",       "isstring",     // 14
    "arrbase",  "isnumeric",    "promote",      "packtype",     // 18
    0,          0,              0,              0,              // 1C

    "copy",     "perm",         "gc",           "protect",      // 20
    "deepcopy", "readonly",     "transient",    "deleted",      // 24
    0,          0,              0,              0,              // 28
    0,          0,              0,              0,              // 2C

    "setjmp",   "longjmp",      "halt",         "save",         // 30
    "restore",  "restart",      0,              0,              // 34
    0,          0,              0,              0,              // 38
    0,          0,              0,              0,              // 3C

    "fix2flt",  "flt2fix",      "min",          "max",          // 40
    "clamp",    "lerp",         "satadd",       "satsub",       // 44
    "abs",      "signum",       0,              0,              // 48
    0,          0,              0,              0,              // 4C

    0,          0,              "intrpush",     "intrpop",      // 50
    "intrexit", 0,              0,              0,              // 54
    0,          0,              0,              0,              // 58
    0,          0,              0,              0,              // 5C

    "array",    "packed",       "string",       "lstring",      // 60
    "pack",     "unpack",       "length",       "shape",        // 64
    "rank",     "concat",       "subr",         "iterate",      // 68
    "reshape",  "dict",         "sizeof",       "width",        // 6C

    "reduce",   "accum",        "inner",        "enclose",      // 70
    "outer",    "replicate",    "disclose",     "reverse",      // 74
    "rotate",   "transpose",    "take",         "drop",         // 78
    "ravel",    "laminate",     "member",       "position",     // 7C

    "encode",   "decode",       "sort",         "unique",       // 80
    "union",    "intersect",    "without",      "increment",    // 84
    "stride",   0,              "getidx",       "setidx",       // 88
    "arrcmp",   "flatten",      0,              0,              // 8C

    0,          0,              0,              0,              // 90
    0,          0,              0,              0,              // 94
    0,          0,              0,              0,              // 98
    0,          0,              0,              0,              // 9C

    0,          0,              0,              0,              // A0
    0,          0,              0,              0,              // A4
    0,          0,              0,              0,              // A8
    0,          0,              0,              0,              // AC

    0,          0,              0,              0,              // B0
    0,          0,              0,              0,              // B4
    0,          0,              0,              0,              // B8
    0,          0,              0,              0,              // BC

    0,          0,              0,              0,              // C0
    0,          0,              0,              0,              // C4
    0,          0,              0,              0,              // C8
    0,          0,              0,              0,              // CC

    "say",      "close",        "readstr",      "print",        // D0
    "read",     "write",        "format",       "rewind",       // D4
    "fseek",    "getchar",      "putchar",      "fflush",       // D8
    "ungetc",   0,              0,              0,              // DC

    "ferror",   "feof",         "ftell",        "binary",       // E0
    "ispipe",   "getswab",      "setswab",      "clearerr",     // E4
    "minval",   "maxval",       "list",         "edit",         // E8
    0,          0,              0,              0,              // EC

    0,          0,              0,              0,              // F0
    0,          0,              0,              0,              // F4
    0,          0,              0,              0,              // F8
    0,          0,              0,              0,              // FC
};

// In this table, the entries have the following meanings:
//      0 - never enter the name
//      1 - always enter the name into the "oadl" namespace
//      2 - conditionally enter the name into the "oadl" namespace
//      3 - always enter the name into the global namespace
const char OADL_BuiltinKinds[256] = {
    1, 1, 1, 2, // arg         nargs           argvec          getlocal      00
    2, 1, 2, 2, // setlocal    matchvec        setglobal       setprop       04
    0, 0, 0, 0, // 0           0               0               0             08
    0, 0, 0, 0, // 0           0               0               0             0C

    3, 1, 1, 2, // typeof      typecheck       is_a            isarray       10
    0, 0, 0, 0, // isinteger   isfloat         ischar          isstring      14
    2, 2, 2, 2, // arrbase     isnumeric       promote         packtype      18
    0, 0, 0, 0, // 0           0               0               0             1C

    2, 1, 1, 1, // copy        perm            gc              protect       20
    2, 1, 1, 1, // deepcopy    readonly        transient       deleted       24
    0, 0, 0, 0, // 0           0               0               0             28
    0, 0, 0, 0, // 0           0               0               0             2C

    1, 1, 1, 1, // setjmp      longjmp         halt            save          30
    1, 1, 0, 0, // restore     restart         0               0             34
    0, 0, 0, 0, // 0           0               0               0             38
    0, 0, 0, 0, // 0           0               0               0             3C

    2, 2, 2, 2, // fix2flt     flt2fix         min             max           40
    2, 2, 2, 2, // clamp       lerp            satadd          satsub        44
    2, 2, 0, 0, // abs         signum          0               0             48
    0, 0, 0, 0, // 0           0               0               0             4C

    0, 0, 2, 2, // 0           0               intrpush        intrpop       50
    2, 0, 0, 0, // intrexit    0               0               0             54
    0, 0, 0, 0, // 0           0               0               0             58
    0, 0, 0, 0, // 0           0               0               0             5C

    2, 2, 2, 2, // array       packed          string          lstring       60
    2, 2, 1, 2, // pack        unpack          length          shape         64
    2, 2, 2, 2, // rank        concat          subr            iterate       68
    2, 2, 2, 0, // reshape     dict            sizeof          width         6C

    2, 0, 0, 2, // reduce      accum           inner           enclose       70
    0, 0, 2, 0, // outer       replicate       disclose        reverse       74
    0, 0, 0, 0, // rotate      transpose       take            drop          78
    0, 0, 0, 0, // ravel       laminate        member          position      7C

    0, 0, 0, 0, // encode      decode          sort            unique        80
    0, 0, 0, 0, // union       intersect       without         increment     84
    0, 0, 0, 0, // stride      0               getidx          setidx        88
    2, 0, 0, 0, // arrcmp      flatten         0               0             8C

    0, 0, 0, 0, // 0           0               0               0             90
    0, 0, 0, 0, // 0           0               0               0             94
    0, 0, 0, 0, // 0           0               0               0             98
    0, 0, 0, 0, // 0           0               0               0             9C

    0, 0, 0, 0, // 0           0               0               0             A0
    0, 0, 0, 0, // 0           0               0               0             A4
    0, 0, 0, 0, // 0           0               0               0             A8
    0, 0, 0, 0, // 0           0               0               0             AC

    0, 0, 0, 0, // 0           0               0               0             B0
    0, 0, 0, 0, // 0           0               0               0             B4
    0, 0, 0, 0, // 0           0               0               0             B8
    0, 0, 0, 0, // 0           0               0               0             BC

    0, 0, 0, 0, // 0           0               0               0             C0
    0, 0, 0, 0, // 0           0               0               0             C4
    0, 0, 0, 0, // 0           0               0               0             C8
    0, 0, 0, 0, // 0           0               0               0             CC

    3, 0, 3, 3, // say         close           readstr         print         D0
    3, 0, 3, 0, // read        write           format          rewind        D4
    0, 3, 3, 0, // fseek       getchar         putchar         fflush        D8
    3, 0, 0, 0, // ungetc      0               0               0             DC

    0, 0, 0, 0, // ferror      feof            ftell           binary        E0
    0, 0, 0, 0, // ispipe      getswab         setswab         clearerr      E4
    0, 0, 0, 0, // minval      maxval          list            edit          E8
    0, 0, 0, 0, // 0           0               0               0             EC

    0, 0, 0, 0, // 0           0               0               0             F0
    0, 0, 0, 0, // 0           0               0               0             F4
    0, 0, 0, 0, // 0           0               0               0             F8
    0, 0, 0, 0, // 0           0               0               0             FC
};

#endif // ]