This commit is contained in:
2026-05-17 09:36:15 -05:00
parent e2692a589a
commit 6f0c3a729b
11 changed files with 342 additions and 49 deletions

View File

@@ -3,7 +3,10 @@
# #
# install prefix # install prefix
PREFIX=/usr/local PREFIX ?= /usr/local
# add functions to debug assembly to console
DEBUG_ASSEMBLY ?= 0
# #
# internal flags/options # 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 CFLAGS+=-std=c99 -D_GNU_SOURCE -fPIC -fvisibility=hidden -isystem lib/contrib -MMD -MP
LDFLAGS+= LDFLAGS+=
ifeq ($(DEBUG_ASSEMBLY),1)
CFLAGS += -DDEBUG_ASSEMBLY
endif
# #
# generic targets # generic targets
# #
@@ -58,7 +65,7 @@ check: tyche-test
./tyche-test ./tyche-test
clean: 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: tyche libtyche.a libtyche.so.${VERSION} lib/tyche.h
install -m 644 libtyche.a libtyche.so.${VERSION} ${PREFIX}/lib install -m 644 libtyche.a libtyche.so.${VERSION} ${PREFIX}/lib
@@ -95,7 +102,7 @@ tyche: src/tyche.o libtyche.a
$(CC) -o $@ $^ ${LDFLAGS} $(CC) -o $@ $^ ${LDFLAGS}
strip $@ strip $@
tyche-test: CFLAGS += ${DEBUG_CFLAGS} tyche-test: CFLAGS += ${DEBUG_CFLAGS} -DDEBUG_ASSEMBLY
tyche-test: LDFLAGS += ${DEBUG_LDFLAGS} tyche-test: LDFLAGS += ${DEBUG_LDFLAGS}
tyche-test: test/tests.o libtyche.a tyche-test: test/tests.o libtyche.a
$(CC) -o $@ $^ ${LDFLAGS} -I../lib $(CC) -o $@ $^ ${LDFLAGS} -I../lib

View File

@@ -24,8 +24,9 @@ Decisions:
- [ ] VM operations - [ ] VM operations
- [x] Expressions - [x] Expressions
- [x] Local variables - [x] Local variables
- [ ] Functions - [x] Functions
- [ ] With parameters - [x] With parameters
- [ ] Debug VM execution
- [ ] Control flow - [ ] Control flow
- [ ] Recursion - [ ] Recursion
- [ ] Strings - [ ] Strings

View File

@@ -32,7 +32,7 @@ Stack operations:
Local variables: Local variables:
a3 c3 e3 pushv [int] Push n nil values into the stack (used to init local vars) 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) a4 c4 e4 dupv [index] Duplicate stack value (load local variable)
a5 c5 e5 setg [int] Set global variable a5 c5 e5 setg [int] Set global variable
a6 c6 e6 getg [int] Get global variable a6 c6 e6 getg [int] Get global variable
@@ -75,7 +75,7 @@ Logical/arithmetic:
Other value operations: Other value operations:
40 len Get table, array or string size 40 len Get table, array or string size
41 type Get type from value at the top of the stack 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 42 ver Return VM version
External code: External code:

View File

@@ -25,6 +25,7 @@ struct Code {
uint32_t* const_addr; uint32_t* const_addr;
uint32_t fn_count; uint32_t fn_count;
uint32_t* fn_addr; uint32_t* fn_addr;
uint32_t* fn_sz;
}; };
Code* code_new(void) Code* code_new(void)
@@ -37,6 +38,7 @@ void code_destroy(Code* code)
{ {
free(code->const_addr); free(code->const_addr);
free(code->fn_addr); free(code->fn_addr);
free(code->fn_sz);
free(code); free(code);
} }
@@ -91,12 +93,16 @@ TYC_RESULT code_load_bytecode(Code* code, uint8_t const* bytecode, size_t byteco
addr += 4; addr += 4;
code->fn_addr = xcalloc(code->fn_count, sizeof(uint32_t)); 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; code->fn_addr[0] = addr;
uint32_t addr_next;
for (size_t i = 1; i < code->fn_count; ++i) { for (size_t i = 1; i < code->fn_count; ++i) {
uint32_t addr_next;
memcpy(&addr_next, &bytecode[addr], sizeof(uint32_t)); memcpy(&addr_next, &bytecode[addr], sizeof(uint32_t));
code->fn_sz[i-1] = addr_next - addr - 4;
addr = code->fn_addr[i] = addr_next; 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; return T_OK;
} }
@@ -132,6 +138,11 @@ uint32_t code_n_functions(Code const* code)
return code->fn_count; 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) Instruction code_next_instruction(Code const* code, uint32_t function_id, uint32_t pc)
{ {
uint32_t addr = code->fn_addr[function_id] + 4 + 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, .operand = operand,
.sz = sz, .sz = sz,
}; };
} }
#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

