smokes: add PHI/core/integration tests; parity uses Python LLVM harness; test runner noise filter\nparser: add opt-in TokenCursor bridge (NYASH_PARSER_TOKEN_CURSOR=1) for expressions\nmir: fix PHI incoming preds to use exit blocks; add debug PHI verification\nplugins(net/filebox): warning cleanup (dead_code), no behavior change\ndocs: smokes v2 README – add test accumulation policy and LLVM harness note\nCURRENT_TASK: Phase 15.5 newline refactor resume + plan

This commit is contained in:
Selfhosting Dev
2025-09-25 06:15:22 +09:00
parent 8fbbe2b3a0
commit d1041f4e22
36 changed files with 812 additions and 58 deletions

View File

@ -175,6 +175,25 @@ run_test "test_name" {
- ログ保存: `artifacts/smokes/<timestamp>/`
- タイムアウト: プロファイル別設定
### 追加ポリシー(テストの“積み”方針)
- Quick/Core: 目安 12〜16 本。意味論の軽量ガードのみ(< 0.5s/
- 増やす基準: バグ/回帰が出たとき最小再現を1本追加
- 既存と同型のバリエーションは増やさない効果逓減を避ける
- Integration/Parity: 目安 810 代表構文の VM LLVM ハーネス一致
- 増やす基準: LLVM 側の修正で差分が出る領域のみ 1 本追加
- Plugins: 13 /プラグイン環境依存は必ず SKIP ガード
- 例: FileBox 未ロード時は SKIPエラーメッセージをマッチして回避
### ノイズ抑止と共通フィルタ
実行出力のノイズは `lib/test_runner.sh` `filter_noise` に集約して管理する
新しいノイズが出たらフィルタへ追加し各テスト個別の `grep -v` は増やさない
### LLVM パリティPython ハーネス)
- Integration `check_parity` LLVM 実行時に `NYASH_LLVM_USE_HARNESS=1` を自動付与して llvmlite ハーネスで検証する
- 使い方:
- `check_parity -c 'print("Hello")' "hello_parity"`
- 同一コードを VM LLVM で実行し終了コードと整形後の標準出力を比較する
## 💡 トラブルシューティング
### よくあるエラー

View File

@ -107,23 +107,49 @@ check_json() {
# パリティテストVM vs LLVM比較
check_parity() {
local program="$1"
local test_name="${2:-parity_test}"
local timeout="${3:-30}"
local code=""
local test_name
local timeout
if [ "$program" = "-c" ]; then
code="$2"
test_name="${3:-parity_test}"
timeout="${4:-30}"
else
test_name="${2:-parity_test}"
timeout="${3:-30}"
fi
local vm_output llvm_output vm_exit llvm_exit
# Rust VM実行
if vm_output=$(timeout "$timeout" bash -c "NYASH_DISABLE_PLUGINS=1 ./target/release/nyash '$program' 2>&1"); then
vm_exit=0
# Rust VM 実行
if [ "$program" = "-c" ]; then
if vm_output=$(timeout "$timeout" bash -c "NYASH_DISABLE_PLUGINS=1 ./target/release/nyash -c \"$code\" 2>&1"); then
vm_exit=0
else
vm_exit=$?
fi
else
vm_exit=$?
if vm_output=$(timeout "$timeout" bash -c "NYASH_DISABLE_PLUGINS=1 ./target/release/nyash \"$program\" 2>&1"); then
vm_exit=0
else
vm_exit=$?
fi
fi
# LLVM実行
if llvm_output=$(timeout "$timeout" bash -c "NYASH_DISABLE_PLUGINS=1 ./target/release/nyash --backend llvm '$program' 2>&1"); then
llvm_exit=0
# LLVMPythonハーネス実行
if [ "$program" = "-c" ]; then
if llvm_output=$(timeout "$timeout" bash -c "NYASH_LLVM_USE_HARNESS=1 NYASH_DISABLE_PLUGINS=1 ./target/release/nyash --backend llvm -c \"$code\" 2>&1"); then
llvm_exit=0
else
llvm_exit=$?
fi
else
llvm_exit=$?
if llvm_output=$(timeout "$timeout" bash -c "NYASH_LLVM_USE_HARNESS=1 NYASH_DISABLE_PLUGINS=1 ./target/release/nyash --backend llvm \"$program\" 2>&1"); then
llvm_exit=0
else
llvm_exit=$?
fi
fi
# 終了コード比較
@ -280,4 +306,4 @@ Examples:
# 性能テスト
check_performance "benchmark.nyash" 5.0 "speed_test"
EOF
}
}

View File

@ -44,6 +44,24 @@ log_error() {
echo -e "${RED}[FAIL]${NC} $*" >&2
}
# 共通イズフィルタVM実行時の出力整形
filter_noise() {
# プラグイン初期化やメタログ、動的ローダの案内等を除去
grep -v "^\[UnifiedBoxRegistry\]" \
| grep -v "^\[FileBox\]" \
| grep -v "^Net plugin:" \
| grep -v "^\[.*\] Plugin" \
| grep -v "Using builtin StringBox" \
| grep -v "Phase 15.5: Everything is Plugin" \
| grep -v "cargo build -p nyash-string-plugin" \
| grep -v "^\[plugin-loader\] backend=" \
| grep -v "^\[using\] ctx:" \
| grep -v "^🔌 plugin host initialized" \
| grep -v "^✅ plugin host fully configured" \
| grep -v "Failed to load nyash.toml - plugins disabled" \
| grep -v "^🚀 Nyash VM Backend - Executing file:"
}
# 環境チェック(必須)
require_env() {
local required_tools=("cargo" "grep" "jq")
@ -122,25 +140,13 @@ run_nyash_vm() {
local tmpfile="/tmp/nyash_test_$$.nyash"
echo "$code" > "$tmpfile"
# プラグイン初期化メッセージを除外
NYASH_VM_USE_PY="$USE_PYVM" NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1 "$NYASH_BIN" "$tmpfile" "$@" 2>&1 | \
grep -v "^\[UnifiedBoxRegistry\]" | grep -v "^\[FileBox\]" | grep -v "^Net plugin:" | grep -v "^\[.*\] Plugin" | \
grep -v "Using builtin StringBox" | grep -v "Phase 15.5: Everything is Plugin" | grep -v "cargo build -p nyash-string-plugin" | \
grep -v "^\[plugin-loader\] backend=" | grep -v "^\[using\] ctx:" | \
grep -v "^🔌 plugin host initialized" | grep -v "^✅ plugin host fully configured" | \
grep -v "Failed to load nyash.toml - plugins disabled" | \
grep -v "^🚀 Nyash VM Backend - Executing file:"
NYASH_VM_USE_PY="$USE_PYVM" NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1 "$NYASH_BIN" "$tmpfile" "$@" 2>&1 | filter_noise
local exit_code=${PIPESTATUS[0]}
rm -f "$tmpfile"
return $exit_code
else
# プラグイン初期化メッセージを除外
NYASH_VM_USE_PY="$USE_PYVM" NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1 "$NYASH_BIN" "$program" "$@" 2>&1 | \
grep -v "^\[UnifiedBoxRegistry\]" | grep -v "^\[FileBox\]" | grep -v "^Net plugin:" | grep -v "^\[.*\] Plugin" | \
grep -v "Using builtin StringBox" | grep -v "Phase 15.5: Everything is Plugin" | grep -v "cargo build -p nyash-string-plugin" | \
grep -v "^\[plugin-loader\] backend=" | grep -v "^\[using\] ctx:" | \
grep -v "^🔌 plugin host initialized" | grep -v "^✅ plugin host fully configured" | \
grep -v "Failed to load nyash.toml - plugins disabled" | \
grep -v "^🚀 Nyash VM Backend - Executing file:"
NYASH_VM_USE_PY="$USE_PYVM" NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1 "$NYASH_BIN" "$program" "$@" 2>&1 | filter_noise
return ${PIPESTATUS[0]}
fi
}

View File

@ -0,0 +1,24 @@
#!/bin/bash
# vm_llvm_compare_basic.sh - VM vs LLVM parity for basic integer comparisons
source "$(dirname "$0")/../../../lib/test_runner.sh"
source "$(dirname "$0")/../../../lib/result_checker.sh"
require_env || exit 2
preflight_plugins || exit 2
test_vm_llvm_compare_basic() {
local code='if 3 > 2 {
if 2 < 3 {
print("OK")
} else {
print("NG")
}
} else {
print("NG")
}'
check_parity -c "$code" "vm_llvm_compare_basic"
}
run_test "vm_llvm_compare_basic" test_vm_llvm_compare_basic

View File

@ -0,0 +1,16 @@
#!/bin/bash
# vm_llvm_concat_string_number.sh - VM vs LLVM parity for string + number concatenation
source "$(dirname "$0")/../../../lib/test_runner.sh"
source "$(dirname "$0")/../../../lib/result_checker.sh"
require_env || exit 2
preflight_plugins || exit 2
test_vm_llvm_concat_string_number() {
local code='print("ab" + 3)'
check_parity -c "$code" "vm_llvm_concat_string_number"
}
run_test "vm_llvm_concat_string_number" test_vm_llvm_concat_string_number

View File

@ -0,0 +1,26 @@
#!/bin/bash
# vm_llvm_early_return.sh - VM vs LLVM parity for early return
source "$(dirname "$0")/../../../lib/test_runner.sh"
source "$(dirname "$0")/../../../lib/result_checker.sh"
require_env || exit 2
preflight_plugins || exit 2
test_vm_llvm_early_return() {
local code='static box Main {
main() {
if 1 {
print("A")
return 0
} else {
print("B")
}
print("C")
}
}'
check_parity -c "$code" "vm_llvm_early_return"
}
run_test "vm_llvm_early_return" test_vm_llvm_early_return

View File

@ -3,6 +3,7 @@
# 共通ライブラリ読み込み(必須)
source "$(dirname "$0")/../../../lib/test_runner.sh"
source "$(dirname "$0")/../../../lib/result_checker.sh"
# 環境チェック(必須)
require_env || exit 2
@ -16,4 +17,4 @@ test_vm_llvm_parity() {
}
# テスト実行
run_test "vm_llvm_parity" test_vm_llvm_parity
run_test "vm_llvm_parity" test_vm_llvm_parity

View File

@ -0,0 +1,25 @@
#!/bin/bash
# vm_llvm_if_else_phi.sh - VM vs LLVM parity for else-if PHI wiring
source "$(dirname "$0")/../../../lib/test_runner.sh"
source "$(dirname "$0")/../../../lib/result_checker.sh"
require_env || exit 2
preflight_plugins || exit 2
test_vm_llvm_if_else_phi() {
local code='local score, x
score = 75
if score >= 80 {
x = "A"
} else if score >= 60 {
x = "B"
} else {
x = "C"
}
print(x)'
check_parity -c "$code" "vm_llvm_if_else_phi"
}
run_test "vm_llvm_if_else_phi" test_vm_llvm_if_else_phi

View File

@ -0,0 +1,21 @@
#!/bin/bash
# vm_llvm_if_without_else_phi.sh - VM vs LLVM parity for if without else (false-edge PHI)
source "$(dirname "$0")/../../../lib/test_runner.sh"
source "$(dirname "$0")/../../../lib/result_checker.sh"
require_env || exit 2
preflight_plugins || exit 2
test_vm_llvm_if_without_else_phi() {
local code='local v
v = "before"
if 0 {
v = "then"
}
print(v)'
check_parity -c "$code" "vm_llvm_if_without_else_phi"
}
run_test "vm_llvm_if_without_else_phi" test_vm_llvm_if_without_else_phi

View File

@ -0,0 +1,25 @@
#!/bin/bash
# vm_llvm_loop_break_continue.sh - VM vs LLVM parity for loop + break/continue
source "$(dirname "$0")/../../../lib/test_runner.sh"
source "$(dirname "$0")/../../../lib/result_checker.sh"
require_env || exit 2
preflight_plugins || exit 2
test_vm_llvm_loop_break_continue() {
local code='local i, sum
i = 0
sum = 0
loop(i < 10) {
i = i + 1
if i % 2 == 0 { continue }
sum = sum + i
if i >= 7 { break }
}
print(sum)'
check_parity -c "$code" "vm_llvm_loop_break_continue"
}
run_test "vm_llvm_loop_break_continue" test_vm_llvm_loop_break_continue

View File

@ -0,0 +1,23 @@
#!/bin/bash
# vm_llvm_loop_sum.sh - VM vs LLVM parity for simple loop accumulation
source "$(dirname "$0")/../../../lib/test_runner.sh"
source "$(dirname "$0")/../../../lib/result_checker.sh"
require_env || exit 2
preflight_plugins || exit 2
test_vm_llvm_loop_sum() {
local code='local i, sum
i = 1
sum = 0
while i <= 5 {
sum = sum + i
i = i + 1
}
print(sum)'
check_parity -c "$code" "vm_llvm_loop_sum"
}
run_test "vm_llvm_loop_sum" test_vm_llvm_loop_sum

View File

@ -0,0 +1,27 @@
#!/bin/bash
# vm_llvm_nested_if.sh - VM vs LLVM parity for nested if with merge PHI
source "$(dirname "$0")/../../../lib/test_runner.sh"
source "$(dirname "$0")/../../../lib/result_checker.sh"
require_env || exit 2
preflight_plugins || exit 2
test_vm_llvm_nested_if() {
local code='local a, b
a = 10
b = 20
if a < b {
if a == 10 {
print("correct")
} else {
print("wrong")
}
} else {
print("error")
}'
check_parity -c "$code" "vm_llvm_nested_if"
}
run_test "vm_llvm_nested_if" test_vm_llvm_nested_if

View File

@ -0,0 +1,29 @@
#!/bin/bash
# comparison_ops.sh - 比較演算(整数)の基本確認
source "$(dirname "$0")/../../../lib/test_runner.sh"
source "$(dirname "$0")/../../../lib/result_checker.sh"
require_env || exit 2
preflight_plugins || exit 2
test_comparisons() {
local script='
// 期待: OK
if 3 > 2 {
if 2 < 3 {
print("OK")
} else {
print("NG")
}
} else {
print("NG")
}
'
local output
output=$(run_nyash_vm -c "$script" 2>&1)
check_exact "OK" "$output" "comparison_basic"
}
run_test "comparison_basic" test_comparisons

View File

@ -0,0 +1,36 @@
#!/bin/bash
# comparisons_extended.sh - 比較演算の拡張セット(整数)
source "$(dirname "$0")/../../../lib/test_runner.sh"
source "$(dirname "$0")/../../../lib/result_checker.sh"
require_env || exit 2
preflight_plugins || exit 2
test_eq_neq() {
local script='
if 5 == 5 {
if 5 != 4 {
print("OK")
} else { print("NG") }
} else { print("NG") }
'
local out; out=$(run_nyash_vm -c "$script" 2>&1)
check_exact "OK" "$out" "eq_neq"
}
test_le_ge() {
local script='
if 5 >= 5 {
if 4 <= 5 {
print("OK")
} else { print("NG") }
} else { print("NG") }
'
local out; out=$(run_nyash_vm -c "$script" 2>&1)
check_exact "OK" "$out" "le_ge"
}
run_test "eq_neq" test_eq_neq
run_test "le_ge" test_le_ge

View File

@ -0,0 +1,30 @@
#!/bin/bash
# early_return.sh - 早期returnの合流確認
source "$(dirname "$0")/../../../lib/test_runner.sh"
source "$(dirname "$0")/../../../lib/result_checker.sh"
require_env || exit 2
preflight_plugins || exit 2
test_early_return_then() {
local script='
static box Main {
main() {
if 1 {
print("A")
return 0
} else {
print("B")
}
print("C") // 到達しない
}
}
'
local output
output=$(run_nyash_vm -c "$script" 2>&1)
check_exact "A" "$output" "early_return_then"
}
run_test "early_return_then" test_early_return_then

View File

@ -0,0 +1,17 @@
#!/bin/bash
# division_by_zero.sh - ゼロ除算エラーパターンの検証
source "$(dirname "$0")/../../../../lib/test_runner.sh"
source "$(dirname "$0")/../../../../lib/result_checker.sh"
require_env || exit 2
preflight_plugins || exit 2
test_division_by_zero() {
local output
output=$(run_nyash_vm -c 'print(1 / 0)' 2>&1 || true)
check_regex "Division by zero" "$output" "division_by_zero"
}
run_test "division_by_zero" test_division_by_zero

View File

@ -0,0 +1,30 @@
#!/bin/bash
# filebox_basic.sh - FileBox の最小E2EコアBoxを使用
source "$(dirname "$0")/../../../lib/test_runner.sh"
source "$(dirname "$0")/../../../lib/result_checker.sh"
require_env || exit 2
preflight_plugins || exit 2
test_filebox_write_bytes() {
local tmp="/tmp/nyash_smoke_file_$$.txt"
local script="
local fb, n
fb = new FileBox()
fb.open(\"$tmp\", \"w\")
n = fb.write(\"hello\")
fb.close()
print(n)
"
local output
output=$(run_nyash_vm -c "$script" 2>&1 || true)
rm -f "$tmp" 2>/dev/null || true
if echo "$output" | grep -q "Unknown Box type: FileBox\|VM fallback error: Invalid instruction: NewBox FileBox failed"; then
test_skip "filebox_write_bytes" "FileBox not available (plugin not loaded)"
return 0
fi
check_exact "5" "$output" "filebox_write_bytes"
}
run_test "filebox_write_bytes" test_filebox_write_bytes

View File

@ -34,7 +34,7 @@ local score
score = 75
if score >= 80 {
print("A")
} elseif score >= 60 {
} else if score >= 60 {
print("B")
} else {
print("C")
@ -70,8 +70,12 @@ test_if_with_and() {
local x, y
x = 5
y = 10
if x > 0 and y > 0 {
print("both positive")
if x > 0 {
if y > 0 {
print("both positive")
} else {
print("not both positive")
}
} else {
print("not both positive")
}
@ -85,4 +89,4 @@ if x > 0 and y > 0 {
run_test "simple_if" test_simple_if
run_test "if_else" test_if_else
run_test "nested_if" test_nested_if
run_test "if_with_and" test_if_with_and
run_test "if_with_and" test_if_with_and

View File

@ -0,0 +1,28 @@
#!/bin/bash
# break_continue.sh - while + break/continue の代表ケース
source "$(dirname "$0")/../../../../lib/test_runner.sh"
source "$(dirname "$0")/../../../../lib/result_checker.sh"
require_env || exit 2
preflight_plugins || exit 2
test_break_continue() {
local script='
local i, sum
i = 0
sum = 0
loop(i < 10) {
i = i + 1
if i % 2 == 0 { continue } // 偶数はスキップ
sum = sum + i
if i >= 7 { break } // 7 で打ち切り(対象: 1,3,5,7
}
print(sum)
'
local out; out=$(run_nyash_vm -c "$script" 2>&1)
# 1+3+5+7 = 16
check_exact "16" "$out" "break_continue"
}
run_test "break_continue" test_break_continue

View File

@ -0,0 +1,29 @@
#!/bin/bash
# if_else_phi.sh - PHI wiring: else-if chain should pick exit predecessors
source "$(dirname "$0")/../../../../lib/test_runner.sh"
source "$(dirname "$0")/../../../../lib/result_checker.sh"
require_env || exit 2
preflight_plugins || exit 2
test_if_else_phi() {
local script='
local score, x
score = 75
if score >= 80 {
x = "A"
} else if score >= 60 {
x = "B"
} else {
x = "C"
}
print(x)
'
local output
output=$(run_nyash_vm -c "$script" 2>&1)
check_exact "B" "$output" "if_else_phi"
}
run_test "if_else_phi" test_if_else_phi

View File

@ -0,0 +1,25 @@
#!/bin/bash
# if_without_else_phi.sh - PHI wiring: elseなしの変数マージfalse-edge→merge
source "$(dirname "$0")/../../../../lib/test_runner.sh"
source "$(dirname "$0")/../../../../lib/result_checker.sh"
require_env || exit 2
preflight_plugins || exit 2
test_if_without_else_phi() {
local script='
local v
v = "before"
if 0 {
v = "then"
}
print(v)
'
local output
output=$(run_nyash_vm -c "$script" 2>&1)
check_exact "before" "$output" "if_without_else_phi"
}
run_test "if_without_else_phi" test_if_without_else_phi

View File

@ -0,0 +1,33 @@
#!/bin/bash
# multi_branch_phi.sh - else-if 多分岐での PHI 配線5枝
source "$(dirname "$0")/../../../../lib/test_runner.sh"
source "$(dirname "$0")/../../../../lib/result_checker.sh"
require_env || exit 2
preflight_plugins || exit 2
test_multi_branch_phi() {
local script='
local n, s
n = 3
if n == 1 {
s = "one"
} else if n == 2 {
s = "two"
} else if n == 3 {
s = "three"
} else if n == 4 {
s = "four"
} else {
s = "many"
}
print(s)
'
local output
output=$(run_nyash_vm -c "$script" 2>&1)
check_exact "three" "$output" "multi_branch_phi"
}
run_test "multi_branch_phi" test_multi_branch_phi

View File

@ -0,0 +1,27 @@
#!/bin/bash
# var_merge_delta.sh - then/else で同一変数を更新 → merge 時に正しい値を選択
source "$(dirname "$0")/../../../../lib/test_runner.sh"
source "$(dirname "$0")/../../../../lib/result_checker.sh"
require_env || exit 2
preflight_plugins || exit 2
test_var_merge_delta() {
local script='
local a
a = 1
if 1 {
a = 2
} else {
a = 3
}
print(a)
'
local output
output=$(run_nyash_vm -c "$script" 2>&1)
check_exact "2" "$output" "var_merge_delta"
}
run_test "var_merge_delta" test_var_merge_delta