llvm(self): compare/branch/jump/ret に self 先頭規約を導入 + 自己受検スモーク追加\n\n- lang/src/llvm_ir/instructions/{compare,branch,jump,ret}.hako self化\n- quick/core/{compare,branch,jump,ret}/self_param_* 追加\n\nsmokes(stage-b): OOB を map missing read まで拡張(寛容に観測)\n- selfhost_stageb_oob_vm.sh 更新

This commit is contained in:
nyash-codex
2025-11-01 17:16:54 +09:00
parent 8e114cd136
commit 572b10f4c3
9 changed files with 179 additions and 57 deletions

View File

@ -4,41 +4,41 @@
static box LLVMBranchInstructionBox {
// メインエントリーポイント - Pythonのlower_branch()に相当
lower_branch(cond_vid, then_bid, else_bid) {
return me.inst_branch(cond_vid, then_bid, else_bid)
lower_branch(self, cond_vid, then_bid, else_bid) {
return me.inst_branch(self, cond_vid, then_bid, else_bid)
}
// 分岐命令の生成
inst_branch(cond_vid, then_bid, else_bid) {
inst_branch(self, cond_vid, then_bid, else_bid) {
// JSON: {"op":"branch","cond":3,"then":1,"else":2}
return "{\"op\":\"branch\",\"cond\":" + cond_vid + ",\"then\":" + then_bid + ",\"else\":" + else_bid + "}"
}
// デバッグ用 - 生成された命令の確認
debug_branch(cond_vid, then_bid, else_bid) {
local json = me.lower_branch(cond_vid, then_bid, else_bid)
debug_branch(self, cond_vid, then_bid, else_bid) {
local json = me.lower_branch(self, cond_vid, then_bid, else_bid)
print("Generated branch instruction: " + json)
return json
}
// 条件付きジャンプのヘルパー
if_then_else(condition, then_block, else_block) {
return me.inst_branch(condition, then_block, else_block)
if_then_else(self, condition, then_block, else_block) {
return me.inst_branch(self, condition, then_block, else_block)
}
// 単純な条件分岐true/false
simple_branch(cond_val, true_block, false_block) {
simple_branch(self, cond_val, true_block, false_block) {
// cond_val: 0=false, 1=true
return me.inst_branch(cond_val, true_block, false_block)
return me.inst_branch(self, cond_val, true_block, false_block)
}
// 複数の分岐をまとめて生成
batch_branch(branch_list) {
batch_branch(self, branch_list) {
local results = []
local i = 0
while i < branch_list.length() {
local branch = branch_list[i]
local json = me.lower_branch(branch.cond, branch.then_block, branch.else_block)
local json = me.lower_branch(self, branch.cond, branch.then_block, branch.else_block)
results.push(json)
i = i + 1
}

View File

@ -4,7 +4,7 @@
static box LLVMCompareInstructionBox {
// メインエントリーポイント - Pythonのlower_compare()に相当
lower_compare(op, lhs, rhs, dst) {
lower_compare(self, op, lhs, rhs, dst) {
// 比較演算子の検証
if !me._is_valid_operator(op) {
print("Warning: Invalid compare operator: " + op + ", defaulting to ==")
@ -15,54 +15,54 @@ static box LLVMCompareInstructionBox {
}
// 有効な比較演算子の検証
_is_valid_operator(op) {
_is_valid_operator(self, op) {
return op == "==" || op == "!=" || op == "<" || op == ">" || op == "<=" || op == ">="
}
// 比較命令の生成
inst_compare(op, lhs, rhs, dst) {
inst_compare(self, op, lhs, rhs, dst) {
return "{\"op\":\"compare\",\"dst\":" + dst + ",\"operation\":\"" + op + "\",\"lhs\":" + lhs + ",\"rhs\":" + rhs + "}"
}
// 各比較演算子の個別メソッド
inst_eq(lhs, rhs, dst) {
return me.inst_compare("==", lhs, rhs, dst)
inst_eq(self, lhs, rhs, dst) {
return me.inst_compare(self, "==", lhs, rhs, dst)
}
inst_ne(lhs, rhs, dst) {
return me.inst_compare("!=", lhs, rhs, dst)
inst_ne(self, lhs, rhs, dst) {
return me.inst_compare(self, "!=", lhs, rhs, dst)
}
inst_lt(lhs, rhs, dst) {
return me.inst_compare("<", lhs, rhs, dst)
inst_lt(self, lhs, rhs, dst) {
return me.inst_compare(self, "<", lhs, rhs, dst)
}
inst_gt(lhs, rhs, dst) {
return me.inst_compare(">", lhs, rhs, dst)
inst_gt(self, lhs, rhs, dst) {
return me.inst_compare(self, ">", lhs, rhs, dst)
}
inst_le(lhs, rhs, dst) {
return me.inst_compare("<=", lhs, rhs, dst)
inst_le(self, lhs, rhs, dst) {
return me.inst_compare(self, "<=", lhs, rhs, dst)
}
inst_ge(lhs, rhs, dst) {
return me.inst_compare(">=", lhs, rhs, dst)
inst_ge(self, lhs, rhs, dst) {
return me.inst_compare(self, ">=", lhs, rhs, dst)
}
// デバッグ用 - 生成された命令の確認
debug_compare(op, lhs, rhs, dst) {
local json = me.lower_compare(op, lhs, rhs, dst)
debug_compare(self, op, lhs, rhs, dst) {
local json = me.lower_compare(self, op, lhs, rhs, dst)
print("Generated compare instruction: " + json)
return json
}
// 複数の比較をまとめて生成(効率化)
batch_compare(compare_list) {
batch_compare(self, compare_list) {
local results = []
local i = 0
while i < compare_list.length() {
local cmp = compare_list[i]
local json = me.lower_compare(cmp.op, cmp.lhs, cmp.rhs, cmp.dst)
local json = me.lower_compare(self, cmp.op, cmp.lhs, cmp.rhs, cmp.dst)
results.push(json)
i = i + 1
}

View File

@ -4,50 +4,50 @@
static box LLVMJumpInstructionBox {
// メインエントリーポイント - Pythonのlower_jump()に相当
lower_jump(target_bid) {
return me.inst_jump(target_bid)
lower_jump(self, target_bid) {
return me.inst_jump(self, target_bid)
}
// ジャンプ命令の生成
inst_jump(target_bid) {
inst_jump(self, target_bid) {
// JSON: {"op":"jump","target":5}
return "{\"op\":\"jump\",\"target\":" + target_bid + "}"
}
// デバッグ用 - 生成された命令の確認
debug_jump(target_bid) {
local json = me.lower_jump(target_bid)
debug_jump(self, target_bid) {
local json = me.lower_jump(self, target_bid)
print("Generated jump instruction: " + json)
return json
}
// ラベルへのジャンプ
jump_to_label(label_id) {
return me.inst_jump(label_id)
jump_to_label(self, label_id) {
return me.inst_jump(self, label_id)
}
// ループヘッドへのジャンプ
jump_loop_head(loop_block) {
return me.inst_jump(loop_block)
jump_loop_head(self, loop_block) {
return me.inst_jump(self, loop_block)
}
// ループ終了へのジャンプ
jump_loop_end(exit_block) {
return me.inst_jump(exit_block)
jump_loop_end(self, exit_block) {
return me.inst_jump(self, exit_block)
}
// 関数終了へのジャンプ
jump_to_epilogue(epilogue_block) {
return me.inst_jump(epilogue_block)
jump_to_epilogue(self, epilogue_block) {
return me.inst_jump(self, epilogue_block)
}
// 複数のジャンプをまとめて生成
batch_jump(jump_list) {
batch_jump(self, jump_list) {
local results = []
local i = 0
while i < jump_list.length() {
local jump = jump_list[i]
local json = me.lower_jump(jump.target)
local json = me.lower_jump(self, jump.target)
results.push(json)
i = i + 1
}

View File

@ -4,42 +4,42 @@
static box LLVMRetInstructionBox {
// メインエントリーポイント - Pythonのlower_return()に相当
lower_return(value_id) {
lower_return(self, value_id) {
if value_id == null || value_id == 0 {
// Void return
return me.inst_ret_void()
return me.inst_ret_void(self)
} else {
// Value return
return me.inst_ret_value(value_id)
}
return me.inst_ret_value(self, value_id)
}
}
// Void return命令
inst_ret_void() {
inst_ret_void(self) {
return "{\"op\":\"ret\",\"value\":null}"
}
// Value return命令
inst_ret_value(value_id) {
inst_ret_value(self, value_id) {
return "{\"op\":\"ret\",\"value\":" + value_id + "}"
}
// 定数値を返す(ショートカット)
ret_const_i64(value) {
ret_const_i64(self, value) {
return "{\"op\":\"ret\",\"value\":null}" // 実際には定数命令 + ret命令が必要
}
// デバッグ用 - 生成された命令の確認
debug_ret(value_id) {
local json = me.lower_return(value_id)
debug_ret(self, value_id) {
local json = me.lower_return(self, value_id)
print("Generated ret instruction: " + json)
return json
}
// プログラム全体のreturn生成定数+returnの組み合わせ
program_with_const_ret(const_value) {
program_with_const_ret(self, const_value) {
local const_inst = "{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":" + const_value + "}}"
local ret_inst = me.inst_ret_value(1)
local ret_inst = me.inst_ret_value(self, 1)
return "{ \"version\": 0, \"functions\": [ { \"name\": \"main\", \"params\": [], \"blocks\": [ { \"id\": 0, \"instructions\": [" +
const_inst + "," +

View File

@ -0,0 +1,24 @@
#!/bin/bash
# Verify LLVMBranchInstructionBox.lower_branch requires self and returns JSON
source "$(dirname "$0")/../../../lib/test_runner.sh"
source "$(dirname "$0")/../../../lib/result_checker.sh"
require_env || exit 2
preflight_plugins || exit 2
test_self_param_branch() {
local src='
using "lang/src/llvm_ir/instructions/branch.hako" as B
box Main { static method main() {
local s = new B.LLVMBranchInstructionBox().lower_branch(3, 1, 2)
if s.contains("\"op\":\"branch\"") && s.contains("\"then\":1") { print(1) } else { print(0) }
} }
'
local out
out=$(run_nyash_vm -c "$src" 2>&1)
check_exact "1" "$out" "self_param_branch"
}
run_test "self_param_branch" test_self_param_branch

View File

@ -0,0 +1,24 @@
#!/bin/bash
# Verify LLVMCompareInstructionBox.lower_compare requires self and returns JSON
source "$(dirname "$0")/../../../lib/test_runner.sh"
source "$(dirname "$0")/../../../lib/result_checker.sh"
require_env || exit 2
preflight_plugins || exit 2
test_self_param_compare() {
local src='
using "lang/src/llvm_ir/instructions/compare.hako" as C
box Main { static method main() {
local s = new C.LLVMCompareInstructionBox().lower_compare("<", 1, 2, 3)
if s.contains("\"op\":\"compare\"") && s.contains("\"operation\":\"<\"") { print(1) } else { print(0) }
} }
'
local out
out=$(run_nyash_vm -c "$src" 2>&1)
check_exact "1" "$out" "self_param_compare"
}
run_test "self_param_compare" test_self_param_compare

View File

@ -0,0 +1,24 @@
#!/bin/bash
# Verify LLVMJumpInstructionBox.lower_jump requires self and returns JSON
source "$(dirname "$0")/../../../lib/test_runner.sh"
source "$(dirname "$0")/../../../lib/result_checker.sh"
require_env || exit 2
preflight_plugins || exit 2
test_self_param_jump() {
local src='
using "lang/src/llvm_ir/instructions/jump.hako" as J
box Main { static method main() {
local s = new J.LLVMJumpInstructionBox().lower_jump(5)
if s.contains("\"op\":\"jump\"") && s.contains("\"target\":5") { print(1) } else { print(0) }
} }
'
local out
out=$(run_nyash_vm -c "$src" 2>&1)
check_exact "1" "$out" "self_param_jump"
}
run_test "self_param_jump" test_self_param_jump

View File

@ -0,0 +1,24 @@
#!/bin/bash
# Verify LLVMRetInstructionBox.lower_return requires self and returns JSON
source "$(dirname "$0")/../../../lib/test_runner.sh"
source "$(dirname "$0")/../../../lib/result_checker.sh"
require_env || exit 2
preflight_plugins || exit 2
test_self_param_ret() {
local src='
using "lang/src/llvm_ir/instructions/ret.hako" as R
box Main { static method main() {
local s = new R.LLVMRetInstructionBox().lower_return(7)
if s.contains("\"op\":\"ret\"") && s.contains("\"value\":7") { print(1) } else { print(0) }
} }
'
local out
out=$(run_nyash_vm -c "$src" 2>&1)
check_exact "1" "$out" "self_param_ret"
}
run_test "self_param_ret" test_self_param_ret

View File

@ -81,5 +81,31 @@ test_oob_array_write() {
run_test "stageb_oob_array_read" test_oob_array_read
run_test "stageb_oob_array_write" test_oob_array_write
exit 0
# Map missing key (read) — accept error or 'null' as pass for now
test_oob_map_missing_read() {
local code='box Main { static method main() { local m={"a":1}; print(m["zzz"]); } }'
local json
json=$(hako_compile_to_mir_stageb "$code") || return 0
if out=$(NYASH_QUIET=1 HAKO_QUIET=1 NYASH_CLI_VERBOSE=0 NYASH_NYRT_SILENT_RESULT=1 \
"$ROOT/target/release/nyash" --json-file "$json" 2>&1); then
local last
last=$(printf '%s\n' "$out" | awk '/^(✅|ResultType|Result:)/{next} NF{last=$0} END{print last}')
if [ "$last" = "null" ]; then
log_success "map missing read returned null (accepted)"
rm -f "$json"
return 0
else
log_warn "map missing read returned '$last' (tolerated for now)"
rm -f "$json"
return 0
fi
else
log_success "map missing read produced error (accepted)"
rm -f "$json"
return 0
fi
}
run_test "stageb_oob_map_missing_read" test_oob_map_missing_read
exit 0