This commit is contained in:
Andre Wagner
2026-05-06 11:12:41 -05:00
parent 0fae9a0b37
commit 88f9ce0ea6
3 changed files with 70 additions and 8 deletions

View File

@@ -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

View File

@@ -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.')

View File

@@ -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()