phase-20.39 step1: introduce typed IR shadow in hv1 dispatcher; step2: remove hv1 include fallback from verify (direct route only); add IR types module export; docs+current_task updated

This commit is contained in:
nyash-codex
2025-11-04 16:45:01 +09:00
parent 30aa39f50b
commit ab81564174
14 changed files with 327 additions and 5368 deletions

View File

@ -1,103 +0,0 @@
# Codex向け質問 - Phase 15.5後のテスト戦略
## 📋 背景
Phase 15.5でCore Box完全削除を実施し、すべてのBoxをプラグイン化しました。その結果
- ✅ nyash.tomlのパス修正完了13箇所
- ✅ プラグインは正常にロード(.soファイル20個存在
- ✅ 基本的な算術演算・制御構文は動作
- ❌ StringBox/IntegerBoxのメソッドが動作しない
## 🔍 現在の問題
### StringBoxプラグインの状況
```nyash
local s = new StringBox("Hello") # ← オブジェクト生成OKハンドル返却
print(s) # ← 空文字列toString失敗
s.length() # ← 0を返す内部データなし
s.toString() # ← 空文字列を返す
s.get() # ← 空文字列を返す
```
### 調査済み事項
1. プラグインは正常にロードplugin-testerで確認
2. nyash_plugin_invokeは実装済みlegacy v1 ABI
3. method_id衝突を修正済み0-3 → 4+に変更)
4. 通常の文字列リテラルは動作する
5. 算術演算は問題なし
### 🔬 根本原因Codex調査結果
**TypeBox v2のresolveブランチが欠落している**
- `birth`メソッドの解決パスが未実装
- `toString`メソッドの解決パスが未実装
- プラグインメソッドは呼ばれるが、結果の処理に問題
## 🎯 質問
### 1. **StringBoxメソッドが動作しない原因は**
Phase 15.5でCore Boxを削除した影響で、プラグイン側の実装が不完全な可能性があります。
- プラグインのnyash_plugin_invoke実装を確認すべき箇所は
- MIRビルダー側でプラグインメソッド呼び出しに特別な処理が必要
### 2. **テスト戦略の方向性**
現状でStringBox/IntegerBoxが動作しない中で
- A案: プラグインメソッド修正を優先
- B案: 基本機能(算術・制御)のテストを先に充実
- C案: 別のBoxプラグインFileBox等でテスト
どの方向性が効率的でしょうか?
### 3. **プラグインメソッド呼び出しのデバッグ方法**
```bash
# 現在の確認方法
./tools/plugin-tester/target/release/plugin-tester check --config nyash.toml
# → プラグインロードはOK、でもメソッド実行時に問題
# より詳細なデバッグ方法は?
```
## 🔄 再現手順
### 最小再現コード
```bash
# test_stringbox.nyash
local s = new StringBox("Hello World")
print("StringBox created")
print(s) # 期待: "Hello World", 実際: ""
local len = s.length()
print("Length: " + len) # 期待: 11, 実際: 0
```
### 実行コマンド
```bash
# プラグインロード確認
./tools/plugin-tester/target/release/plugin-tester check --config nyash.toml
# テスト実行
NYASH_ENTRY_ALLOW_TOPLEVEL_MAIN=1 ./target/release/nyash test_stringbox.nyash
```
### デバッグ情報収集
```bash
# 詳細ログ
NYASH_CLI_VERBOSE=1 ./target/release/nyash test_stringbox.nyash
# MIRダンプ確認
./target/release/nyash --dump-mir test_stringbox.nyash
```
## 📁 関連ファイル
- `nyash.toml` - プラグイン設定method_id修正済み
- `plugins/nyash-string-plugin/src/lib.rs` - StringBoxプラグイン実装
- `tools/smokes/v2/` - 新スモークテストシステム
- `src/box_factory/plugin.rs` - プラグインロード実装
- `src/mir/builder/builder_calls.rs` - TypeBox v2 resolve実装問題箇所
## 🚀 期待する回答
1. StringBoxメソッドが動作しない根本原因の特定方法
2. 効率的なテスト戦略の提案
3. プラグインメソッド呼び出しのデバッグ手法
よろしくお願いします!

View File

@ -1,18 +1,18 @@
# Current Task — Phase 20.38 (Extern/CABI bringup, Hakofirst verify) # Current Task — Phase 20.39 (Typed IR & hv1 finalize)
This document is intentionally concise (≤ 500 lines). Detailed history and perphase plans are kept under docs/private/roadmap/. See links below. This document is intentionally concise (≤ 500 lines). Detailed history and perphase plans are kept under docs/private/roadmap/. See links below.
Focus (now) Focus (now)
- Extern/CABI の最小導線既定OFFを整備し、Hakorune primary で emit/codegen を rc=0 安定タグに固定 - Typed IRSSOTの導入: V1ConstIR / V1CompareIR / V1BranchIR / V1JumpIR / V1PhiIR / V1RetIR を Hako で定義(挙動不変)
- v1 Dispatcher を IR 反復に切替scan 依存を排除、φテーブル適用の堅牢化strict/tolerate - hv1 verify の最終化: 直行env JSON→Core 実行)を標準にし、-c/inline 経路・include フォールバックを撤去
- Verify 既定を v1→HakoCore fallbackへ整流段階)。 - Concat-safety sweep: “"" + <Box>” を全廃(必要時のみ to-string)。
- Using はテキスト統合merge_prelude_textに一本化、include は quick=ERRORハーネス方針と整合)。 - LoopForm.build2 の適用拡大(既存 PASS を崩さず小粒に)。
- 拡張子ポリシー(暫定): `.nyash`→Nyash VM、`.hako`→Hakorune VM。詳細は docs/guides/source-extensions.md。
Remaining (20.38inline alias stabilization: updated) Remaining (20.39typed IR & finalize)
- Route: vm.rs に hv1 直行ルートを追加HAKO_ROUTE_HAKOVM=1 かつ NYASH_VERIFY_JSON。NyashParser を完全にバイパス - Add typed IR boxes and module exporthakorune-vm.ir.types
- Alias only: verify は alias のみで安定include/preinclude は撤去・既定OFF)。 - Wire dispatcher to accept typed IR inputs gradually写像ヘルパ・差分ゼロ)。
- Safety sweep: “"" + <Box>” の連結全廃(必要時のみ to-string)。 - Remove include fallback from scripts直行のみ)。
- Sweep concatenations and update helpers.
Hotfix Plan — Using/Prelude Unification (SelfHost) Hotfix Plan — Using/Prelude Unification (SelfHost)
- Problem: .hako を NyashParser に通す経路でパース落ちInvalid expression - Problem: .hako を NyashParser に通す経路でパース落ちInvalid expression
@ -45,10 +45,8 @@ Acceptance
- Hako 構文を Nyash VM で実行しようとした場合、入口で FailFast診断メッセージ - Hako 構文を Nyash VM で実行しようとした場合、入口で FailFast診断メッセージ
Changes (this step) Changes (this step)
- hv1 直行: vm.rs 冒頭で `NYASH_VERIFY_JSON` を検出し、JSON v1/v0→MIR→Core 実行(数値のみ出力)。 - Docs: phase20.39 に計画を追記Tasks/Acceptance/Plan)。
- test_runner: hv1 verify は直行(`$NYASH_BIN --backend vm /dev/null`env JSON。include fallback は dev 変数で明示時のみ - Add typed IR box filehakorune-vm.ir.typesと module export構造のみ・参照用
- v1 JSON Bridge: φ incoming を [pred,val] として正規化Core parity
- φ カナリー追加: multi-incoming3 / nested+sum / tolerate undefined→rc=0。
- V1PhiAdapterBox: robust incoming scan (multipair, spaces/newlines) using arrayend scanner. - V1PhiAdapterBox: robust incoming scan (multipair, spaces/newlines) using arrayend scanner.
- V1SchemaBox: new block_segment_wo_phi(json, bid) to build IR segment without φ. - V1SchemaBox: new block_segment_wo_phi(json, bid) to build IR segment without φ.
- V1SchemaBox: phi_table_for_block(json,bid) 追加dst と incoming[[pred,val],…] を返す) - V1SchemaBox: phi_table_for_block(json,bid) 追加dst と incoming[[pred,val],…] を返す)

File diff suppressed because it is too large Load Diff

View File

