From 8614f978ea9021036f8089360a47c0c37a9a73ed Mon Sep 17 00:00:00 2001 From: Andre Wagner Date: Tue, 5 May 2026 09:40:22 -0500 Subject: [PATCH] . --- lua-temp/tests.lua | 32 ++++++++++++ lua-temp/tyche-vm.lua | 118 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 147 insertions(+), 3 deletions(-) diff --git a/lua-temp/tests.lua b/lua-temp/tests.lua index 84b1732..99b633f 100644 --- a/lua-temp/tests.lua +++ b/lua-temp/tests.lua @@ -84,6 +84,11 @@ do assert_eq(stack[1], 20) assert_eq(stack[-1], 30) assert_eq(stack[-2], 20) + + stack:pop() + stack:pop() + stack:pop() + assert_eq(#stack, 0) end do @@ -110,4 +115,31 @@ do assert_eq(stack[-2], 10) end +---------------------- +-- -- +-- VM STACK -- +-- -- +---------------------- + +do + local vm = VM:new() + local bytecode = assemble [[ + .func 0 + pushi 2 + pushi 3 + sum + ret + ]] + vm:load(bytecode) + + assert_eq(vm:stack_sz(), 1) + assert_eq(vm:is(-1, 'function'), true) + + vm:call(0) + + assert_eq(vm:stack_sz(), 1) + assert_eq(vm:is(-1, 'integer')) + 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 cf07726..d3d6c8d 100644 --- a/lua-temp/tyche-vm.lua +++ b/lua-temp/tyche-vm.lua @@ -27,14 +27,14 @@ function Stack:push(value) end function Stack:pop(value) - if #self.stack <= self:top_fps() then error("Stack underflow") end + 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) - if #self.stack <= self:top_fps() then error("Stack underflow") end + if #self.stack < self:top_fps() then error("Stack underflow") end return self.stack[#self.stack] end @@ -91,6 +91,35 @@ function Stack:debug() return table.concat(ss) end +---------------------- +-- -- +-- CODE -- +-- -- +---------------------- + +local Code = {} +Code.__index = Code + +function Code.new() + return setmetatable({ + bytecode = nil + }, Code) +end + +function Code:load(bytecode) + -- TODO - what if there's code already loaded? + self.bytecode = bytecode + return 0 -- main function +end + +function Code:next_instruction(function_id, pc) + return { + operator = self.bytecode.functions[function_id][pc][1], + operand = self.bytecode.functions[function_id][pc][2], + instruction_size = 1, + } +end + ---------------------- -- -- -- VM -- @@ -102,8 +131,91 @@ VM.__index = VM function VM.new() return setmetatable({ - stack = Stack.new() + stack = Stack.new(), + code = Code.new(), + loc = {}, }, VM) end +-- +-- code management +-- + +function VM:load(bytecode) + local f_id = self.code:load(bytecode) + self.stack:push({ type = 'function', value = f_id }) + return self +end + +-- +-- stack management +-- + +function VM:push_integer(n) + self.stack:push({ type = 'integer', value = n }) +end + +-- +-- information +-- + +function VM:stack_sz() + return #self.stack +end + +function VM:is(idx, type) + return self.stack[idx].type == type +end + +function VM:to_integer(idx) + local value = self.stack[idx] + if value.type ~= 'integer' then error("Type error: not an integer") end + return value.value +end + +-- +-- code execution +-- + +function VM:call(n_pars) + local f = self.stack:pop() + if f.type ~= 'function' then error("Type error: expected function") end + table.insert(self.loc, { + f_id = f.value, + pc = 1 + }) + self.stack:push_fp() + self:_run_until_return() -- execute code + table.remove(self.loc) + return self +end + +function VM:_run_until_return() + local level = self.stack:fp_level() + while self.stack:fp_level() >= level do + self:_step() + end +end + +function VM:_step() + local loc = self.loc[#self.loc] + local op = self.code:next_instruction(loc.f_id, loc.pc) + print(loc.f_id .. ':' .. loc.pc .. ' ' .. op.operator .. ' ' .. (op.operand and op.operand or '')) + + if op.operator == 'pushi' then + self:push_integer(op.operand) + elseif op.operator == 'sum' then + self:push_integer(self.stack:pop().value + self.stack:pop().value) + elseif op.operator == 'ret' then + local v = self.stack:pop() + self.stack:pop_fp() + self.stack:push(v) + return + else + error("Unknown operator '" .. tostring(op.operator) .. "'") + end + + loc.pc = loc.pc + op.instruction_size +end + return VM \ No newline at end of file