docs(phase80/81): Phase 80/81 完了状態をドキュメントに反映

Phase 80/81 Implementation Summary:
- Phase 80 (c61f4bc7): JoinIR 本線統一(代表 if/loop)
  - should_try_joinir_mainline() 等の SSOT ヘルパー実装
  - NYASH_JOINIR_CORE=1 で JoinIR→MIR が既定に
- Phase 81 (a9e10d2a): selfhost Strict + Fail-Fast
  - selfhost_build.sh に --core/--strict オプション追加
  - 環境変数自動伝播(NYASH_JOINIR_CORE/STRICT)
- Phase 82 (93f51e40): JOINIR_TARGETS SSOT 化
  - is_loop_lowered_function() テーブル参照統一

Documentation Updates:
- docs/private/roadmap2/phases/phase-80-joinir-mainline/README.md
  - Section 80-2: 実装完了マーク追加
  - Section 80-5: commit hash 付きメモ更新
- docs/private/roadmap2/phases/phase-81-joinir-strict/README.md
  - Section 81-4: Done/TODO チェックボックス更新
  - Section 81-4-A: selfhost_build.sh 統合実装詳細追加
- CURRENT_TASK.md
  - Phase 80/81 完了マーク追加(今後の優先タスク順)
  - Phase 82 次の焦点として明記

Next Focus:
- Phase 82-if-phi-retire: if_phi.rs 削除準備開始
This commit is contained in:
nyash-codex
2025-12-02 14:07:19 +09:00
parent 93f51e40ae
commit 573c9e90b6
9 changed files with 242 additions and 31 deletions

View File

