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] Assembler
- [x] Basic VM execution - [x] Basic VM execution
- [x] Logic/arithmetic expressions - [x] Logic/arithmetic expressions
- [ ] Variables - [x] Variables
- [ ] Local variables - [x] Local variables
- [ ] Functions - [ ] Functions
- [ ] Calling functions - [ ] Calling functions
- [ ] Calling functions with parameters - [ ] Calling functions with parameters

View File

@@ -197,4 +197,23 @@ do TEST("VM: local variables")
assert_eq(vm:to_integer(-1), 3) assert_eq(vm:to_integer(-1), 3)
end 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.') print('End.')

View File

@@ -24,7 +24,20 @@ function format_value(v)
elseif v.type == 'nil' then elseif v.type == 'nil' then
return 'nil' return 'nil'
else 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
end end
@@ -51,19 +64,18 @@ function Stack:top_fps()
end end
function Stack:push(value) function Stack:push(value)
assert(type(value) == 'table', "invalid value format (expected { type='...', value=... })") validate_value(value)
assert(TYPE_MAP[value.type], "missing field 'type' in value")
table.insert(self.stack, value) table.insert(self.stack, value)
end end
function Stack:pop(value) function Stack:pop()
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] local v = self.stack[#self.stack]
self.stack[#self.stack] = nil self.stack[#self.stack] = nil
return v return v
end end
function Stack:peek(value) function Stack:peek()
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] return self.stack[#self.stack]
end end
@@ -87,6 +99,7 @@ Stack.__index = function(self, key)
end end
Stack.__newindex = function(self, key, value) Stack.__newindex = function(self, key, value)
validate_value(value)
local idx = tonumber(key) local idx = tonumber(key)
if idx then if idx then
if idx >= 0 then if idx >= 0 then
@@ -261,15 +274,34 @@ end
-- --
function VM:call(n_pars) 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() local f = self.stack:pop()
if f.type ~= 'function' then error("Type error: expected function") end if f.type ~= 'function' then error("Type error: expected function") end
-- enter function
table.insert(self.loc, { table.insert(self.loc, {
f_id = f.value, f_id = f.value,
pc = 1 pc = 1
}) })
self.stack:push_fp() 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) table.remove(self.loc)
return self return self
end end
@@ -293,20 +325,27 @@ function VM:_step()
if op.operator == 'pushi' then if op.operator == 'pushi' then
self:push_integer(op.operand) self:push_integer(op.operand)
elseif op.operator == 'pushf' then
assert(op.operand >= 0)
self.stack:push({ type = 'function', value = op.operand })
-- --
-- local variables -- local variables
-- --
elseif op.operator == 'pushv' then elseif op.operator == 'pushv' then
assert(op.operand >= 0)
for i=1,op.operand do for i=1,op.operand do
self:push_nil() self:push_nil()
end end
elseif op.operator == 'set' then elseif op.operator == 'set' then
assert(op.operand >= 0)
local a = self.stack:pop() local a = self.stack:pop()
self.stack[op.operand + 1] = a self.stack[op.operand + 1] = a
elseif op.operator == 'dupv' then elseif op.operator == 'dupv' then
assert(op.operand >= 0)
local a = self.stack[op.operand + 1] local a = self.stack[op.operand + 1]
self.stack:push(a) self.stack:push(a)
@@ -323,6 +362,10 @@ function VM:_step()
-- function management -- function management
--- ---
elseif op.operator == 'call' then
assert(op.operand >= 0)
self:call(op.operand)
elseif op.operator == 'ret' then elseif op.operator == 'ret' then
local v = self.stack:pop() local v = self.stack:pop()
self.stack:pop_fp() self.stack:pop_fp()