Files
hakorune/docs/development/current/CURRENT_TASK.md
Moe Charm 59b8cb3ace Phase 11.9: 統一文法アーキテクチャ作業中 - MIR builder分割とJIT lower整理
- MIR builder: stmts/exprs/typeingモジュール分割による整理
- JIT lower: core/ops_ext.rs追加(外部呼び出し系の分離)
- 統一文法エンジン基盤構築中(grammar/unified-grammar.toml対応)
- ChatGPT5協調作業: M1完了、M2作業中

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-03 01:37:38 +09:00

51 KiB
Raw Blame History

🎯 CURRENT TASK - 2025-09-01 SnapshotAsync Task System / Phase 11.7 + Plugin-First

このスナップショットは Phase 11.7 の Async Task System 進捗を反映しました。詳細仕様/計画は下記を参照。

  • SPEC: docs/development/roadmap/phases/phase-11.7_jit_complete/async_task_system/SPEC.md
  • PLAN: docs/development/roadmap/phases/phase-11.7_jit_complete/async_task_system/PLAN.md

Async Task System進捗サマリ

  • P1 完了: FutureBox を Mutex+Condvar化。await は safepoint + timeout でハング抑止。
    • VM/Unified: env.future.awaitResult.Ok(value) / Result.Err("Timeout") を返却。
    • JIT: await_hresult.ok_h ラップ済。さらに result.err_h 追加と Ok/Err 分岐を Lowerer に実装。
    • 修正: FutureBox クローンを共有化Arcし、spawn側のsetterと呼び出し側のFutureが同一待機点を共有。
  • P2着手・足場: CancellationToken / TaskGroup雛形
    • VM 経路: env.future.spawn_instancespawn_task_with_token(current_group_token(), ..) に配線no-opトークン
    • 付随: 暗黙グループの子Futureをグローバル登録best-effortし、簡易joinAllの足場global_hooks.join_all_registered_futures
    • TaskGroupBox: cancelAll()/joinAll(ms?) をVM BoxCallで受付plugins-only環境では new は不可)。
    • Runner終端: NYASH_JOIN_ALL_MS(既定2000ms)で暗黙グループの子Futureをbest-effort join。
    • グループ/トークンはスカフォールドPhase 2で実体実装: 伝播/キャンセル/join順序
  • P3第一弾: Await の Result 化JIT側
    • 新規シム: nyash.result.err_h(handle) 追加(<=0時は Err("Timeout") を生成)。
    • Lowerer: awaitawait_h → (ok_h, err_h) → handle==0 で select に更新。

MIR 層の設計(合意メモ)

  • 原則: 「すべては箱」+「汎用呼び出し」で表現し、専用命令は最小限。
  • 箱の面MIRから見えるもの
    • TaskGroupBox: spawn(recv, method, args…) -> Future, cancelAll(), joinAll(timeout_ms?), fini(将来)
    • FutureBox: await(timeout_ms?) -> Result<T, Err>, cancel(), isReady()
    • ResultBox: 既存Ok/Err
  • MIR表現
    • nowait: 当面は ExternCall("env.future","spawn_instance", [recv, mname, ...])。TaskGroup実体が固まり次第 BoxCall TaskGroup.spawn(...) に移行。
    • await: 既存 MirInstruction::Await を使用Lowererが await 前後に env.runtime.checkpoint を自動挿入)。
    • checkpoint: ExternCall("env.runtime","checkpoint") 相当。Verifierで Await の前後必須(実装済)。
  • Loweringと実装対応
    • VM: spawn_instance→scheduler enqueue、Future.get()+timeout→Result.Ok/Err("Timeout")、checkpointでGC+scheduler.poll
    • JIT/AOT: await_h→i64 handle(0=timeout)→result.ok_h/err_hでResult化。checkpointは nyash.rt.checkpoint シムに集約。
  • 効果: VM/JIT/AOTが同形のMIRを見て、JIT/EXEは既存のシムで統一挙動を実現。Verifierでawait安全性を機械チェック。

引き継ぎ2025-09-01, late

  • これまでに着地したもの(コード)

    • Await 正規化JIT: nyash.result.err_h 追加、await_h → ok_h/err_h → select で Result.Ok/Err に統一。
    • Await 安全性: Builder が await 前後に Safepoint 自動挿入、Verifier が前後 checkpoint 必須を検証(--verify)。
    • Future 共有/弱化: FutureBox を Arc 共有に、FutureWeak を追加(downgrade()/is_ready())。
    • 暗黙/明示 TaskGroup 足場:
      • global_hooks: 強/弱レジストリ、関数スコープ push_task_scope()/pop_task_scope()外側でbesteffort join
      • VM: 関数入口/出口にスコープ push/pop を配線JIT早期return含む
      • TaskGroupBox: inner.strong で子Futureを強参照所有、add_future() / joinAll(ms) / cancelAll()scaffold
      • env.future.spawn_instance 生成Futureは「現スコープのTaskGroup」または暗黙グループへ登録。
  • 次の実装順(小粒から順に)

    1. TaskGroupBox.spawn(recv, method, args…)->Future を実装(所有は TaskGroupBox
      • Builder の nowait を BoxCall TaskGroup.spawn に段階移行fallback: ExternCall env.future.spawn_instance)。
    2. LIFO join/cancel: スコープTaskGroupをネスト順で cancelAll→joinAll(まずは join、次段で token 伝播)。
    3. Err 統一P3後半: Cancelled/Panic を Result.Err に統一JIT/AOT必要なら NyRT シム追加)。
    4. テスト/CI:
      • 単体feature-gated: Futureの強/弱参照・join・スコープjoinの確認。
      • E2E: nowait→awaitOk/Timeout、終端join を {vm, jit, aot}×{default, strict} でスモーク化。
      • CI に async 3本timeoutガード付きを最小マトリクスで追加。
  • 実行・フラグ

    • NYASH_AWAIT_MAX_MS既定5000: await のタイムアウト。
    • NYASH_JOIN_ALL_MS既定2000: Runner 終端 join のタイムアウト。
    • NYASH_TASK_SCOPE_JOIN_MS既定1000: 関数スコープ pop 時の join タイムアウト。
  • 参考(動かし方)

    • ビルド: cargo build --release --features cranelift-jit
    • スモーク: tools/smoke_async_spawn.shVM/JIT, timeout 10s + NYASH_AWAIT_MAX_MS=5000
    • デモ: apps/tests/taskgroup-join-demo/main.nyash(スコープ/終端 join の挙動確認)
  • 既知の制約/注意

    • pluginsonly 環境では new TaskGroupBox() は未実装箱自体はVM側で動くが、プラグイン同梱は未
    • cancel はフラグのみ(次段で CancellationToken 伝播と await 時の Cancelled をErrで返す
    • いくつかの既存テストが赤別領域の初期化不備。asyncテストはfeatureゲートで段階導入予定。

参考コード(主要差分)

  • Runtime/スケジューラ+フック
    • src/runtime/scheduler.rs: spawn_with_token を含む Scheduler スケルトン。
    • src/runtime/global_hooks.rs: spawn_task_with_tokencurrent_group_token() を追加。
  • TaskGroup雛形
    • src/boxes/task_group_box.rs: 取消状態のみ保持(将来の伝播に備える)。
  • Await の Result 化
    • VM: src/backend/vm_instructions.rsResult.Okへ包む
    • Unified/V2: src/runtime/plugin_loader_{unified,v2}.rsenv.future.await を Ok/Err(Timeout) で返却)。
    • JIT: src/jit/extern/{async.rs,result.rs}await_hok_h/err_h)、src/jit/lower/core.rsawait分岐src/jit/lower/builder.rs(シンボル登録)。
  • スモーク
    • tools/smoke_async_spawn.shtimeout 10s + NYASH_AWAIT_MAX_MS=5000)。
    • 参考デモ: apps/tests/taskgroup-join-demo/main.nyashRunner終端joinの動作確認