@ -117,20 +117,24 @@
- ✅ RAW観測レイヤ活用成功 (`logs/selfhost/stageb_20251202_101623_2665649.log` 707K) - ✅ RAW観測レイヤ活用成功 (`logs/selfhost/stageb_20251202_101623_2665649.log` 707K)
- ✅ 根本原因特定: **SSA undef (4件)** + **dev verify (1件)** が Program JSON emit失敗を引き起こしている - ✅ 根本原因特定: **SSA undef (4件)** + **dev verify (1件)** が Program JSON emit失敗を引き起こしている
- ✅ JoinIR/プラグイン初期化は **問題なし** (JoinIR経路正常動作、プラグイン成功確認) - ✅ JoinIR/プラグイン初期化は **問題なし** (JoinIR経路正常動作、プラグイン成功確認)
- **SSA undef詳細 (4件)**: - **SSA undef詳細 (初回観測時)**:
1. `ParserCommonUtilsBox.trim/1` - ValueId(272)未定義 1. `ParserCommonUtilsBox.trim/1` - ValueId(272)未定義
2. `ParserBox.trim/1` - ValueId(272)未定義 2. `ParserBox.trim/1` - ValueId(272)未定義
3. `Main._parse_number/1` - ValueId(12)未定義 3. `Main._parse_number/1` - ValueId(12)未定義
4. `ParserBox.parse_block2/2` - ValueId(440)未定義 4. `ParserBox.parse_block2/2` - ValueId(440)未定義
- **dev verify警告 (1件)**: `StageBDriverBox` NewBox直後にbirth()未呼び出し → Phase 71-SSA での `.hako` 側整理により、現在はいずれも解消済みSSA undef 13件→0件
- **完了判定基準**: 観測窓としてのPhase 71は完了。SSA修正はPhase 71-SSA-debugへ引き継ぎ。 - **dev verify警告 (初回観測時)**: `StageBDriverBox` NewBox直後にbirth()未呼び出し
- **詳細レポート**: `docs/development/current/main/phase71-findings-20251202.md` → StageBDriverBox が static box であることを考慮し、lifecycle.rs 側の特例で警告は解消済み。
- **完了判定基準**: 観測窓としてのPhase 71は完了。代表 selfhost パスで JSON v0 emit→VM 実行(出力 `abc`)まで通ることを確認済みで、
SSA 修正は今後 StageB 他ケースと s3/parity 系にフォーカスする。
- **詳細レポート**: `docs/development/current/main/phase71-findings-20251202.md` と Phase 71-SSA 追加レポート
- quick プロファイルでは JoinIR/VM 系は緑維持を目標としつつ、selfhost_minimal / stageb_min_emit は「SSA ラインの観測窓」として赤許容。StageB/SSA 起因の赤は Phase 71-SSA 側でハンドルする。 - quick プロファイルでは JoinIR/VM 系は緑維持を目標としつつ、selfhost_minimal / stageb_min_emit は「SSA ラインの観測窓」として赤許容。StageB/SSA 起因の赤は Phase 71-SSA 側でハンドルする。
- **Phase 72: JoinIR dev フラグ棚卸し**docs + env ポリシー整備済み、配線寄せ残) - **Phase 72: JoinIR dev フラグ棚卸し**
- `config::env::joinir_core_enabled()` / `joinir_dev_enabled()` を追加し、Core/DevOnly/Deprecated の区分を整理 - `config::env::joinir_core_enabled()` / `joinir_dev_enabled()` を追加し、Core/DevOnly/Deprecated の区分を整理
- docs/private/roadmap2/phases/phase-72-joinir-dev-flags/README.md に一覧表を追加済み - `NYASH_JOINIR_EXPERIMENT``HAKO_JOINIR_IF_SELECT` を含む JoinIR 関連フラグの読み書きを、
- コード側のガード集約と smokes タイムアウト調整s3 backend 長尺の扱い)を残タスクとして追う `src/config/env/joinir_dev.rs` / `src/tests/helpers/joinir_env.rs` 経由の SSOT に統一(本体コードからの `std::env` 直読みを排除)。
- docs/private/roadmap2/phases/phase-72-joinir-dev-flags/README.md に一覧表と実装状況メモを追加済み。
- **Phase 73: ENV 整理・不要フラグ削除JoinIRStage3 周辺)** - **Phase 73: ENV 整理・不要フラグ削除JoinIRStage3 周辺)**
- docs/private/roadmap2/phases/phase-73-env-cleanup/README.md に Stage3 / JoinIR / その他 ENV の棚卸しと Dead/Alias/Keep の分類方針を追加 - docs/private/roadmap2/phases/phase-73-env-cleanup/README.md に Stage3 / JoinIR / その他 ENV の棚卸しと Dead/Alias/Keep の分類方針を追加
@ -158,19 +162,21 @@
### 今後の優先タスク順selfhost + hack_check 観点の整理) ### 今後の優先タスク順selfhost + hack_check 観点の整理)
1. **Phase 71-SSA/selfhost 再ブートストラップの収束** 1. **Phase 71-SSA/selfhost 再ブートストラップの収束**
- StageB/SSA ラインを「観測窓」として整えつつ、`selfhost_build + stage1_run_min.hako` が JSON v0 emit まで通るかどうかを確認する。 - 代表パス(selfhost_build + stage1_run_min.hakoが JSON v0 emit→VM 実行まで通ることは確認済みとし、
以降は StageB 他ケースと s3/parity 系を「SSA ラインの観測窓」として整理していく。
- この段階では JoinIR Strict は代表 if/loop/VM ブリッジに限定し、selfhost_minimal/stageb_min_emit の赤は SSA 側の課題として扱う。 - この段階では JoinIR Strict は代表 if/loop/VM ブリッジに限定し、selfhost_minimal/stageb_min_emit の赤は SSA 側の課題として扱う。
2. **Phase 7273: ENV / JoinIR dev フラグの集約完了** 2. **Phase 7273: ENV / JoinIR dev フラグの集約完了**
- `joinir_core_enabled()` / `joinir_dev_enabled()` / `parser_stage3_enabled()` を SSOT として使い切り、tools/selfhost/hako_check/tests から旧 ENV を整理する。 - `joinir_core_enabled()` / `joinir_dev_enabled()` / `parser_stage3_enabled()` を SSOT として使い切り、tools/selfhost/hako_check/tests から旧 ENV を整理する。
- ここまでで「selfhost / hack_check / tests が同じ Stage3 + JoinIR/ENV ポリシー上に乗る」状態を目指す。 - ここまでで「selfhost / hack_check / tests が同じ Stage3 + JoinIR/ENV ポリシー上に乗る」状態を目指す。
3. **Phase 80: VM/LLVM 本線の JoinIR 統一** 3. **Phase 80: VM/LLVM 本線の JoinIR 統一** **完了**2025-12-02 c61f4bc7
- VM/LLVM ランナーで、ループ/if の代表ケースskip_ws/trim/resolve/print_tokens/filter 等)が JoinIR→MIR→VM/LLVM を本線として通ることを確認する。 - 代表 if/loop の本線化を実装。`joinir_core_enabled()` 時は JoinIR→MIR 経路が既定となり、レガシー経路は JoinIR 未対応ケース専用に縮退。
- quick プロファイルでは `NYASH_JOINIR_CORE=1` を既定としつつ、レガシー経路は JoinIR 未対応ケース専用とする - SSOT ヘルパー(`should_try_joinir_mainline()` / `should_panic_on_joinir_failure()`)を実装
4. **Phase 81: selfhost 用 JoinIR Strictfail-fast の確立** - **Phase 82**: JOINIR_TARGETS テーブル SSOT 化93f51e40完了。
- selfhost 実行系・スクリプト側で `NYASH_JOINIR_CORE=1 NYASH_JOINIR_STRICT=1 NYASH_FAIL_FAST=1` を既定とし、 4. **Phase 81: selfhost 用 JoinIR Strictfail-fast の確立****完了**2025-12-02 a9e10d2a
代表パスskip_ws / trim / resolve / print_tokens / filter / Stage1/StageB 代表)が JoinIR 経由でのみ通ることを確認する。 - selfhost_build.sh に `--core` / `--strict` オプション追加。環境変数 `NYASH_JOINIR_CORE` / `NYASH_JOINIR_STRICT` を子プロセスに自動伝播。
- hack_check ラインは引き続き「Stage3 + 旧 MIR Builder + VM」の安定ルートとして維持し、Strict の影響を受けないようにしておく - 代表パスskip_ws / trim / resolve / print_tokens / filter / Stage1/StageB 代表)が JoinIR 経由でのみ通る Strict モード実装完了
5. **Phase 82-if-phi-retire: P3-C 完了if_phi.rs 削除** - hack_check ラインは引き続き「Stage3 + 旧 MIR Builder + VM」の安定ルートとして維持。
5. **Phase 82-if-phi-retire: P3-C 完了if_phi.rs 削除****次の焦点**
- P3-C 代表ケースを含む型決定を GenericTypeResolver で食い切り、`lifecycle.rs` から `infer_type_from_phi*` 呼び出しを排除する。 - P3-C 代表ケースを含む型決定を GenericTypeResolver で食い切り、`lifecycle.rs` から `infer_type_from_phi*` 呼び出しを排除する。
- `collect_assigned_vars_via_joinir` を JoinIR/AST 側の分析モジュールに移し、`phi_core::if_phi` への参照をゼロにした上で `if_phi.rs` を削除する。 - `collect_assigned_vars_via_joinir` を JoinIR/AST 側の分析モジュールに移し、`phi_core::if_phi` への参照をゼロにした上で `if_phi.rs` を削除する。
- 必要であれば、後続フェーズで hack_check 側も JoinIR/型ヒントラインに徐々に寄せていくただし現時点では「selfhost を先に Strict 化、hack_check は安定 VM ライン維持」を優先)。 - 必要であれば、後続フェーズで hack_check 側も JoinIR/型ヒントラインに徐々に寄せていくただし現時点では「selfhost を先に Strict 化、hack_check は安定 VM ライン維持」を優先)。
@ -181,6 +187,7 @@
- quick プロファイルで `stage1_launcher_*` / `phase251*` 系が Stage3 デフォルト環境で不安定。今後、quick では SKIP にするか、StageB emit 抽出ロジックを安定化するかを決める。 - quick プロファイルで `stage1_launcher_*` / `phase251*` 系が Stage3 デフォルト環境で不安定。今後、quick では SKIP にするか、StageB emit 抽出ロジックを安定化するかを決める。
- `MirFunction.blocks: HashMap``BTreeMap` で非決定的テスト解消 - `MirFunction.blocks: HashMap``BTreeMap` で非決定的テスト解消
- Phase 25.1 同様のパターン適用 - Phase 25.1 同様のパターン適用
- selfhost StageB 子プロセスへのソース渡し経路の簡素化(`--source "$SRC_CONTENT"` で argv を肥大化させず、HAKO_SRC 環境変数や一時ファイル経由に統一する設計を将来フェーズで検討)。
- Phase 71-SSA: StageB / selfhost ラインは「SSA デバッグ用の観測窓」として切り出し、 - Phase 71-SSA: StageB / selfhost ラインは「SSA デバッグ用の観測窓」として切り出し、
代表パスselfhost_build + stage1_run_min.hakoが JSON v0 emit まで通るかどうかを別フェーズで追う。 代表パスselfhost_build + stage1_run_min.hakoが JSON v0 emit まで通るかどうかを別フェーズで追う。
@ -198,6 +205,13 @@
あわせて `collect_assigned_vars_via_joinir` を JoinIR/AST 側の分析モジュールに移動し、 あわせて `collect_assigned_vars_via_joinir` を JoinIR/AST 側の分析モジュールに移動し、
`phi_core::if_phi` への実コードからの参照をゼロにした上で `if_phi.rs` 本体を削除する(歴史メモは docs 側にのみ保持)。 `phi_core::if_phi` への実コードからの参照をゼロにした上で `if_phi.rs` 本体を削除する(歴史メモは docs 側にのみ保持)。
- Phase 74-SSA-static-delegation将来フェーズ候補: Phase 71-SSA で判明した「static box 委譲時に ValueId マッピングが壊れる」
Rust MIR ビルダー側の根本バグを正式に修正するライン。
現 HEAD では `.hako` 層で ParserBox → ParserStringUtilsBox などの委譲を外すことで SSA undef は 13件→0件に根治しており、
最小 .hako ではバグを再現できないため、MIR Builder の修正は **再現用テストを用意できる将来フェーズに委譲**する。
当面は「box→static box への薄い委譲メソッドを増やさない」というコーディング規約で安全運用し、
Phase 74 では commit 13ce9e68 以前の形を元にした再現用テストMIR Builder 修正+委譲パターンの復活をまとめて扱う。
--- ---
## 3. 旧フェーズ(過去ログへのポインタ) ## 3. 旧フェーズ(過去ログへのポインタ)

