.
This commit is contained in:
@@ -22,12 +22,13 @@ Stack operations:
|
|||||||
a0 c0 e0 pushi [int] Push int
|
a0 c0 e0 pushi [int] Push int
|
||||||
a1 c1 e1 pushc [index] Push constant
|
a1 c1 e1 pushc [index] Push constant
|
||||||
a2 c2 e2 pushf [function] Push function id
|
a2 c2 e2 pushf [function] Push function id
|
||||||
00 pushz Push zero (or false)
|
00 pushn Push nil
|
||||||
01 pusht Push true
|
01 pushz Push zero (or false)
|
||||||
02 newa Push (create) empty array
|
02 pusht Push true
|
||||||
03 newt Push (create) empty table
|
03 newa Push (create) empty array
|
||||||
04 pop
|
04 newt Push (create) empty table
|
||||||
05 dup
|
05 pop
|
||||||
|
06 dup
|
||||||
|
|
||||||
Local variables:
|
Local variables:
|
||||||
a3 c3 e3 pushv [int] Push n nil values into the stack (used to init local vars)
|
a3 c3 e3 pushv [int] Push n nil values into the stack (used to init local vars)
|
||||||
@@ -88,6 +89,8 @@ Control flow (the destination is always a 16-bit field):
|
|||||||
ca jmp [pc] Unconditional jump
|
ca jmp [pc] Unconditional jump
|
||||||
* Jumps can only happen within the same function.
|
* Jumps can only happen within the same function.
|
||||||
|
|
||||||
|
Memory management:
|
||||||
|
4b gc Call garbage collector
|
||||||
|
|
||||||
Error handling: (0xa0~0xaf)
|
Error handling: (0xa0~0xaf)
|
||||||
???
|
???
|
||||||
|
|||||||
@@ -298,10 +298,47 @@ end
|
|||||||
|
|
||||||
do TEST "VM: managed strings"
|
do TEST "VM: managed strings"
|
||||||
local vm = VM.new():push_string("Hello")
|
local vm = VM.new():push_string("Hello")
|
||||||
|
-- print(vm:debug_heap())
|
||||||
assert_eq(vm:to_string(-1), "Hello")
|
assert_eq(vm:to_string(-1), "Hello")
|
||||||
end
|
end
|
||||||
|
|
||||||
-- TODO - concatenate strings
|
do TEST "VM: concatenate strings"
|
||||||
|
local vm = VM.new():load(assemble [[
|
||||||
|
.const
|
||||||
|
0: "Hello "
|
||||||
|
1: "world"
|
||||||
|
.func 0
|
||||||
|
pushc 0
|
||||||
|
pushc 1
|
||||||
|
sum
|
||||||
|
ret
|
||||||
|
]]):call(0)
|
||||||
|
|
||||||
|
-- print(vm:debug_heap())
|
||||||
|
assert_eq(vm:to_string(-1), "Hello world")
|
||||||
|
assert_eq(vm.heap:size(), 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
do TEST "VM: collect strings"
|
||||||
|
local vm = VM.new():load(assemble [[
|
||||||
|
.const
|
||||||
|
0: "Hello "
|
||||||
|
1: "world"
|
||||||
|
.func 0
|
||||||
|
pushn
|
||||||
|
pushc 0
|
||||||
|
pushc 1
|
||||||
|
sum
|
||||||
|
pop
|
||||||
|
gc
|
||||||
|
ret
|
||||||
|
]]):call(0)
|
||||||
|
|
||||||
|
print(vm:debug_heap())
|
||||||
|
assert_eq(vm:is(-1, 'nil'), true)
|
||||||
|
assert_eq(vm.heap:size(), 0)
|
||||||
|
end
|
||||||
|
|
||||||
-- TODO - collect string (GC)
|
-- TODO - collect string (GC)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -185,24 +185,25 @@ for op,_ in pairs(ARITH_LOGIC_OPS) do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
EXPR.sum.integer.integer = function(vm, b, a) vm:push_integer(a + b) end
|
EXPR.sum.integer.integer = function(vm, b, a) vm:push_integer(a.value + b.value) end
|
||||||
EXPR.sub.integer.integer = function(vm, b, a) vm:push_integer(a - b) end
|
EXPR.sum.string.string = function(vm, b, a) vm:push_string(vm:_extract_string(a) ..vm:_extract_string(b)) end
|
||||||
EXPR.mul.integer.integer = function(vm, b, a) vm:push_integer(a * b) end
|
EXPR.sub.integer.integer = function(vm, b, a) vm:push_integer(a.value - b.value) end
|
||||||
|
EXPR.mul.integer.integer = function(vm, b, a) vm:push_integer(a.value * b.value) end
|
||||||
-- TODO - div
|
-- TODO - div
|
||||||
EXPR.idiv.integer.integer = function(vm, b, a) vm:push_integer(math.floor(a / b)) end
|
EXPR.idiv.integer.integer = function(vm, b, a) vm:push_integer(math.floor(a.value / b.value)) end
|
||||||
EXPR.mod.integer.integer = function(vm, b, a) vm:push_integer(a % b) end
|
EXPR.mod.integer.integer = function(vm, b, a) vm:push_integer(a.value % b.value) end
|
||||||
EXPR.eq.integer.integer = function(vm, b, a) vm:push_integer((a == b) and 1 or 0) end
|
EXPR.eq.integer.integer = function(vm, b, a) vm:push_integer((a.value == b.value) and 1 or 0) end
|
||||||
EXPR.neq.integer.integer = function(vm, b, a) vm:push_integer((a ~= b) and 1 or 0) end
|
EXPR.neq.integer.integer = function(vm, b, a) vm:push_integer((a.value ~= b.value) and 1 or 0) end
|
||||||
EXPR.lt.integer.integer = function(vm, b, a) vm:push_integer((a < b) and 1 or 0) end
|
EXPR.lt.integer.integer = function(vm, b, a) vm:push_integer((a.value < b.value) and 1 or 0) end
|
||||||
EXPR.lte.integer.integer = function(vm, b, a) vm:push_integer((a <= b) and 1 or 0) end
|
EXPR.lte.integer.integer = function(vm, b, a) vm:push_integer((a.value <= b.value) and 1 or 0) end
|
||||||
EXPR.gt.integer.integer = function(vm, b, a) vm:push_integer((a > b) and 1 or 0) end
|
EXPR.gt.integer.integer = function(vm, b, a) vm:push_integer((a.value > b.value) and 1 or 0) end
|
||||||
EXPR.gte.integer.integer = function(vm, b, a) vm:push_integer((a >= b) and 1 or 0) end
|
EXPR.gte.integer.integer = function(vm, b, a) vm:push_integer((a.value >= b.value) and 1 or 0) end
|
||||||
EXPR['and'].integer.integer = function(vm, b, a) vm:push_integer(a & b) end
|
EXPR['and'].integer.integer = function(vm, b, a) vm:push_integer(a.value & b.value) end
|
||||||
EXPR['or'].integer.integer = function(vm, b, a) vm:push_integer(a | b) end
|
EXPR['or'].integer.integer = function(vm, b, a) vm:push_integer(a.value | b.value) end
|
||||||
EXPR.xor.integer.integer = function(vm, b, a) vm:push_integer(a ~ b) end
|
EXPR.xor.integer.integer = function(vm, b, a) vm:push_integer(a.value ~ b.value) end
|
||||||
EXPR.pow.integer.integer = function(vm, b, a) vm:push_integer(a ^ b) end
|
EXPR.pow.integer.integer = function(vm, b, a) vm:push_integer(a.value ^ b.value) end
|
||||||
EXPR.shl.integer.integer = function(vm, b, a) vm:push_integer(a << b) end
|
EXPR.shl.integer.integer = function(vm, b, a) vm:push_integer(a.value << b.value) end
|
||||||
EXPR.shr.integer.integer = function(vm, b, a) vm:push_integer(a >> b) end
|
EXPR.shr.integer.integer = function(vm, b, a) vm:push_integer(a.value >> b.value) end
|
||||||
|
|
||||||
----------------------
|
----------------------
|
||||||
-- --
|
-- --
|
||||||
@@ -230,6 +231,16 @@ function Heap:get_value(key)
|
|||||||
return self.items[key]
|
return self.items[key]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function Heap:size()
|
||||||
|
local n = 0
|
||||||
|
for _ in pairs(self.items) do n = n + 1 end
|
||||||
|
return n
|
||||||
|
end
|
||||||
|
|
||||||
|
function Heap:call_gc()
|
||||||
|
-- TODO
|
||||||
|
end
|
||||||
|
|
||||||
----------------------
|
----------------------
|
||||||
-- --
|
-- --
|
||||||
-- VM --
|
-- VM --
|
||||||
@@ -301,23 +312,29 @@ function VM:to_integer(idx)
|
|||||||
return value.value
|
return value.value
|
||||||
end
|
end
|
||||||
|
|
||||||
function VM:to_string(idx)
|
function VM:_extract_string(value)
|
||||||
local value = self.stack[idx]
|
assert(value)
|
||||||
if value.type ~= 'string' then error("Type error: not a string") end
|
assert(value.type == 'string')
|
||||||
if value.const_ref then
|
if value.const_ref then
|
||||||
return self.code.bytecode.constants[value.const_ref]
|
return self.code.bytecode.constants[value.const_ref]
|
||||||
elseif value.ref then
|
elseif value.ref then
|
||||||
return self.heap:get_value(value.ref)
|
return self.heap:get_value(value.ref)
|
||||||
else
|
else
|
||||||
error()
|
error("Incorrect string value (nor 'const_ref' or 'ref')")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function VM:to_string(idx)
|
||||||
|
local value = self.stack[idx]
|
||||||
|
if value.type ~= 'string' then error("Type error: not a string") end
|
||||||
|
return self:_extract_string(value)
|
||||||
|
end
|
||||||
|
|
||||||
function VM:format_value(v)
|
function VM:format_value(v)
|
||||||
if v.type == 'integer' or v.type == 'real' then
|
if v.type == 'integer' or v.type == 'real' then
|
||||||
return tostring(v.value)
|
return tostring(v.value)
|
||||||
elseif v.type == 'string' then
|
elseif v.type == 'string' then
|
||||||
return '"' .. v.value .. '"'
|
return self_:extract_string(v)
|
||||||
elseif v.type == 'function' then
|
elseif v.type == 'function' then
|
||||||
return '@' .. tostring(v.value)
|
return '@' .. tostring(v.value)
|
||||||
elseif v.type == 'nil' then
|
elseif v.type == 'nil' then
|
||||||
@@ -340,6 +357,19 @@ function VM:debug_stack()
|
|||||||
return table.concat(ss)
|
return table.concat(ss)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function VM:debug_heap()
|
||||||
|
local ss = { "Heap:\n" }
|
||||||
|
for k,v in pairs(self.heap.items) do
|
||||||
|
table.insert(ss, string.format(" [%X] = ", k))
|
||||||
|
if type(v) == 'string' then
|
||||||
|
table.insert(ss, '"' .. v .. '"')
|
||||||
|
else
|
||||||
|
error('Unsupported value in heap')
|
||||||
|
end
|
||||||
|
table.insert(ss, "\n")
|
||||||
|
end
|
||||||
|
return table.concat(ss)
|
||||||
|
end
|
||||||
|
|
||||||
--
|
--
|
||||||
-- code execution
|
-- code execution
|
||||||
@@ -397,8 +427,11 @@ function VM:_step()
|
|||||||
--
|
--
|
||||||
-- stack operations
|
-- stack operations
|
||||||
--
|
--
|
||||||
|
|
||||||
|
if op.operator == 'pushn' then
|
||||||
|
self:push_nil()
|
||||||
|
|
||||||
if op.operator == 'pushi' then
|
elseif op.operator == 'pushi' then
|
||||||
self:push_integer(op.operand)
|
self:push_integer(op.operand)
|
||||||
|
|
||||||
elseif op.operator == 'pushf' then
|
elseif op.operator == 'pushf' then
|
||||||
@@ -413,6 +446,9 @@ function VM:_step()
|
|||||||
error('REAL consts not supported for now.')
|
error('REAL consts not supported for now.')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
elseif op.operator == 'pop' then
|
||||||
|
self.stack:pop()
|
||||||
|
|
||||||
elseif op.operator == 'dup' then
|
elseif op.operator == 'dup' then
|
||||||
self.stack:push(self.stack:peek())
|
self.stack:push(self.stack:peek())
|
||||||
|
|
||||||
@@ -443,7 +479,7 @@ function VM:_step()
|
|||||||
elseif ARITH_LOGIC_OPS[op.operator] then
|
elseif ARITH_LOGIC_OPS[op.operator] then
|
||||||
local a = self.stack:pop()
|
local a = self.stack:pop()
|
||||||
local b = self.stack:pop()
|
local b = self.stack:pop()
|
||||||
EXPR[op.operator][a.type][b.type](self, a.value, b.value)
|
EXPR[op.operator][a.type][b.type](self, a, b)
|
||||||
|
|
||||||
--
|
--
|
||||||
-- function management
|
-- function management
|
||||||
@@ -486,6 +522,13 @@ function VM:_step()
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- memory management
|
||||||
|
--
|
||||||
|
|
||||||
|
elseif op.operator == 'gc' then
|
||||||
|
self.heap:call_gc()
|
||||||
|
|
||||||
--
|
--
|
||||||
-- instruction not found
|
-- instruction not found
|
||||||
--
|
--
|
||||||
|
|||||||
Reference in New Issue
Block a user