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

#ifndef _OADL_VAR_H_INCLUDED // [
#define _OADL_VAR_H_INCLUDED

#include <stdint.h>
#include <cstddef>
using std::size_t;
using std::ptrdiff_t;
#if !defined(ASSERT)
    #define ASSERT(x)
#endif

/* Base types used by OADL */
typedef uint16_t        OADL_HLF;
typedef uint32_t        OADL_WCH;

#if defined(OADL64) // [
    /* OADL 'var's are 64-bit values: */
    typedef uint64_t   OADL_BaseVar;
    typedef int64_t    OADL_SignedVar;
#else
    /* OADL 'var's are 32-bit values: */
    typedef uint32_t   OADL_BaseVar;
    typedef int32_t    OADL_SignedVar;
#endif // ] OADL64

/* The structure of a 64-bit OadlVar is as follows (although they
 * are stacked as if little-endian, that may not be the case):
 *
 * OADL_VT_DOUBLE - 63 significant bits, bit 0 is 0:
 *
 *  3                        
 *  1                                                           1 0
 * +-+-----------------------------------------------------------+-+
 * |                      MantLo:31                              |0|
 * +-+-----------------------------------------------------------+-+
 * +-+---------------------+---------------------------------------+
 * |S|        Exp:11       | MantHi:20                             |
 * +-+---------------------+---------------------------------------+
 *  6 6                   5                                       3
 *  3 2                   2                                       2
 *
 * OADL_VT_LONG - 62 significant bits, bit 0 is 1, bit 1 is 0:
 *
 *  3
 *  1                                                         2 1 0
 * +-----------------------------------------------------------+---+
 * |                       valueLo:30                          |0 1|
 * +-----------------------------------------------------------+---+
 * +---------------------------------------------------------------+
 * |                       valueHi:32                              |
 * +---------------------------------------------------------------+
 *  6                                                             3
 *  3                                                             2
 *
 * OADL_VT_NULL - 0 significant bits, all bits are 1:
 *
 *  3
 *  1                                                             0
 * +---------------------------------------------------------------+
 * |1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1|
 * +---------------------------------------------------------------+
 * +---------------------------------------------------------------+
 * |1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1|
 * +---------------------------------------------------------------+
 *  6                                                             3
 *  3                                                             2
 *
 * Everything else - 32 significant bits, bits 0-2 are 1 (items
 * shorter than 32 bits are right-justified in the value field):
 *
 *  3
 *  1                                             8 7         2 1 0
 * +-----------------------------------------------+-----------+---+
 * |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0|  Type:6   |1 1|
 * +-----------------------------------------------+-----------+---+
 * +---------------------------------------------------------------+
 * |                           value:32                            |
 * +---------------------------------------------------------------+
 *  6                                                             3
 *  3                                                             2
 *
 * The structure of a 32-bit OadlVar is as follows:
 *
 * OADL_VT_FLOAT - 31 significant bits, bit 0 is 0:
 *
 *  3 3             2 2
 *  1 0             3 2                                         1 0
 * +-+---------------+-------------------------------------------+-+
 * |S|     Exp:8     |    Mantissa:22                            |0|
 * +-+---------------+-------------------------------------------+-+
 *
 * OADL_VT_INT - 30 significant bits, bit 0 is 1, bit 1 is 0:
 *
 *  3
 *  1                                                         2 1 0
 * +-----------------------------------------------------------+---+
 * |              value : 30                                   |0 1|
 * +-----------------------------------------------------------+---+
 *
 * OADL_VT_NULL - 0 significant bits, all bits are 1:
 *
 *  3
 *  1                                                             0
 * +---------------------------------------------------------------+
 * |1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1|
 * +---------------------------------------------------------------+
 *
 * Everything else - 24 significant bits, bits 0-2 are 1 (items
 * shorter than 24 bits are right-justified in the value field):
 *
 *  3
 *  1                                             8 7         2 1 0
 * +-----------------------------------------------+-----------+---+
 * |              value : 24                       |  Type:6   |1 1|
 * +-----------------------------------------------+-----------+---+
 */

/*****************************************************************************
 * Type enumeration
 ****************************************************************************/
#if defined(OADL64)
    #define OADL_VT_DOUBLE      0       // 63 valid bits
    #define OADL_VT_LONG        1       // 62 valid bits
    #define OADL_VT_FLOAT       2       // 32 valid bits
    #define OADL_VT_INT         3       // 32 valid bits
#else
    #define OADL_VT_FLOAT       0       // 31 valid bits
    #define OADL_VT_INT         1       // 30 valid bits
    #define OADL_VT_DOUBLE      2       // 24 valid bits, atom idx
    #define OADL_VT_LONG        3       // 24 valid bits, atom idx
#endif

#define OADL_VT_ULONG           4       // 24/32 valid bits, atom idx
#define OADL_VT_UINT            5       // 24/32 valid bits, atom idx iff 24
#define OADL_VT_ARRAY           6       // 24/32 valid bits
#define OADL_VT_OBJECT          7       // 24/32 valid bits
#define OADL_VT_ARR_TYPE        8       // 24/32 valid bits
#define OADL_VT_ENCLOSURE       9       // 24/32 valid bits
//      Unused 24-bit           10-15   // Future 24/32-bit type slots

#define OADL_VT_POINTER         16      // 24/32 valid bits, atom idx
#define OADL_VT_DICT            17      // 24/32 valid bits
#define OADL_VT_PROC            18      // 24/32 valid bits
#define OADL_VT_EXTERN          19      // 24/32 valid bits
#define OADL_VT_PUBLIC          20      // 24/32 valid bits
#define OADL_VT_EXCEPT          21      // 24/32 valid bits (actually, 8)
#define OADL_VT_FILE            22      // 24/32 valid bits
//      Unused 24-bit           23-31   // Future 24/32-bit type slots

// Internal types
#define OADL_VT_GLOBAL          32      // 24/32 valid bits
#define OADL_VT_LOCAL           33      // 24/32 valid bits
#define OADL_VT_ARG             34      // 24/32 valid bits
#define OADL_VT_PROP            35      // 24/32 valid bits
#define OADL_VT_INTR            36      // 24/32 valid bits
#define OADL_VT_FORMAT          37      // 24/32 valid bits
#define OADL_VT_PATTERN         38      // 24/32 valid bits
//      Unused internal         39-47   // Future 24/32-bit type slots

// Inline numeric value types
//      Unused internal         48-53   // Future inline num. val. type slots
#define OADL_VT_WCHAR           54      // 24/32 valid bits (actually, 21)
#define OADL_VT_HALF            55      // 24/32 valid bits (actually, 16)
#define OADL_VT_USHORT          56      // 24/32 valid bits (actually, 16)
#define OADL_VT_SHORT           57      // 24/32 valid bits (actually, 16)
#define OADL_VT_UBYTE           58      // 24/32 valid bits (actually, 8)
#define OADL_VT_BYTE            59      // 24/32 valid bits (actually, 8)
#define OADL_VT_CHAR            60      // 24/32 valid bits (actually, 7)
#define OADL_VT_TYPE            61      // 24/32 valid bits (actually, 7)
#define OADL_VT_BOOL            62      // 24/32 valid bits (actually, 1)
#define OADL_VT_NULL            63      //  0    valid bits

#define OADL_NUM_INLINE         64      // number of inline types