View File

@ -0,0 +1,92 @@
// Phase 74-SSA: Enhanced reproduction - closer to ParserBox pattern
// Goal: Reproduce ValueId undef with more realistic conditions
//
// Added features:
// 1. State fields (like ParserBox.gpos, usings_json)
// 2. using statement (like ParserBox uses sh_core)
// 3. Multiple methods (not just one delegation)
// 4. Method with loop (like ParserBox.trim)
static box TargetBox {
is_digit(ch) {
if ch >= "0" && ch <= "9" { return 1 }
return 0
}
skip_ws(str, i) {
local n = str.length()
loop(i < n) {
local ch = str.substring(i, i + 1)
if ch == " " || ch == "\t" || ch == "\n" { i = i + 1 } else { break }
}
return i
}
trim(s) {
if s == null { return "" }
local str = "" + s
local n = str.length()
local b = TargetBox.skip_ws(str, 0)
if b >= n { return "" }
local e = n
loop(e > b) {
local ch = str.substring(e - 1, e)
if ch == " " || ch == "\t" { e = e - 1 } else { break }
}
if e > b { return str.substring(b, e) }
return ""
}
}
box DelegateBox {
// State fields (like ParserBox)
gpos
data
birth() {
me.gpos = 0
me.data = ""
return 0
}
// Method with loop + delegation (like ParserBox.trim)
trim(s) {
// Phase 74-SSA: This delegation pattern should cause SSA undef
return TargetBox.trim(s)
}
// Simple delegation (like ParserBox.is_digit)
is_digit(ch) {
return TargetBox.is_digit(ch)
}
// Method that uses state + delegation
process(text) {
local t = me.trim(text)
me.data = t
return t
}
}
box Main {
main() {
local delegate = new DelegateBox()
// Test delegation through instance
local text = " hello "
local trimmed = delegate.trim(text)
// Test is_digit delegation
local ch = "7"
local d = delegate.is_digit(ch)
// Test combined (state + delegation)
local result = delegate.process(" world ")
// Use results to avoid dead code elimination
if trimmed.length() > 0 && d == 1 && result.length() > 0 {
return 0
}
return 1
}
}

