diff --git a/TODO.md b/TODO.md index e10c92c..a87803e 100644 --- a/TODO.md +++ b/TODO.md @@ -23,7 +23,7 @@ Decisions: - [x] Execution loop (fast) - [ ] VM operations - [x] Expressions - - [ ] Local variables + - [x] Local variables - [ ] Functions - [ ] With parameters - [ ] Control flow diff --git a/lib/tyche.h b/lib/tyche.h index a9d4691..c5d076a 100644 --- a/lib/tyche.h +++ b/lib/tyche.h @@ -16,7 +16,7 @@ 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, T_ERR_INVALID_OPCODE = -51, T_ERR_EXPR_INCORRECT_TYPES = -52, + T_ERR_TYPE_UNEXPECTED = -50, T_ERR_INVALID_OPCODE = -51, T_ERR_EXPR_INCORRECT_TYPES = -52, T_ERR_VALUE_OUT_OF_RANGE = -53, } TYC_RESULT; typedef enum { @@ -39,6 +39,7 @@ TYC_RESULT tyc_call(TycheVM* t, uint16_t n_pars); // stack manipulation and query size_t tyc_stack_size(TycheVM* T); +void tyc_pushnil(TycheVM* T); 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); diff --git a/lib/vm.c b/lib/vm.c index 6729a64..c194dff 100644 --- a/lib/vm.c +++ b/lib/vm.c @@ -154,6 +154,11 @@ size_t tyc_stack_size(TycheVM* T) return stack_len(T->stack); } +void tyc_pushnil(TycheVM* T) +{ + stack_push(T->stack, create_value_nil()); +} + void tyc_pushinteger(TycheVM* T, int32_t value) { stack_push(T->stack, create_value_integer(value)); @@ -213,10 +218,49 @@ static TYC_RESULT step(TycheVM* T) // stack manipulation // + case TO_PUSHN: + tyc_pushnil(T); + break; + case TO_PUSHI: tyc_pushinteger(T, inst.operand); break; + case TO_PUSHF: + if (inst.operand < 0 || inst.operand > code_n_functions(T->code)) + return T_ERR_VALUE_OUT_OF_RANGE; + TRY(stack_push(T->stack, create_value_idx(TT_FUNCTION, inst.operand))) + break; + + case TO_POP: + TRY(stack_pop(T->stack, NULL)) + break; + + // + // local variables + // + + case TO_PUSHV: + if (inst.operand <= 0) + return T_ERR_VALUE_OUT_OF_RANGE; + for (size_t i = 0; i < inst.operand; ++i) + tyc_pushnil(T); + break; + + case TO_SET: + if (inst.operand < 0) + return T_ERR_VALUE_OUT_OF_RANGE; + TRY(stack_pop(T->stack, &a)) + TRY(stack_set(T->stack, inst.operand, a)) + break; + + case TO_DUPV: + if (inst.operand < 0) + return T_ERR_VALUE_OUT_OF_RANGE; + TRY(stack_at(T->stack, inst.operand, &a)) + stack_push(T->stack, a); + break; + // // expressions // diff --git a/test/code-tests.lua b/test/code-tests.lua index 5aef6ac..0a8eda8 100644 --- a/test/code-tests.lua +++ b/test/code-tests.lua @@ -41,5 +41,20 @@ return { { parameters = { 20, 3, 'shr' }, name = "Shift right", expected_stack_top = 2}, { parameters = { 20, 3, 'mod' }, name = "Modulo", expected_stack_top = 2 }, }, - } + }, + { + name = "VM: local variables", + code = [[ + .func 0 + pushv 2 ; local a, b + pushi 3 ; a = 3 + set 0 + pushi 4 ; b = 4 + set 1 + dupv 0 ; return a + ret + ]], + expected_stack_size = 1, + expected_stack_top = 3, + }, } \ No newline at end of file diff --git a/test/tests.c b/test/tests.c index 6af07ed..f2a1be8 100644 --- a/test/tests.c +++ b/test/tests.c @@ -462,6 +462,6 @@ static void run_assembly_test_template(lua_State* L) lua_pop(L, 1); } - lua_pop(L, 2); + lua_pop(L, 1); free(template); } \ No newline at end of file