次の実装順(合意済み)

  1. Phase 2: VMの暗黙TaskGroup配線現状no-opトークンで着地→次にグループ実体join/cancel実装
  2. Phase 3: JIT側のErr統一Timeout以外: Cancelled/Panicの表出整理、0/None撤去の完了
  3. Verifier: await前後のcheckpoint検証ルール追加実装済・--verifyで有効
  4. CI/Smokes: async系3本を最小マトリクスでtimeoutガード

🎯 CURRENT TASK - 2025-08-30 Restart SnapshotPlugin-First / Core最小化

このスナップショットは最新の到達点へ更新済み。再起動時はここから辿る。

現在の着地(実装済み)

  • プラグイン仕様・ローダー(二層)
    • 各プラグインに plugins/<name>/nyash_box.tomltype_id/methods/lifecycle/artifacts
    • 中央 nyash.toml: [plugins][box_types] を利用、[libraries] は最小互換で維持。
    • Loader: nyash_box.toml 優先で type_id/メソッド解決、従来ネストへフォールバック。
  • 追加プラグイン(最低限)
    • ConsoleBox: stdout 出力log/println
    • Math/Time: MathBox(sqrt/sin/cos/round: f64返り)/TimeBox(now: i64)。
    • 既存: filebox/string/map/array/python/integer/counter/net。
  • MIR/VM 統一
    • 新 MIR 命令 PluginInvoke を導入。Builder は常に PluginInvoke を生成BoxCall廃止方向
    • VM: execute_plugin_invoke 実装TLV encode/戻り decode、f64/handle含む。Handle(tag=8)→PluginBoxV2 復元対応。
  • ビルトイン制御
    • レガシーのビルトインBox工場を削除plugins専用化
    • NYASH_PLUGIN_ONLY=1 で完全プラグイン運用(既定運用)。
    • env.console をプラグインConsoleBoxに自動バインドVMのref_get特例
    • VM側で static birth 緩和プリミティブ受け手→プラグインBox生成
    • 文字列/整数の自動変換: Plugin StringBox→toUtf8()でTLV string、Plugin IntegerBox→get()でTLV i64。
  • PythonプラグインPhase 10.5c 足場)
    • eval/import/getattr/call/str のRO経路をVMで動作autodecode: NYASH_PY_AUTODECODE=1
    • returns_result…R系をVMが尊重し、Ok/ErrをResultに包んで返却。
    • 追加サンプル: py_eval_env_demo.nyash, py_math_sqrt_demo.nyash, py_result_ok_demo.nyash, py_result_error_demo.nyash, py_getattrR_ok_demo.nyash, py_callR_ok_demo.nyash
  • スモーク
    • tools/smoke_plugins.sh: python/integer/console/math_time をVMで実行STRICT/デフォルト)。

AOT/ネイティブ(最小経路の到達点)

  • tools/build_aot.sh + crates/nyrt: JIT→.o 生成→ libnyrt.a とリンクしEXE化に成功。
  • 最小AOT例: examples/aot_py_eval_env_min.nyashNYASH_PY_EVAL_CODE で式注入でバイナリ生成・実行OK。
  • nyrtシム強化: nyash_plugin_invoke3_{i64,f64} が StringBox/IntegerBox ハンドルを TLV(string/i64) に自動変換import/getattr/call で使用可能)。
  • Lowerer緩和: strict時の new/birth/evalPyRuntime/Integerを no-op 許容→未サポカウントを抑制。
  • 現状のAOT結果: 未サポート命令は大幅削減27→5→今後0を目標

🎯 次のやること(短期)

  1. Python3メソッドの AOT 実Emit最小:
    • Lowerer: emit_plugin_invokePyRuntimeBox.import/getattrPyObjectBox.call を直接生成has_ret/argc 正規化)。
    • nyrtシム: 追加の型Bool/Float/Bytesの引数TLVパスを確認し、必要なら拡張。
  2. AOTの結果出力の最小対応:
    • ConsoleBox.println の strict 経路extern寄せ or 直接 PluginInvokeの緩和で簡易表示を可能に。
  3. returns_result サンプルの拡充:
    • importR/getattrR/callR/callKwR の OK/Err を網羅、表示体裁Ok(...)/Err(...))の最終化。
  4. CI/Golden 更新:
    • AOT最小ルートeval/envと VM Python スモークを追加。将来 {vm,jit,aot} × {gc on,off} に拡張。
  5. ドキュメント整備:
    • Plugin-First 運用(NYASH_PLUGIN_ONLY=1)、@env ディレクティブ、最小AOT手順と制約の明記。

🆕 2025-08-30 PM — Python/AOT 進捗と残タスク(引き継ぎ)

到達

  • eval方式NYASH_PY_EVAL_CODE または py.eval(<code>))で AOT unsupported=0 達成。.o 生成OK、Console出力OK。
  • NYASH_PY_AUTODECODE=1 でプリミティブ返りFloatBox→f64を確認例: 4.0)。
  • Console 橋渡し(env.console.log/println → ConsoleBoxを strict 経路で実行可能に。
  • nyrtシムで String/Integer 引数を TLV(tag=6/3) に自動変換import/getattr/call の基盤整備)。
  • 戻りバッファの動的拡張で AOT 実行時の短バッファ起因の不安定さを軽減。
  • VM: per-runtime globals 実装により py.import("math"); py.eval("math.sqrt(16)") が Greenautodecode=1 で 4
    • 例: examples/test_py_context_sharing.nyash(戻り値で最終結果を確認)

現状の制約 / 不具合

  • VM: py.import("math") の後に py.eval("math.sqrt(16)") が "name 'math' is not defined"(文脈共有が未確立)。
    • 2025-08-30 解消: PyRuntimeInstance に per-runtime globals(dict) を実装birthで __main__ dict 確保、import成功時にglobalsへ挿入、evalは同globalsで評価
  • getattr/callPyObjectBox: AOT 実Emitはまだ限定Lowerer が import 返りの Box 型を把握できない)。
    • 対策方針(更新): Python特化の型伝搬を撤廃し、Handle-First で汎用化。戻りが box のメソッドは「HandleTLV tag=8」として扱い、Lowerer は emit_plugin_invoke のみ(箱名固定を行わない)。必要に応じて by-name シムで実行時解決。

