From 6f0c3a729b2703c7dcdc60705a6800e4be7de81f Mon Sep 17 00:00:00 2001 From: Andre Wagner Date: Sun, 17 May 2026 09:36:15 -0500 Subject: [PATCH] . --- Makefile | 13 +++- TODO.md | 5 +- doc/OPCODES | 4 +- lib/code.c | 113 ++++++++++++++++++++++++++++++- lib/compiler/compiler.lua | 12 ++-- lib/priv.h | 16 +++-- lib/stack.c | 4 +- lib/tyche.h | 5 ++ lib/vm.c | 135 ++++++++++++++++++++++++++++++++++++-- test/code-tests.lua | 44 +++++++++---- test/tests.c | 40 +++++++---- 11 files changed, 342 insertions(+), 49 deletions(-) diff --git a/Makefile b/Makefile index dbc9a36..c6cacf1 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,10 @@ # # install prefix -PREFIX=/usr/local +PREFIX ?= /usr/local + +# add functions to debug assembly to console +DEBUG_ASSEMBLY ?= 0 # # internal flags/options @@ -48,6 +51,10 @@ RELEASE_LDFLAGS=-flto=auto CFLAGS+=-std=c99 -D_GNU_SOURCE -fPIC -fvisibility=hidden -isystem lib/contrib -MMD -MP LDFLAGS+= +ifeq ($(DEBUG_ASSEMBLY),1) + CFLAGS += -DDEBUG_ASSEMBLY +endif + # # generic targets # @@ -58,7 +65,7 @@ check: tyche-test ./tyche-test clean: - rm -f tyche libtyche.a libtyche.so* tyche-test **/*.o **/*.d lib/compiler/compiler.h + rm -f tyche libtyche.a libtyche.so* tyche-test **/*.o **/*.d lib/compiler/compiler.lua.h install: tyche libtyche.a libtyche.so.${VERSION} lib/tyche.h install -m 644 libtyche.a libtyche.so.${VERSION} ${PREFIX}/lib @@ -95,7 +102,7 @@ tyche: src/tyche.o libtyche.a $(CC) -o $@ $^ ${LDFLAGS} strip $@ -tyche-test: CFLAGS += ${DEBUG_CFLAGS} +tyche-test: CFLAGS += ${DEBUG_CFLAGS} -DDEBUG_ASSEMBLY tyche-test: LDFLAGS += ${DEBUG_LDFLAGS} tyche-test: test/tests.o libtyche.a $(CC) -o $@ $^ ${LDFLAGS} -I../lib diff --git a/TODO.md b/TODO.md index a87803e..63e690d 100644 --- a/TODO.md +++ b/TODO.md @@ -24,8 +24,9 @@ Decisions: - [ ] VM operations - [x] Expressions - [x] Local variables - - [ ] Functions - - [ ] With parameters + - [x] Functions + - [x] With parameters + - [ ] Debug VM execution - [ ] Control flow - [ ] Recursion - [ ] Strings diff --git a/doc/OPCODES b/doc/OPCODES index 41828c9..edd2715 100644 --- a/doc/OPCODES +++ b/doc/OPCODES @@ -32,7 +32,7 @@ Stack operations: Local variables: a3 c3 e3 pushv [int] Push n nil values into the stack (used to init local vars) - ab cb eb set [index] Set value in stack position (set local variable) + ae ce ee set [index] Set value in stack position (set local variable) a4 c4 e4 dupv [index] Duplicate stack value (load local variable) a5 c5 e5 setg [int] Set global variable a6 c6 e6 getg [int] Get global variable @@ -75,7 +75,7 @@ Logical/arithmetic: Other value operations: 40 len Get table, array or string size 41 type Get type from value at the top of the stack - aa cast [type] Cast type to another type + ad cast [type] Cast type to another type 42 ver Return VM version External code: diff --git a/lib/code.c b/lib/code.c index 6cc422d..1495012 100644 --- a/lib/code.c +++ b/lib/code.c @@ -25,6 +25,7 @@ struct Code { uint32_t* const_addr; uint32_t fn_count; uint32_t* fn_addr; + uint32_t* fn_sz; }; Code* code_new(void) @@ -37,6 +38,7 @@ void code_destroy(Code* code) { free(code->const_addr); free(code->fn_addr); + free(code->fn_sz); free(code); } @@ -91,12 +93,16 @@ TYC_RESULT code_load_bytecode(Code* code, uint8_t const* bytecode, size_t byteco addr += 4; code->fn_addr = xcalloc(code->fn_count, sizeof(uint32_t)); + code->fn_sz = xcalloc(code->fn_count, sizeof(uint32_t)); code->fn_addr[0] = addr; + uint32_t addr_next; for (size_t i = 1; i < code->fn_count; ++i) { - uint32_t addr_next; memcpy(&addr_next, &bytecode[addr], sizeof(uint32_t)); + code->fn_sz[i-1] = addr_next - addr - 4; addr = code->fn_addr[i] = addr_next; } + memcpy(&addr_next, &bytecode[addr], sizeof(uint32_t)); + code->fn_sz[code->fn_count-1] = addr_next - addr - 4; return T_OK; } @@ -132,6 +138,11 @@ uint32_t code_n_functions(Code const* code) return code->fn_count; } +uint32_t code_function_sz(Code const* code, uint32_t f_id) +{ + return code->fn_sz[f_id]; +} + Instruction code_next_instruction(Code const* code, uint32_t function_id, uint32_t pc) { uint32_t addr = code->fn_addr[function_id] + 4 + pc; @@ -161,4 +172,102 @@ Instruction code_next_instruction(Code const* code, uint32_t function_id, uint32 .operand = operand, .sz = sz, }; -} \ No newline at end of file +} + +#ifdef DEBUG_ASSEMBLY + +void code_decompile(Code const* code) +{ + if (code_n_consts(code) > 0) + printf(".const\n"); + + for (size_t const_id = 0; const_id < code_n_consts(code); ++const_id) { + TYC_CONST_TYPE type = code_const_type(code, const_id); + if (type == TC_STRING) + printf(" %03zu: \"%s\"\n", const_id, code_const_string(code, const_id)); + else if (type == TC_REAL) + printf(" %03zu: %f\n", const_id, (double) code_const_real(code, const_id)); + } + + for (uint32_t f_id = 0; f_id < code_n_functions(code); ++f_id) { + printf(".func %d\n", f_id); + uint32_t pc = 0; + while (pc < code_function_sz(code, f_id)) { + Instruction inst = code_next_instruction(code, f_id, pc); + char buf[50]; + code_parse_instruction(inst, buf, sizeof buf); + printf(" %s ; %d\n", buf, pc); + pc += inst.sz; + } + } +} + +void code_parse_instruction(Instruction inst, char* outbuf, size_t sz) +{ + int n; + switch (inst.operator) { + case TO_PUSHI: n = snprintf(outbuf, sz, "pushi "); break; + case TO_PUSHC: n = snprintf(outbuf, sz, "pushc "); break; + case TO_PUSHF: n = snprintf(outbuf, sz, "pushf "); break; + case TO_PUSHN: n = snprintf(outbuf, sz, "pushn "); break; + case TO_PUSHZ: n = snprintf(outbuf, sz, "pushz "); break; + case TO_PUSHT: n = snprintf(outbuf, sz, "pusht "); break; + case TO_NEWA: n = snprintf(outbuf, sz, "newa "); break; + case TO_NEWT: n = snprintf(outbuf, sz, "newt "); break; + case TO_POP: n = snprintf(outbuf, sz, "pop "); break; + case TO_DUP: n = snprintf(outbuf, sz, "dup "); break; + case TO_PUSHV: n = snprintf(outbuf, sz, "pushv "); break; + case TO_SET: n = snprintf(outbuf, sz, "set "); break; + case TO_DUPV: n = snprintf(outbuf, sz, "dupv "); break; + case TO_SETG: n = snprintf(outbuf, sz, "setg "); break; + case TO_GETG: n = snprintf(outbuf, sz, "getg "); break; + case TO_CALL: n = snprintf(outbuf, sz, "call "); break; + case TO_RET: n = snprintf(outbuf, sz, "ret "); break; + case TO_RETI: n = snprintf(outbuf, sz, "reti "); break; + case TO_GETKV: n = snprintf(outbuf, sz, "getkv "); break; + case TO_SETKV: n = snprintf(outbuf, sz, "setkv "); break; + case TO_GETI: n = snprintf(outbuf, sz, "geti "); break; + case TO_SETI: n = snprintf(outbuf, sz, "seti "); break; + case TO_APPND: n = snprintf(outbuf, sz, "appnd "); break; + case TO_NEXT: n = snprintf(outbuf, sz, "next "); break; + case TO_SMT: n = snprintf(outbuf, sz, "smt "); break; + case TO_MT: n = snprintf(outbuf, sz, "mt "); break; + case TO_SUM: n = snprintf(outbuf, sz, "sum "); break; + case TO_SUB: n = snprintf(outbuf, sz, "sub "); break; + case TO_MUL: n = snprintf(outbuf, sz, "mul "); break; + case TO_DIV: n = snprintf(outbuf, sz, "div "); break; + case TO_IDIV: n = snprintf(outbuf, sz, "idiv "); break; + case TO_MOD: n = snprintf(outbuf, sz, "mod "); break; + case TO_EQ: n = snprintf(outbuf, sz, "eq "); break; + case TO_NEQ: n = snprintf(outbuf, sz, "neq "); break; + case TO_LT: n = snprintf(outbuf, sz, "lt "); break; + case TO_LTE: n = snprintf(outbuf, sz, "lte "); break; + case TO_GT: n = snprintf(outbuf, sz, "gt "); break; + case TO_GTE: n = snprintf(outbuf, sz, "gte "); break; + case TO_AND: n = snprintf(outbuf, sz, "and "); break; + case TO_OR: n = snprintf(outbuf, sz, "or "); break; + case TO_XOR: n = snprintf(outbuf, sz, "xor "); break; + case TO_POW: n = snprintf(outbuf, sz, "pow "); break; + case TO_SHL: n = snprintf(outbuf, sz, "shl "); break; + case TO_SHR: n = snprintf(outbuf, sz, "shr "); break; + case TO_LEN: n = snprintf(outbuf, sz, "len "); break; + case TO_TYPE: n = snprintf(outbuf, sz, "type "); break; + case TO_CAST: n = snprintf(outbuf, sz, "cast "); break; + case TO_VER: n = snprintf(outbuf, sz, "ver "); break; + case TO_CMPL: n = snprintf(outbuf, sz, "cmpl "); break; + case TO_ASMBL: n = snprintf(outbuf, sz, "asmbl "); break; + case TO_LOAD: n = snprintf(outbuf, sz, "load "); break; + case TO_BZ: n = snprintf(outbuf, sz, "bz "); break; + case TO_BNZ: n = snprintf(outbuf, sz, "bnz "); break; + case TO_JMP: n = snprintf(outbuf, sz, "jmp "); break; + case TO_GC: n = snprintf(outbuf, sz, "gc "); break; + default: n = snprintf(outbuf, sz, "??? "); break; + } + + if (inst.operator >= OP_8BIT_OPERAND) + snprintf(&outbuf[n], sz + (size_t) n, "%2d", inst.operand); + else + snprintf(&outbuf[n], sz + (size_t) n, " "); +} + +#endif \ No newline at end of file diff --git a/lib/compiler/compiler.lua b/lib/compiler/compiler.lua index 4b53bb9..813002e 100644 --- a/lib/compiler/compiler.lua +++ b/lib/compiler/compiler.lua @@ -95,10 +95,10 @@ local instructions = { -- local variables pushv = 0xa3, - set = 0xa4, - dupv = 0xa5, - setg = 0xa6, - getg = 0xa7, + set = 0xae, + dupv = 0xa4, + setg = 0xa5, + getg = 0xa6, -- function operations call = 0xa7, @@ -138,7 +138,7 @@ local instructions = { -- other value operations len = 0x40, type = 0x41, - cast = 0xaa, + cast = 0xad, ver = 0x42, -- external code @@ -244,7 +244,7 @@ local function assemble(proto) -- add labels if inst.labels then for _, lbl in ipairs(inst.labels) do - labels[lbl] = #bin - function_start - 1 + labels[lbl] = #bin - function_start end end diff --git a/lib/priv.h b/lib/priv.h index 3d3ffb1..3d43bd6 100644 --- a/lib/priv.h +++ b/lib/priv.h @@ -26,10 +26,10 @@ typedef enum { // LOCAL VARIABLES TO_PUSHV = 0XA3, - TO_SET = 0XA4, - TO_DUPV = 0XA5, - TO_SETG = 0XA6, - TO_GETG = 0XA7, + TO_SET = 0XAE, + TO_DUPV = 0XA4, + TO_SETG = 0XA5, + TO_GETG = 0XA6, // FUNCTION OPERATIONS TO_CALL = 0XA7, @@ -69,7 +69,7 @@ typedef enum { // OTHER VALUE OPERATIONS TO_LEN = 0X40, TO_TYPE = 0X41, - TO_CAST = 0XAA, + TO_CAST = 0XAD, TO_VER = 0X42, // EXTERNAL CODE @@ -156,7 +156,7 @@ TYC_RESULT stack_push(Stack* s, VALUE v); TYC_RESULT stack_peek(Stack const* s, VALUE* v_out); TYC_RESULT stack_pop(Stack* s, VALUE* v_out); -size_t stack_len(Stack const* s); +size_t stack_size(Stack const* s); TYC_RESULT stack_at(Stack const* s, int32_t key, VALUE* v); TYC_RESULT stack_set(Stack* s, int32_t key, VALUE v); @@ -224,8 +224,12 @@ T_REAL code_const_real(Code const* code, size_t n); const char* code_const_string(Code const* code, size_t n); uint32_t code_n_functions(Code const* code); +uint32_t code_function_sz(Code const* code, uint32_t f_id); Instruction code_next_instruction(Code const* code, uint32_t function_id, uint32_t pc); +void code_decompile(Code const* code); +void code_parse_instruction(Instruction inst, char* outbuf, size_t sz); + // // EXPRESSIONS // diff --git a/lib/stack.c b/lib/stack.c index 44a4e82..084f01d 100644 --- a/lib/stack.c +++ b/lib/stack.c @@ -74,7 +74,7 @@ TYC_RESULT stack_pop(Stack* s, VALUE* v_out) return T_OK; } -size_t stack_len(Stack const* s) +size_t stack_size(Stack const* s) { return s->stack_n - stack_top_fp(s); } @@ -139,7 +139,7 @@ size_t stack_fp_level(Stack const* s) size_t stack_collectable_array(Stack const* s, VALUE** values) { size_t j = 0; - *values = xmalloc(stack_len(s) * sizeof(VALUE)); + *values = xmalloc(stack_size(s) * sizeof(VALUE)); for (size_t i = 0; i < s->stack_n; ++i) if (type_is_collectable(s->stack[i].type)) diff --git a/lib/tyche.h b/lib/tyche.h index c5d076a..7b0c29f 100644 --- a/lib/tyche.h +++ b/lib/tyche.h @@ -1,6 +1,7 @@ #ifndef TYCHE_TYCHE_H #define TYCHE_TYCHE_H +#include #include #include @@ -33,6 +34,10 @@ typedef struct TycheVM TycheVM; TycheVM* tyc_new(void); void tyc_destroy(TycheVM* t); +// debugging (DEBUG_ASSEMBLY needs to be setup in compilation options) +void tyc_debug_to_console(TycheVM* T, bool activate); +void tyc_assembly_decompile(TycheVM* T); + // code loading and execution TYC_RESULT tyc_load_bytecode(TycheVM* T, uint8_t const* bytecode, size_t bytecode_sz); TYC_RESULT tyc_call(TycheVM* t, uint16_t n_pars); diff --git a/lib/vm.c b/lib/vm.c index 201b772..c08dc1c 100644 --- a/lib/vm.c +++ b/lib/vm.c @@ -1,6 +1,7 @@ #include "priv.h" #include +#include typedef struct Location { uint32_t function_id; @@ -18,6 +19,7 @@ struct TycheVM { Heap* heap; Code* code; LocationStack location_stack; + bool debug; }; static TYC_RESULT step(TycheVM* T); @@ -39,6 +41,7 @@ TycheVM* tyc_new(void) .cap = 4, .sz = 0, }; + t->debug = false; expr_init(); @@ -54,6 +57,95 @@ void tyc_destroy(TycheVM* t) free(t); } +// +// DEBUGGING +// + +void tyc_debug_to_console(TycheVM* T, bool activate) +{ + T->debug = activate; +} + +#ifdef DEBUG_ASSEMBLY + +static void debug_instruction(TycheVM* T, Location* loc, Instruction inst) +{ + if (!T->debug) + return; + + char buf[50]; + code_parse_instruction(inst, buf, sizeof(buf)); + printf(": %02d-%04d %s ", loc->function_id, loc->pc, buf); +} + +static void debug_value(TycheVM* T, VALUE a) +{ + switch (value_type(a)) { + case TT_NIL: + printf("[nil]"); + break; + case TT_INTEGER: + printf("[%d]", value_integer(a)); + break; + case TT_REAL: + printf("[%f]", (double) value_real(a)); + break; + case TT_STRING: { + const char* str; + if (heap_get_string(T->heap, value_idx(a), &str) == T_OK) + printf("[\"%s\"]", str); + else + printf("[\"(not found)\"]"); + break; + } + case TT_STRING_CONST: { + if (code_const_type(T->code, value_idx(a)) != TC_STRING) + printf("[\"(const not a string)\"]"); + else + printf("[\"%s\"]", code_const_string(T->code, value_idx(a))); + break; + } + case TT_ARRAY: + printf("[(not implemented)]\n"); + abort(); + case TT_TABLE: + printf("[(not implemented )]\n"); + abort(); + case TT_FUNCTION: + printf("[func %d]", value_idx(a)); + break; + case TT_NATIVE_PTR: + printf("[ptr %p]", (void *) (intptr_t) value_idx(a)); + break; + case TT_COUNT__: + __builtin_unreachable(); + } +} + +static void debug_stack(TycheVM* T) +{ + if (!T->debug) + return; + if (stack_size(T->stack) == 0) { + printf("|empty|\n"); + return; + } + for (size_t i = 0; i < stack_size(T->stack); ++i) { + VALUE a; + stack_at(T->stack, (int32_t) i, &a); + debug_value(T, a); + printf(" "); + } + printf("\n"); +} + +void tyc_assembly_decompile(TycheVM* T) +{ + code_decompile(T->code); +} + +#endif + // // LOCATION STACK // @@ -152,7 +244,7 @@ TYC_RESULT tyc_call(TycheVM* T, uint16_t n_pars) size_t tyc_stack_size(TycheVM* T) { - return stack_len(T->stack); + return stack_size(T->stack); } void tyc_pushnil(TycheVM* T) @@ -211,7 +303,9 @@ static TYC_RESULT step(TycheVM* T) Location* loc = location_top(T); Instruction inst = code_next_instruction(T->code, loc->function_id, loc->pc); - // TODO - debug instruction +#ifdef DEBUG_ASSEMBLY + debug_instruction(T, loc, inst); +#endif switch (inst.operator) { @@ -299,8 +393,37 @@ static TYC_RESULT step(TycheVM* T) TRY(stack_pop_fp(T->stack)) TRY(stack_push(T->stack, a)) location_pop(T); - // TODO - print stack - return T_OK; + goto dont_update_pc; + + // + // jumps/branching + // + + case TO_JMP: + if (inst.operand < 0) + return T_ERR_VALUE_OUT_OF_RANGE; // TODO - also check function size + loc->pc = (uint32_t) inst.operand; + goto dont_update_pc; + + case TO_BZ: + if (inst.operand < 0) + return T_ERR_VALUE_OUT_OF_RANGE; // TODO - also check function size + TRY(stack_pop(T->stack, &a)) + if (value_is_zero(a)) { + loc->pc = (uint32_t) inst.operand; + goto dont_update_pc; + } + break; + + case TO_BNZ: + if (inst.operand < 0) + return T_ERR_VALUE_OUT_OF_RANGE; // TODO - also check function size + TRY(stack_pop(T->stack, &a)) + if (!value_is_zero(a)) { + loc->pc = (uint32_t) inst.operand; + goto dont_update_pc; + } + break; default: return T_ERR_INVALID_OPCODE; @@ -309,5 +432,9 @@ static TYC_RESULT step(TycheVM* T) // TODO - print stack loc->pc += inst.sz; +dont_update_pc: +#ifdef DEBUG_ASSEMBLY + debug_stack(T); +#endif return T_OK; } diff --git a/test/code-tests.lua b/test/code-tests.lua index 9cd0923..234c2e6 100644 --- a/test/code-tests.lua +++ b/test/code-tests.lua @@ -60,19 +60,41 @@ return { { name = "VM: functions", code = [[ - .func 0 - pushf 1 - pushi 2 - pushi 3 - call 2 - ret - .func 1 - dupv 0 - dupv 1 - sub - ret + .func 0 + pushf 1 + pushi 2 + pushi 3 + call 2 + ret + .func 1 + dupv 0 + dupv 1 + sub + ret ]], expected_stack_size = 1, expected_stack_top = -1, }, + { + name = "VM: jumps (jmp + bnz)", + code = [[ + .func 0 + jmp @x1 ; 0 + pushi 5 ; 3 + @x1: + pushi 1 ; 5 + bnz @x2 ; 7 + pushi 1 ; 10 + bz @x3 ; 12 + @x2: + pushi 6 ; 15 + ret ; 17 + @x3: + pushi 7 ; 18 + ret ; 20 + ]], + decompile = true, + debug = true, + expected_stack_top = 6, + }, } \ No newline at end of file diff --git a/test/tests.c b/test/tests.c index f2a1be8..266342d 100644 --- a/test/tests.c +++ b/test/tests.c @@ -14,8 +14,8 @@ static void run_assembly_tests(void); static void run_assembly_test(lua_State* L); -static void run_assembly_test_code(lua_State* L); -static void run_assembly_test_template(lua_State* L); +static void run_assembly_test_code(lua_State* L, bool debug, bool decompile); +static void run_assembly_test_template(lua_State* L, bool debug, bool decompile); int main(void) { @@ -37,7 +37,7 @@ int main(void) stack_push(s, create_value_integer(30)); VALUE v; - assert(stack_len(s) == 3); + assert(stack_size(s) == 3); assert(stack_at(s, 0, &v) == T_OK); assert(value_integer(v) == 10); assert(stack_at(s, 1, &v) == T_OK); assert(value_integer(v) == 20); assert(stack_at(s, -1, &v) == T_OK); assert(value_integer(v) == 30); @@ -54,7 +54,7 @@ int main(void) assert(stack_pop(s, NULL) == T_OK); assert(stack_at(s, -1, &v) == T_OK); assert(value_integer(v) == 10); assert(stack_pop(s, NULL) == T_OK); - assert(stack_len(s) == 0); + assert(stack_size(s) == 0); assert(stack_pop(s, NULL) == T_ERR_STACK_UNDERFLOW); @@ -74,7 +74,7 @@ int main(void) stack_push(s, create_value_integer(50)); VALUE v; - assert(stack_len(s) == 3); + assert(stack_size(s) == 3); assert(stack_at(s, 0, &v) == T_OK); assert(value_integer(v) == 30); assert(stack_at(s, 1, &v) == T_OK); assert(value_integer(v) == 40); assert(stack_at(s, -1, &v) == T_OK); assert(value_integer(v) == 50); @@ -88,7 +88,7 @@ int main(void) stack_pop_fp(s); - assert(stack_len(s) == 2); + assert(stack_size(s) == 2); assert(stack_at(s, 0, &v) == T_OK); assert(value_integer(v) == 10); assert(stack_at(s, 1, &v) == T_OK); assert(value_integer(v) == 20); assert(stack_at(s, -1, &v) == T_OK); assert(value_integer(v) == 20); @@ -252,6 +252,8 @@ int main(void) assert(code_const_real(code, 0) > 3.13f && code_const_real(code, 0) < 3.15f); assert(strcmp(code_const_string(code, 1), "Hello world") == 0); assert(code_n_functions(code) == 2); + assert(code_function_sz(code, 0) == 6); + assert(code_function_sz(code, 1) == 4); uint32_t addr = 0; Instruction inst = code_next_instruction(code, 0, addr); @@ -296,7 +298,7 @@ int main(void) Instruction inst = code_next_instruction(code, 0, 0); assert(inst.operator == TO_JMP); - assert(inst.operand == 3); + assert(inst.operand == 4); assert(inst.sz == 3); code_destroy(code); @@ -350,11 +352,21 @@ static void run_assembly_test(lua_State* L) printf(" - %s\n", lua_tostring(L, -1)); lua_pop(L, 1); + // debug? + lua_getfield(L, -1, "debug"); + bool debug = lua_isboolean(L, -1) && lua_toboolean(L, -1); + lua_pop(L, 1); + + // decompile + lua_getfield(L, -1, "decompile"); + bool decompile = lua_isboolean(L, -1) && lua_toboolean(L, -1); + lua_pop(L, 1); + // has code? lua_getfield(L, -1, "code"); if (!lua_isnil(L, -1)) { lua_pop(L, 1); - run_assembly_test_code(L); + run_assembly_test_code(L, debug, decompile); return; } else { lua_pop(L, 1); @@ -364,15 +376,16 @@ static void run_assembly_test(lua_State* L) lua_getfield(L, -1, "template"); if (!lua_isnil(L, -1)) { lua_pop(L, 1); - run_assembly_test_template(L); + run_assembly_test_template(L, debug, decompile); } else { lua_pop(L, 1); } } -static void run_assembly_test_code(lua_State* L) +static void run_assembly_test_code(lua_State* L, bool debug, bool decompile) { TycheVM* T = tyc_new(); + tyc_debug_to_console(T, debug); // load code uint8_t* bytecode; size_t bytecode_sz; @@ -382,6 +395,8 @@ static void run_assembly_test_code(lua_State* L) // run code assert(tyc_load_bytecode(T, bytecode, bytecode_sz) == T_OK); + if (decompile) + tyc_assembly_decompile(T); assert(tyc_call(T, 0) == T_OK); // check stack size @@ -405,7 +420,7 @@ static void run_assembly_test_code(lua_State* L) tyc_destroy(T); } -static void run_assembly_test_template(lua_State* L) +static void run_assembly_test_template(lua_State* L, bool debug, bool decompile) { lua_getfield(L, -1, "template"); char* template = strdup(lua_tostring(L, -1)); @@ -440,9 +455,12 @@ static void run_assembly_test_template(lua_State* L) // run code TycheVM* T = tyc_new(); + tyc_debug_to_console(T, debug); uint8_t* bytecode; size_t bytecode_sz; assert(code_assemble(formatted_code, &bytecode, &bytecode_sz) == T_OK); assert(tyc_load_bytecode(T, bytecode, bytecode_sz) == T_OK); + if (decompile) + tyc_assembly_decompile(T); assert(tyc_call(T, 0) == T_OK); // check stack top