#include "dis.h" #include #include #include static void print_const(Chunk *ch, uint8_t ix) { Val k = ch->consts.d[ix]; printf("%-4s : ", typename_str(k)); println_val(k); } static void disasm_chunk_h(Chunk *ch, int depth); void disasm_chunk(Chunk *ch) { disasm_chunk_h(ch, 0); } static size_t disasm_instr_h(Chunk *ch, size_t ip, int depth); size_t disasm_instr(Chunk *ch, size_t ip) { return disasm_instr_h(ch, ip, 0); } static size_t disasm_instr_h(Chunk *ch, size_t ip, int depth) { size_t orig_ip = ip; uint8_t instr = ch->bc.d[ip]; printf("%*s%04zd\t%3d ",depth,"",ip,instr); ip ++; switch (instr) { case OP_LOADK: { uint8_t ix = ch->bc.d[ip++]; printf("loadk #%d\t; ",ix); print_const(ch, ix); break; } case OP_GETGLOBAL: { uint8_t ix = ch->bc.d[ip++]; printf("getglobal #%d\t; ",ix); print_const(ch, ix); break; } case OP_GETLOCAL: { uint8_t ix = ch->bc.d[ip++]; printf("getlocal #%d\n",ix); break; } case OP_SETLOCAL: { uint8_t ix = ch->bc.d[ip++]; printf("setlocal #%d\n",ix); break; } case OP_SETGLOBAL: { uint8_t ix = ch->bc.d[ip++]; printf("setglobal #%d\t; ",ix); print_const(ch, ix); break; } case OP_CALL: { uint8_t nargs = ch->bc.d[ip++]; printf("call #%hhu\n",nargs); break; } case OP_TAILCALL: { uint8_t nargs = ch->bc.d[ip++]; printf("\033[31mtailcall\033[0m #%hhu\n",nargs); break; } case OP_ENDSCOPE: { uint8_t nlocals = ch->bc.d[ip++]; printf("endscope #%hhu\n",nlocals); break; } #define RSHORT() (uint16_t)( ch->bc.d[ip-2] | ch->bc.d[ip-1] << 8 ) case OP_SKIP: { ip += 2; uint16_t offset = RSHORT(); printf("skip +%5hu\t; -> %04zd\n", offset, ip + offset); break; } case OP_0BRANCH: { ip += 2; uint16_t offset = RSHORT(); printf("0branch +%5hu\t; -> %04zd\n", offset, ip + offset); break; } case OP_REDO: { ip += 2; uint16_t offset = RSHORT(); printf("redo -%5hu\t; -> %04zd\n", offset, ip - offset); break; } #undef RSHORT #define SIMPLE_INSTR(opcode, str) \ case opcode: puts(str); break; SIMPLE_INSTR(OP_RET, "ret") SIMPLE_INSTR(OP_DROP, "drop") SIMPLE_INSTR(OP_ADD, "add") SIMPLE_INSTR(OP_SUB, "sub") SIMPLE_INSTR(OP_MUL, "mul") SIMPLE_INSTR(OP_DIV, "div") SIMPLE_INSTR(OP_MOD, "mod") SIMPLE_INSTR(OP_NIL, "nil") SIMPLE_INSTR(OP_TRUE, "true") SIMPLE_INSTR(OP_FALSE, "false") SIMPLE_INSTR(OP_CMP, "cmp") SIMPLE_INSTR(OP_EQU, "equ") SIMPLE_INSTR(OP_HALT, "halt") SIMPLE_INSTR(OP_ARRNEW, "arrnew") SIMPLE_INSTR(OP_ARRAPPEND, "arrappend") #undef SIMPLE_INSTR default: printf("unknown opcode %d\n", instr); } return ip - orig_ip; } static void disasm_chunk_h(Chunk *ch, int depth) { #define P(msg) printf("%*s%s\n",depth,"",msg); P("constants:"); for (uint8_t cix = 0; cix < ch->consts.len; cix++) { printf("%*s%hd\t",depth,"",cix); print_const(ch, cix); } P("bytecode:"); #undef P for (size_t ip = 0; ip < ch->bc.len; ) { ip += disasm_instr_h(ch, ip, depth); } printf("\n"); for (uint8_t cix = 0; cix < ch->consts.len; cix++) { Val c = ch->consts.d[cix]; if (IS_FUNC(c)) { printf("%*sconst %d is function:\n",depth,"", cix); disasm_chunk_h(&AS_FUNC(c)->ch,depth+4); } } }