🎯 次タスク(実装順・更新済)

  1. 設計ドキュメント反映(最優先)
    • phase-10.5/10.5c-handle-first-plugininvoke-plan.md を追加(完了)。
    • MASTER_ROADMAP からの導線追記別PRで可
  2. Lowerer 汎用化Python特化排除
    • Python固有の型伝搬dst=PyObjectBox 記録)を撤去し、戻りが box の場合は Handle として扱う(型名固定なし)。
    • emit_plugin_invoke は従来どおり使用has_ret/argc 正規化)。
  3. メタデータ解決
    • PluginHost.resolve_methodreturns.type を露出。Lowerer が box/primitive のみを参照。
  4. by-name シムの導入(必要時)
    • nyrt/builder に nyash_plugin_invoke_by_name_{i64,f64} を追加し、受け手箱名未確定時の実行時解決に使用。
  5. AOT 実行の安定化
    • nyrt シム: Bytes/Bool/Float/複数引数 TLV のカバレッジ拡大。
    • 連鎖import→getattr→callの最小AOT例を Greenunsupported=0
  6. ドキュメント/サンプル更新
    • Handle-First のガイドと最小AOT手順の追記。

10.5c ドキュメント/サンプル 追加(本スナップショット)

  • FFI最小仕様a0/a1/a2, 戻りTLVを短文化: docs/reference/abi/ffi_calling_convention_min.md
  • birth引数の一般化メモ可変長TLV/例外伝搬): docs/ideas/new-features/2025-08-30-birth-args-tlv-generalization.md
  • Python最小チェーンの追加:
    • VM: examples/py_min_chain_vm.nyash
    • AOT: examples/aot_py_min_chain.nyash

10.5d AOT統合 仕上げ(今回)

  • ガイド追加: docs/guides/build/aot_quickstart.mdCLI/スクリプト/内部フロー/FAQ
  • by-nameシム整理: nyrtの nyash_plugin_invoke_name_{getattr,call}_i64 をFFI要約へ反映
  • スモーク更新: tools/smoke_aot_vs_vm.sh に Python最小チェーンを追加VM側は NYASH_PY_AUTODECODE=1
  • 今後: nyrtシムのTLV拡充bytes/N引数、Windowsのプラグイン探索微調整

10.5e 小仕上げ(今回)

  • nyrtシム TLV拡充: BufferBox→bytes(tag=7) 自動エンコード、3引数目以降はレガシー引数からTLVに詰める暫定N引数対応
  • Windows探索調整: EXE起動時に PATHへexe/plugins/を追加、PYTHONHOME 未設定時は exe\python を自動採用存在時。相対PYTHONHOMEはexe基準に正規化

次フェーズ: 10.6Thread-Safety / Scheduler

  • 計画: docs/development/roadmap/phases/phase-10.6/PLAN.txt新規
  • 10.6a 監査: Array/Map/Buffer/NyashRuntime/Scheduler の共有戦略Arc+RwLock/Mutexを確認し、未整備箇所をTODO化
  • 10.6b スケジューラ: SingleThreadScheduler を Safepoint で poll() 連携(観測: NYASH_SCHED_DEMO/TRACE/POLL_BUDGET
  • 10.6c 並列GC設計: per-thread roots / safepoint協調 / カードマーキングの段階導入メモ確定

橋渡し: 10.7 Python Nativeトランスパイル / All-or-Nothing

  • 方針と計画: docs/development/roadmap/phases/phase-10.7/PLAN.txt新規
  • 二本立て明確化: 実行系現行PyRuntimeBoxと トランスパイル系Python→Nyash→MIR→AOTを併走。自動フォールバック無し
  • サブフェーズ: C1 Parser1週→ C2 Compiler Core2週→ C3 CLI配線3日→ C4 テスト(並行)
  • 既存導線の活用: 生成Nyashは既存 --compile-native でAOT化Strict

Nyash-only パイプライン(作業場 / 最小導線)

  • 目的: すべてNyashで書き、即実行・即修正できる足場を先に用意
  • 追加ファイル: tools/pyc/
    • PythonParserNy.nyashPyRuntimeBox経由で ast.parse/dump。NYASH_PY_CODE を参照)
    • PyIR.nyashIR最小ヘルパ/ PyCompiler.nyashNyash側コンパイラ骨組み/ pyc.nyashエントリ
  • Parser/Compiler Rustプラグインは雛形として併存将来削減。当面はNyash実装を優先

次の順番(小粒で進める)

  1. Parser JSON→IR 変換の最小実装def/return。tools/pyc/PyCompiler.nyash に追加env NYASH_PY_CODE を Pythonで解析→IR生成
  2. IR→Nyash 生成の最小拡張Return定数→Return文字列/数値に対応、If/Assignは後続
  3. All-or-NothingのStrictスイッチunsupported_nodes 非空ならErr。開閉はenvで制御
  4. CLI隠しフラグ --pyc/--pyc-native を追加し、Parser→Compiler→AOT を一本化内部で現行AOTを使用
  5. サンプル/回帰: tools/pyc の最小ケースをVM/AOTで回し、差分を記録

Python AOTサンプルの追加最小

  • examples/aot_py_min_chain.nyashimport→getattr→call
  • examples/aot_py_result_ok.nyashreturns_result: Ok
  • examples/aot_py_result_err.nyashreturns_result: Err
  • kwargs暫定ブリッジenv eval + **dict: examples/aot_py_eval_kwargs_env.nyash

🔧 実行方法(再起動手順)

cargo build --release --features cranelift-jit
# プラグインをビルドし、VMスモーク
bash tools/smoke_plugins.sh
# 厳格ビルトイン無効2ndパス
NYASH_SMOKE_STRICT_PLUGINS=1 bash tools/smoke_plugins.sh

📌 方針ChatGPT5助言に基づく抜粋

  • Coreは Box/意図/MIR だけ(演算・コレクション等は全部プラグイン)。
  • 呼び出しは常に plugin_invoke(type_id, method_id, argv[])VM/JIT共通
  • フォールバックなし: 未実装は即エラー場所とVM参照関数名を出す
  • MIR 生成の一本化: 既存の built-in 特例を削除し、必ず MIR::PluginInvoke に落とす。
  • VM/JIT の特例削除: if (is_string_length) 等の分岐は撤去。
  • 静的同梱: profile=minimal/std/full で nyplug_*.a/.lib をバンドル(動的読込は将来の nyplug.toml
  • バージョン整合: 起動時に Core v0 ⇔ 各 nyash_plugin_abi() 照合(ミスマッチ即終了)。
  • テスト/CI: 各プラグインに GoldenVM→JIT→AOTの trace_hash 一致、CIマトリクス {vm,jit,aot} × {gc on,off}。

箱を固めるBox-First 原則の再確認)

  • 問題は必ず「箱」に包む: 設定/状態/橋渡し/シムは Box/Host/Registry 経由に集約し、境界を越える処理TLV変換・型正規化は1箇所に固定。
  • 目的優先で足場を積む: 先に no-op/strict緩和で「落ちない足場」を作り、次に値の実Emit・型/戻りの厳密化を段階導入。
  • いつでも戻せる: @env/env変数/featureフラグで切替点を1行に集約。実験→可視化→固定化のサイクルを高速化。

🎯 CURRENT TASK - 2025-08-29Phase 10.5 転回JIT分離=EXE専用

Phase 10.10 は完了DoD確認済。アーキテクチャ転回JITは「EXE/AOT生成専用コンパイラ」、実行はVM一本に統一。

🚀 革新的発見プラグインBox統一化

核心的洞察

  • 既存のプラグインシステムBID-FFIがすでに完全なC ABIを持っている
  • すべてのBoxをプラグイン化すれば、JIT→EXEが自然に実現可能
  • "Everything is Box" → "Everything is Plugin" への進化