// Pseudo-types returned by TypeOf.  Always >= 64.
#define OADL_MIN_PACK_TYPE      64      // First packed type
#define OADL_VT_PACK_DOUBLE     64      // Array of IEEE double-precision
#define OADL_VT_PACK_ULONG      65      // Array of signed 64-bit ints
#define OADL_VT_PACK_LONG       66      // Array of signed 64-bit ints
#define OADL_VT_PACK_FLOAT      67      // Array of IEEE single-precision
#define OADL_VT_PACK_UINT       68      // Array of signed 32-bit ints
#define OADL_VT_PACK_INT        69      // Array of signed 32-bit ints
#define OADL_VT_PACK_WCHAR      70      // Array of 21-bit chars
#define OADL_VT_PACK_HALF       71      // Array of 16-bit floats
#define OADL_VT_PACK_USHORT     72      // Array of 16-bit unsigned ints
#define OADL_VT_PACK_SHORT      73      // Array of 16-bit ints
#define OADL_VT_PACK_UBYTE      74      // Array of unsigned 8-bit ints
#define OADL_VT_PACK_BYTE       75      // Array of signed 8-bit ints
#define OADL_VT_PACK_CHAR       76      // Array of 7-bit chars
#define OADL_VT_PACK_BOOL       77      // Packed boolean
#define OADL_VT_WIDE_STRING     78      // 1D Array of 21-bit chars
#define OADL_VT_STRING          79      // 1D Array of 7-bit chars
#define OADL_MAX_PACK_TYPE      79      // Last packed type
#define OADL_VT_LIST            80      // 1D Array of OadlVar
#define OADL_VT_CLASS           81      // A class (vs. an Object)
#define OADL_VT_UNIV_ARRAY      82      // Array[*]

#define OADL_NUM_TYPES          83      // number of types

// Distinguish between the "inline" floating point or integer type,
// and the alternate (either atomic or smaller) type
#if defined(OADL64) // [
    #define OADL_INL_FP         OADL_VT_DOUBLE
    #define OADL_INL_INT        OADL_VT_LONG
    #define OADL_ALT_FP         OADL_VT_FLOAT
    #define OADL_ALT_INT        OADL_VT_INT
    #define OADL_IOFFS          32
#else // ] [
    #define OADL_INL_FP         OADL_VT_FLOAT
    #define OADL_INL_INT        OADL_VT_INT
    #define OADL_ALT_FP         OADL_VT_DOUBLE
    #define OADL_ALT_INT        OADL_VT_LONG
    #define OADL_IOFFS          8
#endif // ]

/*****************************************************************************
 * Useful constants
 ****************************************************************************/
#if defined(OADL64) // [
    /* Maximum positive signed int value we support */
    #define OADL_MAX_INT        0x7FFFFFFF      // 31 bits

    /* The maximum dynamic index value we support */
    #define OADL_MAX_DYNAMIC    0xFFFFFFFFU     // 32 bits

    /* NIL - 64 bits of type, no value. */
    #define OADL_NIL_BITS       ((OADL_BaseVar)0xFFFFFFFFFFFFFFFFULL)
#else // ] [
    /* Maximum positive signed int value we support */
    #define OADL_MAX_INT        0x1FFFFFFF      // 29 bits

    /* The maximum dynamic index value we support */
    #define OADL_MAX_DYNAMIC    0x00FFFFFF      // 24 bits

    /* NIL - 32 bits of type, no value. */
    #define OADL_NIL_BITS       ((OADL_BaseVar)0xFFFFFFFFU)
#endif // ] OADL64


// 16-bit representation of max half precision value - same as 65504.h
#define OADL_MAX_HALF   (0x7B00 | 0x03FF)
#define OADL_MIN_HALF   (0x8000 | OADL_MAX_HALF)
#define OADL_MAX_HALF_F 65504.0f

/* The maximum dimensionality (rank) of an OADL array. Arrays of higher
 * rank can be created, but they end up as Array of Array datastructures.
 * For efficiency, this number must be 2**n - 1
 */
#define OADL_MAX_RANK   15

/* The maximum positive signed long value we support.  Note that
 * this is the same in 32- and 64-bit OADL - the scalar table
 * in 32-bit OADL truncates signed longs to this precision for
 * compatibility.
 */
#define OADL_MAX_LONG       ((int64_t)0x1FFFFFFFFFFFFFFFLL)    // 61 bits

// Other maximum type values
#define OADL_MAX_FLOAT  ((float)FLT_MAX)
#define OADL_MAX_DOUBLE DBL_MAX
#define OADL_MAX_BOOL   1
#define OADL_MAX_BYTE   127
#define OADL_MAX_CHAR   127
#define OADL_MAX_UBYTE  255
#define OADL_MAX_SHORT  32767
#define OADL_MAX_USHORT 65535
#define OADL_MAX_WCHAR  0x1FFFFF
#define OADL_MAX_UINT   0xFFFFFFFFU
#define OADL_MAX_ULONG  0xFFFFFFFFFFFFFFFFULL


// Predeclare various tables and procs
namespace oadl {
    extern const uint8_t typeTable[];
    extern const char *typeNames[];
    extern const char *typeAbbrevs[];
    extern const int typeSizes[];
    extern const uint8_t isSigned[];
    extern const uint8_t isNumeric[];
    extern const uint8_t isIntegral[];
    extern const uint8_t isAtomic[];
    extern const uint8_t isDynamic[];

    /*************************************************************************
     * Utilities for converting between half and float
     * From http://www.fox-toolkit.org/ftp/fasthalffloatconversion.pdf
     * Tables are generated by TESTS/Automated/fp16tables.oad
     ************************************************************************/
    extern uint32_t mantissatable[2048];
    extern uint32_t exponenttable[64];
    extern uint16_t offsettable[64];

    inline const float hlfToFlt(const OADL_HLF x)
    {
        union {float f; uint32_t i;} u;

        u.i = mantissatable[offsettable[x>>10]+(x&0x3ff)]+exponenttable[x>>10];
        return u.f;
    }

    extern uint16_t basetable[512];
    extern uint8_t shifttable[512];

    inline const OADL_HLF fltToHlf(const float f)
    {
        union {float f; uint32_t i;} u;

        u.f = f;
        return basetable[(u.i>>23)&0x1ff]+((u.i&0x007FFFFF)>>shifttable[(u.i>>23)&0x1ff]);
    }
}

/*****************************************************************************
 * The heart of OADL - the OadlVar
 ****************************************************************************/
class OadlVar {
public :
    // The only data item in the class - a 32- or 64-bit thing
    OADL_BaseVar v;

private :
    inline int CHECK_TYPE(int t) const { return (v & 0xFF) == ((t << 2) | 3); }

public :
    // If no initial value, don't initialize anything
    OadlVar() {}

    // Explicitly give type and value
    OadlVar(int t, OADL_BaseVar val) {
        if (t == OADL_INL_INT)      v = (val << 2) | 1;
        else if (t == OADL_INL_FP)  v = val & ~(OADL_BaseVar) 1;
        else if (t == OADL_VT_NULL) v = OADL_NIL_BITS;
        else                        v = (val << OADL_IOFFS) | (t<<2) | 3;
    }

    // Copy-in operator
    OadlVar(OADL_BaseVar val) {
        v = val;
    }

    // Returns OADL_VT_* - what is this OadlVar?
    inline int getType()   const {return oadl::typeTable[v & 0xFF];}

