diff --git a/lib/code.c b/lib/code.c index e7e0578..3968e53 100644 --- a/lib/code.c +++ b/lib/code.c @@ -40,14 +40,14 @@ void code_destroy(Code* code) free(code); } -TYC_RESULT code_load_bytecode(Code* code, uint8_t* bytecode, size_t bytecode_sz) +TYC_RESULT code_load_bytecode(Code* code, uint8_t const* bytecode, size_t bytecode_sz) { // TODO - linking if (bytecode_sz < 24) return T_ERR_BYTECODE_TOO_SMALL; - uint32_t magic = *(uint32_t*) &bytecode[0]; + uint32_t magic = *(uint32_t const*) &bytecode[0]; if (magic != MAGIC) return T_ERR_BYTECODE_INVALID_MAGIC; diff --git a/lib/priv.h b/lib/priv.h index 4c057cf..4398ce1 100644 --- a/lib/priv.h +++ b/lib/priv.h @@ -214,7 +214,7 @@ TYC_RESULT code_assemble(const char* code, uint8_t** bytecode, size_t* bytec Code* code_new(void); void code_destroy(Code* code); -TYC_RESULT code_load_bytecode(Code* code, uint8_t* bytecode, size_t bytecode_sz); +TYC_RESULT code_load_bytecode(Code* code, uint8_t const* bytecode, size_t bytecode_sz); uint32_t code_n_consts(Code const* code); TYC_CONST_TYPE code_const_type(Code const* code, size_t n); diff --git a/lib/tyche.h b/lib/tyche.h index 6ff15d5..e8e25a5 100644 --- a/lib/tyche.h +++ b/lib/tyche.h @@ -1,6 +1,9 @@ #ifndef TYCHE_TYCHE_H #define TYCHE_TYCHE_H +#include +#include + typedef enum { TT_NIL, TT_INTEGER, TT_REAL, TT_STRING, TT_STRING_CONST, TT_ARRAY, TT_TABLE, TT_FUNCTION, TT_NATIVE_PTR, } TYC_TYPE; @@ -12,8 +15,29 @@ typedef enum { T_ERR_TABLE_KEY_NOT_FOUND = -20, T_ERR_ASSEMBLER_SYNTAX_ERROR = -30, T_ERR_BYTECODE_TOO_SMALL = -40, T_ERR_BYTECODE_INVALID_MAGIC = -41, + T_ERR_TYPE_UNEXPECTED = -50, } TYC_RESULT; +typedef enum { + TX_SUM, +} TYC_EXPR; + #define T_REAL float +typedef struct TycheVM TycheVM; + +// create/destroy VM +TycheVM* tyc_new(void); +void tyc_destroy(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); + +// stack manipulation and query +void tyc_pushinteger(TycheVM* T, int32_t value); +TYC_RESULT tyc_type(TycheVM* T, int idx, TYC_TYPE* type); +TYC_RESULT tyc_tointeger(TycheVM* T, int idx, int32_t* value); +TYC_RESULT tyc_expr(TycheVM* T, TYC_EXPR expr); + #endif //TYCHE_TYCHE_H diff --git a/lib/vm.c b/lib/vm.c index 18197cc..13168f4 100644 --- a/lib/vm.c +++ b/lib/vm.c @@ -1 +1,72 @@ -#include "priv.h" \ No newline at end of file +#include "priv.h" + +#include + +struct TycheVM { + Stack* stack; + Heap* heap; + Code* code; +}; + +TycheVM* tyc_new(void) +{ + TycheVM* t = xcalloc(1, sizeof(TycheVM)); + t->stack = stack_new(); + t->heap = heap_new(); + t->code = code_new(); + return t; +} + +void tyc_destroy(TycheVM* t) +{ + code_destroy(t->code); + heap_destroy(t->heap); + stack_destroy(t->stack); + free(t); +} + +TYC_RESULT tyc_load_bytecode(TycheVM* T, uint8_t const* bytecode, size_t bytecode_sz) +{ + return code_load_bytecode(T->code, bytecode, bytecode_sz); +} + +TYC_RESULT tyc_call(TycheVM* T, uint16_t n_pars) +{ + abort(); // TODO +} + +void tyc_pushinteger(TycheVM* T, int32_t value) +{ + stack_push(T->stack, create_value_integer(value)); +} + +TYC_RESULT tyc_type(TycheVM* T, int idx, TYC_TYPE* type) +{ + VALUE v; + TYC_RESULT r = stack_at(T->stack, idx, &v); + if (r == T_OK) + *type = v.type; + return r; +} + +TYC_RESULT tyc_tointeger(TycheVM* T, int idx, int32_t* value) +{ + VALUE v; + TYC_RESULT r = stack_at(T->stack, idx, &v); + if (r == T_OK) { + if (v.type != TT_INTEGER) + return T_ERR_TYPE_UNEXPECTED; + *value = value_integer(v); + } + return r; +} + +TYC_RESULT tyc_expr(TycheVM* T, TYC_EXPR expr) +{ + // TODO + VALUE v1, v2; + stack_pop(T->stack, &v2); + stack_pop(T->stack, &v1); + stack_push(T->stack, create_value_integer(value_integer(v1) + value_integer(v2))); + return T_OK; +} \ No newline at end of file diff --git a/test/code-tests.lua b/test/code-tests.lua index 71e2197..b083784 100644 --- a/test/code-tests.lua +++ b/test/code-tests.lua @@ -9,6 +9,6 @@ return { ret ]], expected_stack_size = 1, - expected_stack_top = { integer = 5 }, + expected_stack_top = 5, }, } \ No newline at end of file diff --git a/test/tests.c b/test/tests.c index d3dca4c..8651942 100644 --- a/test/tests.c +++ b/test/tests.c @@ -6,12 +6,19 @@ #include #include +#include "lua.h" +#include "lauxlib.h" +#include "lualib.h" + #define EQ(a, b) (memcmp(a, b) == 0) +static void run_assembly_tests(void); +static void run_assembly_test(lua_State* L); + int main() { { - printf("### Values\n"); + printf("## Values\n"); assert(value_type(create_value_integer(42)) == TT_INTEGER); assert(value_integer(create_value_integer(-42)) == -42); assert(fabsf(value_real(create_value_real(42.4f)) - 42.4f) < 0.00001f); @@ -19,7 +26,7 @@ int main() } { - printf("### Stack\n"); + printf("## Stack\n"); Stack* s = stack_new(); @@ -53,7 +60,7 @@ int main() } { - printf("### Stack with frame pointer\n"); + printf("## Stack with frame pointer\n"); Stack* s = stack_new(); @@ -92,7 +99,7 @@ int main() } { - printf("### Arrays\n"); + printf("## Arrays\n"); Array* a = array_new(); assert(array_len(a) == 0); @@ -114,7 +121,7 @@ int main() } { - printf("### Table - integer index\n"); + printf("## Table - integer index\n"); Heap* h = heap_new(); Table* t = table_new(h); @@ -135,7 +142,7 @@ int main() } { - printf("### Table - string index\n"); + printf("## Table - string index\n"); Heap* h = heap_new(); Table* t = table_new(h); @@ -162,7 +169,7 @@ int main() } { - printf("### Heap - strings\n"); + printf("## Heap - strings\n"); Heap* h = heap_new(); @@ -178,7 +185,7 @@ int main() } { - printf("### Heap - string GC\n"); + printf("## Heap - string GC\n"); Stack* s = stack_new(); Heap* h = heap_new(); @@ -215,7 +222,7 @@ int main() } { - printf("### Bytecode\n"); + printf("## Bytecode\n"); const char* assembly_code = ".const\n" " 0: 3.14\n" @@ -271,7 +278,7 @@ int main() } { - printf("### Bytecode - labels\n"); + printf("## Bytecode - labels\n"); const char* assembly_code = ".func 0\n" " jmp @my_label\n" @@ -293,4 +300,50 @@ int main() code_destroy(code); free(bytecode); } + + { + printf("## VM - Basic\n"); + + TycheVM* T = tyc_new(); + + tyc_pushinteger(T, 2); + tyc_pushinteger(T, 3); + tyc_expr(T, TX_SUM); + int32_t result; assert(tyc_tointeger(T, -1, &result) == T_OK); + assert(result == 5); + + tyc_destroy(T); + } + + { + printf("## Assembly tests\n"); + run_assembly_tests(); + } +} + +static void run_assembly_tests(void) +{ + lua_State* L = luaL_newstate(); + luaL_openlibs(L); + + int r = luaL_loadfile(L, "./test/code-tests.lua"); + assert(r == LUA_OK); + lua_call(L, 0, 1); + assert(lua_istable(L, -1)); + + int len = luaL_len(L, -1); + for (int i = 0; i < len; ++i) { + lua_geti(L, -1, i + 1); + run_assembly_test(L); + lua_pop(L, 1); + } + + lua_close(L); +} + +static void run_assembly_test(lua_State* L) +{ + lua_getfield(L, -1, "name"); + printf(" - %s\n", lua_tostring(L, -1)); + lua_pop(L, -1); } \ No newline at end of file