⏱️ 今日のサマリArray/Map プラグイン経路の安定化→10.2へ)

  • 実装: Array/Map のプラグインBID-FFI v1を作成し、nyash.toml に統合
  • Lower: NYASH_USE_PLUGIN_BUILTINS=1 で Array(len/get/push/set), Map(size/get/has/set) を emit_plugin_invoke(..) に配線
  • サンプル: array/map デモを追加し VM 実行で正常動作確認
  • 次: 10.2Craneliftの実呼び出しに着手

10.2 追加アップデート2025-08-29 PM

  • static box 内メソッドのMIR関数化に成功

    • 例: Main.helper/1, Main.add/2 が独立関数として生成MIR dumpで確認
    • VM実行でも JIT マネージャの sites に現れる(sites=2
  • JITコンパイル成功

    • Main.helper/1 が JIT コンパイルされ handle 付与handle=1
    • 単純算術(Main.add/2 等)は JIT 実行 exec_ok=1 を確認
  • ArrayBox.length() の値は正しく返るJIT無効時に Result: 3

  • 残課題(ブロッカー)

    1. プラグイン呼び出しの JIT 実行時に Segfault 発生
      • 事象: arr.length() のようなプラグインメソッドで JIT 実行時にクラッシュ
      • 状態: JITコンパイル自体は成功するが実行で落ちるため、DebugBox の i64 シムイベント取得に未到達
    2. i64 シムトレース未取得
      • Segfault解消後に DebugBox.tracePluginCalls(true)getJitEvents() で i64.start/end, tlv 等を観測予定
  • ▶ 次の具体ステップ(提案)

    • Lowerer: ArrayBox.length() を hostcall 経路ANY_LEN_Hから plugin_invoke 経路へ切替 - 目的: i64 シム(nyash_plugin_invoke3_i64を真正面から踏ませ、シムの前後でのcanary・TLVを観測
    • Segfault 再現最小ケースの確立と原因究明 - 候補: 受け手 a0param index/ argc / TLV ヘッダの組み立て、戻りTLVのdecode、ハンドル走査の境界
    • DebugBox での i64 シムイベントログ取得start/end, tlv, rc/out_len/canary
    • 必要に応じて f64 シム (NYASH_JIT_PLUGIN_F64="type:method") の点検

2025-08-29 PM3 再起動スナップショットStrict/分離・ネイティブ基盤固め・Python準備

現在の着地Strict準備済み

  • InvokePolicy/Observe を導入し、Lowerer の分岐をスリム化
    • ArrayBox: length/get/push/set → policy+observe 経由plugin/hostcallの一元化
    • MapBox: size/get/has/set → 同上
    • StringBox: length/is_empty/charCodeAt → 同上
  • VM→Plugin 引数整合の安定化
    • 整数は I64 (tag=3) に統一Plugin IntegerBox は自動プリミティブ化get
  • 予約型の安全な上書き制御
    • NYASH_PLUGIN_OVERRIDE_TYPES=ArrayBox,MapBox(デフォルト同値)で型別に制御
  • StringBoxのpost-birth初期化
    • new StringBox() 直後の length() でsegfaultしないよう、空文字で初期化
  • 特殊コメント(最小)
    • // @env KEY=VALUE, // @jit-debug, // @plugin-builtins, // @jit-strict

Strict/分離Fail-Fast / ノーフォールバック)

  • 目的: 「VM=仕様 / JIT=コンパイル」。JITで未対応/フォールバックがあれば即コンパイル失敗
  • 有効化: 実行はVM固定、JITは --compile-nativeAOTでのみ使用
  • 仕様(現状)
    • Lowerer/Engine: unsupported>0 または compile-phase fallback>0 でコンパイル中止
    • 実行: JITディスパッチ既定OFFVMのみ。StrictはJITを常時JIT-only/handle-only相当で動かす
    • シム: 受け手解決は HandleRegistry 優先(NYASH_JIT_ARGS_HANDLE_ONLY=1

再起動チェックリスト

  • BuildCranelift有効: cargo build --release -j32 --features cranelift-jit
  • Arrayparam受け: examples/jit_plugin_invoke_param_array.nyash → Result: 3
  • MapE2E: examples/jit_map_policy_demo.nyash → Result: 2
  • StringRO: examples/jit_string_length_policy_demo.nyash → Result: 0空文字
  • Strict 観測fail-fast動作確認:
    • ファイル先頭: // @jit-strict // @jit-debug // @plugin-builtins
    • 実行: NYASH_JIT_ONLY=1 ./target/release/nyash --backend vm <file>
    • 期待: 未対応lowerがあれば compile失敗→JIT-onlyでエラーフォールバックなし

観測の標準手順compile/runtime/シム)

cargo build --release --features cranelift-jit

# Arrayparam受け、JIT観測一式
NYASH_USE_PLUGIN_BUILTINS=1 \
NYASH_JIT_EXEC=1 NYASH_JIT_THRESHOLD=1 \
NYASH_JIT_EVENTS=1 NYASH_JIT_EVENTS_COMPILE=1 NYASH_JIT_EVENTS_RUNTIME=1 \
NYASH_JIT_EVENTS_PATH=jit_events.jsonl NYASH_JIT_SHIM_TRACE=1 \
  ./target/release/nyash --backend vm examples/jit_plugin_invoke_param_array.nyash

# Mappolicy/observe経由の確認
NYASH_USE_PLUGIN_BUILTINS=1 NYASH_PLUGIN_OVERRIDE_TYPES=ArrayBox,MapBox \
NYASH_JIT_EXEC=1 NYASH_JIT_THRESHOLD=1 \
NYASH_JIT_EVENTS=1 NYASH_JIT_EVENTS_COMPILE=1 NYASH_JIT_EVENTS_RUNTIME=1 \
NYASH_JIT_EVENTS_PATH=jit_events.jsonl \
  ./target/release/nyash --backend vm examples/jit_map_policy_demo.nyash

# Stringlength RO
NYASH_USE_PLUGIN_BUILTINS=1 NYASH_JIT_EXEC=1 NYASH_JIT_THRESHOLD=1 \
NYASH_JIT_EVENTS=1 NYASH_JIT_EVENTS_COMPILE=1 NYASH_JIT_EVENTS_RUNTIME=1 \
NYASH_JIT_EVENTS_PATH=jit_events.jsonl \
  ./target/release/nyash --backend vm examples/jit_string_length_policy_demo.nyash

# Strictモードフォールバック禁止最小観測
NYASH_USE_PLUGIN_BUILTINS=1 NYASH_JIT_EXEC=1 NYASH_JIT_ONLY=1 NYASH_JIT_STRICT=1 \
NYASH_JIT_EVENTS=1 NYASH_JIT_EVENTS_RUNTIME=1 NYASH_JIT_EVENTS_COMPILE=1 \
NYASH_JIT_EVENTS_PATH=jit_events.jsonl \
  ./target/release/nyash --backend vm examples/jit_plugin_invoke_param_array.nyash

これからの実装(優先順)

  1. ネイティブ基盤の仕上げ10.5b
    • tools/build_aot.{sh,ps1} の導線統一、Windows clang/cl内蔵化の検討
    • プラグイン解決の安定(拡張子変換/lib剥がし/検索パス/警告整備)
  2. プラグイン仕様分離(中央=nyash.toml / 各プラグイン=nyash_box.toml
    • Loaderが plugins/<name>/nyash_box.toml を読み、type_id/メソッドIDを反映
    • 旧[libraries]も後方互換で維持(当面)
  3. Python統合10.5c
    • PyRuntimeBox/PyObjectBox のRO経路eval/import/getattr/call/strをVM/EXEで安定
    • autodecode/エラー伝搬の強化、WindowsでのDLL探索PYTHONHOME/PATH
  4. 観測・サンプル
    • EXEの Result: 統一、VM/EXEスモークのGreen化
    • 追加サンプルは最小限(回帰用の小粒のみ)

現在の達成状況(

  • static box メソッドのMIR関数化に成功
    • 例: Main.helper/1, Main.add/2 が独立関数として生成され、JITの sites に出現
  • JITコンパイル成功実行成功
    • Main.helper/1 に handle が付与handle=1compiled=1exec_ok=1
  • compile-phase イベント出力
    • plugin:ArrayBox:push / plugin:ArrayBox:length(型ヒントにより StringBox へ寄るケースも増加見込み)
  • length() の正値化
    • arr.length() が 3 を返す(受け手解決の安全化・フォールバック整備済み)

既知の課題(

  • runtime-phase イベントが出ない環境がある
    • 対処: NYASH_JIT_EVENTS=1 を併用ベース出力ON、必要に応じて NYASH_JIT_EVENTS_PATH=jit_events.jsonl
    • 純JIT固定: NYASH_JIT_ONLY=1 を付与してフォールバック経路を抑止
  • シムトレース([JIT-SHIM i64])が出ない環境がある
    • 対処: 上記と同時に NYASH_JIT_SHIM_TRACE=1 を指定。plugin_invoke シム経路を確実に踏むため length は plugin 優先

直近で入れた変更(要点)

  • 「型ヒント伝搬」パスを追加(箱化)
    • 追加: src/mir/passes/type_hints.rs、呼び出し元→callee の param 型反映String/Integer/Bool/Float
    • 反映: optimizer.rs から呼び出し、責務を分割
  • length() の plugin_invoke 優先
    • BoxCall簡易hostcallsimple_readsから length を除外、Lowerer の plugin_invoke 経路に誘導
  • シムの受け手解釈を「ハンドル優先」に変更
    • nyash_plugin_invoke3_{i64,f64} で a0 を HandleRegistry から解決→PluginBoxV2/ネイティブ(Array/String)
    • レガシー互換のparam indexも残し、安全フォールバック
  • runtime観測の強化
    • シム入り口で runtime JSON を出力kind:"plugin", id:"plugin_invoke.i64/f64"、type_id/method_id/inst/argc
    • ANY長さnyash_any_length_hにparam indexフォールバックを追加

観測の標準手順(必ずこれで確認)

cargo build --release --features cranelift-jit

# 標準出力に compile/runtime/シムトレースを出す純JIT固定
NYASH_USE_PLUGIN_BUILTINS=1 \
NYASH_JIT_EXEC=1 NYASH_JIT_ONLY=1 NYASH_JIT_THRESHOLD=1 \
NYASH_JIT_EVENTS=1 NYASH_JIT_EVENTS_COMPILE=1 NYASH_JIT_EVENTS_RUNTIME=1 \
NYASH_JIT_SHIM_TRACE=1 \
  ./target/release/nyash --backend vm examples/jit_plugin_invoke_param_array.nyash

# もしくはruntime JSONをファイルに
NYASH_JIT_EVENTS_RUNTIME=1 NYASH_JIT_EVENTS_PATH=jit_events.jsonl \
  ./target/release/nyash --backend vm examples/jit_plugin_invoke_param_array.nyash
cat jit_events.jsonl

設計ルールの曖昧さと「箱」整理(次の箱)

  • TypeHintPass完了: src/mir/passes/type_hints.rs — 型伝搬をここに集約(最小実装済)
  • InvokePolicyPass新規: src/jit/policy/invoke.rs — plugin/hostcall/ANY の経路選択を一元化Lowerer から分離)
  • Observe新規: src/jit/observe.rs — compile/runtime/trace 出力の統一(ガード/出力先/JSONスキーマ

今後のToDo優先度順分離/AOT

  1. 実行モード分離CLI/Runner
    • 目的: nyash file.nyash は常にVM実行。--compile-native -o app でEXE生成。
    • DoD: VM内のJITディスパッチは既定OFF。StrictはJIT=AOTで常時Fail-Fast。
  2. AOTパイプライン確立obj→exe
    • 目的: Lower→CLIF→OBJ→ny_main+libnyrt.aリンクの一発通し
    • DoD: tools/build_aot.sh の内製依存をCLIサブコマンド化。Windows/macOSは後段。
  3. AOT箱の追加
    • AotConfigBox: 出力先/ターゲット/リンクフラグ/プラグイン探索を管理し、apply()でenv同期
    • AotCompilerBox: compile(file, out) でOBJ/EXEを生成、events/結果文字列を返す
  4. 観測の統一
    • 目的: NYASH_JIT_EVENTS=1 で compile/runtime が必ず出力。PATH指定はJSONL追記
    • DoD: jit::observe 経由へ集約

受け入れ条件DoD

  • compile-phase: plugin:* のイベントが関数ごとに安定
  • runtime-phase: plugin_invoke.* が必ず出力stdout または JSONL
  • シムトレース: NYASH_JIT_SHIM_TRACE=1 で [JIT-SHIM …] が可視
  • length(): arr=ArrayBox([…])→3、s=StringBox("Hello")→5どちらもJIT実行時に正値

備考TIPS

  • ConsoleBox.log はVMでは標準出力に流れません。観測は print(...) か runtime JSON を利用してください。
  • runtime JSON が見えない場合は NYASH_JIT_EVENTS=1 を必ず併用ベース出力ON

現在地Done / Doing / Next

  • DonePhase 10.10
    • GC Switchable RuntimeGcConfigBox/ Unified DebugDebugConfigBox
    • JitPolicyBoxallowlist/presets/ HostCallのRO運用events連携
    • CIスモーク導入runtime/compile-events/ 代表サンプル整備
  • 🔧 DoingPhase 10.5 分離/AOT
    • VM実行の既定固定JITディスパッチは既定OFF
    • AOT最小EXE: libnyrt.aシム + ny_main ドライバ + build_aot.sh → CLI化
    • リファクタリング継続core_hostcall.rs→observe/policy統合
  • ⏭️ NextPhase 10.1 実装)
    • Week1: 主要ビルトインBoxの移行RO中心
    • Week2: 静的同梱基盤の設計type_id→nyplug_*_invoke ディスパッチ)
    • Week3: ベンチ/観測性整備JIT fallback理由の粒度
    • Week4: AOT配布体験の改善nyash.toml/soの探索・ガイド

リファクタリング計画(機能差分なし)

  1. core_hostcall 分割イベントloweremit_host_call周辺
    • 追加: src/jit/lower/core_hostcall.rs
    • mod.rs/core.rs のモジュール参照を更新
    • 確認: cargo checkbash tools/smoke_phase_10_10.sh
  2. core_ops 分割(算術/比較/分岐)
    • 追加: src/jit/lower/core_ops.rs
    • CLIF配線やb1正規化カウンタは移動のみ
    • 確認: cargo check → 代表JITデモ2本を手動確認
  3. 仕上げ
    • 1ファイル ~1000行以内目安を満たすこと
    • ドキュメント差分は最小本CURRENT_TASKのみ更新

DoDRefactor

  • cargo check が成功し、tools/smoke_phase_10_10.sh がGreen
  • ログ/イベント出力がリファクタ前と一致(体感差分なし)
  • core.rs/builder.rs の行数削減(目安 < 1000

Phase 10.1 新計画プラグインBox統一化

  • 参照: docs/development/roadmap/phases/phase-10.1/ (新計画)
  • 詳細: docs/ideas/new-features/2025-08-28-jit-exe-via-plugin-unification.md
  • Week1概要
    • ArrayBoxプラグイン実装とテスト
    • JIT→Plugin呼び出しパス確立
    • パフォーマンス測定と最適化

Phase 10.5旧10.1Python統合 / JIT Strict 前倒し

  • 参照: docs/development/roadmap/phases/phase-10.5/ (移動済み)
  • ChatGPT5の当初計画を後段フェーズへ

進捗10.5a→10.5b 最小実装)

  • 新規: plugins/nyash-python-plugin/ 追加ABI v1、動的 libpython3.x ローダ)
  • Box: PyRuntimeBox(type_id=40), PyObjectBox(type_id=41)nyash.toml に登録
  • 実装: birth/finiRuntime, eval/importHandle返却, getattrHandle返却, callint/string/bool/handle対応 callKwkwargs対応・key:stringと値のペア , strString返却
  • 設計ドキュメント: docs/development/roadmap/phases/phase-10.5/10.5a-ABI-DESIGN.md

ビルド/テスト結果2025-08-29

  • Pythonプラグインビルド成功警告ありだが動作問題なし
  • 本体ビルド成功Cranelift JIT有効
  • プラグインロード成功(libnyash_python_plugin.so 初期化OK
  • PyRuntimeBox.birth() 正常実行instance_id=1
  • VM側委譲: PluginBoxV2 メソッドを PluginHost.invoke_instance_method に委譲BoxCallでも実体plugin_invoke実行
  • E2Eデモ: py.import("math").getattr("sqrt").call(9).str() がVM経路で実行examples/py_math_sqrt_demo.nyash
  • R系API: evalR/importR/getattrR/callR/callKwR がResultOk/Errで安定エラーメッセージの保持確認済
  • 自動デコード(オプトイン): NYASH_PY_AUTODECODE=1 で eval/getattr/call/callKw の数値/文字列/bytesがTLVで直接返る
  • kwargs対応: callKw 実装TLVで key:string と value のペア)、examples/py_kw_round_demo.nyash を追加builtins.intで検証

JIT強化10.2 連携の下ごしらえ)

  • 追加: i64シムの戻りdecode拡張I32/I64/Bool/F64[暫定]
  • 追加: f64専用シム nyash_plugin_invoke3_f64emit_plugin_invoke 切替ENV=NYASH_JIT_PLUGIN_F64
  • 目的: Python含むプラグインのROで「数値/Bool/f64選択」戻りをJIT/AOT経路で受ける足場を整備
  • 追加: シム・トレースENV=NYASH_JIT_SHIM_TRACE=1)とカナリー検査(出力バッファのオーバーラン検出)
  • 追加: レシーバ自動解決フォールバックa0<0時はVM引数を走査してPluginBoxV2を特定