    // Type query methods
#if defined(OADL64)
    inline int isDouble()  const {return (v&1) == 0;}
    inline int isLong()    const {return (v&3) == 1;}
    inline int isFloat()   const {return CHECK_TYPE(OADL_VT_FLOAT);}
    inline int isInt()     const {return CHECK_TYPE(OADL_VT_INT);}
#else
    inline int isFloat()   const {return (v&1) == 0;}
    inline int isInt()     const {return (v&3) == 1;}
    inline int isDouble()  const {return CHECK_TYPE(OADL_VT_DOUBLE);}
    inline int isLong()    const {return CHECK_TYPE(OADL_VT_LONG);}
#endif
    inline int isPointer() const {return CHECK_TYPE(OADL_VT_POINTER);}
    inline int isUlong()   const {return CHECK_TYPE(OADL_VT_ULONG);}
    inline int isUint()    const {return CHECK_TYPE(OADL_VT_UINT);}
    inline int isArray()   const {return CHECK_TYPE(OADL_VT_ARRAY);}
    inline int isObject()  const {return CHECK_TYPE(OADL_VT_OBJECT);}
    inline int isDict()    const {return CHECK_TYPE(OADL_VT_DICT);}
    inline int isProc()    const {return CHECK_TYPE(OADL_VT_PROC);}
    inline int isExtern()  const {return CHECK_TYPE(OADL_VT_EXTERN);}
    inline int isPublic()  const {return CHECK_TYPE(OADL_VT_PUBLIC);}
    inline int isFile()    const {return CHECK_TYPE(OADL_VT_FILE);}
    inline int isExcept()  const {return CHECK_TYPE(OADL_VT_EXCEPT);}
    inline int isArrType() const {return CHECK_TYPE(OADL_VT_ARR_TYPE);}
    inline int isWchar()   const {return CHECK_TYPE(OADL_VT_WCHAR);}
    inline int isHalf()    const {return CHECK_TYPE(OADL_VT_HALF);}
    inline int isUshort()  const {return CHECK_TYPE(OADL_VT_USHORT);}
    inline int isShort()   const {return CHECK_TYPE(OADL_VT_SHORT);}
    inline int isUbyte()   const {return CHECK_TYPE(OADL_VT_UBYTE);}
    inline int isByte()    const {return CHECK_TYPE(OADL_VT_BYTE);}
    inline int isChar()    const {return CHECK_TYPE(OADL_VT_CHAR);}
    inline int isType()    const {return CHECK_TYPE(OADL_VT_TYPE);}
    inline int isBool()    const {return CHECK_TYPE(OADL_VT_BOOL);}
    inline int isProp()    const {return CHECK_TYPE(OADL_VT_PROP);}
    inline int isIntr()    const {return CHECK_TYPE(OADL_VT_INTR);}
    inline int isNull()    const {return CHECK_TYPE(OADL_VT_NULL);}
    inline int isEnclosure() const {return CHECK_TYPE(OADL_VT_ENCLOSURE);}
    inline int isFormat()  const {return CHECK_TYPE(OADL_VT_FORMAT);}
    inline int isPattern()  const {return CHECK_TYPE(OADL_VT_PATTERN);}

    inline int isType(int t) const {return getType() == t;}

    /* Many of these get methods rely on the macro OADL_FIND_ATOM being
     * defined as the routine that can look up an index and return a pointer
     * to the atom it refers to. Many others rely on OADL_MAKE_ATOM being
     * defined as the routine that can store an atom in the heap.
     */

#if defined(OADL64) // [
    /* Int/float/double/long/uint gets are different in 32- vs. 64-bit
     * implementations
     */

    inline int getInt() const {
        ASSERT(isInt());
        return ((OADL_SignedVar) v) >> OADL_IOFFS;
    }

    inline float getFloat() const {
        union {uint32_t x; float f;} u;
        ASSERT(isFloat());
        u.x = ((OADL_BaseVar) v) >> OADL_IOFFS;
        return u.f;
    }

    inline double getDouble(void *ctx) const {
        ASSERT(isDouble());
        return *(double *) &v;
    }

    inline int64_t getLong(void *ctx) const {
        ASSERT(isLong());
        return ((int64_t) v) >> 2;
    }

    inline uint32_t getUint(void *ctx) const {
        ASSERT(isUint());
        return (v >> OADL_IOFFS) & 0xFFFFFFFFU;
    }

#else // ] [

    inline int getInt() const {
        ASSERT(isInt());
        return ((int) v) >> 2;
    }

    inline float getFloat() const {
        ASSERT(isFloat());
        return *(float *) &v;
    }

    inline double getDouble(void *ctx) const {
        ASSERT(isDouble());
    #if defined(OADL_FIND_ATOM)
        void *ptr = OADL_FIND_ATOM(ctx, v >> OADL_IOFFS);
        return *(double *)ptr;
    #else
        union {double d; uint64_t x; } u;
        u.x = ~(int64_t) 0;
        return u.d; // NaN
    #endif
    }

    inline int64_t getLong(void *ctx) const {
        ASSERT(isLong());
    #if defined(OADL_FIND_ATOM)
        void *ptr = OADL_FIND_ATOM(ctx, v >> OADL_IOFFS);
        return *(int64_t *)ptr;
    #else
        return ~(uint64_t)0;
    #endif
    }

    inline uint32_t getUint(void *ctx) const {
        ASSERT(isUint());
    #if defined(OADL_FIND_ATOM)
        void *ptr = OADL_FIND_ATOM(ctx, v >> OADL_IOFFS);
        return *(uint32_t *)ptr;
    #else
        return ~(uint32_t)0;
    #endif
    }

#endif // ] !OADL64

    inline uint64_t getUlong(void *ctx) const {
        ASSERT(isUlong());
    #if defined(OADL_FIND_ATOM)
        void *ptr = OADL_FIND_ATOM(ctx, v >> OADL_IOFFS);
        return *(uint64_t *)ptr;
    #else
        return ~(uint64_t)0;
    #endif
    }

    inline void *getPointer(void *ctx) const {
        ASSERT(isPointer());
    #if defined(OADL_FIND_ATOM)
        void *ptr = OADL_FIND_ATOM(ctx, v >> OADL_IOFFS);
        return *(void **)ptr;
    #else
        return (void *)0;
    #endif
    }

    inline void *getPattern(void *ctx) const {
        ASSERT(isPattern());
    #if defined(OADL_FIND_ATOM)
        void *ptr = OADL_FIND_ATOM(ctx, v >> OADL_IOFFS);
        return *(void **)ptr;
    #else
        return (void *)0;
    #endif
    }

    inline float getHalf() const {
        ASSERT(isHalf());
        return oadl::hlfToFlt(v >> OADL_IOFFS);
    }

    inline OADL_HLF getHalfBits() const {
        ASSERT(isHalf());
        return (v >> OADL_IOFFS) & OADL_MAX_DYNAMIC;
    }

    inline OADL_WCH getWchar() const {
        ASSERT(isWchar());
        return (v >> OADL_IOFFS) & 0x1FFFFF;
    }

    inline uint16_t getUshort() const {
        ASSERT(isUshort());
        return (v >> OADL_IOFFS) & 0xFFFF;
    }

    inline int16_t getShort() const {
        ASSERT(isShort());
        return (v >> OADL_IOFFS) & 0xFFFF;
    }

    inline uint8_t getUbyte() const {
        ASSERT(isUbyte());
        return (v >> OADL_IOFFS) & 0xFF;
    }

    inline int8_t getByte() const {
        ASSERT(isByte());
        return (v >> OADL_IOFFS) & 0xFF;
    }

    inline uint8_t getChar() const {
        ASSERT(isChar());
        return (v >> OADL_IOFFS) & 0x7F;
    }

