#define OADLMACH_DEFINE_EXTERNS() {1}

#include "oadlmach.oah"
#include "libio.oah"

proc "[]" hello(a)
{
    for (var i = 0; i < a.length(); i++) {
        "", a[i], '\n';
    }
}

proc decode(prc, nam)
{
    using namespace oadlmach;
    using namespace io;

    try {
        var n = prc.length();
        var i, j, incr;
        var args = new PackUint(2);

        for (i = 0; i < n; i += incr) {
            var op = prc[i];
            var opname;

            incr = OADL_Decode(prc, i, op, args);

            if (op == OP_BUILTIN) {
                opname = builtinTab[Int(args[0])];
            }
            else if (op >= OP_PUSH_32) {
                opname = "PUSH " ## typeTab[op & 63];
            }
            else {
                opname = opcodeTab[op];
            }

            if (op == OP_ADDRESS) {
                if (args[0] & 0x800000) {
                    args[0] = -(1 + ((~args[0]) & 0xFFFFFF));
                }
                args[0] += i + incr + 1;
            }

            printf("%06x: ", i);
            for (j = 0; j < 9; j++) {
                if (j < incr) {
                    printf("%02x", prc[i+j]);
                }
                else {
                    printf("  ");
                }
            }

            if (op == OP_BUILTIN) {
                printf("%s\n", opname);
            }
            else {
                switch (incr) {
                case 1 : printf("%s\n", opname);
                case 2 : printf("%s(%02x)\n", opname, args[0]);
                case 3 : printf("%s(%04x)\n", opname, args[0]);
                case 4 : printf("%s(%06x)\n", opname, args[0]);
                case 5 : printf("%s(%08x)\n", opname, args[0]);
                case 9 : printf("%s(%08x:%08x)\n", opname, args[0], args[1]);
                }
            }
        }
    }
    catch (a) {
        "Cannot read proc ", nam, '\n';
    }
}

proc main()
{
    var i, n;
    decode(hello, "hello");
    decode(main, "main");
}