Compare commits

..

2 Commits

Author SHA1 Message Date
04b9821662 Merge remote-tracking branch 'origin/lua-temp' into lua-temp 2026-05-08 16:32:10 -05:00
b2a829d6e5 . 2026-05-08 16:32:06 -05:00
5 changed files with 135 additions and 19 deletions

4
.idea/misc.xml generated
View File

@@ -3,5 +3,7 @@
<component name="CMakePythonSetting">
<option name="pythonIntegrationState" value="YES" />
</component>
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
<component name="CMakeWorkspace">
<contentRoot DIR="$PROJECT_DIR$" />
</component>
</project>

2
.idea/tyche.iml generated
View File

@@ -1,2 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module classpath="CIDR" type="CPP_MODULE" version="4" />

View File

@@ -151,7 +151,7 @@ end
----------------------
local function arith(a, b, op)
return VM:new():load(assemble(string.format([[
return VM.new():load(assemble(string.format([[
.func 0
pushi %d
pushi %d
@@ -162,7 +162,7 @@ end
do TEST "VM: basic"
local vm = VM:new()
local vm = VM.new()
-- vm.debug = true
local bytecode = assemble [[
.func 0
@@ -206,7 +206,7 @@ do TEST "VM: logic/arithmetic"
end
do TEST "VM: local variables"
local vm = VM:new():load(assemble([[
local vm = VM.new():load(assemble([[
.func 0
pushv 2 ; local a, b
pushi 3 ; a = 3
@@ -222,7 +222,7 @@ do TEST "VM: local variables"
end
do TEST "VM: functions"
local vm = VM:new():load(assemble([[
local vm = VM.new():load(assemble([[
.func 0
pushf 1
pushi 2
@@ -240,4 +240,63 @@ do TEST "VM: functions"
assert_eq(vm:to_integer(-1), -1)
end
do
TEST "VM: jumps (jmp + bnz)"
local vm = VM.new():load(assemble [[
.func 0
jmp @x1
pushi 5
@x1:
pushi 1
bnz @x2
bz @x3
@x2:
pushi 6
ret
@x3:
pushi 7
ret
]]):call(0)
assert_eq(vm:to_integer(-1), 6)
end
do
TEST "VM: jumps (bz)"
pprint(assemble [[
.func 0
jmp @x1
pushi 5
@x1:
pushi 0
bnz @x2
pushi 0
bz @x3
@x2:
pushi 6
ret
@x3:
pushi 7
ret
]])
local vm = VM.new():set_debug(true):load(assemble [[
.func 0
jmp @x1
pushi 5
@x1:
pushi 0
bnz @x2
bz @x3
@x2:
pushi 6
ret
@x3:
pushi 7
ret
]]):call(0)
assert_eq(vm:to_integer(-1), 7)
end
print('End.')

View File

@@ -37,10 +37,10 @@ local function assemble(source)
end
elseif section == 'function' then
local regexes = {
"^%s*(%a+)%s+(%d+)%s*$", -- instruction + parameter
"^%s*(%a+)%s+(@[%a_]+)%s*$", -- instruction + label
"^%s*(%a+)%s*$", -- instruction only
"^(@[%a_]+):%s*$", -- label
"^%s*(%a+)%s+(%d+)%s*$", -- instruction + parameter
"^%s*(%a+)%s+(@[%a_][%a%d_]*)%s*$", -- instruction + label
"^%s*(%a+)%s*$", -- instruction only
"^(@[%a_][%a%d_]*):%s*$", -- label
}
local match = false
for i,regex in ipairs(regexes) do

View File

@@ -14,7 +14,7 @@ local ARITH_LOGIC_OPS = {
-- --
----------------------
function format_value(v)
local function format_value(v)
if v.type == 'integer' or v.type == 'real' then
return tostring(v.value)
elseif v.type == 'string' then
@@ -28,9 +28,10 @@ function format_value(v)
end
end
function validate_value(v)
local 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(v) == 'table',
"invalid value format (expected { type='...', value=... }), received: " .. pprint.pformat(v))
assert(TYPE_MAP[v.type], "missing field 'type' in value")
if v.type == 'nil' then
assert(v.value == nil)
@@ -41,6 +42,12 @@ function validate_value(v)
end
end
function is_zero(v)
if v.type == 'nil' then return true end
if v.type == 'integer' and v.value == 0 then return true end
return false
end
----------------------
-- --
-- STACK --
@@ -168,6 +175,18 @@ function Code:next_instruction(function_id, pc)
}
end
function Code:find_label(function_id, label)
for pc, op in ipairs(self.bytecode.functions[function_id]) do
if op.labels then
for _,lbl in ipairs(op.labels) do
if lbl == label then
return pc
end
end
end
end
end
----------------------
-- --
-- EXPR --
@@ -182,7 +201,7 @@ for op,_ in pairs(ARITH_LOGIC_OPS) do
for _,type1 in ipairs(TYPES) do
EXPR[op][type1] = {}
for _,type2 in ipairs(TYPES) do
EXPR[op][type1][type2] = function(vm, a, b) error(string.format("Type mismatch for operation '%s': types '%s' and '%s'", op, type1, type2)) end
EXPR[op][type1][type2] = function(_, _, _) error(string.format("Type mismatch for operation '%s': types '%s' and '%s'", op, type1, type2)) end
end
end
end
@@ -310,6 +329,12 @@ function VM:_run_until_return()
end
end
function VM:_debug_stack()
if self.debug then
print(self.stack:debug())
end
end
function VM:_step()
local loc = self.loc[#self.loc]
local op = self.code:next_instruction(loc.f_id, loc.pc)
@@ -327,13 +352,16 @@ function VM:_step()
assert(op.operand >= 0)
self.stack:push({ type = 'function', value = op.operand })
elseif op.operator == 'dup' then
self.stack:push(self.stack:peek())
--
-- local variables
--
elseif op.operator == 'pushv' then
assert(op.operand >= 0)
for i=1,op.operand do
for _=1,op.operand do
self:push_nil()
end
@@ -369,14 +397,43 @@ function VM:_step()
self.stack:pop_fp()
self.stack:push(v)
table.remove(self.loc)
if self.debug then print(self.stack:debug()) end
self:_debug_stack()
return
else
--
-- jumps/branching
--
elseif op.operator == 'jmp' then
loc.pc = self.code:find_label(loc.f_id, op.operand)
self:_debug_stack()
return
elseif op.operator == 'bz' then
local v = self.stack:pop()
if is_zero(v) then
loc.pc = self.code:find_label(loc.f_id, op.operand)
self:_debug_stack()
return
end
elseif op.operator == 'bnz' then
local v = self.stack:pop()
if not is_zero(v) then
loc.pc = self.code:find_label(loc.f_id, op.operand)
self:_debug_stack()
return
end
--
-- instruction not found
--
else
error("Unknown operator '" .. tostring(op.operator) .. "'")
end
if self.debug then print(self.stack:debug()) end
self:_debug_stack()
loc.pc = loc.pc + op.instruction_size
end