    inline uint8_t getBool() const {
        ASSERT(isBool());
        return (v >> OADL_IOFFS) & 1;
    }

    inline int extractIval() {
        if ((v & 3) == 3)      return v >> OADL_IOFFS;
        else if ((v & 3) == 1) return ((OADL_SignedVar)v) >> 2;
        else                   return v;
    }

    inline OADL_BaseVar getVal() const {
        ASSERT((v&3)==3);
        return (v >> OADL_IOFFS) & OADL_MAX_DYNAMIC;
    }

    inline OADL_BaseVar getVal(int typ) const {
        ASSERT((v&0xFF)==((typ<<2)|3));
        return (v >> OADL_IOFFS) & OADL_MAX_DYNAMIC;
    }

    inline int isSigned() const {
        return oadl::isSigned[(v & 0xF8) >> 3] & (1 << (v & 0x7));
    }

    inline int isNumeric() const {
        return oadl::isNumeric[(v & 0xF8) >> 3] & (1 << (v & 0x7));
    }

    inline int isIntegral() const {
        return oadl::isIntegral[(v & 0xF8) >> 3] & (1 << (v & 0x7));
    }

    inline int isAtomic() const {
        return oadl::isAtomic[(v & 0xF8) >> 3] & (1 << (v & 0x7));
    }

    inline int isDynamic() const {
        return oadl::isDynamic[(v & 0xF8) >> 3] & (1 << (v & 0x7));
    }

    inline int isNil() const { return v == OADL_NIL_BITS; }

    // Easily convert from OadlVar to OADL_BaseVar
    operator OADL_BaseVar() const { return v; }

    // Equivalence operators
    int operator == (OadlVar const rhs) { return v == rhs.v; }
    int operator != (OadlVar const rhs) { return v != rhs.v; }

    template <class typ> inline int getNumeric(void *ctx, typ *res, int idx = 1)
    const {
        switch (getType()) {
        case OADL_VT_INT :    *res = (typ) getInt();       return 1;
        case OADL_VT_USHORT : *res = (typ) getUshort();    return 1;
        case OADL_VT_SHORT :  *res = (typ) getShort();     return 1;
        case OADL_VT_UBYTE :  *res = (typ) getUbyte();     return 1;
        case OADL_VT_BYTE :   *res = (typ) getByte();      return 1;
        case OADL_VT_HALF :   *res = (typ) getHalf();      return 1;
        case OADL_VT_FLOAT :  *res = (typ) getFloat();     return 1;
        case OADL_VT_BOOL :   *res = (typ) getBool();      return idx;
        case OADL_VT_CHAR :   *res = (typ) getChar();      return idx;
        case OADL_VT_WCHAR :  *res = (typ) getWchar();     return idx;
        case OADL_VT_ULONG :  *res = (typ) getUlong(ctx);  return 1;
        case OADL_VT_LONG :   *res = (typ) getLong(ctx);   return 1;
        case OADL_VT_UINT :   *res = (typ) getUint(ctx);   return 1;
        case OADL_VT_DOUBLE : *res = (typ) getDouble(ctx); return 1;
        default :                                          return 0;
        }
    }
};

/* Various convenience subclasses for OADLtypes that don't easily fit
 * in the initializer scheme of OadlVar. Note again the difference
 * between 32- and 64-bit in Int/Float/Double/Long/Uint
 */
#if defined(OADL64) // [

class OadlInt : public OadlVar {
public :
    OadlInt(int i) {
        v = ((OADL_BaseVar)i << OADL_IOFFS) | (OADL_VT_INT << 2) | 3;
    }
};

class OadlFloat : public OadlVar {
public :
    OadlFloat(float f) {
        union {float f; uint32_t x;} u;
        u.f = f;
        v = ((OADL_BaseVar)u.x << OADL_IOFFS) | (OADL_VT_FLOAT << 2) | 3;
    }
};

class OadlLong : public OadlVar {
public :
    OadlLong(void *ctx, int64_t i) {
        v = (i << 2) | 1;
    }
};

class OadlDouble : public OadlVar {
public :
    OadlDouble(void *ctx, double d) {
        v = (*(uint64_t *) &d) & ~1;
    }
};

class OadlUint : public OadlVar {
public :
    OadlUint(void *ctx, uint32_t i) {
        v = (((OADL_BaseVar) i) << OADL_IOFFS) | (OADL_VT_UINT << 2) | 3;
    }
};

#else // ] [

class OadlInt : public OadlVar {
public :
    OadlInt(int i) {
        v = (i << 2) | 1;
    }
};

class OadlFloat : public OadlVar {
public :
    OadlFloat(float f) {
        v = (*(uint32_t *) &f) & ~1;
    }
};

class OadlLong : public OadlVar {
public :
    OadlLong(void *ctx, int64_t l) {
    #if defined(OADL_MAKE_ATOM)
        OADL_BaseVar i = OADL_MAKE_ATOM(ctx, OADL_VT_LONG, (void *)&l);
        v = (i << OADL_IOFFS) | (OADL_VT_LONG << 2) | 3;
    #else
        v = OADL_NIL_BITS;
    #endif
    }
};

class OadlDouble : public OadlVar {
public :
    OadlDouble(void *ctx, double d) {
    #if defined(OADL_MAKE_ATOM)
        OADL_BaseVar i = OADL_MAKE_ATOM(ctx, OADL_VT_DOUBLE, (void *)&d);
        v = (i << OADL_IOFFS) | (OADL_VT_DOUBLE << 2) | 3;
    #else
        v = OADL_NIL_BITS;
    #endif
    }
};

class OadlUint : public OadlVar {
public :
    OadlUint(void *ctx, uint32_t i) {
    #if defined(OADL_MAKE_ATOM)
        OADL_BaseVar a = OADL_MAKE_ATOM(ctx, OADL_VT_UINT, (void *)&i);
        v = (a << OADL_IOFFS) | (OADL_VT_UINT << 2) | 3;
    #else
        v = OADL_NIL_BITS;
    #endif
    }
};

#endif // ] !OADL64

class OadlWchar : public OadlVar {
public :
    OadlWchar(OADL_BaseVar x) {
        v = ((x & 0x001FFFFF) << OADL_IOFFS) | (OADL_VT_WCHAR << 2) | 3;
    }
};

class OadlShort : public OadlVar {
public :
    OadlShort(OADL_BaseVar x) {
        v = ((x & 0x0000FFFF) << OADL_IOFFS) | (OADL_VT_SHORT << 2) | 3;
    }
};

class OadlUshort : public OadlVar {
public :
    OadlUshort(OADL_BaseVar x) {
        v = ((x & 0x0000FFFF) << OADL_IOFFS) | (OADL_VT_USHORT << 2) | 3;
    }
};

class OadlUbyte : public OadlVar {
public :
    OadlUbyte(OADL_BaseVar x) {
        v = ((x & 0x000000FF) << OADL_IOFFS) | (OADL_VT_UBYTE << 2) | 3;
    }
};

class OadlByte : public OadlVar {
public :
    OadlByte(OADL_BaseVar x) {
        v = ((x & 0x000000FF) << OADL_IOFFS) | (OADL_VT_BYTE << 2) | 3;
    }
};

class OadlChar : public OadlVar {
public :
    OadlChar(OADL_BaseVar x) {
        v = ((x & 0x0000007F) << OADL_IOFFS) | (OADL_VT_CHAR << 2) | 3;
    }
};

class OadlBool : public OadlVar {
public :
    OadlBool (OADL_BaseVar x) {
        v = ((x & 0x00000001) << OADL_IOFFS) | (OADL_VT_BOOL << 2) | 3;
    }
};