View File

@ -0,0 +1,105 @@
// Phase 74-SSA: Critical reproduction - box delegates to static box AND calls via me.method()
// Goal: Reproduce ValueId undef with the EXACT pattern from ParserBox
//
// Critical pattern found:
// - ParserBox had: me.to_int() → calls ParserBox.to_int() → delegates to ParserStringUtilsBox.to_int()
// - This is: instance call → instance method → static box delegation
//
// This is the key difference from the original minimal code!
static box TargetBox {
is_digit(ch) {
if ch >= "0" && ch <= "9" { return 1 }
return 0
}
to_int(s) {
if s == null { return 0 }
local str = "" + s
local n = str.length()
if n == 0 { return 0 }
local i = 0
local acc = 0
loop(i < n) {
local ch = str.substring(i, i + 1)
if ch < "0" || ch > "9" { break }
acc = acc * 10 + ("0123456789".indexOf(ch))
i = i + 1
}
return acc
}
trim(s) {
if s == null { return "" }
local str = "" + s
return str
}
}
box DelegateBox {
gpos
birth() {
me.gpos = 0
return 0
}
// Phase 74-SSA: These delegation methods should cause SSA undef when called via me.method()
is_digit(ch) {
return TargetBox.is_digit(ch)
}
to_int(s) {
return TargetBox.to_int(s)
}
trim(s) {
return TargetBox.trim(s)
}
// Method that calls me.to_int() - THIS IS THE CRITICAL PATTERN
parse_number(text) {
local pos = text.lastIndexOf("@")
if pos >= 0 {
local num_str = text.substring(pos + 1, text.length())
// 🔥 THIS IS IT: me.to_int() calls the delegation method
local num = me.to_int(num_str)
me.gpos = num
return num
}
return 0
}
// Another method calling me.is_digit() via me
check_char(ch) {
// 🔥 me.is_digit() → ParserBox pattern
return me.is_digit(ch)
}
// Method calling me.trim()
clean_text(text) {
// 🔥 me.trim() → ParserBox pattern
return me.trim(text)
}
}
box Main {
main() {
local delegate = new DelegateBox()
// Test parse_number (me.to_int delegation)
local num = delegate.parse_number("data@42")
// Test check_char (me.is_digit delegation)
local d = delegate.check_char("7")
// Test clean_text (me.trim delegation)
local text = delegate.clean_text(" hello ")
// Use results to avoid dead code elimination
if num == 42 && d == 1 && text.length() > 0 {
return 0
}
return 1
}
}

