smokes: 追加カバレッジ — ループ比較のネスト版、Stage‑B OOB(opt‑in)、const/binop 自己受検\n\n- loops/compare_loop_nested_vm.sh(SMOKES_ENABLE_LOOP_COMPARE=1)\n- selfhost_stageb_oob_vm.sh(SMOKES_ENABLE_STAGEB_OOB=1)\n- const/binop self_param_*(インスタンス経由の lower_* を確認)

This commit is contained in:
nyash-codex
2025-11-01 17:04:06 +09:00
parent e86151e20f
commit e9bb4422a5
6 changed files with 217 additions and 7 deletions

View File

@ -4,7 +4,7 @@
static box LLVMBinOpInstructionBox {
// メインエントリーポイント - Pythonのlower_binop()に相当
lower_binop(op, lhs, rhs, dst) {
lower_binop(self, op, lhs, rhs, dst) {
// 比較演算子はcompare命令に委譲
if op == "==" || op == "!=" || op == "<" || op == ">" || op == "<=" || op == ">=" {
return me._delegate_to_compare(op, lhs, rhs, dst)
@ -57,7 +57,7 @@ static box LLVMBinOpInstructionBox {
}
// 比較演算子の委譲
_delegate_to_compare(op, lhs, rhs, dst) {
_delegate_to_compare(self, op, lhs, rhs, dst) {
// JSON: {"op":"compare","dst":3,"operation":">","lhs":1,"rhs":2}
return "{\"op\":\"compare\",\"dst\":" + dst + ",\"operation\":\"" + op + "\",\"lhs\":" + lhs + ",\"rhs\":" + rhs + "}"
}
@ -105,8 +105,8 @@ static box LLVMBinOpInstructionBox {
}
// デバッグ用 - 生成された命令の確認
debug_binop(op, lhs, rhs, dst) {
local json = me.lower_binop(op, lhs, rhs, dst)
debug_binop(self, op, lhs, rhs, dst) {
local json = me.lower_binop(self, op, lhs, rhs, dst)
print("Generated binop instruction: " + json)
return json
}

View File

@ -4,7 +4,7 @@
static box LLVMConstInstructionBox {
// メインエントリーポイント - Pythonのlower_const()に相当
lower_const(dst, value_dict) {
lower_const(self, dst, value_dict) {
local const_type = value_dict.type
local const_val = value_dict.value
@ -72,8 +72,8 @@ static box LLVMConstInstructionBox {
}
// デバッグ用 - 生成された命令の確認
debug_const(dst, value_dict) {
local json = me.lower_const(dst, value_dict)
debug_const(self, dst, value_dict) {
local json = me.lower_const(self, dst, value_dict)
print("Generated const instruction: " + json)
return json
}

View File

@ -0,0 +1,26 @@
#!/bin/bash
# Verify LLVMBinOpInstructionBox.lower_binop requires self (implicit receiver) 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_binop() {
local src='
using "lang/src/llvm_ir/instructions/binop.hako" as BinOpInst
box Main {
static method main() {
local s = new BinOpInst.LLVMBinOpInstructionBox().lower_binop("+", 1, 2, 3)
if s.contains("\"op\":\"binop\"") && s.contains("\"operation\":\"+\"") { print(1) } else { print(0) }
}
}
'
local out
out=$(run_nyash_vm -c "$src" 2>&1)
check_exact "1" "$out" "self_param_binop"
}
run_test "self_param_binop" test_self_param_binop

View File

@ -0,0 +1,27 @@
#!/bin/bash
# Verify LLVMConstInstructionBox.lower_const requires self (implicit receiver) 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_const() {
local src='
using "lang/src/llvm_ir/instructions/const.hako" as ConstInst
box Main {
static method main() {
local v = new MapBox(); v.set("type","i64"); v.set("value",42)
local s = new ConstInst.LLVMConstInstructionBox().lower_const(1, v)
if s.contains("\"op\":\"const\"") && s.contains("\"i64\"") { print(1) } else { print(0) }
}
}
'
local out
out=$(run_nyash_vm -c "$src" 2>&1)
check_exact "1" "$out" "self_param_const"
}
run_test "self_param_const" test_self_param_const

View File

@ -0,0 +1,72 @@
#!/bin/bash
# Direct(Builder) vs Bridge(JSON v0) parity — nested loops
# 既定は SKIPopt-in: SMOKES_ENABLE_LOOP_COMPARE=1
source "$(dirname "$0")/../../../lib/test_runner.sh"
source "$(dirname "$0")/../../../lib/result_checker.sh"
require_env || exit 2
preflight_plugins || exit 2
if [ "${SMOKES_ENABLE_LOOP_COMPARE:-0}" != "1" ]; then
test_skip "compare_loop_nested_vm" "opt-in (set SMOKES_ENABLE_LOOP_COMPARE=1)" && exit 0
fi
test_compare_loop_nested() {
local src='
local i, j, count
i = 0
count = 0
loop(i < 3) {
j = 0
loop(j < 2) {
count = count + 1
j = j + 1
}
i = i + 1
}
print(count)
'
local direct_out
direct_out=$(run_nyash_vm -c "$src" 2>&1)
local tmp_json="/tmp/nyash_compare_loop_nested_$$.json"
cat > "$tmp_json" <<'JSON'
{"version":0,"kind":"Program","body":[
{"type":"Local","name":"i","expr":{"type":"Int","value":0}},
{"type":"Local","name":"j","expr":{"type":"Int","value":0}},
{"type":"Local","name":"count","expr":{"type":"Int","value":0}},
{"type":"Loop",
"cond":{"type":"Compare","op":"<","lhs":{"type":"Var","name":"i"},"rhs":{"type":"Int","value":3}},
"body":[
{"type":"Local","name":"j","expr":{"type":"Int","value":0}},
{"type":"Loop",
"cond":{"type":"Compare","op":"<","lhs":{"type":"Var","name":"j"},"rhs":{"type":"Int","value":2}},
"body":[
{"type":"Local","name":"count","expr":{"type":"Binary","op":"+","lhs":{"type":"Var","name":"count"},"rhs":{"type":"Int","value":1}}},
{"type":"Local","name":"j","expr":{"type":"Binary","op":"+","lhs":{"type":"Var","name":"j"},"rhs":{"type":"Int","value":1}}}
]
},
{"type":"Local","name":"i","expr":{"type":"Binary","op":"+","lhs":{"type":"Var","name":"i"},"rhs":{"type":"Int","value":1}}}
]},
{"type":"Extern","iface":"env.console","method":"log","args":[{"type":"Var","name":"count"}]}
]}
JSON
local bridge_out
bridge_out=$(NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1 "$NYASH_BIN" --backend vm --json-file "$tmp_json" 2>&1 | filter_noise)
rm -f "$tmp_json"
check_exact "6" "$direct_out" "direct_loop_nested"
check_exact "6" "$bridge_out" "bridge_loop_nested"
if [ "$direct_out" != "$bridge_out" ]; then
echo "[FAIL] compare_loop_nested: direct != bridge" >&2
echo " direct: $direct_out" >&2
echo " bridge: $bridge_out" >&2
return 1
fi
return 0
}
run_test "compare_loop_nested" test_compare_loop_nested

View File

@ -0,0 +1,85 @@
#!/bin/bash
# StageB OOB canariesoptin: 配列/Map の OOB 振る舞い確認(現状は SKIP 既定)
set -uo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
ROOT="$(cd "$SCRIPT_DIR/../../../../.." && pwd)"
source "$ROOT/tools/smokes/v2/lib/test_runner.sh"
source "$ROOT/tools/smokes/v2/lib/result_checker.sh"
require_env || exit 2
preflight_plugins || exit 2
if [ "${SMOKES_ENABLE_STAGEB_OOB:-0}" != "1" ]; then
test_skip "selfhost_stageb_oob" "opt-in (set SMOKES_ENABLE_STAGEB_OOB=1)" && exit 0
fi
HAKO_BIN_DEFAULT="$ROOT/tools/bin/hako"
HAKO_BIN="${HAKO_BIN:-$HAKO_BIN_DEFAULT}"
require_hako() {
if [ ! -x "$HAKO_BIN" ]; then
log_warn "Hako binary not found: $HAKO_BIN (set HAKO_BIN to override)"
exit 0
fi
}
hako_compile_to_mir_stageb() {
local code="$1"
local hako_tmp="/tmp/hako_stageb_oob_$$.hako"
local json_out="/tmp/hako_stageb_oob_$$.mir.json"
printf "%s\n" "$code" > "$hako_tmp"
local raw="/tmp/hako_stageb_oob_raw_$$.txt"
NYASH_PARSER_ALLOW_SEMICOLON=1 HAKO_ALLOW_USING_FILE=1 NYASH_ALLOW_USING_FILE=1 \
HAKO_PARSER_STAGE3=1 NYASH_PARSER_STAGE3=1 \
NYASH_VARMAP_GUARD_STRICT=0 NYASH_BLOCK_SCHEDULE_VERIFY=0 \
NYASH_QUIET=1 HAKO_QUIET=1 NYASH_CLI_VERBOSE=0 \
"$ROOT/target/release/nyash" --backend vm \
"$ROOT/lang/src/compiler/entry/compiler_stageb.hako" -- --source "$(cat "$hako_tmp")" > "$raw" 2>&1
awk '/"version":0/ && /"kind":"Program"/ {print; exit}' "$raw" > "$json_out"
rm -f "$raw" "$hako_tmp"
echo "$json_out"
}
run_mir_via_gate_c() {
local json_path="$1"
NYASH_QUIET=1 HAKO_QUIET=1 NYASH_CLI_VERBOSE=0 NYASH_NYRT_SILENT_RESULT=1 \
"$ROOT/target/release/nyash" --json-file "$json_path" >/tmp/hako_stageb_oob_run.txt 2>&1
local rc=$?
cat /tmp/hako_stageb_oob_run.txt >&2
rm -f "$json_path" /tmp/hako_stageb_oob_run.txt
return $rc
}
test_oob_array_read() {
local code='box Main { static method main() { local a=[1,2]; print(a[5]); } }'
local json
json=$(hako_compile_to_mir_stageb "$code") || return 0 # emit失敗はここではスキップ
if run_mir_via_gate_c "$json"; then
log_warn "array OOB read did not error (allowed by current semantics)."
return 0
else
log_success "array OOB read produced error (expected)"
return 0
fi
}
test_oob_array_write() {
local code='box Main { static method main() { local a=[1,2]; a[5]=9; print(a[1]); } }'
local json
json=$(hako_compile_to_mir_stageb "$code") || return 0
if run_mir_via_gate_c "$json"; then
log_warn "array OOB write did not error (allowed by current semantics)."
return 0
else
log_success "array OOB write produced error (expected)"
return 0
fi
}
run_test "stageb_oob_array_read" test_oob_array_read
run_test "stageb_oob_array_write" test_oob_array_write
exit 0