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"> <component name="CMakePythonSetting">
<option name="pythonIntegrationState" value="YES" /> <option name="pythonIntegrationState" value="YES" />
</component> </component>
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" /> <component name="CMakeWorkspace">
<contentRoot DIR="$PROJECT_DIR$" />
</component>
</project> </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) local function arith(a, b, op)
return VM:new():load(assemble(string.format([[ return VM.new():load(assemble(string.format([[
.func 0 .func 0
pushi %d pushi %d
pushi %d pushi %d
@@ -162,7 +162,7 @@ end
do TEST "VM: basic" do TEST "VM: basic"
local vm = VM:new() local vm = VM.new()
-- vm.debug = true -- vm.debug = true
local bytecode = assemble [[ local bytecode = assemble [[
.func 0 .func 0
@@ -206,7 +206,7 @@ do TEST "VM: logic/arithmetic"
end end
do TEST "VM: local variables" do TEST "VM: local variables"
local vm = VM:new():load(assemble([[ local vm = VM.new():load(assemble([[
.func 0 .func 0
pushv 2 ; local a, b pushv 2 ; local a, b
pushi 3 ; a = 3 pushi 3 ; a = 3
@@ -222,7 +222,7 @@ do TEST "VM: local variables"
end end
do TEST "VM: functions" do TEST "VM: functions"
local vm = VM:new():load(assemble([[ local vm = VM.new():load(assemble([[
.func 0 .func 0
pushf 1 pushf 1
pushi 2 pushi 2
@@ -240,4 +240,63 @@ do TEST "VM: functions"
assert_eq(vm:to_integer(-1), -1) assert_eq(vm:to_integer(-1), -1)
end 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.') print('End.')

View File

@@ -37,10 +37,10 @@ local function assemble(source)
end end
elseif section == 'function' then elseif section == 'function' then
local regexes = { local regexes = {
"^%s*(%a+)%s+(%d+)%s*$", -- instruction + parameter "^%s*(%a+)%s+(%d+)%s*$", -- instruction + parameter
"^%s*(%a+)%s+(@[%a_]+)%s*$", -- instruction + label "^%s*(%a+)%s+(@[%a_][%a%d_]*)%s*$", -- instruction + label
"^%s*(%a+)%s*$", -- instruction only "^%s*(%a+)%s*$", -- instruction only
"^(@[%a_]+):%s*$", -- label "^(@[%a_][%a%d_]*):%s*$", -- label
} }
local match = false local match = false
for i,regex in ipairs(regexes) do 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 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
@@ -28,9 +28,10 @@ function format_value(v)
end end
end end
function validate_value(v) local function validate_value(v)
assert(v, "value cannot be nil") 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") assert(TYPE_MAP[v.type], "missing field 'type' in value")
if v.type == 'nil' then if v.type == 'nil' then
assert(v.value == nil) assert(v.value == nil)
@@ -41,6 +42,12 @@ function validate_value(v)
end end
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 -- -- STACK --
@@ -168,6 +175,18 @@ function Code:next_instruction(function_id, pc)
} }
end 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 -- -- EXPR --
@@ -182,7 +201,7 @@ for op,_ in pairs(ARITH_LOGIC_OPS) do
for _,type1 in ipairs(TYPES) do for _,type1 in ipairs(TYPES) do
EXPR[op][type1] = {} EXPR[op][type1] = {}
for _,type2 in ipairs(TYPES) do 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 end
end end
@@ -310,6 +329,12 @@ function VM:_run_until_return()
end end
end end
function VM:_debug_stack()
if self.debug then
print(self.stack:debug())
end
end
function VM:_step() function VM:_step()
local loc = self.loc[#self.loc] local loc = self.loc[#self.loc]
local op = self.code:next_instruction(loc.f_id, loc.pc) local op = self.code:next_instruction(loc.f_id, loc.pc)
@@ -327,13 +352,16 @@ 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 == 'dup' then
self.stack:push(self.stack:peek())
-- --
-- local variables -- local variables
-- --
elseif op.operator == 'pushv' then elseif op.operator == 'pushv' then
assert(op.operand >= 0) assert(op.operand >= 0)
for i=1,op.operand do for _=1,op.operand do
self:push_nil() self:push_nil()
end end
@@ -369,14 +397,43 @@ function VM:_step()
self.stack:pop_fp() self.stack:pop_fp()
self.stack:push(v) self.stack:push(v)
table.remove(self.loc) table.remove(self.loc)
if self.debug then print(self.stack:debug()) end self:_debug_stack()
return 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) .. "'") error("Unknown operator '" .. tostring(op.operator) .. "'")
end end
if self.debug then print(self.stack:debug()) end self:_debug_stack()
loc.pc = loc.pc + op.instruction_size loc.pc = loc.pc + op.instruction_size
end end