From 88f9ce0ea625ff96b801db84097161ee0fead1dd Mon Sep 17 00:00:00 2001 From: Andre Wagner Date: Wed, 6 May 2026 11:12:41 -0500 Subject: [PATCH] . --- lua-temp/TODO.md | 4 ++-- lua-temp/tests.lua | 19 +++++++++++++++ lua-temp/tyche-vm.lua | 55 ++++++++++++++++++++++++++++++++++++++----- 3 files changed, 70 insertions(+), 8 deletions(-) diff --git a/lua-temp/TODO.md b/lua-temp/TODO.md index 7f64cee..283a45c 100644 --- a/lua-temp/TODO.md +++ b/lua-temp/TODO.md @@ -3,8 +3,8 @@ Progress of the Lua port: - [x] Assembler - [x] Basic VM execution - [x] Logic/arithmetic expressions -- [ ] Variables - - [ ] Local variables +- [x] Variables + - [x] Local variables - [ ] Functions - [ ] Calling functions - [ ] Calling functions with parameters diff --git a/lua-temp/tests.lua b/lua-temp/tests.lua index cc65f37..7476687 100644 --- a/lua-temp/tests.lua +++ b/lua-temp/tests.lua @@ -197,4 +197,23 @@ do TEST("VM: local variables") assert_eq(vm:to_integer(-1), 3) end +do TEST("VM: functions") + local vm = VM:new():set_debug(true):load(assemble([[ + .func 0 + pushf 1 + pushi 2 + pushi 3 + call 2 + ret + .func 1 + dupv 0 + dupv 1 + sum + ret + ]])):call(0) + + assert_eq(vm:stack_sz(), 1) + assert_eq(vm:to_integer(-1), 5) +end + print('End.') \ No newline at end of file diff --git a/lua-temp/tyche-vm.lua b/lua-temp/tyche-vm.lua index 9cc1782..c9f4e00 100644 --- a/lua-temp/tyche-vm.lua +++ b/lua-temp/tyche-vm.lua @@ -24,7 +24,20 @@ function format_value(v) elseif v.type == 'nil' then return 'nil' else - return pprint.format(v) + return pprint.pformat(v) + end +end + +function validate_value(v) + assert(v, "value cannot be nil") + assert(type(v) == 'table', "invalid value format (expected { type='...', value=... }), received: " .. pprint.pformat(value)) + assert(TYPE_MAP[v.type], "missing field 'type' in value") + if v.type == 'nil' then + assert(v.value == nil) + elseif v.type == 'number' then + assert(type(v.value) == 'number') + elseif v.type == 'function' then + assert(type(v.value) == 'number' and v.value >= 0, "function must be a positive number") end end @@ -51,19 +64,18 @@ function Stack:top_fps() end function Stack:push(value) - assert(type(value) == 'table', "invalid value format (expected { type='...', value=... })") - assert(TYPE_MAP[value.type], "missing field 'type' in value") + validate_value(value) table.insert(self.stack, value) end -function Stack:pop(value) +function Stack:pop() if #self.stack < self:top_fps() then error("Stack underflow") end local v = self.stack[#self.stack] self.stack[#self.stack] = nil return v end -function Stack:peek(value) +function Stack:peek() if #self.stack < self:top_fps() then error("Stack underflow") end return self.stack[#self.stack] end @@ -87,6 +99,7 @@ Stack.__index = function(self, key) end Stack.__newindex = function(self, key, value) + validate_value(value) local idx = tonumber(key) if idx then if idx >= 0 then @@ -261,15 +274,34 @@ end -- function VM:call(n_pars) + -- get parameters + local vars = {} + for i=1,n_pars do + vars[i] = self.stack:pop() + end + + -- get function local f = self.stack:pop() if f.type ~= 'function' then error("Type error: expected function") end + + -- enter function table.insert(self.loc, { f_id = f.value, pc = 1 }) self.stack:push_fp() - self:_run_until_return() -- execute code + + -- pass parameters + for i=1,n_pars do + self.stack:push(vars[#vars-i+1]) + end + + -- execute function + self:_run_until_return() + + -- exit function table.remove(self.loc) + return self end @@ -293,20 +325,27 @@ function VM:_step() if op.operator == 'pushi' then self:push_integer(op.operand) + elseif op.operator == 'pushf' then + assert(op.operand >= 0) + self.stack:push({ type = 'function', value = op.operand }) + -- -- local variables -- elseif op.operator == 'pushv' then + assert(op.operand >= 0) for i=1,op.operand do self:push_nil() end elseif op.operator == 'set' then + assert(op.operand >= 0) local a = self.stack:pop() self.stack[op.operand + 1] = a elseif op.operator == 'dupv' then + assert(op.operand >= 0) local a = self.stack[op.operand + 1] self.stack:push(a) @@ -323,6 +362,10 @@ function VM:_step() -- function management --- + elseif op.operator == 'call' then + assert(op.operand >= 0) + self:call(op.operand) + elseif op.operator == 'ret' then local v = self.stack:pop() self.stack:pop_fp()