方針決定Built-inとの関係

  • いまはビルトインBoxを削除しない。余計な変更を避け、プラグイン優先の運用で干渉を止める。
  • 例・テスト・CIをプラグイン経路に寄せ、十分に安定してから段階的に外す。

次アクション(小さく通す)

  1. JIT Strict モード(最優先)
    • // @jit-strictENV: NYASH_JIT_STRICT=1で有効化
    • Lowerer: unsupported>0 でコンパイル中止(診断を返す)
    • 実行: JIT_ONLYと併用でフォールバック禁止fail-fast
    • シム: 受け手解決は HandleRegistry 優先param-index 経路は無効化)
  2. Array/Map のパリティ検証strict
    • examples/jit_plugin_invoke_param_array.nyash / examples/jit_map_policy_demo.nyash で compile/runtime/シム整合を確認
  3. Python統合RO中心の継続
    • eval/import/getattr/call の strict 観測と整合、数値/Bool/文字列の戻りデコード

すぐ試せるコマンド(現状維持の確認)

# BuildCranelift込み推奨
cargo build --release -j32 --features cranelift-jit

# Smoke10.10の代表確認)
bash tools/smoke_phase_10_10.sh

# HostCallHH直実行・read-only方針
NYASH_JIT_EXEC=1 NYASH_JIT_THRESHOLD=1 NYASH_JIT_HOSTCALL=1 NYASH_JIT_EVENTS=1 \
  ./target/release/nyash --backend vm examples/jit_map_get_param_hh.nyash