View File

@ -14,7 +14,7 @@ fi
export NYASH_LLVM_USE_HARNESS=1 export NYASH_LLVM_USE_HARNESS=1
# Accept Stage-3 surface in Rust parser for these inputs # Accept Stage-3 surface in Rust parser for these inputs
export NYASH_PARSER_STAGE3=1 export NYASH_FEATURES=stage3
# Lower try/throw using Result-style structured blocks (MVP path) # Lower try/throw using Result-style structured blocks (MVP path)
export NYASH_TRY_RESULT_MODE=1 export NYASH_TRY_RESULT_MODE=1

View File

@ -34,7 +34,7 @@ HCODE
export HAKO_FAIL_FAST_ON_HAKO_IN_NYASH_VM=0 export HAKO_FAIL_FAST_ON_HAKO_IN_NYASH_VM=0
export NYASH_DISABLE_NY_COMPILER=1 export NYASH_DISABLE_NY_COMPILER=1
export NYASH_FEATURES="${NYASH_FEATURES:-stage3}" export NYASH_FEATURES="${NYASH_FEATURES:-stage3}"
export HAKO_PARSER_STAGE3=1 export NYASH_FEATURES=stage3
export NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1 export NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1
export NYASH_ENABLE_USING=1 export NYASH_ENABLE_USING=1
export HAKO_ENABLE_USING=1 export HAKO_ENABLE_USING=1

View File

@ -25,7 +25,7 @@ HCODE
export HAKO_FAIL_FAST_ON_HAKO_IN_NYASH_VM=0 export HAKO_FAIL_FAST_ON_HAKO_IN_NYASH_VM=0
export NYASH_DISABLE_NY_COMPILER=1 export NYASH_DISABLE_NY_COMPILER=1
export NYASH_FEATURES="${NYASH_FEATURES:-stage3}" export NYASH_FEATURES="${NYASH_FEATURES:-stage3}"
export HAKO_PARSER_STAGE3=1 export NYASH_FEATURES=stage3
export NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1 export NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1
export NYASH_ENABLE_USING=1 export NYASH_ENABLE_USING=1
export HAKO_ENABLE_USING=1 export HAKO_ENABLE_USING=1

