.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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.')
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user