NYASH_JIT_THRESHOLD=1 NYASH_JIT_HOSTCALL=1 \
  ./target/release/nyash --backend vm examples/jit_policy_whitelist_demo.nyash

# GC countingVMパス
./target/release/nyash --backend vm examples/gc_counting_demo.nyash

# compileイベントのみ必要時
NYASH_JIT_EVENTS_COMPILE=1 NYASH_JIT_HOSTCALL=1 NYASH_JIT_EVENTS_PATH=events.jsonl \
  ./target/release/nyash --backend vm examples/jit_map_get_param_hh.nyash

# Strictモードフォールバック禁止最小観測
NYASH_USE_PLUGIN_BUILTINS=1 NYASH_JIT_EXEC=1 NYASH_JIT_ONLY=1 NYASH_JIT_STRICT=1 \
  NYASH_JIT_EVENTS=1 NYASH_JIT_EVENTS_RUNTIME=1 NYASH_JIT_EVENTS_COMPILE=1 \
  NYASH_JIT_EVENTS_PATH=jit_events.jsonl \
  ./target/release/nyash --backend vm examples/jit_plugin_invoke_param_array.nyash

# Plugin demosArray/Map
(cd plugins/nyash-array-plugin && cargo build --release)
(cd plugins/nyash-map-plugin && cargo build --release)
NYASH_CLI_VERBOSE=1 ./target/release/nyash --backend vm examples/array_plugin_demo.nyash
NYASH_CLI_VERBOSE=1 ./target/release/nyash --backend vm examples/array_plugin_set_demo.nyash
NYASH_CLI_VERBOSE=1 ./target/release/nyash --backend vm examples/map_plugin_ro_demo.nyash

# Python plugin demoPhase 10.5
(cd plugins/nyash-python-plugin && cargo build --release)
NYASH_CLI_VERBOSE=1 ./target/release/nyash --backend vm examples/py_eval_demo.nyash
# 追加デバッグTLVダンプ
NYASH_DEBUG_PLUGIN=1 NYASH_CLI_VERBOSE=1 ./target/release/nyash --backend vm examples/py_eval_demo.nyash

# math.sqrtデモimport→getattr→call→str
NYASH_CLI_VERBOSE=1 ./target/release/nyash --backend vm examples/py_math_sqrt_demo.nyash

# kwargsデモbuiltins.int
NYASH_CLI_VERBOSE=1 ./target/release/nyash --backend vm examples/py_kw_round_demo.nyash

# 自動デコードevalの数値/文字列が直接返る)
NYASH_PY_AUTODECODE=1 NYASH_CLI_VERBOSE=1 ./target/release/nyash --backend vm examples/py_eval_autodecode_demo.nyash

