.
This commit is contained in:
@@ -242,8 +242,7 @@ do TEST "VM: functions"
|
|||||||
assert_eq(vm:to_integer(-1), -1)
|
assert_eq(vm:to_integer(-1), -1)
|
||||||
end
|
end
|
||||||
|
|
||||||
do
|
do TEST "VM: jumps (jmp + bnz)"
|
||||||
TEST "VM: jumps (jmp + bnz)"
|
|
||||||
local vm = VM.new():load(assemble [[
|
local vm = VM.new():load(assemble [[
|
||||||
.func 0
|
.func 0
|
||||||
jmp @x1
|
jmp @x1
|
||||||
@@ -264,9 +263,8 @@ do
|
|||||||
assert_eq(vm:to_integer(-1), 6)
|
assert_eq(vm:to_integer(-1), 6)
|
||||||
end
|
end
|
||||||
|
|
||||||
do
|
do TEST "VM: jumps (bz)"
|
||||||
TEST "VM: jumps (bz)"
|
local vm = VM.new():load(assemble [[
|
||||||
local vm = VM.new():set_debug(true):load(assemble [[
|
|
||||||
.func 0
|
.func 0
|
||||||
jmp @x1
|
jmp @x1
|
||||||
pushi 5
|
pushi 5
|
||||||
@@ -286,5 +284,25 @@ do
|
|||||||
assert_eq(vm:to_integer(-1), 7)
|
assert_eq(vm:to_integer(-1), 7)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
do TEST "VM: string from const"
|
||||||
|
local vm = VM.new():load(assemble [[
|
||||||
|
.const
|
||||||
|
0: "Hello"
|
||||||
|
.func 0
|
||||||
|
pushc 0
|
||||||
|
ret
|
||||||
|
]]):call(0)
|
||||||
|
|
||||||
|
assert_eq(vm:to_string(-1), "Hello")
|
||||||
|
end
|
||||||
|
|
||||||
|
do TEST "VM: managed strings"
|
||||||
|
local vm = VM.new():push_string("Hello")
|
||||||
|
assert_eq(vm:to_string(-1), "Hello")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- TODO - concatenate strings
|
||||||
|
-- TODO - collect string (GC)
|
||||||
|
|
||||||
|
|
||||||
print('End.')
|
print('End.')
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ local ARITH_LOGIC_OPS = {
|
|||||||
['and']=true, ['or']=true, xor=true, pow=true, shl=true, shr=true, mod=true
|
['and']=true, ['or']=true, xor=true, pow=true, shl=true, shr=true, mod=true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
math.randomseed(os.time())
|
||||||
|
|
||||||
----------------------
|
----------------------
|
||||||
-- --
|
-- --
|
||||||
-- UTIL --
|
-- UTIL --
|
||||||
@@ -25,6 +27,8 @@ local function validate_value(v)
|
|||||||
assert(type(v.value) == 'number')
|
assert(type(v.value) == 'number')
|
||||||
elseif v.type == 'function' then
|
elseif v.type == 'function' then
|
||||||
assert(type(v.value) == 'number' and v.value >= 0, "function must be a positive number")
|
assert(type(v.value) == 'number' and v.value >= 0, "function must be a positive number")
|
||||||
|
elseif v.type == 'string' then
|
||||||
|
assert(type(v.ref) == 'number' or type(v.const_ref) == 'number')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -200,6 +204,32 @@ EXPR.pow.integer.integer = function(vm, b, a) vm:push_integer(a ^ b) 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 << b) 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 >> b) end
|
||||||
|
|
||||||
|
----------------------
|
||||||
|
-- --
|
||||||
|
-- HEAP --
|
||||||
|
-- --
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
local Heap = {}
|
||||||
|
Heap.__index = Heap
|
||||||
|
|
||||||
|
function Heap.new()
|
||||||
|
return setmetatable({
|
||||||
|
items = {}
|
||||||
|
}, Heap)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Heap:add_value(value)
|
||||||
|
local key = math.random(math.mininteger, math.maxinteger)
|
||||||
|
while self.items[key] do key = math.random(math.mininteger, math.maxinteger) end
|
||||||
|
self.items[key] = value
|
||||||
|
return key
|
||||||
|
end
|
||||||
|
|
||||||
|
function Heap:get_value(key)
|
||||||
|
return self.items[key]
|
||||||
|
end
|
||||||
|
|
||||||
----------------------
|
----------------------
|
||||||
-- --
|
-- --
|
||||||
-- VM --
|
-- VM --
|
||||||
@@ -212,6 +242,7 @@ VM.__index = VM
|
|||||||
function VM.new()
|
function VM.new()
|
||||||
return setmetatable({
|
return setmetatable({
|
||||||
stack = Stack.new(),
|
stack = Stack.new(),
|
||||||
|
heap = Heap.new(),
|
||||||
code = Code.new(),
|
code = Code.new(),
|
||||||
loc = {},
|
loc = {},
|
||||||
debug = false,
|
debug = false,
|
||||||
@@ -239,10 +270,17 @@ end
|
|||||||
|
|
||||||
function VM:push_integer(n)
|
function VM:push_integer(n)
|
||||||
self.stack:push({ type = 'integer', value = n })
|
self.stack:push({ type = 'integer', value = n })
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
function VM:push_string(str)
|
||||||
|
self.stack:push({ type = 'string', ref = self.heap:add_value(str) })
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
function VM:push_nil()
|
function VM:push_nil()
|
||||||
self.stack:push({ type = 'nil' })
|
self.stack:push({ type = 'nil' })
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--
|
--
|
||||||
@@ -263,6 +301,18 @@ function VM:to_integer(idx)
|
|||||||
return value.value
|
return value.value
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function VM:to_string(idx)
|
||||||
|
local value = self.stack[idx]
|
||||||
|
if value.type ~= 'string' then error("Type error: not a string") end
|
||||||
|
if value.const_ref then
|
||||||
|
return self.code.bytecode.constants[value.const_ref]
|
||||||
|
elseif value.ref then
|
||||||
|
return self.heap:get_value(value.ref)
|
||||||
|
else
|
||||||
|
error()
|
||||||
|
end
|
||||||
|
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)
|
||||||
@@ -273,6 +323,7 @@ function VM:format_value(v)
|
|||||||
elseif v.type == 'nil' then
|
elseif v.type == 'nil' then
|
||||||
return 'nil'
|
return 'nil'
|
||||||
else
|
else
|
||||||
|
print('warning: cannot convert from type ' .. v.type)
|
||||||
return pprint.pformat(v)
|
return pprint.pformat(v)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -354,6 +405,14 @@ function VM:_step()
|
|||||||
assert(op.operand >= 0)
|
assert(op.operand >= 0)
|
||||||
self.stack:push({ type = 'function', value = op.operand })
|
self.stack:push({ type = 'function', value = op.operand })
|
||||||
|
|
||||||
|
elseif op.operator == 'pushc' then
|
||||||
|
local c = self.code.bytecode.constants[op.operand]
|
||||||
|
if type(c) == 'string' then
|
||||||
|
self.stack:push({ type = 'string', const_ref = op.operand })
|
||||||
|
elseif type(c) == 'number' then
|
||||||
|
error('REAL consts not supported for now.')
|
||||||
|
end
|
||||||
|
|
||||||
elseif op.operator == 'dup' then
|
elseif op.operator == 'dup' then
|
||||||
self.stack:push(self.stack:peek())
|
self.stack:push(self.stack:peek())
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user