View File

@ -22,7 +22,7 @@ echo ""
# LoopSSA v2 の EXIT PHI を有効化して実行BreakFinder/PhiInjector 経由) # LoopSSA v2 の EXIT PHI を有効化して実行BreakFinder/PhiInjector 経由)
HAKO_LOOPSSA_EXIT_PHI=1 \ HAKO_LOOPSSA_EXIT_PHI=1 \
NYASH_DISABLE_PLUGINS=1 NYASH_PARSER_STAGE3=1 \ NYASH_DISABLE_PLUGINS=1 NYASH_FEATURES=stage3 \
"$NYASH_BIN" --backend vm "$TEST_FILE" 2>&1 "$NYASH_BIN" --backend vm "$TEST_FILE" 2>&1
echo "" echo ""

View File

@ -20,7 +20,7 @@ echo ""
# LoopSSA v2 の EXIT PHI を有効化して実行BreakFinder/PhiInjector 経由) # LoopSSA v2 の EXIT PHI を有効化して実行BreakFinder/PhiInjector 経由)
HAKO_LOOPSSA_EXIT_PHI=1 \ HAKO_LOOPSSA_EXIT_PHI=1 \
NYASH_DISABLE_PLUGINS=1 NYASH_PARSER_STAGE3=1 \ NYASH_DISABLE_PLUGINS=1 NYASH_FEATURES=stage3 \
"$NYASH_BIN" --backend vm "$TEST_FILE" 2>&1 "$NYASH_BIN" --backend vm "$TEST_FILE" 2>&1
echo "" echo ""

View File

@ -22,7 +22,7 @@ echo ""
# Test 1: Direct VM execution (should work) # Test 1: Direct VM execution (should work)
echo "--- Test 1: Direct VM execution ---" echo "--- Test 1: Direct VM execution ---"
NYASH_DISABLE_PLUGINS=1 NYASH_PARSER_STAGE3=1 \ NYASH_DISABLE_PLUGINS=1 NYASH_FEATURES=stage3 \
"$NYASH_BIN" --backend vm "$TEST_FILE" 2>&1 | tail -10 "$NYASH_BIN" --backend vm "$TEST_FILE" 2>&1 | tail -10
echo "" echo ""
@ -31,7 +31,7 @@ echo "--- Test 2: Stage-B compilation ---"
NYASH_JSON_ONLY=1 \ NYASH_JSON_ONLY=1 \
NYASH_DISABLE_NY_COMPILER=1 HAKO_DISABLE_NY_COMPILER=1 \ NYASH_DISABLE_NY_COMPILER=1 HAKO_DISABLE_NY_COMPILER=1 \
HAKO_STAGEB_FUNC_SCAN=1 \ HAKO_STAGEB_FUNC_SCAN=1 \
NYASH_PARSER_STAGE3=1 HAKO_PARSER_STAGE3=1 \ NYASH_FEATURES=stage3 NYASH_FEATURES=stage3 \
NYASH_PARSER_ALLOW_SEMICOLON=1 \ NYASH_PARSER_ALLOW_SEMICOLON=1 \
NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 \ NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 \
HAKO_LOOPSSA_EXIT_PHI="$HAKO_LOOPSSA_EXIT_PHI" \ HAKO_LOOPSSA_EXIT_PHI="$HAKO_LOOPSSA_EXIT_PHI" \
@ -44,7 +44,7 @@ echo ""
# Test 3: MIR verification (check for SSA errors) # Test 3: MIR verification (check for SSA errors)
echo "--- Test 3: MIR verification ---" echo "--- Test 3: MIR verification ---"
NYASH_VM_VERIFY_MIR=1 \ NYASH_VM_VERIFY_MIR=1 \
NYASH_DISABLE_PLUGINS=1 NYASH_PARSER_STAGE3=1 \ NYASH_DISABLE_PLUGINS=1 NYASH_FEATURES=stage3 \
"$NYASH_BIN" --backend vm "$TEST_FILE" 2>&1 | \ "$NYASH_BIN" --backend vm "$TEST_FILE" 2>&1 | \
grep -E "(Undefined|verification|✅)" || echo "No verification errors (good!)" grep -E "(Undefined|verification|✅)" || echo "No verification errors (good!)"
echo "" echo ""