View File

@@ -95,10 +95,10 @@ local instructions = {
-- local variables -- local variables
pushv = 0xa3, pushv = 0xa3,
set = 0xa4, set = 0xae,
dupv = 0xa5, dupv = 0xa4,
setg = 0xa6, setg = 0xa5,
getg = 0xa7, getg = 0xa6,
-- function operations -- function operations
call = 0xa7, call = 0xa7,
@@ -138,7 +138,7 @@ local instructions = {
-- other value operations -- other value operations
len = 0x40, len = 0x40,
type = 0x41, type = 0x41,
cast = 0xaa, cast = 0xad,
ver = 0x42, ver = 0x42,
-- external code -- external code
@@ -244,7 +244,7 @@ local function assemble(proto)
-- add labels -- add labels
if inst.labels then if inst.labels then
for _, lbl in ipairs(inst.labels) do for _, lbl in ipairs(inst.labels) do
labels[lbl] = #bin - function_start - 1 labels[lbl] = #bin - function_start
end end
end end

View File

@@ -26,10 +26,10 @@ typedef enum {
// LOCAL VARIABLES // LOCAL VARIABLES
TO_PUSHV = 0XA3, TO_PUSHV = 0XA3,
TO_SET = 0XA4, TO_SET = 0XAE,
TO_DUPV = 0XA5, TO_DUPV = 0XA4,
TO_SETG = 0XA6, TO_SETG = 0XA5,
TO_GETG = 0XA7, TO_GETG = 0XA6,
// FUNCTION OPERATIONS // FUNCTION OPERATIONS
TO_CALL = 0XA7, TO_CALL = 0XA7,
@@ -69,7 +69,7 @@ typedef enum {
// OTHER VALUE OPERATIONS // OTHER VALUE OPERATIONS
TO_LEN = 0X40, TO_LEN = 0X40,
TO_TYPE = 0X41, TO_TYPE = 0X41,
TO_CAST = 0XAA, TO_CAST = 0XAD,
TO_VER = 0X42, TO_VER = 0X42,
// EXTERNAL CODE // 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_peek(Stack const* s, VALUE* v_out);
TYC_RESULT stack_pop(Stack* 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_at(Stack const* s, int32_t key, VALUE* v);
TYC_RESULT stack_set(Stack* 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); const char* code_const_string(Code const* code, size_t n);
uint32_t code_n_functions(Code const* code); 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); 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 // EXPRESSIONS
// //

View File

@@ -74,7 +74,7 @@ TYC_RESULT stack_pop(Stack* s, VALUE* v_out)
return T_OK; 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); 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 stack_collectable_array(Stack const* s, VALUE** values)
{ {
size_t j = 0; 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) for (size_t i = 0; i < s->stack_n; ++i)
if (type_is_collectable(s->stack[i].type)) if (type_is_collectable(s->stack[i].type))

View File

@@ -1,6 +1,7 @@
#ifndef TYCHE_TYCHE_H #ifndef TYCHE_TYCHE_H
#define TYCHE_TYCHE_H #define TYCHE_TYCHE_H
#include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
@@ -33,6 +34,10 @@ typedef struct TycheVM TycheVM;
TycheVM* tyc_new(void); TycheVM* tyc_new(void);
void tyc_destroy(TycheVM* t); 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 // code loading and execution
TYC_RESULT tyc_load_bytecode(TycheVM* T, uint8_t const* bytecode, size_t bytecode_sz); 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); TYC_RESULT tyc_call(TycheVM* t, uint16_t n_pars);

135
lib/vm.c
View File

@@ -1,6 +1,7 @@
#include "priv.h" #include "priv.h"
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
typedef struct Location { typedef struct Location {
uint32_t function_id; uint32_t function_id;
@@ -18,6 +19,7 @@ struct TycheVM {
Heap* heap; Heap* heap;
Code* code; Code* code;
LocationStack location_stack; LocationStack location_stack;
bool debug;
}; };
static TYC_RESULT step(TycheVM* T); static TYC_RESULT step(TycheVM* T);
@@ -39,6 +41,7 @@ TycheVM* tyc_new(void)
.cap = 4, .cap = 4,
.sz = 0, .sz = 0,
}; };
t->debug = false;
expr_init(); expr_init();
@@ -54,6 +57,95 @@ void tyc_destroy(TycheVM* t)
free(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 // LOCATION STACK
// //
@@ -152,7 +244,7 @@ TYC_RESULT tyc_call(TycheVM* T, uint16_t n_pars)
size_t tyc_stack_size(TycheVM* T) size_t tyc_stack_size(TycheVM* T)
{ {
return stack_len(T->stack); return stack_size(T->stack);
} }
void tyc_pushnil(TycheVM* T) void tyc_pushnil(TycheVM* T)
@@ -211,7 +303,9 @@ static TYC_RESULT step(TycheVM* T)
Location* loc = location_top(T); Location* loc = location_top(T);
Instruction inst = code_next_instruction(T->code, loc->function_id, loc->pc); 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) { switch (inst.operator) {
@@ -299,8 +393,37 @@ static TYC_RESULT step(TycheVM* T)
TRY(stack_pop_fp(T->stack)) TRY(stack_pop_fp(T->stack))
TRY(stack_push(T->stack, a)) TRY(stack_push(T->stack, a))
location_pop(T); location_pop(T);
// TODO - print stack goto dont_update_pc;
return T_OK;
//
// 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: default:
return T_ERR_INVALID_OPCODE; return T_ERR_INVALID_OPCODE;
@@ -309,5 +432,9 @@ static TYC_RESULT step(TycheVM* T)
// TODO - print stack // TODO - print stack
loc->pc += inst.sz; loc->pc += inst.sz;
dont_update_pc:
#ifdef DEBUG_ASSEMBLY
debug_stack(T);
#endif
return T_OK; return T_OK;
} }

View File

@@ -60,19 +60,41 @@ return {
{ {
name = "VM: functions", name = "VM: functions",
code = [[ code = [[
.func 0 .func 0
pushf 1 pushf 1
pushi 2 pushi 2
pushi 3 pushi 3
call 2 call 2
ret ret
.func 1 .func 1
dupv 0 dupv 0
dupv 1 dupv 1
sub sub
ret ret
]], ]],
expected_stack_size = 1, expected_stack_size = 1,
expected_stack_top = -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,
},
} }

View File

@@ -14,8 +14,8 @@
static void run_assembly_tests(void); static void run_assembly_tests(void);
static void run_assembly_test(lua_State* L); static void run_assembly_test(lua_State* L);
static void run_assembly_test_code(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); static void run_assembly_test_template(lua_State* L, bool debug, bool decompile);
int main(void) int main(void)
{ {
@@ -37,7 +37,7 @@ int main(void)
stack_push(s, create_value_integer(30)); stack_push(s, create_value_integer(30));
VALUE v; 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, 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);
assert(stack_at(s, -1, &v) == T_OK); assert(value_integer(v) == 30); 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_pop(s, NULL) == T_OK);
assert(stack_at(s, -1, &v) == T_OK); assert(value_integer(v) == 10); assert(stack_at(s, -1, &v) == T_OK); assert(value_integer(v) == 10);
assert(stack_pop(s, NULL) == T_OK); 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); assert(stack_pop(s, NULL) == T_ERR_STACK_UNDERFLOW);
@@ -74,7 +74,7 @@ int main(void)
stack_push(s, create_value_integer(50)); stack_push(s, create_value_integer(50));
VALUE v; 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, 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) == 40);
assert(stack_at(s, -1, &v) == T_OK); assert(value_integer(v) == 50); assert(stack_at(s, -1, &v) == T_OK); assert(value_integer(v) == 50);
@@ -88,7 +88,7 @@ int main(void)
stack_pop_fp(s); 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, 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);
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(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(strcmp(code_const_string(code, 1), "Hello world") == 0);
assert(code_n_functions(code) == 2); assert(code_n_functions(code) == 2);
assert(code_function_sz(code, 0) == 6);
assert(code_function_sz(code, 1) == 4);
uint32_t addr = 0; uint32_t addr = 0;
Instruction inst = code_next_instruction(code, 0, addr); Instruction inst = code_next_instruction(code, 0, addr);
@@ -296,7 +298,7 @@ int main(void)
Instruction inst = code_next_instruction(code, 0, 0); Instruction inst = code_next_instruction(code, 0, 0);
assert(inst.operator == TO_JMP); assert(inst.operator == TO_JMP);
assert(inst.operand == 3); assert(inst.operand == 4);
assert(inst.sz == 3); assert(inst.sz == 3);
code_destroy(code); code_destroy(code);
@@ -350,11 +352,21 @@ static void run_assembly_test(lua_State* L)
printf(" - %s\n", lua_tostring(L, -1)); printf(" - %s\n", lua_tostring(L, -1));
lua_pop(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? // has code?
lua_getfield(L, -1, "code"); lua_getfield(L, -1, "code");
if (!lua_isnil(L, -1)) { if (!lua_isnil(L, -1)) {
lua_pop(L, 1); lua_pop(L, 1);
run_assembly_test_code(L); run_assembly_test_code(L, debug, decompile);
return; return;
} else { } else {
lua_pop(L, 1); lua_pop(L, 1);
@@ -364,15 +376,16 @@ static void run_assembly_test(lua_State* L)
lua_getfield(L, -1, "template"); lua_getfield(L, -1, "template");
if (!lua_isnil(L, -1)) { if (!lua_isnil(L, -1)) {
lua_pop(L, 1); lua_pop(L, 1);
run_assembly_test_template(L); run_assembly_test_template(L, debug, decompile);
} else { } else {
lua_pop(L, 1); 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(); TycheVM* T = tyc_new();
tyc_debug_to_console(T, debug);
// load code // load code
uint8_t* bytecode; size_t bytecode_sz; uint8_t* bytecode; size_t bytecode_sz;
@@ -382,6 +395,8 @@ static void run_assembly_test_code(lua_State* L)
// run code // run code
assert(tyc_load_bytecode(T, 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); assert(tyc_call(T, 0) == T_OK);
// check stack size // check stack size
@@ -405,7 +420,7 @@ static void run_assembly_test_code(lua_State* L)
tyc_destroy(T); 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"); lua_getfield(L, -1, "template");
char* template = strdup(lua_tostring(L, -1)); char* template = strdup(lua_tostring(L, -1));
@@ -440,9 +455,12 @@ static void run_assembly_test_template(lua_State* L)
// run code // run code
TycheVM* T = tyc_new(); TycheVM* T = tyc_new();
tyc_debug_to_console(T, debug);
uint8_t* bytecode; size_t bytecode_sz; uint8_t* bytecode; size_t bytecode_sz;
assert(code_assemble(formatted_code, &bytecode, &bytecode_sz) == T_OK); assert(code_assemble(formatted_code, &bytecode, &bytecode_sz) == T_OK);
assert(tyc_load_bytecode(T, 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); assert(tyc_call(T, 0) == T_OK);
// check stack top // check stack top