This commit is contained in:
2026-05-09 10:24:09 -05:00
parent a6adb9b723
commit 83b80f6e7d
3 changed files with 114 additions and 31 deletions

View File

@@ -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)
??? ???

View File

@@ -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)

View File

@@ -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
@@ -398,7 +428,10 @@ function VM:_step()
-- stack operations -- stack operations
-- --
if op.operator == 'pushi' then if op.operator == 'pushn' then
self:push_nil()
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
-- --