# JITf64戻りのシム選択: type_id:method_id を指定)
# 例: PyObjectBox.callR(=12) を f64 扱いにする(実験用)
NYASH_JIT_PLUGIN_F64="41:12" NYASH_CLI_VERBOSE=1 ./target/release/nyash --backend vm examples/py_math_sqrt_demo.nyash

# kwargsデモbuiltins.int
NYASH_CLI_VERBOSE=1 ./target/release/nyash --backend vm examples/py_kw_round_demo.nyash

## AOT最小EXENew!
```bash
# 1) .o生成Cranelift必須
NYASH_AOT_OBJECT_OUT=target/aot_objects \
NYASH_USE_PLUGIN_BUILTINS=1 NYASH_JIT_EXEC=1 NYASH_JIT_THRESHOLD=1 \
  ./target/release/nyash --backend vm examples/aot_min_string_len.nyash

# 2) libnyrtビルド + リンク + 実行Linux例
(cd crates/nyrt && cargo build --release)
cc target/aot_objects/main.o -L crates/nyrt/target/release \
  -Wl,--whole-archive -lnyrt -Wl,--no-whole-archive -lpthread -ldl -lm -o app
./app

# 3) ワンコマンド
bash tools/build_aot.sh examples/aot_min_string_len.nyash -o app

⏭️ NextPhase 10.2: JIT実呼び出しの実体化

  • 目的: Craneliftの emit_plugin_invoke を実装し、JITでも実体のプラグインAPIを呼ぶ
  • 方針:
    • シム関数 extern "C" nyash_plugin_invoke3_i64(type_id, method_id, argc, a0, a1, a2) -> i64 を実装
      • a0: 受け手param index負なら未解決
      • args: i64 を TLV にエンコードして plugin invoke_fn へ橋渡し
      • 戻り: TLVi64/Boolの最初の値を i64 に正規化
    • CraneliftBuilder: emit_plugin_invoke で上記シムを import→call常に6引数
    • 対象: Array(len/get/push/set), Map(size/get/has/set) の i64 1〜2引数経路

### 10.2 追加: AOT接続.o出力
- 新規: `NYASH_AOT_OBJECT_OUT=/path/to/dir-or-file` を指定すると、JITでコンパイル成功した関数ごとに Cranelift ObjectModule で `.o` を生成します。
  - ディレクトリを指定した場合: `/<dir>/<func>.o` に書き出し
  - ファイルを指定した場合: そのパスに上書き
- 現状の到達性: JITロワラーで未対応命令が含まれる関数はスキップされるため、完全カバレッジ化が進むにつれて `.o` 出力関数が増えます。
- 未解決シンボル: `nyash_plugin_invoke3_i64`(暫定シム)。次フェーズで `libnyrt.a` に実装を移し、`nyrt_*`/`nyplug_*` 記号と共に解決します。

### 10.2b: JITカバレッジの最小拡張ブロッカー解消
- 課題: 関数内に未対応命令が1つでもあると関数全体をJITスキップ現在の保守的ポリシー。`new StringBox()` 等が主因で、plugin_invoke のテストや `.o` 出力まで到達しづらい。
- 対応方針(優先度順)
  1) NewBox→birth の lowering 追加(プラグイン birth を `emit_plugin_invoke(type_id, 0, argc=1レシーバ扱い)` に変換)
  2) Print/Debug の no-op/hostcall化スキップ回避
  3) 既定スキップポリシーは維持しつつ、`NYASH_AOT_ALLOW_UNSUPPORTED=1` で .o 出力だけは許容(検証用途)
- DoD:
  - `examples/aot_min_string_len.nyash` がJITコンパイルされ `.o` が出力されるCranelift有効ビルド時
  - String/Integer の RO メソッドで plugin_invoke がイベントに現れる

### 現状の診断(共有事項)
- JITは「未対応 > 0」で関数全体をスキップする保守的設計決め打ち。plugin_invoke 自体は実装済みだが、関数がJIT対象にならないと動かせない。
- プラグインはVM経路で完全動作しており、JIT側の命令サポート不足がAOT検証のボトルネック。

## 参考リンク
- Phase 10.1(新): `docs/development/roadmap/phases/phase-10.1/README.md` - プラグインBox統一化
- Phase 10.5旧10.1: `docs/development/roadmap/phases/phase-10.5/README.md` - Python統合
- Phase 10.10: `docs/development/roadmap/phases/phase-10/phase_10_10/README.md`
- プラグインAPI: `src/bid/plugin_api.rs`
- MIR命令セット: `docs/reference/mir/INSTRUCTION_SET.md`

## Checkpoint再起動用メモ
- 状態確認: `git status` / `git log --oneline -3` / `cargo check`
- スモーク: `bash tools/smoke_phase_10_10.sh`
- 次の一手: core_hostcall → core_ops の順に分割、毎回ビルド/スモークで確認

---

### 新規フェーズ(提案): Phase 10.11 Builtins → Plugins 移行
- 目的: 内蔵Box経路を段階的に廃止し、プラグイン/ユーザーBoxに一本化する不具合の温床を解消
- 現在の足場(済):
  - ConsoleBox コンストラクタをレジストリ委譲(プラグイン優先)に変更
  - `NYASH_DISABLE_BUILTINS=1` でビルトインFactory登録を抑止可能
  - 設計ドキュメント: docs/development/roadmap/phases/phase-10.11-builtins-to-plugins.md
- 次ステップ:
  - 非基本コンストラクタの委譲徹底Math/Random/Sound/Debugなど
  - 主要ビルトインの plugin 化nyash_box.toml 整備)
  - CIに `NYASH_USE_PLUGIN_BUILTINS=1` / `NYASH_PLUGIN_OVERRIDE_TYPES` のスモークを追加

---

## 引き継ぎPhase 11.9 / 統一文法アーキテクチャ + JIT分割

現状サマリ(実装済み)
- 統一文法スキャフォールド
  - build時コード生成: `build.rs` → `src/grammar/generated.rs`
    - `KEYWORDS`(最小)と `OPERATORS_ADD_COERCION`, `OPERATORS_ADD_RULES` を生成
    - TOML未整備でも add 既定規則を生成側で補完
  - エンジン: `src/grammar/engine.rs``is_keyword_str`/`add_coercion_strategy`/`add_rules`/`decide_add_result`
  - Tokenizerに非侵襲差分ログ`NYASH_GRAMMAR_DIFF=1`
- Add 規則の非侵襲導入
  - JIT: `lower_binop(Add)` で grammar ヒントをイベント出力
  - VM/Interpreter: 期待と実際の型を差分ログ(`NYASH_GRAMMAR_DIFF=1`
  - オプトイン強制適用(挙動変更は未既定): `NYASH_GRAMMAR_ENFORCE_ADD=1`
- スナップショットテスト
  - `tests/grammar_add_rules.rs`grammar 期待 と 現行セマンティクスの一致検証)→ 単体実行で緑

JIT分割 進捗(継続観点)
- 完了: builder分割`builder/cranelift.rs`、core 第一段階分割(`core_ops.rs`、`core/analysis.rs`、`core/cfg.rs`
- jit-direct スモーク緑debug: mir-branch-ret=1 / mir-phi-min=10 / mir-branch-multi=1

使い方(開発時)
- 差分ログ: `NYASH_GRAMMAR_DIFF=1`Tokenizer/VM/Interp/JIT各所
- 規則強制: `NYASH_GRAMMAR_ENFORCE_ADD=1`Add のみ、他は非侵襲)
- JITスモーク例: `NYASH_JIT_THRESHOLD=1 ./target/debug/nyash --jit-direct apps/tests/mir-branch-ret/main.nyash`
- テスト(本件のみ): `cargo test -q --test grammar_add_rules`

次のTODO優先順
1) JITロワラー分割の続き
   - 大きい分岐Extern/PluginInvoke/BoxCallを `src/jit/lower/core/ops_ext.rs` へ抽出
   - 各ステップごとに jit-direct スモーク確認
2) 統一文法の拡張
   - operators: Sub/Mul/Div の `type_rules` を TOML → 生成 → VM/Interp/JIT に非侵襲ログ(必要なら `*_ENFORCE_*`を用意)
   - keywords/alias/context の雛形を TOML 化(差分ログ継続)
3) スナップショット整備
   - add 以外の演算子でも「grammar期待 vs 実際」の表テストを追加
   - 将来、Tokenizer/Parser でも「grammar期待 vs 実際構文」のスナップショットを追加

注意
- 既存の他テストには未整備部分があり全体 `cargo test` は赤が出るため、当面は個別テスト/スモークを推奨
- Release の jit-direct 実行は `--features cranelift-jit` が必要

## Update: Phase 11.9  統一文法アーキテクチャMVP導入計画

目的: Tokenizer/Parser/Interpreter/MIR/VM/JIT の解釈差異を解消するため、単一の文法・意味・実行定義を導入(詳細は `docs/development/roadmap/phases/phase-11.9/unified-grammar-architecture.md` と `docs/development/roadmap/phases/phase-11.9/PLAN.md`)。

直近TODOM1/M2のMVP範囲
- [ ] scaffolding: `build.rs` + `src/grammar/{mod.rs,engine.rs}` + `src/grammar/generated.rs`codegen方式
- [ ] `grammar/unified-grammar.toml` 初期化keywords: `me`,`from`,`loop`; operators: `add`
- [ ] Tokenizer に `engine.is_keyword()` を差し込み(`NYASH_GRAMMAR_DIFF=1` で差分ログ)
- [ ] `ExecutionSemantics` に `operators.add` を実装し、Interpreter/VM/JIT へ薄く統合(既存実装はフォールバック)
- [ ] 予約語マッピングの一貫性テストと、加算セマンティクスの VM/JIT/Interpreter 一致テスト

備考
- ランタイム I/O は避け、TOML→生成コードに変換して起動/ホットパスへの影響を最小化
- プラグイン拡張は将来の統合対象(優先度・名前空間・競合検知を設計)

## Progress: JIT Lowering リファクタ状況11.8/12系

完了
- [x] builder 分割(`src/jit/lower/builder.rs` を薄いハブ化、`builder/cranelift.rs` へ移動)
- [x] jit-direct の最小スモーク安定debug
  - apps/tests/mir-branch-ret → 1
  - apps/tests/mir-phi-min → 10
  - apps/tests/mir-branch-multi → 1
- [x] core.rs の第一段階分割:
  - `src/jit/lower/core_ops.rs` にヘルパー移設push_value_if_known_or_param, cover_if_supported, BinOp/Compareなど
-  - `src/jit/lower/core/analysis.rs` 追加Bool/PHI推論統計
-  - `src/jit/lower/core/cfg.rs` 追加PHI受け口順序とCFGダンプ

次の分割候補
- [ ] Extern/PluginInvoke/BoxCall 周辺の肥大化した分岐を `core/ops_ext.rs` に整理
- [ ] `analysis`/`cfg` の補助関数succ_phi_inputs など)の関数化
- [ ] 分割ごとに jit-direct スモークの緑維持debug / release+feature

---

## 🆕 Update (Phase 11.9) — M3→M4 引き継ぎメモ2025-09-02

到達M1M3 要約)
- M1: 予約語レジストリbuild.rs→generated.rs、Tokenizer 後段に `engine.is_keyword_str()``NYASH_GRAMMAR_DIFF=1` 差分ログ)
- M2: `operators.{add,sub,mul,div}` を TOML→生成未記載は既定補完。VM/Interp/JIT に `NYASH_GRAMMAR_DIFF=1` ログ、Add 強制は `NYASH_GRAMMAR_ENFORCE_ADD=1`
- M3: 構文規則スキャフォールド(`syntax.statements.allow` / `syntax.expressions.allow_binops`を生成し、Parser に非侵襲統合(差分ログのみ)
- JIT: `ops_ext.rs` 新設。`I::BoxCall` は ops_ext に完全委譲core 旧分岐は削除/到達不能化。jit-direct スモークbranch-ret/phi-min/branch-multi緑維持

提案M4: スナップショット/差分検出・CI 整備)
- 目的: 新旧ルートの整合をスナップショット+マトリクスで機械的に検証し、回帰を防止
- スコープ:
  - Parser→MIR のスナップショットテスト(代表ケースから開始)
  - 実行マトリクス `{vm,jit,aot} × {gc on,off}` の最小スモークを追加。出力/trace のハッシュ一致で検証
  - ログ: `NYASH_GRAMMAR_DIFF=1` をCIで有効化初期は Allow-failure 的に集計・監視、収束後に強化)

実施順(小粒→段階導入)
1) スナップショット追加
   - `tests/snapshots/parser_mir/` に代表ケースif/loop/return、二項演算 add/sub/mul/div、簡単なメソッド呼び
   - `assert_snapshot!(print_mir(func))` 形式 or 既存プリンタ出力の文字列一致
2) マトリクス・スモーク
   - `tools/smoke_matrix.sh` を追加VM/JIT/AOT × GC on/off。既存 `apps/tests/*` を利用
   - 出力ハッシュ(`sha256sum`)と軽量 trace行フィルタ後の hashで一致確認
   - JIT は `--features cranelift-jit`、AOT は LLVM18 前提(`LLVM_SYS_180_PREFIX`
3) CI 連携
   - Workflow にマトリクスを追加。最初は JIT/VM のみ → AOT は opt-inCI 環境用意後に拡張)
   - `NYASH_GRAMMAR_DIFF=1` を付与し差分ログを保存(失敗条件には含めない)。収束後に閾値/厳格化を検討
4) ドキュメント
   - `docs/guides/testing/unified-grammar-ci.md`(テスト方針/実行方法/FAQを追加

注意/メモ
- AOT は LLVM18 が前提CIでは apt.llvm.org を想定。Windows 環境は別途 runner で段階導入
- リポ全体 `cargo test` は未整備テストで赤があり得るため、当面は対象テスト/スモークに集中
- 差分ログは冗長になり得るため、CIではフィルタ例: INFO/WARN のみ、件数集計)を併用

実行/確認コマンド(ローカル)
- ビルドJIT/VM: `cargo build --features cranelift-jit`
- jit 直実行(例): `NYASH_JIT_THRESHOLD=1 ./target/debug/nyash --jit-direct apps/tests/mir-branch-ret/main.nyash`
- テスト(本領域):
  - `cargo test -q --test grammar_add_rules`
  - `cargo test -q --test grammar_other_ops`
  - 追加予定: `tests/snapshots/parser_mir_*`