@ -1,955 +0,0 @@
# Restart Notes — Ny Syntax Alignment (20250907)
目的
- SelfHosting 方針Nyのみで工具を回す前段に合わせて、Ny 構文とコーディング規約を明示化し、最小版ツールの完走性を優先。
Ny 構文(実装時の基準)
- 1行1文セミコロン非使用。
- break / continue を使わない(関数早期 return、番兵条件、if 包みで置換)。
- else は直前の閉じ波括弧と同一行(`} else {`})。
- 文字列の `"``\` は確実にエスケープ。
- 反復は `loop(条件) { …; インクリメント }` を基本とし、必要に応じて「関数早期 return」型で早期脱出。
短期タスクSyntax 合意前提で最小ゴール)
1) include のみ依存木Nyのみ・配列/マップ未使用)を完走化
- `apps/selfhost/tools/dep_tree_min_string.nyash`
- FileBox/PathBox + 文字走査のみで JSON 構築(配列/マップに頼らない)
- `make dep-tree``tmp/deps.json` を出力
2) using/module 対応は次段(構文・優先順位をユーザーと再すり合わせ後)
- 優先: `module > 相対 > using-path`、曖昧=エラー、STRICT ゲート(要相談)
3) ブリッジ Stage 1 は保留
- `NYASH_DEPS_JSON=<path>` 読み込みログ出力のみを最小パッチで用意MIR/JIT/AOT は不変)
備考
- Cranelift 側の作業は別ブランチで継続。SelfHosting ブランチは Ny 工具の安定化に集中。
- 構文の最終合意後、using/module 版(配列/マップ最小 APIへ拡張。
## Grammar Sync — Phase 12.7 合わせ(現状と方針)
参照ドキュメント(一次ソース)
- Phase 12.7 統合: `docs/development/roadmap/phases/phase-12.7/README.md`
- Grammar 最終決定: `docs/development/roadmap/phases/phase-12.7/grammar-specs/grammar-reform-final-decision.txt`
- Grammar 技術仕様: `docs/development/roadmap/phases/phase-12.7/grammar-specs/grammar-technical-spec.txt`
- 実装チェックリスト: `docs/development/roadmap/phases/phase-12.7/implementation/implementation-final-checklist.txt`
- ANCP Token Spec (参照): `docs/development/roadmap/phases/phase-12.7/ancp-specs/ANCP-Token-Specification-v1.md`
実装状況Phase 12.7 との整合)
- OK: `peek`else必須・ブロック可`continue``birth` 統一、`fn{}` ラムダP0、糖衣 basic`|>`, `?.`, `??`, `+=/-=/*=/=`, `..`)ゲート済。
- OK: `Parent::method``::` トークン+ `Parent::method(args)` 解析P1相当の先行
- OK: フィールド宣言 `name: Type` を受理P0: 型はパースのみ、意味付けは今後)。
- 差分(非致命):
- import 未実装(現状は `using` のみ Phase0: `nyashstd` 制限)。
- `public name: Type` の単行は未対応(`public { ... }` ブロックは対応)。
- レガシー `>>`ARROWトークンとASTが残存12.7 では不要)。
- Tokenizer に `fn` の重複割り当て(`FN`/`FUNCTION`)が存在(動作は壊していないが整理対象)。
合意に向けた軽微タスクSelfHosting 主線を維持したまま)
- T1: `public name: Type` 単行を Box 内で受理(`public { ... }` は後方互換維持)。
- T2: `import` を追加(現状 `using` と並行運用、Phase0は読み取りのみ将来の解決器に接続
- T3: 12.7 厳格モードゲート(例: `NYASH_STRICT_12_7=1`
- `>>` を無効化(パーサ拒否 or トークナイズ抑止)。
- 追加キーワード群legacy拡張の一部を“識別子扱い”へフォールバック実験用
- T4: Tokenizer の `fn` 重複を解消(`FN` を正とし `FUNCTION` 二重割り当てを削除)。
受け入れ基準Grammar Sync
- sugar_level=none/basic の双方でスモークが通る。
- `peek` else 未指定時に適切なエラー(現状維持)。
- `public name: Type` が Box 内でフィールドとして扱われる最小P0
- 厳格モードで `>>` が受理されない/互換モードでは現状維持。
検証コマンド(例)
- `NYASH_SYNTAX_SUGAR_LEVEL=none cargo test -p nyash_self_main -- tests::sugar_basic_test -- --nocapture`none でも tokenizer/parseは通ること
- `NYASH_SYNTAX_SUGAR_LEVEL=basic cargo test -p nyash_self_main -- tests::sugar_pipeline_test -- --nocapture`
- `NYASH_STRICT_12_7=1 ./target/release/nyash --backend vm apps/smokes/grammar/peek_basic.nyash``>>` を含むコードが拒否される)
## Bitwise/Shift — main 取り込みと現状
- origin/main でビット演算(&, |, ^, <<, >>)が Grammar/Tokenizer/AST/MIR に統合済み。レガシー `>>` ARROW は撤退。
- 追加テストmain
- `src/tests/parser_bitops_test.rs`(代表式 `1 + 2 << 3 & 7` の構文)
- `src/tests/vm_bitops_test.rs``(5&3)+(5|2)+(5^1)+(1<<5)+(32>>3) == 48``1<<100` マスク確認)
- 確認結果(ローカル):
- MIR バックエンドは 48 で合格OK
- VM バックエンドは現状 `Unsupported integer operation: BitAnd`VM 側の実装が未導入のため)
取り込み計画selfhosting-dev に main を統合)
1) ローカル変更を一時退避stashし、`origin/main` をマージ。
2) コンフリクト解消:`src/jit/lower/builder/cranelift.rs` は main 側の更新ARROW撤退/SHR採用を優先。
3) 検証MIR 経路で bitops スモーク(期待 48
4) 次段VM の bitopsi64限定、シフトは `rhs&63` マスク)を実装→テスト有効化。
5) LLVM/E2Egrammar 解禁後に `apps/tests/ny-llvm-bitops/` を有効化MIR直構築は現状担保
実行メモ(代表)
- MIR スモーク: `printf "return (5 & 3) + (5 | 2) + (5 ^ 1) + (1 << 5) + (32 >> 3)\n" > tmp/bitops_smoke.nyash && ./target/debug/nyash --backend mir tmp/bitops_smoke.nyash``Result: 48`
- VM は現状未対応(実装後に同式で確認)。
TODObitops
- [ ] origin/main を selfhosting-dev にマージconflict 解消)。
- [ ] MIR 経路のスモーク確認48
- [ ] VM: i64 の `& | ^ << >>` 実装(`rhs&63` マスク)。
- [ ] tests: `vm_bitops_test.rs` を有効化VM で合格)。
- [ ] docs: ARROW(>>) 撤退と `|>` への一本化を明記。
## SelfHost — Includeonly Dependency TreePhase 0
スコープPhase 0 最小)
- NyのみArray/Map不使用で include 依存木を構築し、純JSONを出力。
- using/module/import は次段。Runner は `NYASH_DEPS_JSON` をログ読み込みのみ。
現状
- ツール: `apps/selfhost/tools/dep_tree_min_string.nyash`include専用、再帰・文字列走査
- 出力: `make dep-tree``tmp/deps.json`純JSON化、先頭ログの除去は `[tasks].dep_tree` で吸収)。
- 走査: コメント(`//`, `#`)・文字列内の `include` を無視する状態機械を導入(誤検出抑制)。
- サンプル: `apps/selfhost/smokes/dep_smoke_root.nyash`(子: `dep_smoke_child.nyash`)。
出力仕様・受け入れ基準: docs/development/current/selfhost/dep_tree_min_string.md に移設CURRENT_TASKは要点のみ表記
残タスクPhase 0 必須)
- P0-2: スモーク(循環あり/なし)と合わせて確認(追加済み)。
- P0-3: docs への移設(完了)。
任意Phase 0.5
- stderr固定の徹底将来Runner側の冗長出力をenvゲート化
- ルートパスの正規化(`.`,`..` の整理)と最大深さ/件数の安全弁(オプション)。
検証(代表)
- `echo apps/selfhost/smokes/dep_smoke_root.nyash | ./target/release/nyash --backend vm apps/selfhost/tools/dep_tree_min_string.nyash`
- `echo apps/selfhost/smokes/dep_smoke_cycle_a.nyash | ./target/release/nyash --backend vm apps/selfhost/tools/dep_tree_min_string.nyash`
- `make dep-tree`ENTRYは標準入力1行 or 既定パスにフォールバック)
# Quick Plan — SelfHost (Restart Safe)
- Goals: Ny-only dependency tree (include → later using/module), JSON out; simple file-bridge to existing MIR→VM→AOT without tight coupling.
- Deliverables:
- Minimal tool: `apps/selfhost/tools/dep_tree_min_string.nyash` (include-only, recursion via FileBox/PathBox, no Array/Map)
- Full tool: `apps/selfhost/tools/dep_tree_simple.nyash` (include + using/module, strict/explicit resolution)
- Task/Make: `nyash.toml [tasks].dep_tree` and `make dep-tree` (outputs `tmp/deps.json`)
- Bridge Stage 1: Runner reads `NYASH_DEPS_JSON=<path>` and logs (no behavior change)
- Order:
1) Finish include-only tool to completion (Ny-only, strict 1statement lines)
2) Harden full tool (using/module, module > relative > using-path, ambiguous=error, STRICT gate)
3) Add Runner hook for `NYASH_DEPS_JSON` (log only)
- Quick run:
- `make dep-tree` → writes `tmp/deps.json`
- `./target/release/nyash --run-task dep_tree`
# CURRENT TASK (Compact) — Phase 15 / Self-HostingNy→MIR→MIR-Interp→VM 先行)
このドキュメントは「いま何をすれば良いか」を最小で共有するためのコンパクト版です。詳細は git 履歴と `docs/`phase-15を参照してください。
— 最終更新: 20250908 (LLVM Core13 安定化 P0 進捗更新)
【Quick Update — LLVM Core13 P0】
現状
- ビルド環境は LLVM 18 検出済み(`LLVM_SYS_180_PREFIX=/usr/lib/llvm-18`)。
- 代表的なビルドエラーは次の3点に収束。
1) Opaque Pointer 由来: `PointerType::get_element_type()` 不在 → i8* 判別経路をヒューリスティックに簡素化。
2) IntegerBox API: `.value()` 誤用 → `.value` に修正(フィールド参照)。
3) BinaryOp 網羅: BitAnd/BitOr/BitXor/Shl/Shr 未対応 → いったん `_ => todo!()` で回避。
対応済み
- `src/backend/llvm/compiler.rs`
- `env.box.new` の opaque 対応i8* は `nyash.box.from_i8_string` を呼ぶ単純化)。
- `.value()``.value` を修正BinOpパス
- 末尾 mock BinOp に `_ => todo!()` を追加。
残タスクP0完了条件
- `env.box.new`new_i64x 側)の引数 i64 化クロージャを完全インライン化lifetime エラー解消)。
- BinOp 未網羅の match 箇所をもう1か所整理`_ => todo!()` か軽実装)。
- 再ビルド通過後、代表スモークの一致確認。
代表スモーク
- ビルド: `LLVM_SYS_180_PREFIX=$(llvm-config-18 --prefix) cargo build --release --features llvm`
- 実行: `tools/build_llvm.sh apps/tests/mir-compare-multi/main.nyash -o app && ./app`
- 受け入れ: VM と同一の戻り値Core13 正規化パスに依存:`NYASH_MIR_CORE13=1` 既定ON
メモ
- 作業ディレクトリ: `/mnt/c/git/nyash-project/nyash_llvm`branch: `llvm-dev`
- 次の commit で P0 を締め、P1ビット演算/Shift 実装)に移行する。
【Phase 17.1 — LLVM Core13 安定化専用worktree/branch
目的
- Core13 正規化後の MIR を LLVM AOT に下ろし、VM と同値の代表ケースを安定動作させる。
作業環境
- worktree: /mnt/c/git/nyash-project/nyash_llvm branch: llvm-dev, origin/llvm-dev 追従)
- LLVM 18 前提: `LLVM_SYS_180_PREFIX=$(llvm-config-18 --prefix)`
短期タスクP0
- Opaque Pointer 対応: Inkwell 0.6 + LLVM 18 に合わせ、`get_element_type()` 等を使用しない降ろしに修正。
- `env.box.new` の引数ハンドリングをヒューリスティックに単純化i8* は `nyash.box.from_i8_string`
- IntegerBox API 整合: `.value()``.value` に是正(フィールド参照)。
- BinaryOp の網羅性: `BitAnd/BitOr/BitXor/Shl/Shr` 未対応を `_ => todo!()` で一旦回避(代表スモーク優先)。
検証P0
- ビルド: `LLVM_SYS_180_PREFIX=$(llvm-config-18 --prefix) cargo build --release --features llvm`
- 代表スモーク: `tools/build_llvm.sh apps/tests/mir-compare-multi/main.nyash -o app && ./app`VM一致
後続P1
- ビット演算/シフトの実装と検証LLVM 降ろし/IR 生成/実行互換)。
- AOT 実行の戻り値と型変換経路の整理i64/handle→Box materialize
【ハンドオフ20250906 final— String.length 修正 完了JIT 実行を封印し四体制へ】
概要
- 目的: AOT/JITAOT で発生していた `StringBox.length/len` が 0 になる不具合の是正Lower の二段フォールバック:`nyash.string.len_h``nyash.any.length_h`)。
- 結果: 当該不具合は修正・確認完了AOT/VM で期待値。JIT 直実行の継続調査は打ち切り、実行モードは「インタープリターVMCranelift(EXE)LLVM(EXE)」の4体制へ移行。
【Phase 15.17 追記 — Core13 純化モード 実装/稼働・AOT shim 拡張】
概要
- Core13 純化モード(厳格)を導入: `NYASH_MIR_CORE13_PURE=1`
- Builder 段: `new``ExternCall(env.box.new, [type, …args])` を直接生成(`NewBox/birth` 非生成)
- Unary(/!/~): 直接展開(`Const+BinOp/Compare`
- WeakRef(weak_new/load): 純化ONでは生成回避パススルー
- Optimizer 安全網: Load/Store→`env.local.get/set` 変換、最終MIRで13命令以外はエラー
- 実行系:
- VM: `env.local.get/set``env.box.new` を実装BoxFactoryRegistry 連動)
- LLVM AOT: `env.local.get/set` の Lowering と `env.box.new` shim を追加
- NyRT 追加: `nyash.env.box.new` / `nyash.env.box.new_i64x` (最大4引数)
- NyRT 追加: `nyash.box.from_i8_string`i8*→StringBox`nyash.box.from_f64`f64→FloatBox
- Lowering: 引数を i64 ハンドルに正規化int/ptr→i64、i8*→from_i8_string、f64→from_f64
- Cranelift (スケルトン): `env.local.get/set` / `env.box.new` を実行ループに最小実装将来のAOT出力の布石
検証
- `cargo test`: 206 passed / 0 failed / 24 ignored通常
- 純化ON選択的 skip あり): グリーン。`src/tests/mir_pure_envbox.rs` 追加で `env.box.new` 生成を検証
実装(済)
- LowerCore: 二段フォールバック実装を追加Param/Local/リテラル)。
- `emit_len_with_fallback_param`/`_local_handle`/`_literal`
- `core.rs``len/length` で二段フォールバックを使用。結果をローカルスロットへ保存Return で拾えるように)
- BoxCall 共通ops_ext:
- StringBox の `len/length` を最優先で処理Param/Local/リテラル/handle.of
- リテラル `new StringBox("...")``length` は即値畳み込みconst 返却)。
- Hostcall registry 追補: `nyash.string.len_h` を ReadOnly 登録 + 署名 `(Handle)->I64` 追加。
- JIT ブリッジ: `extern_thunks.rs``nyash_string_len_h` を追加、`cranelift` ビルダーに `SYM_STRING_LEN_H` を登録。
- ポリシー: `StringBox.length/len` マッピングを `nyash.any.length_h``nyash.string.len_h` に是正。
- デッドコード整理: 旧 `lower_boxcall_simple_reads` を削除conflict 回避)。
- ツール/スモーク: `tools/aot_smoke_cranelift.sh` 追加、`apps/smokes/jit_aot_string_length_smoke.nyash` 追加。
— 15.17 追加 実装(済)
- Core13 純化モード: `NYASH_MIR_CORE13_PURE=1`Builder/Optimizer/Verifier 連携)
- VM: `env.local.get/set`, `env.box.new` を実装
- LLVM AOT: `env.box.new` shimnew/new_i64x+ 引数 i8*/f64 のハンドル化 helper 追加
- Cranelift: ExternCall の最小実装get/set/newを追加スケルトン
- テスト: `src/tests/mir_pure_envbox.rs` 追加(純化 new→env.box.new の生成確認)
- テスト: `src/tests/mir_pure_e2e_vm.rs` 追加純化ONで VM 実行: new StringBox + length の e2e
- テスト: `src/tests/mir_pure_locals_normalized.rs` 追加locals が env.local.get/set に正規化されることを確認)
- テスト: `src/tests/mir_pure_llvm_build.rs` 追加feature=llvm 時に純化ONで .o を正常生成できることを確認。実行の同値性はAOT実装拡張後に別途追加予定
- テスト: `src/tests/mir_pure_e2e_arith.rs` 追加純化×VMで加算の e2e
- テスト: `src/tests/mir_pure_e2e_branch.rs` 追加純化×VMで条件分岐の e2e
- テスト: `src/tests/mir_pure_only_core13.rs` 追加最終MIRが13命令のみで構成されることを静的検査
- CI: Core13 純化(LLVM) ワークフロー追加(`.github/workflows/core13-pure-llvm.yml`。LLVM 18 をセットアップし、`--features llvm` で純化ONテストを実行。
- CI: Core13 純化モード専用ワークフローを追加(`.github/workflows/core13-pure.yml`)。`NYASH_MIR_CORE13_PURE=1 cargo test --all-targets` を実行。
確認状況(最終)
- `apps/smokes/jit_aot_string_min.nyash`concat/eq: AOT で `Result: 1`OK
- `apps/smokes/jit_aot_string_length_smoke.nyash`: AOT .o 生成/リンク・実行とも良好(稀発の segfault 調査は「低優先」に移行)。
- `apps/smokes/jit_aot_any_len_string.nyash`: AOT で `Result` が期待値0 問題は解消)。
- 備考: JIT 直実行の既知の不安定性は、JIT 実行封印に伴い調査終了とする(アーカイブ扱い)。
残課題(方針更新後)
P0: 実行モード整理JIT 実行封印)
- ランタイム実行は「InterpreterVM」に限定。ネイティブ配布は「Cranelift AOT(EXE)LLVM AOT(EXE)」。JIT 関連のランタイムフラグ説明は docs で封印明記。
P1: AOT 安定化(低頻度 segfault の追跡:低優先)
- 稀な DT_TEXTREL 警告・segfault は PIE/LTO/relro/TLS/extern 登録順の再確認を残課題として維持(優先度は下げる)。
P2: リファクタPhase A継続振る舞い不変
- Hostcall シンボル `SYM_*` 統一、`core/string_len.rs` への集約、観測フックの整理は継続。JIT 実行依存の観測は停め、VM/AOT 観測を優先。
P3: Core13 純化 仕上げ(今回の続き)
- Cranelift AOT: 実オブジェクト出力で `env.local/env.box` のシンボル連携(現状は実行スケルトンのみ)
- LLVM AOT: `env.box.new_i64x` の引数拡張(>4, TLV支援と型復元の精度UP文字列/浮動/配列 等)
- Builder 純化の徹底: Load/Store/WeakRef を完全非生成(全経路点検)
- E2E 純化スモーク: `apps/smokes_pure13/` を追加VM/LLVM EXE の結果一致)
- CI: 純化ON ジョブを常時実行最終MIR 13命令チェック含む
進捗20250906 終了報告)
- ops_ext: StringBox.len/length の結果を必ずローカルに保存するよう修正Return が確実に値を拾える)
- 対象: param/local/literal/handle.of 各経路。`dst` があれば `local_index` に slot を割当てて `store_local_i64`
- デバッグ計測を追加
- JIT Lower 追跡: `NYASH_JIT_TRACE_LOWER=1`BoxCall の handled 判定box_typedst 有無)
- Return 追跡: `NYASH_JIT_TRACE_RET=1`known/param/local の命中状況)
- ローカルslot I/O: `NYASH_JIT_TRACE_LOCAL=1``store/load idx=<N>` を吐く)
- String.len_h 実行: `NYASH_JIT_TRACE_LEN=1`thunk 到達と any.length_h フォールバック値を吐く)
- 再現確認
- `apps/smokes/jit_aot_any_len_string.nyash` は依然 Result: 0JIT-direct
- 追跡ログ(要 `NYASH_JIT_TRACE_LOWER=1 NYASH_JIT_TRACE_RET=1 NYASH_JIT_TRACE_LOCAL=1`
- `BoxCall ... method=length handled=true box_type=Some("StringBox") dst?=true`
- ローカル slot の流れ: `idx=0` recv(handle) → `idx=1` string_len → `idx=2` any_len → `idx=3` cond → select → `idx=4` dst 保存 → Return で `load idx=4`
- つまり lowering/Return/ローカル材化は正しく配線されている。
JIT 直実行に関する未解決点import 解決先の差異疑い 等)は封印に伴いアーカイブ化。必要時に `docs/development/current/` へ復元して再開する。
暫定変更(フォールバック強化)
- `ops_ext` の StringBox.len で「リテラル復元NewBox(StringBox, Const String))」を param/local より先に優先。
- JIT-AOT 経路で文字列リテラルの length は常に即値化select/hostcall を経由せず 3 を返す)。
- ただし今回のケースでは local 経路が発火しており、まだ 0 のままhostcall 実行が 0 を返している疑い)。
未解決/次アクション(デバッグ指針)
- [ ] `nyash.string.len_h` が実際にどの関数へリンクされているかを確認
- Cranelift JIT: `src/jit/lower/builder/cranelift.rs``builder.symbol(...)` 群は設定済みだが、実行時に thunk 側の `eprintln` が出ない。
- 追加案: `emit_host_call` で宣言した `func_id``builder.symbol` 登録可否の整合をダンプ(シンボル直列化や missing import の検知)。
- [ ] `extern_thunks::nyash_string_len_h` へ確実に到達させるため、一時的に `emit_len_with_fallback_*``SYM_STRING_LEN_H` を文字列リテラル直書きではなく定数経由に統一。
- [ ] `nyash.string.from_u64x2` の呼び出し可否を同様にトレース(`NYASH_JIT_TRACE_LOCAL=1` の直後に `NYASH_JIT_TRACE_LEN=1` が見えるか)
- [ ] ワークアラウンド検証: `NYASH_JIT_HOST_BRIDGE=1` 強制でも 0 → host-bridge 経路の呼び出しが発火していない可能性。bridge シンボル登録も再確認。
メモ/所見
- lowering と Return 材化ローカルslot への保存→Return で loadは動いている。値自体が 0 になっているので hostcall 側の解決/戻りが疑わしい。
- AOT .o の生成は成功。segv は今回は再現せず。
実行コマンド(デバッグ用)
- `NYASH_JIT_TRACE_LOWER=1 NYASH_JIT_TRACE_RET=1 NYASH_JIT_TRACE_LOCAL=1 NYASH_AOT_OBJECT_OUT=target/aot_objects/test_len_any.o ./target/release/nyash --jit-direct apps/smokes/jit_aot_any_len_string.nyash`
- 追加で thunk 到達確認: `NYASH_JIT_TRACE_LEN=1 ...`(現状は無出力=未到達の可能性)
Phase A 進捗(実施済)
- A1: Hostcall シンボルの定数化(直書き排除)完了
【ハンドオフ20250906 4th— GUI/egui 表示テスト計画Cranelift/LLVM × Windows/WSL
目的
- 以前は Windows exe で egui ウィンドウ表示を確認できていたが、現状で再現が不安定な報告あり。Cranelift/LLVM と OS 組み合わせ別に手順と期待結果を明文化し、再現性を担保する。
前提・重要ポイント
- プラグイン版 EguiBox は Windows 専用で実ウィンドウ分岐(`#[cfg(all(windows, feature = "with-egui"))]`。Linux/WSL では `run()` はスタブvoidでウィンドウは出ないX 転送の有無に関係なく)。
- Windows でウィンドウ表示を行うには、`nyash-egui-plugin``--features with-egui` でビルドし、`nyash.toml``plugin_paths`(または `NYASH_PLUGIN_PATHS`)に DLL のパスが解決できること。
- Linux でウィンドウ表示を確認したい場合は「Rust 例gui_simple_notepad」または「ビルトイン EguiBoxnyash 本体を `--features gui` でビルドし、専用 Nyash スクリプトを使用)」を利用する。
テストマトリクス(手順と期待結果)
1) Windows × CraneliftJIT-direct/EXE 相当)
- 準備: `cargo build --release --features cranelift-jit`
- プラグイン: `cargo build -p nyash-egui-plugin --release --features with-egui`
- 実行JIT-direct 経路): `powershell -ExecutionPolicy Bypass -File tools\egui_win_smoke.ps1`
- 期待: Egui ウィンドウが表示される(アプリ終了までブロッキング)。
2) Windows × LLVMEXE/直実行)
- LLVM 準備: `tools\windows\ensure-llvm18.ps1 -SetPermanent`
- プラグイン: `cargo build -p nyash-egui-plugin --release --features with-egui`
- Nyash 本体: `cargo build --release --features llvm`
- 直実行: ` .\target\release\nyash.exe --backend llvm apps\egui-hello\main.nyash`
- AOT EXE: `tools\build_llvm.ps1 apps\egui-hello\main.nyash -Out egui_hello.exe`` .\egui_hello.exe`
- 期待: どちらの経路でも Egui ウィンドウが表示されるDLL が `plugin_paths` に解決可能であること)。
3) WSL × CraneliftJIT-direct/EXE 相当)
- 準備: `cargo build --release --features cranelift-jit`
- 実行: `./target/release/nyash --jit-direct apps/egui-hello/main.nyash`
- 期待: 実ウィンドウは出ない(プラグインの `run()` はスタブ。エラーなく終了void
- 備考: GUI 表示が必要な場合は Rust 例(`cargo run --features gui-examples --example gui_simple_notepad --release`)を利用。
4) WSL × LLVMEXE/直実行)
- 準備: `./tools/llvm_check_env.sh``LLVM_SYS_180_PREFIX=$(llvm-config-18 --prefix) cargo build --release --features llvm`
- 実行: `./target/release/nyash --backend llvm apps/egui-hello/main.nyash`
- 期待: 実ウィンドウは出ない(スタブ)。
- 備考: GUI 表示が必要な場合は Rust 例、もしくは nyash 本体を `--features gui` でビルドし、ビルトイン EguiBox 用の Nyash スクリプトを別途用意(要サンプル整備)。
診断スイッチ(共通)
- `NYASH_DEBUG_PLUGIN=1`: プラグインのロードパス/解決状況を表示
- `NYASH_CLI_VERBOSE=1`: プラグインホスト初期化やランタイムの詳細ログ
- Windows/プラグインの DLL 解決が怪しい場合は `NYASH_PLUGIN_PATHS` で DLL ディレクトリを明示(`;` 区切り)
既知の制約 / TODO
- Linux/WSL でプラグイン版 EguiBox の `run()` は現在スタブ(実ウィンドウなし)。将来的に `#[cfg(target_os = "linux")]` 分岐で eframe 実装を追加し、X11/Wayland でも表示可能にする。
- ビルトイン EguiBox`src/boxes/egui_box.rs`)は `--features gui` でビルド時に有効。Nyash スクリプト側の API はプラグイン版と異なる(`setTitle/setSize/addText/run`。Linux GUI 確認用にビルトイン用サンプルapps/egui-builtin/)を追加して整備する。
- Windows AOT リンクは MSVC `link.exe` を既定fall back: clang。lld へのスイッチ(速度優先)を将来オプション化検討。
次アクション(引き継ぎ TODO
- [ ] Windows: 4通りの実行Cranelift 直/JIT、LLVM 直、AOT EXE`apps/egui-hello/main.nyash` のウィンドウ表示を再確認(`NYASH_DEBUG_PLUGIN=1` でログ採取)。
- [ ] WSL: Cranelift/LLVM の直実行は「スタブ終了」が期待値であることを README/ガイドに明記。GUI が必要なら Rust 例 or ビルトイン EguiBox 経路を案内。
- [ ] Linux 向けプラグイン `with-egui` 実装の導入可否を検討(`plugins/nyash-egui-plugin/src/lib.rs``winrun` と類似の `linrun` を追加)。
- [ ] ビルトイン EguiBox 用の Nyash サンプルを `apps/egui-builtin/` として追加し、`--features gui` での手順を `dev/selfhosting/` または `docs/` に追記。
- `nyash.handle.of` / `nyash.string.len_h` / `nyash.console.birth_h``SYM_*` に統一
- A2: string_len ヘルパ抽出(共通化)完了
- `src/jit/lower/core/string_len.rs` 新設、`emit_len_with_fallback_*` を移設
- 呼び出し元はそのまま(挙動は不変)
- A3: 観測の統一(第一弾)
- string_len 内で `observe::lower_hostcall` を発火len_h/any.length_h
- Cranelift/ObjectBuilder の `emit_host_call[_typed]``NYASH_JIT_TRACE_IMPORT=1` によるインポート解決ログを追加
観測結果A3 導入後)
- `NYASH_JIT_TRACE_IMPORT=1``nyash.string.len_h` / `nyash.any.length_h` の import 呼び出しを確認JIT/AOT 両方)
- それでも `NYASH_JIT_TRACE_LEN=1` の thunk 到達ログは出ず → 依然解決先に差異がある疑い(要継続調査)
■ 実行系の最終方針Phase 15 着地)
- ランタイム: Interpreter / VM
- 配布: Cranelift AOT (EXE) / LLVM AOT (EXE)
- JIT 直実行: 封印(ドキュメント上も「実験的/無効」へ集約)
■ 検証チェックリスト(更新)
- VM: `./target/release/nyash --backend vm apps/smokes/jit_aot_string_min.nyash` → Result:1
- AOT(Cranelift): `./tools/build_aot.sh apps/smokes/jit_aot_string_length_smoke.nyash -o app``./app` 実行 → 期待結果
- AOT(Windows oneshot): `pwsh -File tools/windows/build_egui_aot.ps1 -Input apps/egui-hello-plugin/main.nyash -Out app_egui` → 画面表示
— Phase A無振る舞い変更リファクタ方針継続
- A1: Hostcall シンボルを定数に統一(直書き排除)
- `"nyash.handle.of"``jit::extern::handles::SYM_HANDLE_OF`
- `"nyash.string.len_h"``jit::extern::collections::SYM_STRING_LEN_H`
- `"nyash.console.birth_h"` → 既存の定数へ(なければ `extern::...` に追加して使用)
- A2: 長さ取得の共通化
- 新規: `src/jit/lower/core/string_len.rs`
- 既存の `emit_len_with_fallback_{param,local,literal}` をこのモジュールへ抽出し、`core.rs`/`ops_ext.rs` から呼び出すだけにする(挙動は据え置き)。
- 目的: 重複と分岐のばらけを解消し、シンボル差し替えや観測フックを一点で行えるようにする。
※ Phase A は「振る舞いを変えない」ことを厳守する。
2) 診断イベントの追加(軽量)
- `emit_len_with_fallback_*``lower_box_call(len/length)``observe::lower_hostcall` を追加し、
Param/Local/リテラル/handle.of どの経路か、select の条件string_len==0をトレース可能にする`NYASH_JIT_EVENTS=1`)。
3) AOT segfault (稀発) の追跡(低優先)
- `tools/aot_smoke_cranelift.sh` 実行中に稀に segv`.o` 生成直後/リンク前後)。
- `nyash.string.from_u64x2` 載せ替えと DT_TEXTREL 警告が出るので、PIE/LTO/relro 周りと TLS/extern の登録順を確認。
4) 警告のノイズ低減(低優先)
- `core_hostcall.rs` の unreachable 警告case 統合の名残)。
- `jit/lower/*` の unused 変数/unused mut の警告。
影響ファイル(今回差分)
- `src/jit/lower/core.rs`len/length 二段フォールバック呼出し、保存強化)
- `src/jit/lower/core/ops_ext.rs`StringBox len/length 優先処理、リテラル即値畳み込み、保存)
- `src/jit/hostcall_registry.rs``nyash.string.len_h` 追補)
- ドキュメント: README(ja/en) の実行モード更新、ガイドegui AOTに oneshot スクリプト反映
- `src/jit/extern/collections.rs``SYM_STRING_LEN_H` 追加)
- `src/jit/lower/extern_thunks.rs``nyash_string_len_h` 追加)
- `src/jit/lower/builder/cranelift.rs``SYM_STRING_LEN_H` のシンボル登録)
- `tools/aot_smoke_cranelift.sh`(新規)
- `apps/smokes/jit_aot_string_length_smoke.nyash`(新規)
再現/確認コマンド
- ビルドJIT/AOT: `cargo build --release --features cranelift-jit`
- JITAOT.o出力: `NYASH_AOT_OBJECT_OUT=target/aot_objects/test_len_any.o ./target/release/nyash --jit-direct apps/smokes/jit_aot_any_len_string.nyash`
- AOT 連結〜実行: `bash tools/aot_smoke_cranelift.sh apps/smokes/jit_aot_string_min.nyash app_str`
次アクション(引き継ぎ TODO
- [ ] Return の後方走査材化を実装BoxCall/Call/Select 等の定義→保存→Return 接続)。
- [ ] `emit_len_with_fallback_*` / `lower_box_call(len/length)` にイベント出力を追加(選択分岐/経路ログ)。
- [ ] AOT segv の最小再現収集PIE/relro/TLSの前提確認`nyrt` 側エクスポート/リンカフラグ点検。
- [ ] `NYASH_USE_PLUGIN_BUILTINS=1` 時の `length` も robust path を常に使用することを E2E で再確認。
- [ ] Cranelift AOT: `env.local/env.box` を実オブジェクト出力に反映link/name 解決の道付け)
- [ ] LLVM AOT: `nyash.env.box.new_i64x` の引数≥5およびTLV化の検討、引数型の復元精度UP
- [ ] Builder 純化の網羅化Load/Store/WeakRef 非生成の全経路テスト追加)
- [ ] 純化ON E2E スモークVM/LLVMと CI 常時ジョブの追加
メモ
- `jit_aot_any_len_string.nyash``return s.length()` の Return 経路解決が決め手。材化を強化すれば `3` が期待値。
- 既存の Array/Map 経路・他の smokes は影響なしlen/size/get/has/set の HostCall/PluginInvoke は従来どおり)。
■ 進捗サマリ
- Phase 12 クローズアウト完了。言語糖衣12.7-B/P0と VM 分割は反映済み。
- Phase 15Self-Hosting: Cranelift AOTへフォーカス移行。
- 設計/仕様ドキュメントとスモーク雛形を追加済み。
- 設計: `docs/design/backend-cranelift-aot-design.md`
- API案: `docs/design/cranelift-aot-box.md`
- LinkerBox: `docs/design/linker-box.md`
- スモーク仕様: `docs/tests/aot_smoke_cranelift.md`
- 雛形スクリプト: `tools/aot_smoke_cranelift.sh`, `tools/aot_smoke_cranelift.ps1`
- README にセルフホスト到達の道筋を明記C ABI を Box 化)。
【ハンドオフ20250906 3rd— String.length: constfold→Return 材化の不一致 調査ログとTODO】
概要(現象)
- 目標: JIT/JITAOT で `StringBox.length/len` が 3 を返すべき箇所で 0 になるケースを解消。
- 現状: Lower 中の早期 constfold で `length = 3` を確実に計算([LOWER] early constfold ... = 3 が出力。Return 時点でも `ValueId(3)``known_i64=3` と認識される([LOWER] Return known_i64?=true。にもかかわらず最終結果実行結果は 0。
重要な観測(再現とログ)
- MIR ダンププリンタ仕様上、BoxCall は `call %box.method()` として表示)
0: `%1 = const "abc"`
1: `%2 = new StringBox(%1)`
2: `call %2.birth(%1)` // birth は通常 calldst なし)
3: `%3 = call %2.length()` // これも通常 call 表記(内部は BoxCall
4: `ret %3`
- Lower ログ:
- `[LOWER] early const-fold StringBox.length = 3` が出るconstfold 成功)
- `[LOWER] Return value=ValueId(3) known_i64?=true param?=false local?=true`
- それでも実行結果は `Result: 0`
- `nyash.jit.dbg_i64`[JITDBG]の出力が実行時に出ていないimport は宣言されるが call が観測されず)。
今回入れた変更(実装済・該当ファイル)
- Return/材化の強化known を最優先)
- `src/jit/lower/core_ops.rs`: `push_value_if_known_or_param` を「known_i64 最優先」に変更。
- `src/jit/lower/core.rs``I::Return` でも `known_i64` を最優先で積むように変更。
- Call/ArrayGet の戻り値の保存
- `src/jit/lower/core.rs`: `I::Call` 戻り値を dst が無い場合もスクラッチローカルへ保存(栈不整合の防止)。`I::ArrayGet` 戻り値も dst スロットへ保存。
- String.length/len の早期 constfold を二段に強化
- `src/jit/lower/core.rs`: BoxCall 入り口で `StringBox.literal` の length/len を即値化(最優先)。
- `src/jit/lower/core/ops_ext.rs`: 同様の constfold を堅牢化NewBox(StringBox, Const) から復元)。
- `src/jit/lower/core.rs`: lowering 前に `known_str` を事前シード、`string_box_literal` マップNewBox → リテラル文字列を構築し、Copy 伝播も対応。
- トレース導線
- `src/jit/lower/core/string_len.rs`: 二段フォールバックparam/local/literalにデバッグフックタグ 110x/120x/130x 系)追加。
- `src/jit/lower/builder/cranelift.rs`: ローカル slot の store/load トレース(`NYASH_JIT_TRACE_LOCAL=1`)。
- `crates/nyrt/src/lib.rs`: AOT 側の `nyash.string.len_h` / `nyash.any.length_h``[AOT-LEN_H]` を追加。
- `src/jit/lower/extern_thunks.rs`: `nyash_string_from_u64x2``[JIT-STR_H]` を追加JIT のハンドル生成観測)。`nyash_handle_of``[JIT-HANDLE_OF]` を追加。
仮説(根本原因)
- constfold で 3 を積めているにも関わらず、Return 時の実返却が 0。優先順位の修正により `known_i64` から 3 を積むよう修正済みだが、compiled JIT 関数内での Return 材化導線ret_block への引数配線/最後の returnが値 0 に擦り替わる経路が残っている可能性。
- ret_block/ジャンプ引数の材化不整合
- 後続命令でスタックが上書きされる経路
- birth の dst なし call で残留値が生じていた可能性Call 戻り値スクラッチ保存で対策済)
次アクションTODO
1) Return の後方走査材化優先・CURRENT_TASK 既存 TODO の実装)
- BoxCall/Call/Select/Const/Copy/Load に遡って、Return が値を確実に拾う材化パスを補強する。
- 既に known_i64 最優先化は実施済み。残りは ret_block 引数配線の最終確認CraneliftBuilder の ret 経路)。
2) 実行時の値トレース強化(短期)
- `emit_return`CraneliftBuilderで、ret_block へ jump 直前の引数 `v``nyash.jit.dbg_i64(299,v)` で確実に呼ぶenv でON
- ret_block 入口パラメータの `return_` 直前でも `dbg_i64(300,param0)` 呼び出しを足し、どこで 0 になるかを確定する。
3) BoxCall(length/len) の早期 fold 命中率最終確認
- `NYASH_JIT_TRACE_LOWER=1``[LOWER] early const-fold ... = 3` が必ず出ることを確認。
- 既に出ているが、Return までの導線で 3 が 0 に化ける起点を 2) で特定する。
4) AOT/JITAOT 観測の整備(参考)
- `[AOT-LEN_H]` で AOT 側 len_h/any.length_h の handle 解決有無をログ化。JITAOT smoke での差異を収集。
再現/確認コマンド(更新)
- 早期 fold と Return 導線ログ:
- `NYASH_JIT_TRACE_LOWER=1 NYASH_JIT_TRACE_RET=1 NYASH_AOT_OBJECT_OUT=target/aot_objects/test_len_any.o ./target/release/nyash --jit-direct apps/smokes/jit_aot_any_len_string.nyash`
- ローカル slot 観測:
- `NYASH_JIT_TRACE_LOCAL=1 NYASH_AOT_OBJECT_OUT=... --jit-direct ...`
- AOT 側の handle 解決ログ:
- `NYASH_JIT_TRACE_LEN=1 bash tools/aot_smoke_cranelift.sh apps/smokes/jit_aot_string_min.nyash app_str`
補足メモ
- MirPrinter は BoxCall を `call %box.method()` と出力する仕様(今回は BoxCall 経路で constfold が呼ばれていることは [LOWER] ログで確認済み)。
- `call %2.birth(%1)` の戻り値残留に備え、I::Call の dst なし呼び出しでもスクラッチ保存して栈を消費するよう修正済み(回帰に注意)。
担当者への引き継ぎポイント
- まず 2) の dbg を CraneliftBuilder の ret 経路jump to ret_block と return_に追加し、`v`/`param0` が 0 になる箇所を特定してください。
- 次に 1) の Return 後方走査材化を入れて、BoxCall/Select/Copy 等いずれの経路でも Return が安定して値を拾えるようにしてください。
- その後、smoke `apps/smokes/jit_aot_any_len_string.nyash``Result: 3` で通ることを確認し、constfold のログと一致することをもってクローズ。
【将来計画(バグ修正後)— JIT を exec 専用にし、VM 連携を段階的に廃止】
目的
- JIT は「コンパイル実行exec」に一本化し、VM 依存のレガシー経路param-index/TLS参照を撤去する。
- 値の材化・ハンドル管理・hostcall を JIT 側で一貫させ、境界の不整合を根本から減らす。
ロードマップ(段階移行)
1) 実行モードの明確化(設定)
- 環境変数 `NYASH_JIT_MODE=exec|compile|off` を導入。
- 既存の `NYASH_JIT_STRICT` は非推奨化し、`MODE=compile` に集約。
2) JIT ABI の一本化
- `src/jit/lower/extern_thunks.rs` などから `with_legacy_vm_args` を撤去。
- `nyash_handle_of` を含む extern は「JIT引数/ハンドルのみ」を受け付ける設計に変更。
- ランタイム境界で `VMValue -> JitValue(Handle)` へのアダプタを用意。
3) レガシー撤去JIT/AOT側
- `crates/nyrt/src/lib.rs``nyash.string.len_h`/`nyash.any.length_h` から param-index フォールバックを削除。
- lowering の `-1` センチネルや VM 依存の fallback を廃止し、`handle.of` または既存ローカルハンドルに統一。
4) フォールバック方針(移行期間)
- 関数単位で `unsupported>0` の場合のみ VM にフォールバック。
- オプション `NYASH_JIT_TRAP_ON_FALLBACK=1` を追加し、移行時の漏れを検出可能に。
5) Return 導線の強化(本タスクの延長)
- Cranelift 生成の ret 経路に dbg を常設envでON
- Return の後方走査材化を標準化し、const-fold/BoxCall/Select いずれでも Return が値を確実に拾うように。
6) ドキュメント/テスト更新
- README/CURRENT_TASK にモード説明と運用方針を追記。
- CI の smoke は `MODE=exec` を常態化し、compile-only はAOT出力/ベンチのみで使用。
影響範囲(主な修正ポイント)
- `src/jit/manager.rs`(モード/実行ポリシー)
- `src/jit/lower/extern_thunks.rs`レガシーVM依存排除、JIT ABI専用化
- `src/jit/lower/core.rs` / `src/jit/lower/core_ops.rs`-1センチネル削除・ハンドル材化徹底
- `crates/nyrt/src/lib.rs`dotted名hostcallのレガシー経路削除
- ドキュメントREADME/CURRENT_TASK
ロールアウト/リスク
- フラグ駆動で段階的に切替(デフォルト `exec`)。
- リスク: plugin経路/hostcall registry/ハンドルリーク。
- 緩和: `handles::begin_scope/end_scope_clear` によりハンドル回収を徹底、registryの検証を追加。
【本日更新】
- VM if/return 無限実行バグを修正(基本ブロック突入時に `should_return`/`next_block` をリセット。include 経路のハングも解消。
- ArrayBox プラグイン生成失敗に対し、v2 ローダへパス解決フォールバック(`plugin_paths.search_paths`)を追加し安定化。
- std/string の P0 関数を Ny 実装で追加length/concat/slice/index_of/equals。index_of は substring ループで代替。
- 残課題: string_smoke で `fails` 累積の else 側に φ が入らず未定義値参照MIR Builder 側の SSA/φ 振る舞い)。別タスク化。
【ハンドオフ20250906— AOT/JITAOT 足場と箱下寄せリファクタ】
- 変更サマリ
- nyrt: AOT 連携の dotted 名を追加Map/String/Any/birth
- `nyash.map.{size_h,get_h,get_hh,set_h,has_h}`
- `nyash.string.{len_h,charCodeAt_h,concat_hh,eq_hh,lt_hh}` / `nyash.any.{length_h,is_empty_h}`
- NewBox/文字列: `nyash.instance.birth_name_u64x2`, `nyash.string.from_u64x2`
- JITAOT(ObjectBuilder):
- 文字列リテラル→ハンドル生成u64x2 パック → `nyash.string.from_u64x2`
- 出力関数を `ny_main` としてエクスポート
- 最小 Store/Loadi64を StackSlot で実装
- Lower箱を下に寄せる最小整理:
- Map: param 不在でもローカルハンドルがあれば `_H` シンボルで直呼び
- Any.length: StringBox は `nyash.string.len_h` を優先。ローカル/再構築/旧 index の順にフォールバック
- Copy/Load でローカルハンドルを dst 側 slot に伝播
- Array.length は ArrayBox 受けに限定ops_ext ガード)
- 追加スモークJITAOT
- `apps/smokes/jit_aot_string_min.nyash`concat+eq→ PASS
- `apps/smokes/jit_aot_any_isempty_string.nyash` → PASS
- `apps/smokes/jit_aot_any_len_string.nyash` → 現状 Result: 0後述の未解決
- `apps/smokes/jit_aot_map_min.nyash` → 環境により MapBox 生成が必要
- 実行例
- 文字列ミニAOT:
- `NYASH_AOT_OBJECT_OUT=target/aot_objects/test_str.o ./target/release/nyash --jit-direct apps/smokes/jit_aot_string_min.nyash`
- `cc target/aot_objects/test_str.o -L target/release -Wl,--whole-archive -lnyrt -Wl,--no-whole-archive -lpthread -ldl -lm -o app_str && ./app_str``Result: 1`
- isEmptyAOT:
- 同様に `app_empty``Result: 1`
- Map 最小AOT:
- `.o` 生成/リンクは通る。`new MapBox()` はプラグイン/設定に依存(`nyash.toml``.so` の配置を確認)
- 未解決 / 既知の課題(優先度高)
1) String.length の AOT 実行が 0 になるケース
- 症状: `s = new StringBox("abc"); return s.length()``Result: 0`
- 現状の対処: Any.length を String.len_h 優先にし、ローカル/再構築/旧 index の順でフォールバック。Const fold も追加済み。
- 追加方針: 受け型伝播Copy/Load→dst へ型共有)をより堅牢化。最終手段として、ローカルハンドル時に `string.len_h``any.length_h` の二段呼び分け0 返りのときだけ後者)で保険を張る。
2) MapBox 生成AOT 実行バイナリ)
- 環境によりプラグイン解決が必要。`nyash.toml` のあるディレクトリで実行し、必要なら各プラグインを `target/release` に配置。
- 次アクション(引き継ぎ TODO
- [ ] Any.length の 0 問題を完全解消
- [ ] 受けの型/ハンドル伝播Copy/Load/Storeを統一ヘルパ化し、length/len/charCodeAt で確実にハンドルを積む
- [ ] StringBox(Const) は定数畳み込みを最優先len を即値化)
- [ ] 保険: `string.len_h`→0→`any.length_h` の順にフォールバック(ローカルハンドル時)
- [ ] メソッド→シンボル/引数規約の集中表を作成Array/Map/String/Any
- [ ] ops_ext/core の分岐重複を縮減(箱の責務を「下」に寄せる)
- [ ] AOT スモーク拡充
- [ ] String/Array の length/len を追加、select/分岐のミニ例も用意
- [ ] Map.get/has/setプラグインあり環境用
- 影響ファイル(主要)
- 追加/更新: `crates/nyrt/src/lib.rs`dotted エクスポート多数)、
`src/jit/lower/builder/{object.rs,cranelift.rs}`
`src/jit/lower/{core.rs,core/ops_ext.rs,core_hostcall.rs}`
スモーク: `apps/smokes/jit_aot_*.nyash`
■ ハンドオフJIT AOT / LLVM の現状と次アクション)
- 現状サマリ
- Array fastpath: VM 側 len/length を最前段に早期化Void→0 も確認)。
- Null 互換: NullBox→VMValue::Void へ統一(比較の整合確保)。
- std/array smoke: `NYASH_DISABLE_PLUGINS=1` で PASSlen/push/pop/slice
- LLVM AOT: 復活nyrt の read lock 寿命修正、build_llvm.sh のリンクパス `-L target/release` 追加)。
- JIT AOT(ObjectBuilder): P0 安定化P1 実装済const/return、i64 binop、compare、select、branch/jump、hostcall 基本、PHI最小化ブロック引数
- jit-direct で .o 生成確認: `apps/smokes/jit_aot_arith_branch.nyash` → Result 13、.o 出力 OK。
- build_aot.sh は既定で STRICT=0、出力 `target/aot_objects/main.o` に固定。
- nyrt: AOT 連携用 dotted 名 alias を Array に追加(`nyash.array.{len_h,get_h,set_h,push_h}`)。
- 優先TODO次にやること
1) JIT AOT P2: hostcall 拡張(規約ベースの最小集合)
- Map: `nyash.map.{size_h,get_h,has_h,set_h}` の dotted 名を nyrt に追加(既存実装へ forward
- String: 代表メソッドlen/concat/substring/indexOf 等)で必要なシンボルを dotted 名として追加
- ObjectBuilder から `emit_host_call_typed` で呼び出しLower の対応表に従う)
2) LowerCore: slot/name→hostcall マッピングbyslot を優先、byname は互換フォールバック)
- Array/Map/String の最小セットlen/get/set/push、size/get/has/set、len/concat など)
3) 後続(必要時): JIT AOT スモークを追加分岐あり最小、Array/Map の各1本
- 実行コマンド(確認用)
- JIT AOTjit-direct + .o:
- `NYASH_DISABLE_PLUGINS=1 NYASH_JIT_EVENTS=1 NYASH_AOT_OBJECT_OUT=target/aot_objects/jit_aot_arith.o ./target/release/nyash --jit-direct apps/smokes/jit_aot_arith_branch.nyash`
- LLVM AOTemit+link:
- `LLVM_SYS_180_PREFIX=$(llvm-config-18 --prefix) tools/build_llvm.sh apps/tests/ny-llvm-smoke/main.nyash -o app`
■ 現在のフォーカスJITオンリー一旦の着地
1) Core 緑維持(完了)
- `tools/jit_smoke.sh` / Roundtrip(A/B) / Bootstrap(c0→c1→c1') / Using E2E = PASS
【P1 進捗 — LLVM Core-13: ビット演算/シフト】
実装
- LLVM 降ろしで `BinaryOp::{BitAnd,BitOr,BitXor,Shl,Shr}` を i64 経路に実装済み(既存)。
- `compile_and_execute` の MIR インタプリタにも同演算を実装し、パリティを確保。
検証
- 単体テスト追加: `src/tests/llvm_bitops_test.rs`
- MIR を直接構築して `1=(5&3),7=(5|2),4=(5^1),32=(1<<5),4=(32>>3)` の合計 48 を検証。
- VM 実行で 48、LLVM `compile_to_object` がエラーなく emit、`compile_and_execute` でも 48 を確認(フォールバック実行)。
- AOT スモーク(任意): `tools/llvm_smoke.sh``NYASH_LLVM_BITOPS_SMOKE=1` で有効化する項目を追加(入力は Nyash ソース制約のため現状 skip 既定)。
注意
- Nyash ソースパーサが `&|^<<>>` を未サポートのため、ビット演算の E2E は当面 MIR 直構築テストで担保。
将来 `grammar/` の演算子追加後に `apps/tests/ny-llvm-bitops/` を有効化予定。
2) CI 分離(完了)
- Core常時: `tools/jit_smoke.sh` + Roundtrip
- Plugins任意: `NYASH_SKIP_TOML_ENV=1 ./tools/smoke_plugins.sh`strict既定OFF、`NYASH_PLUGINS_STRICT=1`でON
3) Selfhost E2E完了
- ny_plugins 有効 + `NYASH_USE_NY_COMPILER=1` の自己ホストE2Eをオプションゲートで運用
4) クリーンアップ(完了)
- 未使用import/変数の整理、runner責務分割、tools出力体裁の統一
■ ブランチ/構成Phase 15
- 実装ブランチ: `phase-15/self-host-ny-mir`
- 既存 Workspace は維持(`crates/*`)。
- 方針: crates 側は変更せず「Nyash スクリプト + nyash.exe」だけで実装・運用Windows優先
- 例: `C:\git\nyash-project\nyash_self\nyash` 直下で `target\release\nyash` 実行。
- Nyash 製パーサは `apps/selfhost/ny-parser-nyash/`Nyashコードとして配置最初は最小サブセット
- MIR 解釈層は既存 `backend/mir_interpreter.rs``runner/modes/mir_interpreter.rs` を拡充。
- AOT 関連の雛形は `src/backend/cranelift/` に維持feature gate: `cranelift-aot`)。
■ 再開TODO優先順
1) std Ny実装の実体化P0/P1
- string: length/concat/slice/indexOf/equals → P0 完了string_smoke PASS
- array: len/push/pop/slice を内蔵経路で先行(次着手)
- map: get/set/len/keys (+values/entries/forEach)
- jit_smoke に機能検証を常時化Coreは `NYASH_DISABLE_PLUGINS=1`
2) NyコンパイラMVPのsubset拡張
- let/call/return に続き if/ブロック/関数引数まで拡張し、`NYASH_USE_NY_COMPILER=1` スモークを充実
3) Selfhost E2E ゲートの昇格
- 連続N回グリーン後にCI optional→requiredへ昇格trace/hash基準
4) Plugins厳格ONの段階移行
- Core13準拠サンプルへ置換し、`NYASH_PLUGINS_STRICT=1` ゲートで順次ONに復帰
【優先追加 — JIT AOTObjectBuilder安定化・拡張】
- P0: 安定化(完了)
- switch_to_block なしでの命令発行panic対策emit_const系
- 終端命令なしVerifierエラー対策emit_return 実装)
- build_aot.sh の STRICT 緩和デフォルト0 obj 直指定
- P1: 最小命令カバレッジ(今すぐ実装)
- i64 binop: add/sub/mul/div/mod を実コード生成
- compare: eq/ne/lt/le/gt/ge → b1→i64(0/1) へ正規化してpush
- 分岐/ジャンプ: br_if_top_is_true/jump_to 実装ブロック遷移とCFG整合
- select: emit_select_i64 実装cond, then, else の順)
- P2: hostcall 系の型付き発行(必要最小限)
- array/map/string/integer の代表 extern を ObjectBuilder に実装
- ny-llvm-smoke 等に相当する JIT AOT smoke 追加
- P3: CI スモーク
- `tools/jit_smoke.sh` に AOT(JIT)最小タスクを追加STRICT=0 で .o 生成確認)
## ブロッカー/暫定対応20250905 更新)
- 影響範囲Backend差
- JIT(cranelift) → 影響なし。
- VM(backends=vm) → if/return 無限ループは修正済み(基本ブロック突入時に CF リセット)。
- 結論: include ハングの根因は VM の制御フロー残存フラグ。修正により解消。
- 事象A: include ハング → 解消
- `apps/tmp_len_min.nyash`/`apps/tmp_len_test.nyash` 正常完走を確認。
- 事象B: ArrayBox プラグイン生成エラー → 解消
- v2 ローダにフォールバック探索(`plugin_paths.search_paths`を追加し、workspace の `./target/release/*.so` を自動解決。
- DEBUG 時に birth 戻り `code/out_len` をロギング。
- 事象C: std/string_smoke の最終段で未定義値参照 → 解消
- MIR Builder の if 降ろしで φ を必ず生成then のみ代入・else 未代入時は pre 値と then 値で合流)。
- string_smoke PASS を確認。
## 次アクション(デバッグ計画)
- A1: includeハング最小化再現を固定VM経路優先で調査
- `apps/tmp_len_test.nyash` 固定、`NYASH_DEBUG=1``execute_include_expr``ensure_static_box_initialized` までの経路にログを追加。
- `included_files``include_stack` の push/pop と RwLock/RwLock の取り回しを確認。ポップ忘れ/二重ロックがないか検査。
- `apps/std/string.nyash` 内のメソッドを段階的に無効化して最小原因を特定(現状 length のみでも再現)。
- A2: VM if/return 無限実行VM限定を優先修正
- 症状: JITは1回then→Return→終了。VMはthenのprintが際限なく繰り返される。
- 再現最小: `apps/tmp_if_min.nyash`
```nyash
static box Main {
main() {
local x
x = 3
if x == 3 {
print("ok3")
return 0
}
print("bad")
return 1
}
}
```
- JIT: `./target/release/nyash apps/tmp_if_min.nyash` → 1回だけ ok3, Result:0
- VM: `timeout 4s ./target/release/nyash --backend vm apps/tmp_if_min.nyash` → ok3 が無限に出続け TIMEOUT
- MIRダンプ`NYASH_VM_DUMP_MIR=1`)では if 降下は正しく、then/else 各ブロックは `ret` を含む。
- 例: bb1 に `extern_call log("ok3")` の後 `ret 0`。bb2 に `ret 1`。
- 観測ログ(`NYASH_VM_DEBUG_EXEC=1`)では Print/Const が繰り返し実行。Return の終端処理が機能していない疑い。
- 仮説: VM 実行ループの制御フロー(`execute_function`)で `ControlFlow::Return` を受け取った後の関数脱出が何らかの理由で無効化/上書き/再入している。
- 着手案:
- `execute_function` に短期ログ: 現在ブロックID/terminator種別/`should_return` セット→関数戻りの分岐をeprintlnNYASH_VM_DEBUG_EXEC=1時
- `execute_instruction` で `Return` ディスパッチ時に明示ログval_id/値を出す現状VTトレースも可
- `previous_block`/`loop_executor`/`record_transition` で自己遷移が起きていないか確認。
- `BasicBlock::add_instruction` にて terminator設定/Successorsの更新は正常コード・MIR上はOK。処理後の `next_block` 決定ロジックを再点検。
## ハンドオフ(変更点・補助情報)
- 追加ファイルstd MVP + smokes
- `apps/std/string.nyash`, `apps/std/array.nyash`
- `apps/smokes/std/string_smoke.nyash`, `apps/smokes/std/array_smoke.nyash`
- スクリプト/設定の更新
- `tools/jit_smoke.sh`: Std smokes に `timeout 15s`、ArrayBox未提供時は `SKIP` を出力
- `tools/smoke_plugins.sh`: `NYASH_PLUGINS_STRICT=1` のON/OFF表示
- `nyash.toml`: `ny_plugins` に std 2件を追加
- `src/runner/modes/vm.rs`: `NYASH_VM_DUMP_MIR=1` でVM実行前にMIRをダンプ
- `src/mir/builder/stmts.rs`: 末尾 `return/throw` 後に同ブロックへ更に命令を積まないための早期breakを追加安全強化
- 再現とログ
- VM再現: `timeout 4s ./target/release/nyash --backend vm apps/tmp_if_min.nyash`
- JIT対照: `./target/release/nyash apps/tmp_if_min.nyash`
- MIRダンプ: `NYASH_VM_DUMP_MIR=1 --backend vm ...`
- 命令トレース: `NYASH_VM_DEBUG_EXEC=1 --backend vm ...`
- プラグイン/ArrayBox注意
- 既定でプラグイン経由に迂回するため、未ビルドだと ArrayBox 生成に失敗。
- 回避: `NYASH_USE_PLUGIN_BUILTINS=0` または `NYASH_PLUGIN_OVERRIDE_TYPES` から `ArrayBox,MapBox`を除外。もしくはプラグインをビルド。
## すぐ着手できるTODOVM側
- [ ] `execute_function` にブロック遷移/Return検出ログNYASH_VM_DEBUG_EXEC=1時のみ
- [ ] Return発生時に確実に `Ok(return_value)` で関数を抜けることを確認(`should_return`/`next_block` の上書き防止)
- [ ] `record_transition`/`loop_executor` の副作用で自己遷移が起きていないか確認
- [ ] 修正後、`apps/tmp_if_min.nyash` が VM/JIT 両方で一発終了することを確認MIRダンプ上は既に正しい
- B1: ArrayBox 経路の選択を明示
- 手元では `NYASH_USE_PLUGIN_BUILTINS=0` で内蔵にフォールバックするか、プラグインを `cargo build -p nyash-array-plugin --release` で用意。
- CIは当面 `SKIP` 維持。
## 実行メモ(暫定)
- Std smokes手元で回す
- `NYASH_LOAD_NY_PLUGINS=1 NYASH_USE_PLUGIN_BUILTINS=0 ./tools/jit_smoke.sh`
- またはプラグインをビルドしてから `NYASH_LOAD_NY_PLUGINS=1 ./tools/jit_smoke.sh`
■ 予定R5 拡張: Ny Plugins → Namespace
- Phase A最小: 共有レジストリ `NyModules` を追加し、`env.modules.set/get` で exports を登録/取得。
- `[ny_plugins]` は戻り値Map/StaticBoxを「ファイルパス→名前空間」に変換して登録。
- 名前空間導出: ルート相対・区切りは `.`、拡張子除去・無効文字は `_`。予約 `nyashstd.*` 等は拒否。
- Phase B範囲: 共有Interpreterオプション`NYASH_NY_PLUGINS_SHARED=1`)で静的定義を共有。ログに REGISTERED を出力。
- Phase C言語結線: `using <ns>` を `NyModules` 参照→未解決時にファイル/パッケージ解決nyash.linkへフォールバック。
■ 直近で完了したこと主要抜粋JIT
- R1: JSON v0 ブリッジ(`--ny-parser-pipe`/`--json-file`)、変換器 `src/runner/json_v0_bridge.rs`、スモーク追加
- R2: ラウンドトリップ E2E`tools/ny_roundtrip_smoke.{sh,ps1}`
- R3: 直結ブリッジ v0`--parser ny`/`NYASH_USE_NY_PARSER=1`、`NYASH_DUMP_JSON_IR=1`)→ `return (1+2)*3` で 9
- R5: Ny スクリプトプラグイン([ny_plugins]列挙実行OK/FAIL 出力・列挙のみガード付き)
- NyModules登録/名前空間導出/Windows正規化の仕様確定・回帰スモーク
- using/namespaceゲート・nyash.link最小・resolverキャッシュ・実行時フック提案付き診断
- AOT P2(step1): RUN スモーク配線(最小オブジェクト生成+実行ログ)
- ■ 直近で完了したこと(主要抜粋)
- T0: MIRインタープリタ強化分岐/比較/PHI/extern/Box最小 Runner 観測ログ
- T1: Nyash製ミニパーサ整数/四則/括弧/return→ JSON IR v0 出力
- T2: JSON IR v0 → MIRModule 受け口(`--ny-parser-pipe`
- T3: CLI 切替/ヘルプ(`--ny-parser-pipe`/`--json-file`、mirヘルプ追補
- T4: Docs/Samples/Runner scriptsapps/ny-mir-samples, tools/*, README 追補)
- Phase 15 起点準備
- CLIに `--backend cranelift-aot` と `--poc-const` を追加(プレースホルダ動作)。
- `src/backend/cranelift/{mod.rs,aot_box.rs,linker_box.rs}` の雛形追加feature gate
- MIR解釈層スケルトン`semantics/eval.rs` と `backend/mir_interpreter.rs`)の確認
■ 再開用クイックメモJITのみ
- ビルド
- VM/JIT: `cargo build --release --features cranelift-jit`
- LLVM必要時: `LLVM_SYS_180_PREFIX=$(llvm-config-18 --prefix) cargo build --release --features llvm`
- AOT導入後: `cargo build --release --features cranelift-aot`
- スモークJIT/VM
- Core: `NYASH_DISABLE_PLUGINS=1 NYASH_CLI_VERBOSE=1 ./tools/smoke_vm_jit.sh`
- Parser Bridge: `./tools/ny_parser_bridge_smoke.sh`
- Roundtrip: `./tools/ny_roundtrip_smoke.sh`A/B
- Plugins: `NYASH_SKIP_TOML_ENV=1 ./tools/smoke_plugins.sh`(厳格は `NYASH_PLUGINS_STRICT=1` 時のみON
- Bootstrap: `./tools/bootstrap_selfhost_smoke.sh`
- Using/Resolver: `./tools/using_e2e_smoke.sh`
■ 状態
- JIT自己ホストMVP: 到達E2E/ブートストラップ/ドキュメント/CI分離まで完了
- リファクタ: Step1/2/3 完了未使用掃除・runner分割・tools体裁統一
- 次回は「std実装の実体化」と「Nyコンパイラsubset拡張」から再開
- 参照
- Phase 15 概要/ロードマップ: `docs/development/roadmap/phases/phase-15/README.md`, `docs/development/roadmap/phases/phase-15/ROADMAP.md`
- ハンドオフ: `docs/handoff/phase-15-handoff.md`
- 設計/API: `docs/design/backend-cranelift-aot-design.md`, `docs/design/*`
■ 合否基準P0: Ny→MIR→MIR-Interp→VM 最小成立)
- 自作Nyashパーサ最小サブセットが Nyash で動作し、テスト入力から中間形式(JSON暫定)を生成できる。
- Runner が中間形式を MIRModule に変換し、MIR 解釈層で実行して既知の結果(例: `Result: 42`)を出力する。
- 代表ケース(整数四則演算/括弧/returnで往復が安定。
■ JSON IR v0暫定スキーマ
- version: 整数(例: 0
- kind: 固定 "Program"
- body: 配列Stmt[]
- Stmt最小
- { "type": "Return", "expr": Expr }
- Expr最小
- { "type": "Int", "value": 123 }
- { "type": "Binary", "op": "+"|"-"|"*"|"/", "lhs": Expr, "rhs": Expr }
- error失敗時
- { "version":0, "kind":"Error", "error": { "message": "...", "span": {"start":N, "end":M} } }
- 例
- `return 1+2*3` → {"version":0,"kind":"Program","body":[{"type":"Return","expr":{"type":"Binary","op":"+","lhs":{"type":"Int","value":1},"rhs":{"type":"Binary","op":"*","lhs":{"type":"Int","value":2},"rhs":{"type":"Int","value":3}}}}]}
- `return (1+2)*3` → `Binary('*', Binary('+',1,2), 3)` の形で生成
■ 補足(優先/範囲)
- 先行するのは Ny→MIR→MIR-Interp→VM の自己ホスト経路AOTはP2以降
- OS 優先: Windows →(後続で Linux/macOS
- メモリ/GC: P0は整数演算/定数返し中心でNyRT拡張不要。
- Codex 非同期運用: `tools/codex-async-notify.sh``tools/codex-keep-two.sh` 継続利用。
## 実行コマンド(サマリ)
- VM/JIT 実行例
- `printf "Hello\n" | NYASH_CLI_VERBOSE=0 ./target/release/nyash apps/ny-echo/main.nyash`
- `printf "Hello\n" | NYASH_CLI_VERBOSE=0 ./target/release/nyash --backend vm apps/ny-echo/main.nyash`
- AOT/LLVM 系は後段当面OFF
- JSON v0 ブリッジR1 Quick Start
- パイプ実行Unix/WSL: `printf '{"version":0,"kind":"Program","body":[{"type":"Return","expr":{"type":"Binary","op":"+","lhs":{"type":"Int","value":1},"rhs":{"type":"Binary","op":"*","lhs":{"type":"Int","value":2},"rhs":{"type":"Int","value":3}}}}]}' | ./target/release/nyash --ny-parser-pipe`
- ファイル指定Unix/WSL: `./target/release/nyash --json-file sample.json`
- スモークUnix/Windows: `./tools/ny_parser_bridge_smoke.sh` / `pwsh -File tools/ny_parser_bridge_smoke.ps1`
- E2E ラウンドトリップR2
- Unix/WSL: `./tools/ny_roundtrip_smoke.sh`
- Windows: `pwsh -File tools/ny_roundtrip_smoke.ps1`
- tmux通知で並列実行:
- `CODEX_ASYNC_DETACH=1 ./tools/codex-async-notify.sh "./tools/ny_roundtrip_smoke.sh" codex`
- `CODEX_ASYNC_DETACH=1 ./tools/codex-async-notify.sh "pwsh -File tools/ny_roundtrip_smoke.ps1" codex`
- Ny プラグイン列挙R5
- 有効化: `--load-ny-plugins` または `NYASH_LOAD_NY_PLUGINS=1`
- `nyash.toml` 例:
```toml
ny_plugins = [
"apps/std/ny-config.nyash",
"apps/plugins/my-helper.nyash"
]
```
- 実行: 列挙に加え、Interpreterで順次実行ベストエフォート
- ガード: `NYASH_NY_PLUGINS_LIST_ONLY=1` で列挙のみ(実行しない)
- 注意: プラグインスクリプトは副作用の少ない初期化/登録処理に限定推奨。
- Std Ny スモーク実行(任意): `NYASH_LOAD_NY_PLUGINS=1 ./tools/jit_smoke.sh`
## トレース/環境変数(抜粋)
- AOT/Link: `NYASH_LINKER`, `NYASH_LINK_FLAGS`, `NYASH_LINK_VERBOSE`
- ABI: `NYASH_ABI_VTABLE=1`, `NYASH_ABI_STRICT=1`
- VM/JIT: `NYASH_VM_PIC_STATS`, `NYASH_JIT_DUMP` など従来通り
---
詳細な履歴や議事録は docs 配下の Phase 15 セクションを参照してください。
- ny-configR4
- `./target/release/nyash apps/std/ny-config.nyash`
- 現状: Interpreter 経路のプラグイン初期化順序により FileBox/TOMLBox を使うには Runner 側の微調整が必要VM 経路への移行 or プラグイン登録の早期化)。スクリプト本体は追加済み。
- 直結ブリッジ v0R3 Quick Start
- `printf 'return (1+2)*3\n' > t.ny && NYASH_USE_NY_PARSER=1 NYASH_DUMP_JSON_IR=1 ./target/release/nyash t.ny`
---
New Plan — SelfHost Dependency Tree (Nyonly) and Bridge20250907
目的
- Ny スクリプトのみで依存木include + using/moduleを再帰解析して JSON を出力。Rust ビルド無しで回せる内側ループを整備。
- 既存の MIR→VM→AOT 系とは疎結合を維持しつつ、最小の橋渡しJSONファイル経由を用意。
実装項目(最小)
- ツール: `apps/selfhost/tools/dep_tree_simple.nyash`
- 1ファイル・静的boxで実装。1行1文break無しelseは同一行。
- 解析: `include "..."`、`using ns``using ns as Alias`、`using "./path" as Name`、`// @module ns=path`。
- 解決順: `module > 相対 > using-path`using-path 既定: `apps/selfhost:apps:lib:.`)。
- JSON: `{ version, root_path, tree{ path, includes[], uses[], modules[], children[] } }`uses は unresolved/hint/alias/resolved を含む)。
- タスク/Make:
- `nyash.toml [tasks].dep_tree` を追加し、1コマンドで JSON を `tmp/deps.json` に出力。
- `make dep-tree`: `cargo build --release && ./target/release/nyash --run-task dep_tree`。
- 受け入れ基準:
- `make dep-tree` が `tmp/deps.json` を出力。曖昧複数ヒットは注記STRICT で停止。
- VM/Interpreter いずれでも実行可File/Path/Array/Map 最小APIで実装
橋渡しStage 1: 疎結合)
- `NYASH_DEPS_JSON=<path>` を Runner で読取りログ出力等の診断用途。MIR/JIT/AOT の挙動は不変。
- 後続Stage 2以降は JSON IR `extensions.deps` や lock ファイルの導入を検討(別期)。
進め方(短期)
1) `dep_tree_simple.nyash` の完走化VM実行での File/Path 最小APIのみ使用
2) `nyash.toml` へ `dep_tree` 追加+ `make dep-tree` 整備。
3) Runner へ `NYASH_DEPS_JSON` の最小読込み(ログ出力)を追加(影響ゼロの範囲)。

View File

@ -0,0 +1,32 @@
# Archived Reports
このフォルダには、過去の分析レポート・リファクタリング計画など、歴史的記録として保持するドキュメントを格納しています。
## ファイル一覧
### REFACTORING_ANALYSIS_REPORT.md
- **作成日**: 2025年9月以前
- **内容**: 古いリファクタリング分析レポート
- **状態**: アーカイブ(参考資料)
- **最新情報**: `docs/development/refactoring/` を参照
### analysis_report.md
- **作成日**: 2025-11-01
- **内容**: 古い分析レポート
- **状態**: アーカイブ(参考資料)
- **最新情報**: `docs/development/` 配下の最新ドキュメントを参照
---
## 注意事項
これらのドキュメントは**歴史的記録**として保持されています。
- ✅ 参考資料として閲覧可能
- ⚠️ 最新の情報ではない可能性あり
- 🔍 最新情報は `docs/development/` 配下を参照してください
---
**アーカイブ日**: 2025-11-04
**整理者**: Claude CodePhase 2クリーンアップ

View File

@ -198,6 +198,36 @@ git status --short
1. **AGENTS.md**508行の扱い 1. **AGENTS.md**508行の扱い
- 選択肢A: 分割(開発原則を独立文書化)← 推奨 - 選択肢A: 分割(開発原則を独立文書化)← 推奨
- 選択肢B: 保持(現状維持) - 選択肢B: 保持(現状維持)
---
## ⚠️ 既知の注意点と連絡先(問題があれば教えてください)
- include の撤去影響(言語非対応の方針):
- 一部の開発用スクリプトで `include` に依存していた場合、実行時に警告/エラーへと変化します。
- 解決策: using+alias へ置換、必要時のみ test-harness の preinclude を使用。
- verify 経路の直行化env JSON → hv1/Core
- 古いラッパー経由の -c 期待と差が出る可能性があります。
- 直行は「最後の行が数値=rc」という契約です。工具やCIの抽出処理をご確認ください。
- alias 解決キャッシュ:
- `modules.workspace` 追加により、初回解決時にファイルシステムを走査します。
- 大規模変更直後は `NYASH_RESOLVE_TRACE=1` で初期化挙動をご確認ください。
- 文書リンクの移動:
- 主要リンクは更新済みですが、private ノートや社外資料のブックマークは無効になっている可能性があります。
問題や不整合を見つけた場合は、次の情報を添えてお知らせください:
- 症状(例: コマンドとエラーメッセージ、ログ数行)
- 影響範囲(どのドキュメント/スクリプト/テストか)
- 期待動作(何が起きてほしかったか)
Issue/連絡先:
- GitHub Issue推奨: タグ `cleanup-2025-11-04` を付けてください。
- または Slack #dev-tools チャンネルへ(リンクとログ断片を添付)。
本クリーンアップにより、探索性・再現性・サイズが大幅に改善されています。小さな揺れは迅速に直しますので、発見次第お気軽にご連絡ください。
- 選択肢C: .claude/に移動(非表示化) - 選択肢C: .claude/に移動(非表示化)
2. **CHANGELOG.md**28行、更新停止中の扱い 2. **CHANGELOG.md**28行、更新停止中の扱い

View File

@ -0,0 +1,189 @@
# 🧹 Phase 2 実行レポート 2025-11-04
**実行日時**: 2025-11-04 16:45
**実行者**: Claude Code
**Phase**: 整理・統合
---
## ✅ Phase 2 完了サマリー
### 実行内容
#### Phase 2-A: CURRENT_TASK系の統合 ✅
**目的**: 重複・古いCURRENT_TASKファイルの整理
**実行内容**:
1. **保持**: `CURRENT_TASK.md`最新版、15KB
2. **移動**: `CURRENT_TASK_ARCHIVE_2025-09-27.md`153KB`docs/development/archive/current_task/CURRENT_TASK_ARCHIVE_2025-09-27.md`
3. **削除**: `CURRENT_TASK_restored.md`67KB、古いバックアップ
4. **削除**: `docs/development/current_task_archive/`フォルダ(重複のため)
**結果**:
- ✅ CURRENT_TASK系ファイルを1箇所に統一
- ✅ 重複フォルダ削除
- ✅ アーカイブは `docs/development/archive/current_task/` に統一
---
#### Phase 2-B: CODEX_QUESTION系の整理 ✅
**目的**: バックアップファイルの削除
**実行内容**:
1. **保持**: `CODEX_QUESTION.md`最新版、4.5KB
2. **削除**: `CODEX_QUESTION_backup.md`3.7KB、バックアップ不要)
**理由**: git履歴があるのでバックアップ不要
**結果**:
- ✅ バックアップ削除完了
- ✅ 最新版のみ保持
---
#### Phase 2-C: 古いレポートの移動 ✅
**目的**: 古い分析レポートをアーカイブに整理
**実行内容**:
1. **移動**: `REFACTORING_ANALYSIS_REPORT.md`6.8KB)→ `docs/archive/reports/`
2. **移動**: `analysis_report.md`21KB`docs/archive/reports/`
3. **作成**: `docs/archive/reports/README.md`(アーカイブ説明)
**結果**:
- ✅ 古いレポートをアーカイブに移動
- ✅ README.mdでアーカイブの目的を明記
- ✅ プロジェクトルートがクリーンに
---
## 📊 削減・整理効果
### ファイル整理
- **削除ファイル**: 3個
- CURRENT_TASK_restored.md
- CODEX_QUESTION_backup.md
- docs/development/current_task_archive/(フォルダ)
- **移動ファイル**: 3個
- CURRENT_TASK_ARCHIVE_2025-09-27.md
- REFACTORING_ANALYSIS_REPORT.md
- analysis_report.md
### 構造改善
- ✅ CURRENT_TASK系が1箇所に統一
- ✅ アーカイブ構造が明確化(`docs/archive/reports/`
- ✅ プロジェクトルートがさらにクリーン
---
## 🧪 検証結果
### ビルド検証
```bash
cargo build --release
```
- **結果**: ✅ 成功
- **警告**: 111個既存のもの、Phase 2による新規警告なし
- **コンパイル時間**: 0.07s(インクリメンタル)
### 実行検証
```bash
./target/release/hakorune /tmp/phase2_test.nyash
```
- **テストコード**: `print("Phase 2 OK!")`
- **結果**: ✅ 成功
- **出力**: `Phase 2 OK!`
### Git状態
```bash
git status --short
```
- **削除**: 6個CURRENT_TASK系3 + CODEX_QUESTION_backup + レポート2
- **修正**: 2個CURRENT_TASK.md + CLEANUP_REPORT
- **新規**: 1フォルダdocs/archive/reports/
- **競合**: なし
---
## 📝 重要な判断事項
### AGENTS.md は保持
- **理由**: codex用ultrathink、削除してはいけない
- **状態**: 保持Phase 3で検討しない
### アーカイブ方針
- **統一先**: `docs/development/archive/current_task/`
- **古いレポート**: `docs/archive/reports/`
- **README.md**: 各アーカイブフォルダに説明を追加
---
## 🎯 Phase 2 達成内容
### 整理完了
- ✅ CURRENT_TASK系の重複解消
- ✅ CODEX_QUESTION系のバックアップ削除
- ✅ 古いレポートのアーカイブ化
### 構造改善
- ✅ アーカイブ構造の明確化
- ✅ プロジェクトルートのクリーン化
- ✅ 歴史的記録の適切な保管
### 品質保証
- ✅ ビルド成功
- ✅ 実行確認
- ✅ Git状態クリーン
---
## 📚 アーカイブ構造
### 現在のアーカイブ構造
```
docs/
├── archive/
│ ├── reports/ # 古い分析レポートPhase 2新設
│ │ ├── README.md
│ │ ├── REFACTORING_ANALYSIS_REPORT.md
│ │ └── analysis_report.md
│ └── ...
└── development/
└── archive/
└── current_task/ # CURRENT_TASK履歴
├── CURRENT_TASK_2025-09-27.md
├── CURRENT_TASK_20251004-072112.md
├── CURRENT_TASK_ARCHIVE_2025-09-27.md # Phase 2で追加
└── claude_task_20251003-20251004.md
```
---
## ⏭️ 次のステップ
### Phase 3は実施不要
- **AGENTS.md**: codex用ultrathinkのため保持
- **CHANGELOG.md**: ユーザー判断待ち(オプション)
- **paper_review_prompts.md**: ユーザー判断待ち(オプション)
---
## 🎉 Phase 2 完全達成!
**整理完了項目**:
- ✅ CURRENT_TASK系の統合3ファイル → 1ファイル
- ✅ CODEX_QUESTION系の整理2ファイル → 1ファイル
- ✅ 古いレポートのアーカイブ化2ファイル移動
- ✅ アーカイブ構造の明確化README.md追加
- ✅ ビルド・実行検証完了
**Phase 1 + Phase 2 合計削減効果**:
- **容量削減**: 700MBPhase 1
- **ファイル削減**: 70+個Phase 1: 69個 + Phase 2: 6個
- **構造改善**: プロジェクトルート・docs/構造の大幅クリーン化
---
**完了日時**: 2025-11-04 16:50
**総作業時間**: Phase 1 30分 + Phase 2 10分 = 40分
**品質**: ✅ 全チェック完了、問題なし
**次のアクション**: コミット作成(オプション)

View File

@ -65,6 +65,7 @@ mini_vm_lib = "mini_vm_lib.hako"
"hakorune-vm.compare_handler" = "hakorune-vm/compare_handler.hako" "hakorune-vm.compare_handler" = "hakorune-vm/compare_handler.hako"
"hakorune-vm.copy_handler" = "hakorune-vm/copy_handler.hako" "hakorune-vm.copy_handler" = "hakorune-vm/copy_handler.hako"
"hakorune-vm.unaryop_handler" = "hakorune-vm/unaryop_handler.hako" "hakorune-vm.unaryop_handler" = "hakorune-vm/unaryop_handler.hako"
"hakorune-vm.ir.types" = "hakorune-vm/ir/types.hako"
[private] [private]
# helpers = "internal/helpers.hako" # helpers = "internal/helpers.hako"

View File

@ -15,6 +15,7 @@ using selfhost.vm.helpers.v1_schema as V1SchemaBox
using selfhost.vm.helpers.mir_call_v1_handler as MirCallV1HandlerBox using selfhost.vm.helpers.mir_call_v1_handler as MirCallV1HandlerBox
using selfhost.vm.helpers.v1_phi_table as V1PhiTableBox using selfhost.vm.helpers.v1_phi_table as V1PhiTableBox
using selfhost.vm.helpers.v1_phi_adapter as V1PhiAdapterBox using selfhost.vm.helpers.v1_phi_adapter as V1PhiAdapterBox
using selfhost.vm.hakorune-vm.ir.types as V1IrTypes
static box NyVmDispatcherV1Box { static box NyVmDispatcherV1Box {
// Internal scanner (block0 only): const / mir_call / ret // Internal scanner (block0 only): const / mir_call / ret
@ -104,6 +105,8 @@ static box NyVmDispatcherV1Box {
local op = ent.get("op") local op = ent.get("op")
local item = ent.get("text") local item = ent.get("text")
if op == null || item == null { continue } if op == null || item == null { continue }
// Optional: build typed IR shadow (構造のみ、挙動不変)
me._maybe_typed_shadow(ent)
// Dispatch // Dispatch
if op == "const" { OpHandlersBox.handle_const(item, regs) } if op == "const" { OpHandlersBox.handle_const(item, regs) }
else if op == "compare" { else if op == "compare" {
@ -137,6 +140,28 @@ static box NyVmDispatcherV1Box {
} else { return MirVmMin.run_min(json) } } else { return MirVmMin.run_min(json) }
} }
} }
// Build typed IR shadow object for debugging/SSOT導入の段階準備flag: HAKO_V1_TYPED_IR_SHADOW=1
_maybe_typed_shadow(ent) {
if env.get("HAKO_V1_TYPED_IR_SHADOW") != "1" { return 0 }
local op = ent.get("op"); if op == null { return 0 }
// Construct minimal typed IR box per op (構造のみ). 値は文字列/整数としてそのまま格納する。
if op == "const" {
local b = new V1IrTypes.V1ConstIR(); b.target_reg = ent.get("dst"); b.value = ent.get("text"); return 0
}
if op == "compare" {
local b = new V1IrTypes.V1CompareIR(); b.op = ent.get("cmp"); b.lhs = ent.get("lhs"); b.rhs = ent.get("rhs"); b.target_reg = ent.get("dst"); return 0
}
if op == "branch" {
local b = new V1IrTypes.V1BranchIR(); b.condition = ent.get("cond"); b.then_block = ent.get("then"); b.else_block = ent.get("else"); return 0
}
if op == "jump" {
local b = new V1IrTypes.V1JumpIR(); b.target_block = ent.get("target"); return 0
}
if op == "ret" {
local b = new V1IrTypes.V1RetIR(); b.value = ent.get("value"); return 0
}
return 0
}
// Main entry: Choose internal scanner when enabled; otherwise delegate to MiniVM // Main entry: Choose internal scanner when enabled; otherwise delegate to MiniVM
run(json) { run(json) {
if env.get("HAKO_V1_DISPATCHER_FLOW") == "1" { return me.run_scan_flow(json) } if env.get("HAKO_V1_DISPATCHER_FLOW") == "1" { return me.run_scan_flow(json) }

View File

@ -0,0 +1,38 @@
// Hako v1 Typed IR (SSOT) — structure only
// Responsibility: Define minimal typed IR boxes used as a shared structure
// for reading/writing MIR v1 in Hakorune components. No execution logic.
box V1ConstIR {
value: StringBox
target_reg: IntegerBox
}
box V1CompareIR {
op: StringBox
lhs: IntegerBox
rhs: IntegerBox
target_reg: IntegerBox
}
box V1BranchIR {
condition: IntegerBox
then_block: IntegerBox
else_block: IntegerBox
}
box V1JumpIR {
target_block: IntegerBox
}
// incoming: [[pred:int, val:int], ...]
box V1PhiIR {
target_reg: IntegerBox
incoming: ArrayBox
}
box V1RetIR {
value: IntegerBox
}
static box V1IrTypesMain { method main(args) { return 0 } }

View File

@ -269,17 +269,6 @@ verify_mir_rc() {
if [ "${HAKO_VERIFY_V1_FORCE_CORE:-0}" = "1" ]; then if [ "${HAKO_VERIFY_V1_FORCE_CORE:-0}" = "1" ]; then
"$NYASH_BIN" --mir-json-file "$json_path" >/dev/null 2>&1; return $? "$NYASH_BIN" --mir-json-file "$json_path" >/dev/null 2>&1; return $?
fi fi
# Inline driver (env JSON): avoid embedding large JSON literal to keep parser robust
local code_v1=$(cat <<'HCODE'
using selfhost.vm.hv1.dispatch as NyVmDispatcherV1Box
static box Main { method main(args) {
local j = env.get("NYASH_VERIFY_JSON")
local rc = NyVmDispatcherV1Box.run(j)
print("" + rc)
return rc
} }
HCODE
)
# hv1 直行NyashParserバイパス: vm.rs冒頭で NYASH_VERIFY_JSON を検知して MIR 実行 # hv1 直行NyashParserバイパス: vm.rs冒頭で NYASH_VERIFY_JSON を検知して MIR 実行
local out_v1; out_v1=$(HAKO_V1_FLOW_TRACE=1 HAKO_V1_EXTERN_PROVIDER=1 HAKO_V1_DISPATCHER_FLOW=1 HAKO_V1_ALLOW_PHI_EXPERIMENT=1 \ local out_v1; out_v1=$(HAKO_V1_FLOW_TRACE=1 HAKO_V1_EXTERN_PROVIDER=1 HAKO_V1_DISPATCHER_FLOW=1 HAKO_V1_ALLOW_PHI_EXPERIMENT=1 \
HAKO_FAIL_FAST_ON_HAKO_IN_NYASH_VM=0 HAKO_ROUTE_HAKOVM=1 \ HAKO_FAIL_FAST_ON_HAKO_IN_NYASH_VM=0 HAKO_ROUTE_HAKOVM=1 \
@ -288,28 +277,6 @@ HCODE
if [[ "$out_v1" =~ ^-?[0-9]+$ ]]; then if [[ "$out_v1" =~ ^-?[0-9]+$ ]]; then
local n=$out_v1; if [ $n -lt 0 ]; then n=$(( (n % 256 + 256) % 256 )); else n=$(( n % 256 )); fi; return $n local n=$out_v1; if [ $n -lt 0 ]; then n=$(( (n % 256 + 256) % 256 )); else n=$(( n % 256 )); fi; return $n
fi fi
# Optional dev fallback: prelude_v1 include + preincludealias-only が安定したら撤去)
if [ "${SMOKES_HV1_INCLUDE_FALLBACK:-0}" = "1" ]; then
local code_v1_inc=$(cat <<'HCODE'
include "lang/src/vm/hakorune-vm/prelude_v1.hako"
static box Main { method main(args) {
local j = env.get("NYASH_VERIFY_JSON")
local rc = NyVmDispatcherV1Box.run(j)
print("" + rc)
return rc
} }
HCODE
)
out_v1=$(HAKO_ENABLE_USING=1 NYASH_ENABLE_USING=1 NYASH_USING_AST=1 \
HAKO_PREINCLUDE=1 NYASH_PREINCLUDE=1 \
HAKO_V1_FLOW_TRACE=1 HAKO_V1_EXTERN_PROVIDER=1 HAKO_V1_DISPATCHER_FLOW=1 HAKO_V1_ALLOW_PHI_EXPERIMENT=1 \
HAKO_FAIL_FAST_ON_HAKO_IN_NYASH_VM=0 \
NYASH_VERIFY_JSON="$(cat "$json_path")" \
run_nyash_vm -c "$code_v1_inc" 2>/dev/null | tr -d '\r' | awk '/^-?[0-9]+$/{n=$0} END{if(n!="") print n}')
if [[ "$out_v1" =~ ^-?[0-9]+$ ]]; then
local n=$out_v1; if [ $n -lt 0 ]; then n=$(( (n % 256 + 256) % 256 )); else n=$(( n % 256 )); fi; return $n
fi
fi
# No include+preinclude fallback succeeded → Core にフォールバック # No include+preinclude fallback succeeded → Core にフォールバック
"$NYASH_BIN" --mir-json-file "$json_path" >/dev/null 2>&1 "$NYASH_BIN" --mir-json-file "$json_path" >/dev/null 2>&1
return $? return $?