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:
@ -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
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -0,0 +1,72 @@
|
||||
#!/bin/bash
|
||||
# Direct(Builder) vs Bridge(JSON v0) parity — nested loops
|
||||
# 既定は SKIP(opt-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
|
||||
|
||||
@ -0,0 +1,85 @@
|
||||
#!/bin/bash
|
||||
# Stage‑B OOB canaries(opt‑in): 配列/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
|
||||
|
||||
Reference in New Issue
Block a user