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