class OadlHalf : public OadlVar {
public :
    OadlHalf(float f) {
        OADL_BaseVar h = oadl::fltToHlf(f);
        v = (h << OADL_IOFFS) | (OADL_VT_HALF << 2) | 3;
    }
};

class OadlArray : public OadlVar {
public :
    OadlArray(OADL_BaseVar x) {
        v = (x << OADL_IOFFS) | (OADL_VT_ARRAY << 2) | 3;
    }
};

class OadlObject : public OadlVar {
public :
    OadlObject(OADL_BaseVar x) {
        v = (x << OADL_IOFFS) | (OADL_VT_OBJECT << 2) | 3;
    }
};

class OadlDict : public OadlVar {
public :
    OadlDict(OADL_BaseVar x) {
        v = (x << OADL_IOFFS) | (OADL_VT_DICT << 2) | 3;
    }
};

class OadlPointer : public OadlVar {
public :
    OadlPointer(void *ctx, void *ptr) {
    #if defined(OADL_MAKE_ATOM)
        OADL_BaseVar i = OADL_MAKE_ATOM(ctx, OADL_VT_POINTER, (void *)&ptr);
        v = (i << OADL_IOFFS) | (OADL_VT_POINTER << 2) | 3;
    #else
        v = OADL_NIL_BITS;
    #endif
    }
};

class OadlPattern : public OadlVar {
public :
    OadlPattern(void *ctx, void *ptr) {
    #if defined(OADL_MAKE_ATOM)
        OADL_BaseVar i = OADL_MAKE_ATOM(ctx, OADL_VT_PATTERN, (void *)&ptr);
        v = (i << OADL_IOFFS) | (OADL_VT_PATTERN << 2) | 3;
    #else
        v = OADL_NIL_BITS;
    #endif
    }
};

class OadlUlong : public OadlVar {
public :
    OadlUlong(void *ctx, uint64_t ul) {
    #if defined(OADL_MAKE_ATOM)
        OADL_BaseVar i = OADL_MAKE_ATOM(ctx, OADL_VT_ULONG, (void *)&ul);
        v = (i << OADL_IOFFS) | (OADL_VT_ULONG << 2) | 3;
    #else
        v = OADL_NIL_BITS;
    #endif
    }
};

namespace oadl {
    static inline int typeIsSigned(unsigned t) {
        if ((t == OADL_INL_FP) || (t == OADL_INL_INT)) return 1;
        if (t >= OADL_NUM_INLINE) return 0;
        OadlVar v = OadlVar(t,0);
        return v.isSigned();
    }
    static inline int typeIsNumeric(unsigned t) {
        if ((t == OADL_INL_FP) || (t == OADL_INL_INT)) return 1;
        if (t >= OADL_NUM_INLINE) return 0;
        OadlVar v = OadlVar(t,0);
        return v.isNumeric();
    }
    static inline int typeIsIntegral(unsigned t) {
        if (t == OADL_INL_INT) return 1;
        if (t >= OADL_NUM_INLINE) return 0;
        OadlVar v = OadlVar(t,0);
        return v.isIntegral();
    }
    static inline int typeIsAtomic(unsigned t) {
        if ((t == OADL_INL_FP) || (t == OADL_INL_INT)) return 0;
        if (t >= OADL_NUM_INLINE) return 0;
        OadlVar v = OadlVar(t,0);
        return v.isAtomic();
    }
}

/* Standard constants, heavily used everywhere */
static const OadlVar OADL_NIL = OadlVar(OADL_NIL_BITS);
static const OadlVar OADL_TRUE = OadlVar(OADL_VT_BOOL, 1);
static const OadlVar OADL_FALSE = OadlVar(OADL_VT_BOOL, 0);

/******************************************************************************
 * Convenience arrays:
 *      1. Mapping the least-significant bits of an OadlVar to a type
 *      2. table of packed array sizes for each type (or 0 if none)
 *      3. Map a type to a character string
 *      4. Map a type to an abbreviated character string
 *      5. table of whether a variable is numeric
 *      6. table of whether a variable is integral
 *      7. table of whether a variable is atomic
 *      8. table of whether a variable is dynamic
 *****************************************************************************/
#if defined(OADL_DEFINE_TYPE_TABLE) // [

