diff --git a/lang/src/llvm_ir/instructions/binop.hako b/lang/src/llvm_ir/instructions/binop.hako index 6e791c88..259ca1d8 100644 --- a/lang/src/llvm_ir/instructions/binop.hako +++ b/lang/src/llvm_ir/instructions/binop.hako @@ -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 } diff --git a/lang/src/llvm_ir/instructions/const.hako b/lang/src/llvm_ir/instructions/const.hako index c6d2f74d..b2196f61 100644 --- a/lang/src/llvm_ir/instructions/const.hako +++ b/lang/src/llvm_ir/instructions/const.hako @@ -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 } diff --git a/tools/smokes/v2/profiles/quick/core/binop/self_param_binop_vm.sh b/tools/smokes/v2/profiles/quick/core/binop/self_param_binop_vm.sh new file mode 100644 index 00000000..2d8a9d72 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/binop/self_param_binop_vm.sh @@ -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 + diff --git a/tools/smokes/v2/profiles/quick/core/const/self_param_const_vm.sh b/tools/smokes/v2/profiles/quick/core/const/self_param_const_vm.sh new file mode 100644 index 00000000..3749bbbe --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/const/self_param_const_vm.sh @@ -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 + diff --git a/tools/smokes/v2/profiles/quick/core/loops/compare_loop_nested_vm.sh b/tools/smokes/v2/profiles/quick/core/loops/compare_loop_nested_vm.sh new file mode 100644 index 00000000..ab41f47d --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/loops/compare_loop_nested_vm.sh @@ -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 + diff --git a/tools/smokes/v2/profiles/quick/core/selfhost_stageb_oob_vm.sh b/tools/smokes/v2/profiles/quick/core/selfhost_stageb_oob_vm.sh new file mode 100644 index 00000000..938d499d --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/selfhost_stageb_oob_vm.sh @@ -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 +