namespace oadl {
const uint8_t typeTable[256] = {
    // Double-long-float-int only range
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_NULL,    // 000000 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_NULL,    // 000001 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_ALT_FP,     // 000010 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_ALT_INT,    // 000011 xx
    // 24/32-bit value range (type number of 4 to 15)
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_ULONG,   // 000100 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_UINT,    // 000101 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_ARRAY,   // 000110 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_OBJECT,  // 000111 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_ARR_TYPE,// 001000 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_ENCLOSURE,//001001 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_NULL,    // 001010 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_NULL,    // 001011 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_NULL,    // 001100 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_NULL,    // 001101 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_NULL,    // 001110 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_NULL,    // 001111 xx
    // More 24/32-bit types (non-promotable)
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_POINTER, // 010000 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_DICT,    // 010001 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_PROC,    // 010010 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_EXTERN,  // 010011 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_PUBLIC,  // 010100 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_EXCEPT,  // 010101 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_FILE,    // 010110 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_NULL,    // 010111 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_NULL,    // 011000 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_NULL,    // 011001 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_NULL,    // 011010 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_NULL,    // 011011 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_NULL,    // 011100 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_NULL,    // 011101 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_NULL,    // 011110 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_NULL,    // 011111 xx
    // Internal types (type number of 32 to 36)
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_GLOBAL,  // 100000 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_LOCAL,   // 100001 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_ARG,     // 100010 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_PROP,    // 100011 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_INTR,    // 100100 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_FORMAT,  // 100101 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_PATTERN, // 100110 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_NULL,    // 100111 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_NULL,    // 101000 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_NULL,    // 101001 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_NULL,    // 101010 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_NULL,    // 101011 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_NULL,    // 101100 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_NULL,    // 101101 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_NULL,    // 101110 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_NULL,    // 101111 xx
    // Possible inline numeric types
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_NULL,    // 110000 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_NULL,    // 110001 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_NULL,    // 110010 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_NULL,    // 110011 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_NULL,    // 110100 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_NULL,    // 110101 xx
    // Shorter types (type number of 54 to 63)
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_WCHAR,   // 110110 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_HALF,    // 110111 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_USHORT,  // 111000 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_SHORT,   // 111001 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_UBYTE,   // 111010 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_BYTE,    // 111011 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_CHAR,    // 111100 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_TYPE,    // 111101 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_BOOL,    // 111110 xx
    OADL_INL_FP, OADL_INL_INT, OADL_INL_FP, OADL_VT_NULL,    // 111111 xx
};

/* Packed array type sizes */
const int typeSizes[] = {
#if defined(OADL64)
    8, /* DOUBLE */  8, /* LONG */   4, /* FLOAT */   4, /* INT */
#else
    4, /* FLOAT */   4, /* INT */    8, /* DOUBLE */  8, /* LONG */
#endif
    8, /* ULONG */   4, /* UINT */   sizeof(OadlVar), 0, /* OBJECT */
    0, /* ARR_TYPE */0, /* ENCL */   0, /* 10 */      0, /* 11 */
    0, /* 12 */      0, /* 13 */     0, /* 14 */      0, /* 15 */
    0, /* POINTER */ 0, /* DICT */   0, /* PROC */    0, /* EXTERN */
    0, /* PUBLIC */  0, /* EXCEPT */ 0, /* FILE */    0, /* 23 */
    0, /* 24 */      0, /* 25 */     0, /* 26 */      0, /* 27 */
    0, /* 28 */      0, /* 29 */     0, /* 30 */      0, /* 31 */
    0, /* GLOBAL */  0, /* LOCAL */  0, /* ARG */     0, /* PROP */
    0, /* INTRINSIC*/0, /* FORMAT */ 0, /* PATTERN */ 0, /* 39 */
    0, /* 40 */      0, /* 41 */     0, /* 42 */      0, /* 43 */
    0, /* 44 */      0, /* 45 */     0, /* 46 */      0, /* 47 */
    0, /* 48 */      0, /* 49 */     0, /* 50 */      0, /* 51 */
    0, /* 52 */      0, /* 53 */     4, /* WCHAR */   2, /* HALF */
    2, /* USHORT */  2, /* SHORT */  1, /* UBYTE */   1, /* BYTE */
    1, /* CHAR */    0, /* TYPE */   1, /* BOOL */    0, /* NULL */
};

const char *typeNames[] = {
#if defined(OADL64) // [
    "Double",    "Long",        "Float",        "Int",          // 0
#else
    "Float",     "Int",         "Double",       "Long",         // 0
#endif // ]
    "Ulong",     "Uint",        "Array",        "Object",       // 4
    "ArrayType", "Enclosure",   0,              0,              // 8
    0,           0,             0,              0,              // 12
    "Pointer",   "Dict",        "Proc",         "Extern",       // 16
    "Public",    "Exception",   "File",         0,              // 20
    0,           0,             0,              0,              // 24
    0,           0,             0,              0,              // 28
    "Global",    "Local",       "Arg",         "Prop",          // 32
    "Intrinsic", "Format",      "Pattern",      0,              // 36
    0,           0,             0,              0,              // 40
    0,           0,             0,              0,              // 44
    0,           0,             0,              0,              // 48
    0,           0,             "WideChar",     "Half",         // 52
    "Ushort",    "Short",       "Ubyte",        "Byte",         // 54
    "Char",      "Type",        "Bool",         "Null",         // 58
    "PackDouble","PackUlong",   "PackLong",     "PackFloat",    // 64
    "PackUint",  "PackInt",     "PackWideChar", "PackHalf",     // 68
    "PackUshort","PackShort",   "PackUbyte",    "PackByte",     // 72
    "PackChar",  "PackBool",    "WideString",   "String",       // 76
    "List",      "Class",       "Array[*]"                      // 80
};

const char *typeAbbrevs[] = {
#if defined(OADL64) // [
    "DBL",       "I64",         "FLT",          "INT",          // 0
#else
    "FLT",       "INT",         "DBL",          "I64",          // 0
#endif // ]
    "U64",       "U32",         "ARR",          "#OBJ",         // 4
    "ATY",       "ENC",         0,              0,              // 8
    0,           0,             0,              0,              // 12
    "#PTR",      "DCT",         "#PRC",         "EXT",          // 16
    "PUB",       "XCP",         "FIL",          0,              // 20
    0,           0,             0,              0,              // 24
    0,           0,             0,              0,              // 28
    "GLB",       "LCL",         "ARG",          "PRP",          // 32
    "NTR",       "FMT",         "PAT",          0,              // 36
    0,           0,             0,              0,              // 40
    0,           0,             0,              0,              // 44
    0,           0,             0,              0,              // 48
    0,           0,             "WCH",          "F16",          // 52
    "U16",       "I16",         "UI8",          "BYT",          // 56
    "CHR",       "TYP",         "BOO",          "NUL",          // 60
};

const uint8_t isSigned[32] = {
    0x77,       // 00000 xxx : F,I,F,  ill,      F,I,F,  ill      0
    0xFF,       // 00001 xxx : F,I,F,  F32/F64,  F,I,F,  I32/I64  2
    0x77,       // 00010 xxx : F,I,F,  U64,      F,I,F,  U32      4
    0x77,       // 00011 xxx : F,I,F,  ARR,      F,I,F,  OBJ      6
    0x77,       // 00100 xxx : F,I,F,  ATY,      F,I,F,  ill      8
    0x77,       // 00101 xxx : F,I,F,  ill,      F,I,F,  ill     10
    0x77,       // 00110 xxx : F,I,F,  ill,      F,I,F,  ill     12
    0x77,       // 01001 xxx : F,I,F,  ill,      F,I,F,  ill     14
    0x77,       // 01001 xxx : F,I,F,  PTR,      F,I,F,  DCT     16
    0x77,       // 01001 xxx : F,I,F,  PRC,      F,I,F,  EXT     18
    0x77,       // 01001 xxx : F,I,F,  PUB,      F,I,F,  XCP     20
    0x77,       // 01001 xxx : F,I,F,  FIL,      F,I,F,  ill     22
    0x77,       // 01001 xxx : F,I,F,  ill,      F,I,F,  ill     24
    0x77,       // 01001 xxx : F,I,F,  ill,      F,I,F,  ill     26
    0x77,       // 01001 xxx : F,I,F,  ill,      F,I,F,  ill     28
    0x77,       // 01001 xxx : F,I,F,  ill,      F,I,F,  ill     30

    0x77,       // 00111 xxx : F,I,F,  GLB,      F,I,F,  LCL     32
    0x77,       // 01000 xxx : F,I,F,  ARG,      F,I,F,  PRP     34
    0x77,       // 01001 xxx : F,I,F,  NTR,      F,I,F,  FMT     36
    0x77,       // 01010 xxx : F,I,F,  PAT,      F,I,F,  ill     38
    0x77,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     40
    0x77,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     42
    0x77,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     44
    0x77,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     46
    0x77,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     48
    0x77,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     50
    0x77,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     52
    0xF7,       // 01011 xxx : F,I,F,  WCH,      F,I,F,  F16     54
    0xF7,       // 01100 xxx : F,I,F,  U16,      F,I,F,  I16     56
    0xF7,       // 01101 xxx : F,I,F,  UI8,      F,I,F,  SI8     58
    0x77,       // 01110 xxx : F,I,F,  CHR,      F,I,F,  TYP     60
    0x77,       // 01111 xxx : F,I,F,  BIT,      F,I,F,  NUL     62
};

const uint8_t isNumeric[32] = {
    0x77,       // 00000 xxx : F,I,F,  ill,      F,I,F,  ill      0
    0xFF,       // 00001 xxx : F,I,F,  F32/F64,  F,I,F,  I32/I64  2
    0xFF,       // 00010 xxx : F,I,F,  U64,      F,I,F,  U32      4
    0x77,       // 00011 xxx : F,I,F,  ARR,      F,I,F,  OBJ      6
    0x77,       // 00100 xxx : F,I,F,  ATY,      F,I,F,  ill      8
    0x77,       // 00101 xxx : F,I,F,  ill,      F,I,F,  ill     10
    0x77,       // 00110 xxx : F,I,F,  ill,      F,I,F,  ill     12
    0x77,       // 01001 xxx : F,I,F,  ill,      F,I,F,  ill     14
    0x77,       // 01001 xxx : F,I,F,  PTR,      F,I,F,  DCT     16
    0x77,       // 01001 xxx : F,I,F,  PRC,      F,I,F,  EXT     18
    0x77,       // 01001 xxx : F,I,F,  PUB,      F,I,F,  XCP     20
    0x77,       // 01001 xxx : F,I,F,  FIL,      F,I,F,  ill     22
    0x77,       // 01001 xxx : F,I,F,  ill,      F,I,F,  ill     24
    0x77,       // 01001 xxx : F,I,F,  ill,      F,I,F,  ill     26
    0x77,       // 01001 xxx : F,I,F,  ill,      F,I,F,  ill     28
    0x77,       // 01001 xxx : F,I,F,  ill,      F,I,F,  ill     30

    0x77,       // 00111 xxx : F,I,F,  GLB,      F,I,F,  LCL     32
    0x77,       // 01000 xxx : F,I,F,  ARG,      F,I,F,  PRP     34
    0x77,       // 01001 xxx : F,I,F,  NTR,      F,I,F,  FMT     36
    0x77,       // 01010 xxx : F,I,F,  PAT,      F,I,F,  ill     38
    0x77,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     40
    0x77,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     42
    0x77,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     44
    0x77,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     46
    0x77,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     48
    0x77,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     50
    0x77,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     52
    0xFF,       // 01011 xxx : F,I,F,  WCH,      F,I,F,  F16     54
    0xFF,       // 01100 xxx : F,I,F,  U16,      F,I,F,  I16     56
    0xFF,       // 01101 xxx : F,I,F,  UI8,      F,I,F,  SI8     58
    0x7F,       // 01110 xxx : F,I,F,  CHR,      F,I,F,  TYP     60
    0x77,       // 01111 xxx : F,I,F,  BIT,      F,I,F,  NUL     62
};

#if defined(OADL64) // [
    /* Note that U32 is not integral because generally we cannot
     * extract it in one step
     */
    const uint8_t isIntegral[32] = {
        0x00,       // 00000 xxx : F,I,F,  ill,      F,I,F,  ill     0
        0x80,       // 00001 xxx : F,I,F,  F32/F64,  F,I,F,  I32/I64 2
        0x00,       // 00010 xxx : F,I,F,  U64,      F,I,F,  U32     4
        0x00,       // 00011 xxx : F,I,F,  ARR,      F,I,F,  OBJ     6
        0x00,       // 00100 xxx : F,I,F,  ATY,      F,I,F,  ill     8
        0x00,       // 00101 xxx : F,I,F,  ill,      F,I,F,  ill    10
        0x00,       // 00110 xxx : F,I,F,  ill,      F,I,F,  ill    12
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill    14
        0x00,       // 01010 xxx : F,I,F,  PTR,      F,I,F,  DCT    16
        0x00,       // 01010 xxx : F,I,F,  PRC,      F,I,F,  EXT    18
        0x00,       // 01010 xxx : F,I,F,  PUB,      F,I,F,  XCP    20
        0x00,       // 01010 xxx : F,I,F,  FIL,      F,I,F,  ill    22
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill    24
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill    26
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill    28
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill    30

        0x00,       // 00111 xxx : F,I,F,  GLB,      F,I,F,  LCL    32
        0x00,       // 01000 xxx : F,I,F,  ARG,      F,I,F,  PRP    34
        0x00,       // 01001 xxx : F,I,F,  NTR,      F,I,F,  FMT    36
        0x00,       // 01010 xxx : F,I,F,  PAT,      F,I,F,  ill    38
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill    40
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill    42
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill    44
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill    46
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill    48
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill    50
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill    52
        0x08,       // 01011 xxx : F,I,F,  WCH,      F,I,F,  F16    54
        0x88,       // 01100 xxx : F,I,F,  U16,      F,I,F,  I16    56
        0x88,       // 01101 xxx : F,I,F,  UI8,      F,I,F,  SI8    58
        0x08,       // 01110 xxx : F,I,F,  CHR,      F,I,F,  TYP    60
        0x00,       // 01111 xxx : F,I,F,  BIT,      F,I,F,  NUL    62
    };
#else // ] [
    /* Note that U32 is not integral because generally we cannot
     * extract it in one step
     */
    const uint8_t isIntegral[32] = {
        0x22,       // 00000 xxx : F,I,F,  ill,      F,I,F,  ill      0
        0x22,       // 00001 xxx : F,I,F,  F32/F64,  F,I,F,  I32/I64  2
        0x22,       // 00010 xxx : F,I,F,  U64,      F,I,F,  U32      4
        0x22,       // 00011 xxx : F,I,F,  ARR,      F,I,F,  OBJ      6
        0x22,       // 00100 xxx : F,I,F,  ATY,      F,I,F,  ill      8
        0x22,       // 00101 xxx : F,I,F,  ill,      F,I,F,  ill     10
        0x22,       // 00110 xxx : F,I,F,  ill,      F,I,F,  ill     12
        0x22,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     14
        0x22,       // 01010 xxx : F,I,F,  PTR,      F,I,F,  DCT     16
        0x22,       // 01010 xxx : F,I,F,  PRC,      F,I,F,  EXT     18
        0x22,       // 01010 xxx : F,I,F,  PUB,      F,I,F,  XCP     20
        0x22,       // 01010 xxx : F,I,F,  FIL,      F,I,F,  ill     22
        0x22,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     24
        0x22,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     26
        0x22,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     28
        0x22,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     30

        0x22,       // 00111 xxx : F,I,F,  GLB,      F,I,F,  LCL     32
        0x22,       // 01000 xxx : F,I,F,  ARG,      F,I,F,  PRP     34
        0x22,       // 01001 xxx : F,I,F,  NTR,      F,I,F,  FMT     36
        0x22,       // 01010 xxx : F,I,F,  PAT,      F,I,F,  ill     38
        0x22,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     40
        0x22,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     42
        0x22,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     44
        0x22,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     46
        0x22,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     48
        0x22,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     50
        0x22,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     52
        0x2A,       // 01011 xxx : F,I,F,  WCH,      F,I,F,  F16     54
        0xAA,       // 01100 xxx : F,I,F,  U16,      F,I,F,  I16     56
        0xAA,       // 01101 xxx : F,I,F,  UI8,      F,I,F,  SI8     58
        0x2A,       // 01110 xxx : F,I,F,  CHR,      F,I,F,  TYP     60
        0x22,       // 01111 xxx : F,I,F,  BIT,      F,I,F,  NUL     62
    };
#endif // ]

#if defined(OADL64) // [
    const uint8_t isAtomic[32] = {
        0x00,       // 00000 xxx : F,I,F,  ill,      F,I,F,  ill      0
        0x00,       // 00001 xxx : F,I,F,  F32,      F,I,F,  I32      2
        0x08,       // 00010 xxx : F,I,F,  U64,      F,I,F,  U32      4
        0x00,       // 00011 xxx : F,I,F,  ARR,      F,I,F,  OBJ      6
        0x00,       // 00100 xxx : F,I,F,  ATY,      F,I,F,  ill      8
        0x00,       // 00101 xxx : F,I,F,  ill,      F,I,F,  ill     10
        0x00,       // 00110 xxx : F,I,F,  ill,      F,I,F,  ill     12
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     14
        0x08,       // 01010 xxx : F,I,F,  PTR,      F,I,F,  DCT     16
        0x00,       // 01010 xxx : F,I,F,  PRC,      F,I,F,  EXT     18
        0x00,       // 01010 xxx : F,I,F,  PUB,      F,I,F,  XCP     20
        0x00,       // 01010 xxx : F,I,F,  FIL,      F,I,F,  ill     22
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     24
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     26
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     28
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     30

        0x00,       // 00111 xxx : F,I,F,  GLB,      F,I,F,  LCL     32
        0x00,       // 01000 xxx : F,I,F,  ARG,      F,I,F,  PRP     34
        0x00,       // 01001 xxx : F,I,F,  NTR,      F,I,F,  FMT     36
        0x08,       // 01010 xxx : F,I,F,  PAT,      F,I,F,  ill     38
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     40
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     42
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     44
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     46
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     48
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     50
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     52
        0x00,       // 01011 xxx : F,I,F,  WCH,      F,I,F,  F16     54
        0x00,       // 01100 xxx : F,I,F,  U16,      F,I,F,  I16     56
        0x00,       // 01101 xxx : F,I,F,  UI8,      F,I,F,  SI8     58
        0x00,       // 01110 xxx : F,I,F,  CHR,      F,I,F,  TYP     60
        0x00,       // 01111 xxx : F,I,F,  BIT,      F,I,F,  NUL     62
    };
#else // ] [
    const uint8_t isAtomic[32] = {
        0x00,       // 00000 xxx : F,I,F,  ill,      F,I,F,  ill      0
        0x88,       // 00001 xxx : F,I,F,  F64,      F,I,F,  I64      2
        0x88,       // 00010 xxx : F,I,F,  U64,      F,I,F,  U32      4
        0x00,       // 00011 xxx : F,I,F,  ARR,      F,I,F,  OBJ      6
        0x00,       // 00100 xxx : F,I,F,  ATY,      F,I,F,  ill      8
        0x00,       // 00101 xxx : F,I,F,  ill,      F,I,F,  ill     10
        0x00,       // 00110 xxx : F,I,F,  ill,      F,I,F,  ill     12
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     14
        0x08,       // 01010 xxx : F,I,F,  PTR,      F,I,F,  DCT     16
        0x00,       // 01010 xxx : F,I,F,  PRC,      F,I,F,  EXT     18
        0x00,       // 01010 xxx : F,I,F,  PUB,      F,I,F,  XCP     20
        0x00,       // 01010 xxx : F,I,F,  FIL,      F,I,F,  ill     22
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     24
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     26
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     28
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     30

        0x00,       // 00111 xxx : F,I,F,  GLB,      F,I,F,  LCL     32
        0x00,       // 01000 xxx : F,I,F,  ARG,      F,I,F,  PRP     34
        0x00,       // 01001 xxx : F,I,F,  NTR,      F,I,F,  FMT     36
        0x08,       // 01010 xxx : F,I,F,  PAT,      F,I,F,  ill     38
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     40
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     42
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     44
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     46
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     48
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     50
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     52
        0x00,       // 01011 xxx : F,I,F,  WCH,      F,I,F,  F16     54
        0x00,       // 01100 xxx : F,I,F,  U16,      F,I,F,  I16     54
        0x00,       // 01101 xxx : F,I,F,  UI8,      F,I,F,  SI8     58
        0x00,       // 01110 xxx : F,I,F,  CHR,      F,I,F,  TYP     60
        0x00,       // 01111 xxx : F,I,F,  BIT,      F,I,F,  NUL     62
    };
#endif // ]

#if defined(OADL64) // [
    const uint8_t isDynamic[32] = {
        0x00,       // 00000 xxx : F,I,F,  ill,      F,I,F,  ill      0
        0x00,       // 00001 xxx : F,I,F,  F32,      F,I,F,  I32      2
        0x08,       // 00010 xxx : F,I,F,  U64,      F,I,F,  U32      4
        0x88,       // 00011 xxx : F,I,F,  ARR,      F,I,F,  OBJ      6
        0x88,       // 00100 xxx : F,I,F,  ATY,      F,I,F,  ENC      8
        0x00,       // 00101 xxx : F,I,F,  ill,      F,I,F,  ill     10
        0x00,       // 00110 xxx : F,I,F,  ill,      F,I,F,  ill     12
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     14
        0x88,       // 01010 xxx : F,I,F,  PTR,      F,I,F,  DCT     16
        0x00,       // 01010 xxx : F,I,F,  PRC,      F,I,F,  EXT     18
        0x00,       // 01010 xxx : F,I,F,  PUB,      F,I,F,  XCP     20
        0x00,       // 01010 xxx : F,I,F,  FIL,      F,I,F,  ill     22
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     24
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     26
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     28
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     30

        0x00,       // 00111 xxx : F,I,F,  GLB,      F,I,F,  LCL     32
        0x00,       // 01000 xxx : F,I,F,  ARG,      F,I,F,  PRP     34
        0x80,       // 01001 xxx : F,I,F,  NTR,      F,I,F,  FMT     36
        0x08,       // 01010 xxx : F,I,F,  PAT,      F,I,F,  ill     38
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     40
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     42
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     44
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     46
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     48
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     50
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     52
        0x00,       // 01011 xxx : F,I,F,  WCH,      F,I,F,  F16     54
        0x00,       // 01100 xxx : F,I,F,  U16,      F,I,F,  I16     56
        0x00,       // 01101 xxx : F,I,F,  UI8,      F,I,F,  SI8     58
        0x00,       // 01110 xxx : F,I,F,  CHR,      F,I,F,  TYP     60
        0x00,       // 01111 xxx : F,I,F,  BIT,      F,I,F,  NUL     62
    };
#else // ] [
    const uint8_t isDynamic[32] = {
        0x00,       // 00000 xxx : F,I,F,  ill,      F,I,F,  ill      0
        0x88,       // 00001 xxx : F,I,F,  F64,      F,I,F,  I64      2
        0x88,       // 00010 xxx : F,I,F,  U64,      F,I,F,  U32      4
        0x88,       // 00011 xxx : F,I,F,  ARR,      F,I,F,  OBJ      6
        0x88,       // 00100 xxx : F,I,F,  ATY,      F,I,F,  ENC      8
        0x00,       // 00101 xxx : F,I,F,  ill,      F,I,F,  ill     10
        0x00,       // 00110 xxx : F,I,F,  ill,      F,I,F,  ill     12
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     14
        0x88,       // 01010 xxx : F,I,F,  PTR,      F,I,F,  DCT     16
        0x00,       // 01010 xxx : F,I,F,  PRC,      F,I,F,  EXT     18
        0x00,       // 01010 xxx : F,I,F,  PUB,      F,I,F,  XCP     20
        0x00,       // 01010 xxx : F,I,F,  FIL,      F,I,F,  ill     22
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     24
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     26
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     28
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     30

        0x00,       // 00111 xxx : F,I,F,  GLB,      F,I,F,  LCL     32
        0x00,       // 01000 xxx : F,I,F,  ARG,      F,I,F,  PRP     34
        0x80,       // 01001 xxx : F,I,F,  NTR,      F,I,F,  FMT     36
        0x08,       // 01010 xxx : F,I,F,  PAT,      F,I,F,  ill     38
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     40
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     42
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     44
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     46
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     48
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     50
        0x00,       // 01010 xxx : F,I,F,  ill,      F,I,F,  ill     52
        0x00,       // 01011 xxx : F,I,F,  WCH,      F,I,F,  F16     54
        0x00,       // 01100 xxx : F,I,F,  U16,      F,I,F,  I16     54
        0x00,       // 01101 xxx : F,I,F,  UI8,      F,I,F,  SI8     58
        0x00,       // 01110 xxx : F,I,F,  CHR,      F,I,F,  TYP     60
        0x00,       // 01111 xxx : F,I,F,  BIT,      F,I,F,  NUL     62
    };
#endif // ]


} // namespace oadl

#endif // ] OADL_DEFINE_TYPE_TABLE

#endif  // ] _OADL_VAR_H_INCLUDED