# Current Task — Phase 21.8 / 25 / 25.1 / 25.2(Numeric Core & Stage0/Stage1 Bootstrap) Update (2025-11-17 PM — Phase 25.1d: CalleeBoxKind構造ガード実装完了) - ✅ **静的Box/ランタイムBox混線問題を構造レベルで解決!** - **実装内容**: - `CalleeBoxKind` enum追加: `StaticCompiler` / `RuntimeData` / `UserDefined` の3種別でBox種類を構造的に分類 - `classify_box_kind()`: Box名から種別を判定(StageBArgsBox/Stage1UsingResolverBox等の静的コンパイラBox、MapBox/ArrayBox等のランタイムDataBoxを明示的に列挙) - `convert_target_to_callee()`: Callee::Method生成時にbox_kindを自動付与 - `apply_static_runtime_guard()`: emit_unified_call内で静的Box名とランタイム値の混線を検出・正規化: - box_kind==StaticCompiler かつ receiver型==同一Box名 → me-call判定、静的メソッド降下に委ねる(そのまま通す) - box_kind==StaticCompiler かつ receiver型==異なるランタイムBox → 正規化(MapBox/ArrayBoxなど実際のruntime型に修正) - **効果**: `StageBArgsBox.resolve_src/1` 内の `args.get(i)` が `Stage1UsingResolverBox.get` に化ける問題を根絶 - **エラー変化(進歩の証拠)**: - 修正前: `❌ Invalid value: use of undefined value ValueId(150/187) (callee: Method { box_name: "Stage1UsingResolverBox", ... })` - 修正後: `❌ Unknown method 'is_space' on StringBox` (別のknown issue、StringBoxの実装不足) - **箱理論の実践**: 「境界を作る」原則に従い、Stage-B/Stage-1コンパイラBoxとランタイムDataBoxを構造的に分離 - **ファイル**: `src/mir/definitions/call_unified.rs`, `src/mir/builder/calls/call_unified.rs`, `src/mir/builder/calls/emit.rs` 他 - **ドキュメント**: `docs/development/roadmap/phases/phase-25.1d/README.md` の箱化メモセクションに詳細追記 Update (2025-11-17 AM — Phase 25.1d: Rust MIR SSA/PHI & Stage‑B path) - Status: Rust MIR ビルダー側の SSA/PHI と Stage‑B 最小ハーネスまわりを重点的にデバッグ中。スタックオーバーフロー系は Rust 側の再帰バグを潰しきって、いまは「Stage‑B 経由 VM 実行での undefined ValueId」と「受信箱推論(box_name / value_origin_newbox)の誤り」にフォーカスが移っている。 - Rust MIR ビルダー修正(概要): - LocalSSA / PHI 系: 既存の ValueId 再利用バグ(PHI で %0 を再割当するなど)と use-before-def 系を修正し、Copy 生成失敗時に「新しい未定義 ValueId を返してしまう」挙動を廃止。LocalSSA は emit_instruction 失敗時に元の ValueId を返すよう安全化した。 - BoxCompilationContext: `src/mir/builder/context.rs` で static box ごとに `variable_map / value_origin_newbox / value_types` を分離するコンテキストを導入し、`src/mir/builder/calls/lowering.rs` 側で `prepare_lowering_context` / `restore_lowering_context` 時に `value_types` も含めてクリアするように統一。`lower_root` と `lower_static_method_as_function` から利用し、Stage0/Stage1/Stage‑B など複数 box をコンパイルしてもメタデータが相互汚染しない構造にした(特に Stage1UsingResolverBox → StageBArgsBox 間の型リークを防ぐ)。 - me-call 再帰バグ: `handle_me_method_call` ↔ `try_handle_me_direct_call` ↔ `try_build_me_method_call` の循環を解消し、`handle_me_method_call` に一本化。`build_expression` / `build_method_call` / `emit_unified_call` には軽量な depth ガードを入れて「構造バグがあっても OS レベル stack overflow ではなくエラーとして露出する」ようにした。 - コンパイルトレース: `NYASH_MIR_COMPILE_TRACE=1` で static box ごとの lowering をログ出力するようにし、Stage‑B (`compiler_stageb.hako`) のどの box までコンパイルできているかを追跡しやすくした。 - Stage‑B 最小ハーネスの現状: - `tools/test_stageb_min.sh`: - Test1(`stageb_min_sample.hako` を直接 VM 実行): RC=0 で PASS。 - Test3(同ソースを直接 MIR verify): MirVerifier 緑(SSA/PHI エラーなし)。 - Test2(`compiler_stageb.hako` 経由の Stage‑B パス): Rust 側の stack overflow は解消済みで、MIR コンパイルも最後まで通るが、VM 実行時に `Invalid value: use of undefined value` が発生。 - 代表的な現象: `StageBArgsBox.resolve_src/1` で - `callee = Method { box_name: "Stage1UsingResolverBox", method: "get", receiver: Some(ValueId(150)) }` - `%150` の定義が MIR 上に存在しない(もしくは call 以降に現れる)ため、VM 側で undefined ValueId エラーとなる。 - `.hako` 側では `.get` を呼んでいるのは主に `MapBox` / `ArrayBox` 系であり、`Stage1UsingResolverBox` 自体に `get` メソッドはないため、「receiver に付いている box_name メタデータがどこかで誤って Stage1UsingResolverBox になっている」可能性が高い。 - env / extern まわり: - `env.get` / `env.set` は Rust VM 側で extern として実装済みで、`Callee::Extern("env.get/1")` 経由で dispatch される。現在の undefined ValueId は env 実装というより、Stage‑B / UsingResolver / BundleResolver 周辺での receiver 推論・コピー挿入・メタデータ伝播の問題とみられる。 - Next steps(25.1d 継続タスク): - StageBArgsBox.resolve_src/1: - `NYASH_VM_DUMP_MIR=1` で当該関数の MIR を常時ダンプし、`bb3510` 周辺で `call_method Stage1UsingResolverBox.get(...) [recv: %150]` のような「静的 box 名付き Method callee + 未定義 receiver」がどのように生成されているかを追跡する(現状、MIR 上では `%150` の定義が存在せず、LocalSSA の Copy でも補えないことを確認済み)。 - `NYASH_BUILDER_TRACE_RECV=1` / `NYASH_CALLEE_RESOLVE_TRACE=1` を併用し、`emit_box_or_plugin_call` → `emit_unified_call` → `call_unified::convert_target_to_callee` → `emit_guard::finalize_call_operands` の流れの中で、`UnknownBox.get` や `MapBox.get` がどのタイミングで `Stage1UsingResolverBox.get` に化けるか(`box_name` の決定経路)を特定する。 - `convert_target_to_callee` / `emit_unified_call` に「静的 box 名(StageBArgsBox / Stage1UsingResolverBox など)が Method callee の `box_name` に入ってきた場合は、強制的に BoxCall 経路にフォールバックする」ガードを追加する案を検討する(by-name ではなく構造レベルの安全弁として設計する)。 - StageBArgsBox.resolve_src に近い最小パターン(`if args != null { local n = args.length(); /* map/array.get */ }` など)を Rust テストとして既に用意している `src/tests/mir_stageb_like_args_length.rs` ラインにぶら下げる形で拡張し、「UnknownBox/MapBox.get を含む if+loop パターンでも MirVerifier 緑かつ VM で receiver 未定義にならない」ことを追加で固定する。 - Stage‑B/Stage‑1 ほかの SSA 問題: - 既に verifier が赤を出している関数(BundleResolver.resolve/4, Stage1UsingResolverBox.resolve_for_source/4, ParserBox.parse_program2/1 など)は、それぞれ最小 Hako 断片を Rust テスト化して MirVerifier にかけ、1 関数=1 バグ=1 テストの方針で潰していく。 - ドキュメント: - 本 `CURRENT_TASK.md` に Phase 25.1d の状況(MIR SSA/PHI 修正と Stage‑B パスの現状)を反映済み。 - `docs/development/roadmap/phases/phase-25.1d/README.md`(または 25.1c の追記)側にも、BoxCompilationContext 導入と StageBArgsBox/BundleResolver まわりの SSA 課題を整理しておく。 Update (2025-11-14 — Phase 25.1 kickoff: Stage0/Stage1 bootstrap design) - Status: Phase 25.1 で「Rust 製 hakorune=Stage0 ブートストラップ」「Hakorune コードで構成された selfhost バイナリ=Stage1」という二段構え方針を導入。 - Decisions: - Stage0(Rust bootstrap binary): プロセス起動・FFI・VM/LLVM コアのみを担当し、ランタイムロジックや数値コアは持たない。 - Stage1(Hakorune selfhost binary): Stage‑B / MirBuilder / AotPrep / numeric core などの自己ホストコアを .hako で実装し、AOT して EXE 化する本命バイナリとする。 - バイナリ配置案: `target/release/hakorune-bootstrap`(Stage0), `target/selfhost/hakorune`(Stage1)を想定。 - Docs: - `docs/development/roadmap/phases/phase-25.1/README.md` に Stage0/Stage1 の責務と禁止事項、将来の自己ホストサイクル案を記載。 - `docs/development/roadmap/phases/phase-25/README.md` の Related docs に Phase 25.1 / numeric ABI / System Hakorune subset / ENV_VARS をリンク(構造的な入口を統一)。 Update (2025-11-15 — Phase 25.1: Stage1 build wiring initial implementation) - Status: Stage0/Stage1 の「バイナリ分離」をビルド導線レベルで実現(Rust bin と selfhost bin を別パスに配置)。 - Implemented: - Stage0(Rust CLI): - `cargo build --release` → `target/release/nyash` を Stage0 ブートストラップとして扱う(名称は将来 `hakorune-bootstrap` へ移行予定)。 - `Makefile` に `stage0-release` ターゲットを追加(Rust 側のみをビルドする専用ターゲット)。 - Stage1(Hakorune selfhost binary — Ny Executor プロトタイプ): - `tools/selfhost/build_stage1.sh` を追加。 - 入力: `apps/selfhost-runtime/runner.hako`(Ny Executor entry)。 - 経路: `tools/hakorune_emit_mir.sh` → `tools/ny_mir_builder.sh --emit exe` → native EXE。 - 出力: `target/selfhost/hakorune`(Phase 25.1 時点では「MIR v0 Executor」専用 EXE)。 - `Makefile` に `stage1-selfhost` ターゲットを追加し、`make stage0-release` → `tools/selfhost/build_stage1.sh` のシーケンスを固定。 - Docs: - `docs/development/roadmap/phases/phase-25.1/README.md`: - Status を design+partial implementation に更新。 - Stage0/Stage1 の「現在の実体(nyash / build_stage1.sh)」と「将来の名称(hakorune-bootstrap / hakorune)」を明示。 - Makefile ターゲットと build_stage1.sh の役割を記載。 - `tools/selfhost/README.md`: - Stage1 selfhost binary セクションを追加し、`tools/selfhost/build_stage1.sh` の使い方とパイプラインを説明。 - `Cargo.toml`: - `[[bin]] 付近にコメントで「Stage0=nyash(Rust CLI), Stage1=hakorune(tools/selfhost/build_stage1.sh 経由)」の方針を追記。 Update (2025-11-15 — Phase 25.1: Stage1 runtime independence & selfhost cycle plan) - Clarified model: - Stage1 `hakorune` は、実行時には Stage0 CLI(`nyash`)から独立した selfhost EXE として振る舞う。 - VM/LLVM/ny-llvmc などのバックエンド機能には、Ny 側から `env.mirbuilder.emit` / `env.codegen.emit_object` / `env.codegen.link_object` 等の extern を通じてアクセスする。 - つまり「Stage1 の backend」として `nyash` コマンドを前提にせず、Ring0 のサービスは C-ABI/extern レイヤで見る構造にする。 - 一方で現時点では、Stage1 自身のビルド(Stage0→Stage1)には `NYASH_BIN` (nyash) を利用している: - `tools/hakorune_emit_mir.sh` / `tools/selfhost_exe_stageb.sh` が Stage‑B / MirBuilder を実行する際に Stage0 をブートストラップとして使用。 - これにより「実行時は独立・ビルド時は Stage0 依存」という段階的自己ホスト状態になっている。 - Plan (selfhost cycle): - 次フェーズ以降で「Stage1→Stage1'」の自己ホストサイクルを確認する: - Stage1 が自分自身のソース(launcher/runner/CLI を含む)を取り込み、AOT して Stage1' バイナリを生成できること。 - Stage1 / Stage1' 間で CLI インターフェースと代表的な挙動が一致することをスモーク/ゴールデンで検証する(差分が収束することを確認)。 - Fix status: - ✅ Rust provider (`env.mirbuilder.emit` → `program_json_to_mir_json_with_imports`) で発生していた `[mirbuilder/parse/error] undefined variable: args` を修正。 - `lower_program` のメイン関数に仮引数 `args` を追加し、Stage‑B が出力する `Main.main(args)` を正しく降ろせるようにした。 - ✅ `tools/selfhost_exe_stageb.sh` / `tools/selfhost/build_stage1.sh` から selfhost builder (hako.mir.builder) を既定OFF に切り替え、provider ルートのみで `.hako → MIR(JSON) → EXE` を再び通せるようにした。 - `NYASH_LLVM_SKIP_BUILD=1 tools/selfhost/build_stage1.sh --out /tmp/hakorune-dev` が成功し、Stage1 dev バイナリを生成できることを確認済み。 - selfhost builder (`HAKO_SELFHOST_BUILDER_FIRST=1`) の再有効化は後続タスクとして扱う。 - 最終的には「Stage0 はブートストラップ専用・Stage1 単独で Stage1 を維持できる」状態を目標とする。 Update (2025-11-15 — Phase 25.1: Stage1 CLI first commands wired) - Stage1 CLI(launcher.hako): - `lang/src/runner/launcher.hako` に `HakoCli` dispatcher を実装し、`Main.main(args)` を Stage1 エントリとして固定。 - コマンド実装(Phase 25.1 実装範囲): - `hakorune emit program-json [-o ] [--quiet] `: - `FileBox` で `` を読み取り、`BuildBox.emit_program_json_v0(src, null)` で Program(JSON v0) を生成。 - `"version":0` / `"kind":"Program"` を含むことを確認し、stdout または `-o/--out` で指定されたファイルに Program(JSON v0) を出力(失敗時は exit 92)。 - `hakorune emit mir-json [--from-program-json ] [-o ] [--quiet] []`: - `--from-program-json` 指定時は Program(JSON v0) から、`.hako` 指定時は `.hako → Program(JSON v0) → MIR(JSON)` のパイプラインで `MirBuilderBox.emit_from_program_json_v0` を実行。 - 成功時は MIR(JSON) を stdout またはファイルに出力(失敗時は exit 92)。 - `hakorune build exe [-o ] [--quiet] `: - `.hako → Program(JSON v0) → MIR(JSON)` まで同様に進めた後、`env.codegen.emit_object` / `env.codegen.link_object` を通じて EXE を生成。 - C-API ルート(`NYASH_LLVM_USE_CAPI=1`, `HAKO_V1_EXTERN_PROVIDER_C_ABI=1` など)が有効な環境で、EXE パスを表示(`--quiet` 指定時は非表示)。 - 未実装のコマンド: - `run` / `check` はプレースホルダのまま(`[hakorune] : not implemented yet` を表示し、90–93 の固定コードで終了)。 - Tools/docs: - `tools/selfhost/build_stage1.sh`: - デフォルト entry を `apps/selfhost-runtime/runner.hako` から `lang/src/runner/launcher.hako` に変更(Stage1 CLI ベースの dev bin を生成)。 - `tools/selfhost/README.md`: - Stage1 entry の説明を launcher.hako に合わせて更新。 - `docs/development/runtime/cli-hakorune-stage1.md`: - `emit program-json` / `emit mir-json` のセクションに「Phase 25.1 実装範囲」を反映(サポートされるフラグと I/O 挙動を具体化)。 Update (2025-11-15 — Phase 25.1a: Stage1 build pipeline hotfix progress) - Context: - Stage1 CLI(launcher.hako)と selfhost AOT パイプライン(build_stage1.sh)は設計上つながっているが、現状 selfhost builder (MirBuilderBox on VM) は Stage1 CLI の Program(JSON) をフルで扱えず 171 bytes の stub MIR を返してしまうため、provider-first を既定としている。 - CLI 側の `.hako → Program(JSON v0) → MIR(JSON) → EXE` ロジックは Ny コードとして実装済みで、Rust 側の Program→MIR(env.mirbuilder.emit)も修復済み。 - Current symptoms (after first fixes): - `tools/hakorune_emit_mir.sh lang/src/runner/launcher.hako /tmp/launcher_mir.json`: - Stage‑B: `[emit:trace] Stage-B: SUCCESS - Generated Program(JSON)` まで成功(Program(JSON v0) 自体は安定して取得可能)。 - selfhost builder 経路(try_selfhost_builder)は、当初の `Parse error: Unexpected token FN` → LoopForm/`init` 予約語衝突 → `self._is_on/1` 未解決 → `NewClosure` 未実装、という段階的なエラーが出ていたが、 - `lang/src/mir/builder/func_lowering.hako` の `local fn` をリネーム、 - `lang/src/shared/mir/loop_form_box.hako` / `lang/src/mir/builder/internal/lower_loop_count_param_box.hako` の `init`→`start_value` リネーム、 - `BuilderConfigBox._is_on` 呼び出しを `me._is_on` に統一し、 - `MirBuilderBox` / `MirBuilderMinBox` の `norm_if = fn(...)` を helper メソッド(`_norm_if_apply` / `_norm_json_if_needed`)に置き換えて lambda/closure を排除、 によって Stage‑3 パース/VM 実行の両方で builder Runner が launcher.hako を通せるようになった(`[OK] MIR JSON written (selfhost-first)` まで到達)。 - selfhost builder 経路(try_selfhost_builder): - 現状 launcher.hako に対しては selfhost-first で Program→MIR が成功しているが、一般の lambda/closure (`fn(...) { ... }`) は VM 側で未サポートのままなので、selfhost builder のコードからは意図的に排除している(lambda の完全な意味論実装は後続フェーズに送る)。 - provider 経路(try_provider_emit → env.mirbuilder.emit): - Rust 側の Program→MIR ルート修正後は `[mirbuilder/parse/error] undefined variable: args` が発生しなくなり、`launcher.hako` から MIR(JSON) を安定して生成できる状態(delegate:provider 経路が暫定のメインパス)。selfhost builder 実行が `self._is_on/1` で落ちても、最終的な MIR(JSON) は provider 経由で出力されている。 - legacy CLI 経路(--program-json-to-mir): - Program(JSON) を一時ファイルに書いて `nyash --program-json-to-mir` を叩くフォールバックは、Phase 25.1a では退避路扱いのまま(通常は provider 経路が先に成功する)。 - Plan (Phase 25.1a, updated): - Stage1 CLI ソース(launcher.hako)を Stage‑3 VM で素直に通るように整える(using 解決と文法を selfhost 既存パターンに合わせる)タスクは継続。 - `tools/hakorune_emit_mir.sh` の Program→MIR 部分については、provider 経路が安定していることを確認しつつ、selfhost builder 経路(MirBuilderBox.emit_from_program_json_v0)が Stage1 CLI に対して stub MIR を返してしまう根本課題を Phase 25.1b で解く(現時点では `HAKO_SELFHOST_BUILDER_FIRST=0` を維持)。 - デバッグ導線(マージ後 Hako を `/tmp/hako_builder_merged.hako` に保存 etc.)は既に整備済みで、次のフェーズで原因特定と修正を行う。 - `.hako → MIR(JSON) → EXE` スモークは provider-first(`HAKO_SELFHOST_BUILDER_FIRST=0`)でグリーン。selfhost-first(`=1`)は Stage1 CLI の Program(JSON) を完全には扱えないため stub MIR になり、EXE が空挙動になる。MirBuilderBox 側の対応後(Phase 25.1b 以降)に再度 selfhost-first へ戻す予定。*** - Phase 25.1b の具体タスク(selfhost builder 拡張): - `Program.defs` を MirBuilder 側で反映し、`HakoCli` 内の各メソッドを MIR 関数として生成する。 - `func_lowering` / `call_resolve` 相当の処理を Hako 側でも実装し、`Call("cmd_emit_*")` を `Global` resolve できるようにする。 - Loop / branch / boxcall など Stage1 CLI で出現する全ステートメントを lowering するため、`lang/src/mir/builder/internal/*` の helper を統合。 - JSON 出力を jsonfrag ベースで構築し、functions 配列に複数関数を格納可能にする。 - 上記の完了後、selfhost-first を既定に戻し Stage1 CLI EXE の JSON stdout 契約(Rust/llvmlite と同等)を仕上げる。 - ループについては LoopForm 正規化を前提とし、LoopForm の制約を満たさない形(キャリア3変数以上・順序再配置不能など)は selfhost builder では扱わず、タグ付き Fail‑Fast で検知する(PHI ノード生成は既存 LoopForm/LowerLoop helper に一元化)。 - 新規: Stage‑3 VM で `"" + MapBox` に頼らないよう、Rust parity の Box 型情報 API を設計・実装する。 - Hako 側には `lang/src/shared/common/box_type_inspector_box.hako`(`BoxTypeInspectorBox`)を追加し、`method kind(value)` / `is_map(value)` / `is_array(value)` 等の API を提供する。 - Stage0 Rust には `env.box_introspect` extern を追加し、`hostbridge.extern_invoke("env.box_introspect","kind",[value]) -> { kind: "MapBox", type_name: "MapBox", type_id: … }` のような応答を返す(plugin loader v2 経由)。Stage‑3 VM から `BoxTypeInspectorBox._describe` → `hostbridge.extern_invoke("env.box_introspect","kind",[value])` → `env.box_introspect.kind` provider という経路が動作することを確認する。 - `BoxHelpers` / `JsonEmitBox` / `LoopOptsBox.build2` / `MirSchemaBox` など、Box 種別に依存するすべての箇所はこの API で判定し、`String + Box` を禁止する(fallback は「env/provider が使えないデバッグ専用」として限定)。 - doc: Phase 25.1b README に Step3.1 として記載済み。`CURRENT_TASK.md` にも同タスク項目を追記。*** - 進捗(2025-11-16): BoxHelpers / MirSchemaBox / JsonEmitBox が BoxTypeInspectorBox 経由に差し替わり、`"" + MapBox` 依存が排除された。Stage‑3 VM 経路で `BoxTypeInspectorBox.kind` / `is_map` / `is_array` が MapBox / ArrayBox を正しく認識し、小さな Hako テストで env.box_introspect.kind provider 経路が end‑to‑end で動作することを確認済み。次は LoopOptsBox.build2 / JsonEmitBox._quote 等の残差に適用して multi-carrier LoopForm の selfhost-first を復旧する。 - docs: `docs/development/roadmap/phases/phase-25.1b/README.md` を design deep‑dive 版に更新し、FuncLoweringBox / MirBuilderBox の現状把握と拡張方針(Fail‑Fast ポリシー・LoopForm/PHI ポリシー・Step0〜6 の実装順序など)を整理済み。Step0(Fail‑Fast/観測導線)は 2025-11-15 実装済み(defs_only/no_match タグ+ `_lower_func_body` トレース)、Step1 は `HAKO_MIR_BUILDER_REQUIRE_MAIN=1` トグルによる main 必須チェックを inject_funcs に入れるところまで完了。Step2 では `FuncBodyBasicLowerBox` を追加して Local/If/Return パターンを既存の minimal lowers で箱化し、`_lower_func_body` から段階的に呼び出せるようにした。Step3(LoopForm対応)も 2025-11-15 実装完了:`FuncBodyBasicLowerBox._try_lower_loop` から `LowerLoopSumBcBox`/`LowerLoopSimpleBox` を呼び、LoopForm正規化済みループをMIRに落とす導線を確立、PHI/キャリア処理は既存Loop lowersに完全委譲、制約外は `[builder/funcs:unsupported:loopform]` でFail-Fast。Step4(MethodCall/ExternCall パリティ)は Rust 層 (`builder_calls.rs` / extern handler) と Stage‑B Program(JSON) の形を読み解いた設計メモに基づき、`FuncBodyBasicLowerBox._try_lower_return_method` による ArrayBox.size/get(params ベース receiver)と StringBox.length(引数なし)の最小カバーを実装しつつ、新箱 `ExternCallLowerBox`(`lang/src/mir/builder/func_body/extern_call_box.hako`)で `Return(hostbridge.extern_invoke(\"env.codegen\",\"emit_object\"|\"link_object\", Var(arg)))` を `externcall env.codegen.emit_object|link_object`+`ret` に落とす経路を追加した。`FuncLoweringBox._lower_func_body` から BasicLowerBox の次に ExternCallLowerBox を呼ぶよう配線済み。Step1/Step2 の一環として `CliEntryLowerBox` / `CliRunShapeScannerBox` / `CliRunLowerBox` を追加し、Stage1 CLI エントリ(`Main.main`→`HakoCli.run`)と `HakoCli.run` の JSON 形状をタグ付きで観測できるようにした。`CliRunLowerBox` には `_check_shape`+`_emit_mir` を実装し、MVP 用の `HakoCli.run`(argc 初期化・args.size/get・run/build/emit/check 4分岐・unknown=2)のみを `HAKO_MIR_BUILDER_CLI_RUN=1` ガード付きで selfhost builder から MIR に降ろせるようにした(Stage1 本番の run にはまだ適用していない)。さらに Stage‑B 側の func_scan トグル(`HAKO_STAGEB_FUNC_SCAN`)は「未設定なら既定ON、`\"0\"` のときだけ OFF」とするように compiler_stageb.hako を変更し、Stage‑B を直接叩いたときに env 立て忘れで defs が欠落するバグを構造的に防ぐようにした。*** - LoopForm 複雑ケースについては、「Rust 側の LoopForm/PHI 実装をオラクルとし、同じ .hako を provider-first と selfhost-first の両方で通す」方針を docs に追記。LoopForm/PHI のロジック自体は Hako 側では `lower_loop_*_box.hako` 群に閉じ込め、FuncLowering/MirBuilder 本体は `_rebind` 呼び出しのみを行う。Rust は Stage‑B/MIR→LLVM の検証と既存 provider 経路の「正解」としてだけ使う。 - 新しい LoopForm 用 helper 箱 `lower_loop_multi_carrier_box.hako` を追加し、multi-carrier ループ(fib 風)を Program(JSON v0) 上で検出して `[mirbuilder/internal/loop:multi_carrier:detected:limit_kind=const|param,...]` を出しつつ `LoopFormBox.build2(mode="multi_count")` へ委譲(limit が `Int` だけでなく `Var(n)`=パラメータ参照でも処理可能に)。 - スモーク構成について、「Rust builder 用スモークと selfhost builder 用スモークをペアで置く」ルール(`*_provider_vm.sh` / `*_selfhost_vm.sh` 命名、同じ .hako を共有)を phase-25.1b README に記載。今後は loop/method/extern/Stage1 CLI 用の selfhost-first canary を `phase251` 配下に追加していく。 Update (2025-11-16 — Stage‑B using resolver alias 化 & 環境導線) - Stage‑B entry (`compiler_stageb.hako`) の `using "hako.compiler.entry.bundle_resolver"` / `using "lang/src/compiler/entry/using_resolver_box.hako"` を module alias (`hako.compiler.entry.bundle_resolver`, `lang.compiler.entry.using_resolver`) に置き換え、Stage‑3 パーサが string literal using を弾いていた問題を解消。 - `tools/hakorune_emit_mir.sh` では `nyash.toml` `[modules]` を Python で読み取り `name=path` を `HAKO_STAGEB_MODULES_LIST`(`|||` 区切り)として export 済み。Stage‑B 側では `Stage1UsingResolverBox` がこの env を `MapBox` 化し、`using lang.mir.builder.MirBuilderBox` などの module alias を元の .hako に展開してから parse する。 - 同じく `tools/hakorune_emit_mir.sh` 内の `HAKO_MIRBUILDER_IMPORTS` 生成ロジックを拡張し、`using ns.path.Type as Alias` だけでなく `using ns.path.Type` 形式からも末尾セグメント(例: `MirBuilderBox`)を alias として抽出するようにした。これにより Stage‑B 経由で生成された Program(JSON v0) を `env.mirbuilder.emit` が処理するときに、`MirBuilderBox` や `BuildBox` といった static box 名が `undefined variable` にならず、imports 経由で Const(String) に解決されるようになった。 - Rust 側 JSON v0 ブリッジ(`src/runner/json_v0_bridge/lowering/expr.rs`)には `hostbridge` 名の変数を well-known グローバルとして扱う最小の分岐を追加し、`hostbridge.extern_invoke(...)` を含む Program(JSON v0) でも `undefined variable: hostbridge` エラーが出ないようにした(値は `Const(String(\"hostbridge\"))` を発行する placeholder とし、実際の extern dispatch は VM/ランタイム側で担保)。 - Stage1 CLI (`lang/src/runner/launcher.hako`) の emit/build コマンドを整理し、FileBox 操作を `_read_file` / `_write_file` helper に集約。Option 解析の重複を解消しつつ Stage‑3 friendly な `local` 宣言へ寄せた結果、`tools/hakorune_emit_mir.sh lang/src/runner/launcher.hako /tmp/launcher_cli_mir.json` が provider delegate で安定して成功する状態を quick smoke (`phase251/stage1_launcher_program_to_mir_canary_vm`) でカバー。 - 検証: - `HAKO_SELFHOST_TRACE=1 ./tools/hakorune_emit_mir.sh basic_test.hako /tmp/test_mir_stageb.json` が `[emit:trace] Stage-B: SUCCESS - Generated Program(JSON)` の後に `delegate:provider` で MIR を出力し、`[OK] MIR JSON written (delegate:provider)` で終了(`direct-emit` フォールバックに落ちない)。 - `HAKO_SELFHOST_TRACE=1 ./tools/hakorune_emit_mir.sh lang/src/runner/launcher.hako /tmp/launcher_mir.json` でも `env.mirbuilder.emit` が `undefined variable: MirBuilderBox` / `hostbridge` を出さずに 0 exit し、MIR(JSON) を生成できることを確認。 - Next: - Stage1 CLI (`lang/src/runner/launcher.hako`) 側の `using` も module alias に揃え、Stage‑B から box 定義が Program(JSON) に落ちるようにする。 - selfhost builder Runner (`try_selfhost_builder`) は引き続き opt-in。Stage‑B 改修により Program(JSON) 生成が安定したので、次のターンは builder prelude の VM 実行エラー(`self._is_on` 等)を潰し selfhost-first を既定ONに戻せるかを調査する。 Update (2025-11-15 — Phase 25.1a extension: ny-llvmc / llvmlite I/O semantics) - Decision: - Stage1 EXE(ny-llvmc 経由で生成されたバイナリ)が提供する `emit program-json` / `emit mir-json` の I/O 挙動は、llvmlite ハーネス(`NYASH_LLVM_USE_HARNESS=1` 経路)の挙動に揃える。 - 具体的には: - stdout: JSON をそのまま吐く(`Result: 0` のようなハーネス用メッセージは既定OFF/verbose専用に寄せる)、エラー時は JSON ではなく明示的なエラーメッセージ+非0 exit code。 - exit code: Rust CLI / llvmlite ハーネスと同じく、0=成功、非0=失敗(Stage1 CLI 側の 90–93 番台コードと整合)。 - Scope (Phase 25.1a 内でやる範囲): - `tools/ny_mir_builder.sh` / ny-llvmc ハーネスで、Stage1 EXE(`target/selfhost/hakorune` 等)が `emit program-json` / `emit mir-json` を呼び出す場合に、llvmlite ハーネスと同じ I/O 契約(stdout に JSON、exit code で成否を表現)になるように調整する。 - `docs/development/runtime/cli-hakorune-stage1.md` に「Stage1 EXE の emit I/O 挙動は llvmlite ハーネスを参照する」ことを明記し、さらなる profile 切替(dev/ci/lite 等)は Phase 25.2 以降のタスクとして扱う。 - Helper: `tools/selfhost/run_stage1_cli.sh` を追加し、Stage1 CLI 実行時に `NYASH_NYRT_SILENT_RESULT=1` / `NYASH_DISABLE_PLUGINS=1` / `NYASH_FILEBOX_MODE=core-ro` を既定ONにして呼び出せるようにした。これにより JSON stdout が ny-llvmc / llvmlite ハーネスと同一契約になり、`tools/selfhost_exe_stageb.sh --run` も Result 行を出さずに exit code だけで評価できる。 - 現在の状況(2025-11-16 調査): - Stage-B では `HakoCli` 本体や `cmd_emit_*` が Program(JSON v0) に落ちるようになったが、VM 側 selfhost builder は Stage1 CLI をほぼ no-op に潰してしまい、171 bytes の stub MIR しか出力していない。 - provider 経由 (`env.mirbuilder.emit`) は `.hako → Program(JSON) → MIR(JSON)` を安定して通すため、Phase 25.1a では `HAKO_SELFHOST_BUILDER_FIRST=0` を維持してこのルートを採用する。 - Stage1 EXE (`target/selfhost/hakorune`) の CLI コマンドは現在 `Result: 0` しか出力しない(MIR が stub のため)。selfhost builder の機能拡張後に JSON stdout を Rust/llvmlite と揃えるタスクを再開する。 Update (2025-11-14 — Phase 25 closure & Phase 25.2 deferral) - Phase 25: - Ring0/Ring1 設計と numeric_core (MatI64.mul_naive) の BoxCall→Call 降ろし用 AotPrep パスの MVP 実装までを達成。 - `NYASH_AOT_NUMERIC_CORE=1` で MatI64.mul_naive を `Call("NyNumericMatI64.mul_naive", args=[receiver, ...])` に書き換える処理は、代表的な MIR パターン(13 PHI / 1 PHI 両方)で動作確認済み。 - STRICT モードは「AotPrep.run_json 後の MIR(JSON) に対してのみ BoxCall(mul_naive) 残存をチェックする」運用に整理し、pre-AotPrep の MirBuilder には干渉しない形に修正済み。 - Phase 25.2 への移管: - `matmul_core` microbench(`tools/perf/microbench.sh --case matmul_core --backend llvm --exe`)の EXE/LLVM 統合と性能チューニングは Phase 25.2 に移す。 - 本フェーズでは「numeric_core の構造と導線」を優先し、heavy な microbench 最適化は Stage1 構築後の Phase 25.2 で扱う。 --- Update (2025-11-14 — Phase 25 MVP SUCCESS! numeric_core transformation working!) - Status: ✅ **Phase 25 MVP BoxCall→Call transformation完全動作!** - Breakthrough: - `numeric_core.hako` の重大バグを2つ発見・修正し、MatI64.mul_naive の BoxCall→Call 変換に成功 - 変換例: `BoxCall(MatI64, "mul_naive")` → `Call("NyNumericMatI64.mul_naive", args=[receiver, ...args])` - Fixed bugs: 1. **Missing nyash.toml mapping** (Critical): `selfhost.llvm.ir.aot_prep.passes.numeric_core` module path was missing from nyash.toml:224 - Without this, the `using` statement couldn't resolve and the pass never loaded 2. **JSON parsing bug** (Critical): `build_type_table()` and `build_copy_map()` were treating entire JSON as one instruction - Root cause: Used `text.indexOf("{", pos)` which found the root `{` of entire JSON document - Fix: Changed to op-marker-first pattern: find `"op":"..."` → `lastIndexOf("{")` → `_seek_object_end()` - Result: Now correctly processes individual instruction objects within the instructions array - Debug output confirms success: ``` [aot/numeric_core] MatI64.new() result at r2 [aot/numeric_core] MatI64.new() result at r3 [aot/numeric_core] type table size: 3 [aot/numeric_core] transformed BoxCall(MatI64, mul_naive) → Call(NyNumericMatI64.mul_naive) [aot/numeric_core] transformed 1 BoxCall(s) → Call ``` - Files modified: - `/home/tomoaki/git/hakorune-selfhost/nyash.toml` (added module mapping) - `/home/tomoaki/git/hakorune-selfhost/lang/src/llvm_ir/boxes/aot_prep/passes/numeric_core.hako` (fixed JSON parsing) - Next steps: - Test with actual matmul benchmark using `NYASH_AOT_NUMERIC_CORE=1` - Verify VM and LLVM execution paths both work - Measure performance improvement (expected: 10-100x for large matrices) - How to verify: ```bash # Standalone test (already confirmed working) bash /tmp/run_numeric_core_test.sh 2>&1 | grep -E "\[aot/numeric_core" # Full benchmark test NYASH_AOT_NUMERIC_CORE=1 NYASH_SKIP_TOML_ENV=1 NYASH_DISABLE_PLUGINS=1 \ tools/perf/microbench.sh --case matmul_core --backend llvm --exe --runs 1 --n 64 ``` Update (2025-11-14 — Phase 21.8 wrap-up: builder/importsまでで一旦クローズ) - Status: - Phase 21.8 は「Stage‑B / Bridge / MirBuilder への IntArrayCore/MatI64 導線(imports)」まで完了とし、EXE/LLVM ベンチ統合は Phase 25 に移管する。 - Done in 21.8: - BridgeEnv に `imports: HashMap` フィールドを追加し、using 由来の alias 情報を JSON→MIR 変換に渡せるようにした。 - `MapVars::resolve` を拡張し、`env.imports` を参照して `MatI64` / `IntArrayCore` などの静的 box 名を「有効な変数」として解決できるようにした。 - `parse_json_v0_to_module_with_imports` / `program_json_to_mir_json_with_imports` を導入し、Program(JSON v0)→MIR(JSON) 経路が imports マップを受け取れるようにした。 - `collect_using_and_strip` の戻り値を `(cleaned, prelude_paths, imports)` に拡張し、using から alias 一覧を収集できるようにした(既存呼び出しは `_imports` として無視し、挙動不変)。 - `HAKO_MIRBUILDER_IMPORTS` 経由で imports を Rust 側 MirBuilder へ渡す読み取り側の配線を追加(env.mirbuilder.emit ルート)。 - Deferred to Phase 25: - `matmul_core` microbench の EXE/LLVM 統合(MatI64/IntArrayCore を LLVM ラインで実行可能にする設計と実装)。 - Numeric core AOT ライン(Ring1 numeric runtime を .hako 実装+汎用 `ExternCall`/numeric ABI 経由で LLVM に乗せる設計)。 - これらの後続タスクは `docs/development/roadmap/phases/phase-25/README.md` に移し、Ring0/Ring1 再編フェーズ(Phase 25)の一部として扱う。 Helper (2025-11-14 — numeric_core 開発用ラッパ追加) - 新しい開発用スクリプト: - `tools/dev_numeric_core_prep.sh ` - 常に `HAKO_APPLY_AOT_PREP=1` と `NYASH_AOT_NUMERIC_CORE=1` を立てて `tools/hakorune_emit_mir.sh` を呼び出す。 - `NYASH_SKIP_TOML_ENV=1 NYASH_DISABLE_PLUGINS=1 HAKO_SELFHOST_TRACE=1 NYASH_JSON_ONLY=1` を既定ONにして、環境変数漏れで numeric_core が動かない問題を避ける。 - Claude Code / Codex への推奨: - numeric_core / AotPrep 関連のテスト・デバッグは、直接 env を組むのではなく **このラッパを使う** こと。 - 例: `tools/dev_numeric_core_prep.sh tmp/matmul_core_test.hako tmp/matmul_core_test_mir.json` - こうして生成した MIR(JSON) に対して `NYASH_AOT_NUMERIC_CORE_STRICT=1` + `NYASH_LLVM_DUMP_MIR_IN=...` を使えば、LLVM/EXE ラインでも同じ MIR を共有できる。 Update (2025-11-16 — Phase 25.1b: selfhost builder multi-carrier & BoxTypeInspector 経路の一段落) - 状況: - selfhost builder 側の LoopForm multi-carrier 経路(`LowerLoopMultiCarrierBox` → `LoopFormBox.build_loop_multi_carrier`)は設計と骨格実装まで到達済みで、Box 型情報 API(`BoxTypeInspectorBox` / `env.box_introspect.kind`)もひととおり配線済み。 - fib multi-carrier 経路と selfhost multi-carrier smoke 用 canary(`tools/smokes/v2/profiles/quick/core/phase251/selfhost_mir_loopform_multi_carrier_vm.sh`)は、BoxTypeInspector 経由の multi-carrier LoopForm で PASS するところまで到達した(`[mirbuilder/internal/loop:multi_carrier:detected:limit_kind=param,...]` と `[funcs/basic:loop.multi_carrier] -> TestBox.fib/1` ログを確認済み)。 - 進捗(Codex run, 2025-11-16): - `BoxTypeInspectorBox._describe` → `hostbridge.extern_invoke("env.box_introspect","kind",[value])` → `env.box_introspect.kind` provider → plugin loader v2 の BoxIntrospect 実装までの経路を Stage‑3 VM で確認済み(MapBox / ArrayBox に対して kind / is_map / is_array が正しく返る)。 - selfhost builder 経由の fib multi-carrier emit(`tools/hakorune_emit_mir.sh tmp/fib_multi.hako tmp/fib_multi_mir.json`)では、`env.box_introspect.kind` / `JSON.stringify` 起因の Invalid instruction が消え、child rc=0 で完走する。ログには multi-carrier detection タグと `[funcs/basic:loop.multi_carrier] -> TestBox.fib/1` が出力される。 - 出力 MIR(JSON) には `"name":"TestBox.fib/1"` を持つ関数が含まれており、selfhost-first multi-carrier 経路が Box 型 API 依存で起動できることを確認済み。ただしトップレベル JSON 形(`{"functions":[{...main...},{...kind:\"MIR\"...}]}` と provider 側の module 形の差)は残っており、これは 25.1c 以降の構造タスクとして整理予定。 - 追加メモ(Stage‑B / selfhost CLI canary 周りの現状把握): - `tools/smokes/v2/profiles/quick/core/phase251/selfhost_cli_run_basic_vm.sh` で使っている簡易 HakoCli.run サンプルに対しては、以前は Stage‑B (`compiler_stageb.hako`) 実行中に VM エラー: - `❌ VM error: Invalid value: use of undefined value ValueId(N)` (%0 / 97842 / 22 など)が発生し、Program(JSON v0) が一行としては出力されなかった。 - 現在(Task先生+Claude code 君修正後)の状況: - Rust MIR builder 側で ValueId 割り当てを全面的に見直し(関数ローカル ID への統一+`next_value_id()` 導入)、`NYASH_VM_VERIFY_MIR=1` で報告されていた `%0` 由来の Undefined value は 0 件になった。 - さらに `src/mir/phi_core/loop_phi.rs` の loop header PHI 準備処理から「`__pin$*` 変数を PHI 対象から除外する」ロジックを削除し、ピン済み変数にも header/exit 両方で PHI を張るようにしたことで、ループ後レシーバー未定義(ValueId(22))問題は解消された(pinned recv が正しく loop exit まで SSA で運ばれるようになった)。 - `src/runner/modes/vm.rs` 側では、`static_box_decls` を InlineUserBoxFactory の `decls` にも統合し、`NewBox` から静的 Box(HakoCli など)も user factory 経由で生成できるようにした(plugins disabled でも HakoCli の NewBox 自体は成功する)。 - If‑block 側の PHI 再割り当て問題についても、`src/mir/utils/phi_helpers.rs` の `insert_phi()` がグローバルアロケーター(`value_gen.next()`)を直接叩いていた箇所を関数ローカルアロケーター(`MirFunction::next_value_id()` 経由)に切り替えることで、`%0` など既存 ValueId との衝突/再定義が発生しないよう修正済み。これにより「if 内でメソッド呼び出し前に PHI が既存 ValueId を上書きする」タイプの SSA 破綻も消えている。 - さらに Rust VM 側の `MirInterpreter::reg_load` に開発用の追加情報を付けたことで、`Invalid value: use of undefined value ValueId(N)` が発生した際に `fn` / `last_block` / `last_inst` がエラーメッセージに含まれるようになり、Stage‑B / Stage‑B 用最小ハーネス内の `ParserBox.length()` 呼び出しが recv 未定義で落ちていることを特定できるようになった(NYASH_VM_TRACE/NYASH_VM_TRACE_EXEC 未設定時でも場所が分かる)。 - なお、Stage‑B を selfhost CLI サンプルに対して実行した際に現時点で見えている残存課題は次の 3 点: - 1) `if args { ... }` まわりの truthy 判定(ArrayBox を boolean 条件に使っている部分)の扱いに起因する型エラーであり、これは SSA ではなく「条件式の型/truthy 規約」をどう定義するかという別問題として扱う(Phase 25.1c 以降の型システム整理タスクで扱う想定)。 - 2) Stage‑B 用最小ハーネス(`lang/src/compiler/tests/stageb_min_sample.hako` + `tools/test_stageb_min.sh` の Test2)を Stage‑B 経由で実行した際に、以前は `❌ VM error: Invalid value: use of undefined value ValueId(21)` が報告されていたが、Rust MIR builder 側の BoxCompilationContext 導入と ValueId 割り当て修正により、この Undefined value 系は解消済み。ただし現在も `compiler_stageb.hako` を経由する Test2 では stack overflow(`thread 'main' has overflowed its stack`)が発生しており、これは emit_unified_call ↔ BoxCall の再帰ルートではなく、Stage‑B Nyash ボックス側の自己再帰/循環に起因する可能性が高い。Phase 25.1e 以降で Nyash 側に浅い再帰ガード(depth カウンタ)を入れ、どの Box.method が再帰しているかを特定するタスクとして扱う。 - 3) Rust 側では emit_unified_call / emit_box_or_plugin_call / emit_legacy_call に対して再入防止フラグ(`in_unified_boxcall_fallback`)と再帰深度カウンタ(build_expression / build_method_call / emit_unified_call)を導入済みであり、call 系の自己再帰は構造的に防止されている。Stage‑B 経路の stack overflow 調査は、これを前提に Nyash 側の構造へフォーカスする。 - Next tasks (Phase 25.1b → 25.1c handoff / Codex): 1. Rust 層 Call/ExternCall 契約のドキュメント固定(Step 4.1) - `src/mir/builder/builder_calls.rs` / `src/backend/mir_interpreter/handlers/{calls,externs,extern_provider}.rs` / `src/runtime/plugin_loader_v2/enabled/extern_functions.rs` をベースに、「MethodCall/ExternCall/hostbridge.extern_invoke/ env.codegen/env.mirbuilder」の SSOT を Phase 25.1b README に記録(実施済み)。 2. Stage1 CLI defs / MethodCall / ExternCall 拡張(Step4 本体) - 対象: `lang/src/runner/launcher.hako` 内で実際に使われている `FileBox` / `ArrayBox` / `MapBox` / `String` メソッドと `hostbridge.extern_invoke("env.codegen", "emit_object"|"link_object", args)` などを selfhost builder 側でも lowering できるようにする(ただし Rust 側の SSOT に合わせて挙動をコピーするだけで、新仕様は足さない)。 3. selfhost builder 出力 MIR(JSON) のトップレベル形の正規化(25.1c 構造タスク) - 現状の selfhost-first 出力(`{"functions":[{name:\"main\",...},{kind:\"MIR\",...}]}`)を、Rust provider と同じく「トップレベルが MIR module(kind=MIR, functions=[...])」の形に揃える(LoopForm / LoopOpts / JsonEmit 側の責務分離込みで要整理)。 4. Stage1 CLI run / launcher 用 canary の拡張 - 既存の `tools/smokes/v2/profiles/quick/core/phase251/stage1_launcher_program_to_mir_selfhost_vm.sh` は入口検出タグ(`[builder/cli:entry_detected]` / `[builder/cli:run_shape]`)まで PASS しているので、今後は `HAKO_MIR_BUILDER_CLI_RUN=1` を使った run 本体の MIR 生成 canary を追加し、Step4 の MethodCall/ExternCall パリティを継続的に検証する。 5. Ny selfhost パイプライン(Ny→JSON v0)の現状と無限ループ疑い(構造的デバッグタスク) - Ny selfhost は `.ny`/Nyash 用の補助ルートであり、`.hako → Program(JSON v0) → MIR(JSON)` の Stage‑B/MirBuilder/selfhost builder 経路とは別レイヤ(`src/runner/selfhost.rs`)に置く。 - Phase 25.1b で `NYASH_USE_NY_COMPILER` の既定値を OFF に変更し、明示的に `NYASH_USE_NY_COMPILER=1` を立てない限り Runner から `try_run_selfhost_pipeline` が呼ばれないようにした(Ny selfhost は opt-in のみ)。`.hako` 実行や `tools/hakorune_emit_mir.sh` 経由のメイン経路はこの影響を受けない。 - Python MVP ハーネス(`tools/ny_parser_mvp.py`)も `NYASH_NY_COMPILER_USE_PY=1` のときだけ起動するようにし、selfhost パイプラインからの Python 依存は既定では完全に外した。 - 一方で Ny selfhost を明示 ON(`NYASH_USE_NY_COMPILER=1`)かつ inline 経路(`inline_selfhost_emit.hako`)を通した場合、`ParserBox.parse_program2` 周辺で 60s タイムアウトし、その後の VM 実行で `Undefined variable: local`(Stage‑3 キーワード)エラーが出ていることを確認。これは Ny selfhost の parser/Stage‑3/using 周りに無限ループ相当のバグが残っている疑いとして切り出す。 - Phase 25.1b 本体では `.hako` selfhost builder 側のフォールバック禁止と BoxTypeInspector/LoopForm 経路の整備までをゴールとし、Ny selfhost 側は `src/runner/selfhost.rs` のログ強化(`[ny-compiler] inline timeout ...`+`[ny-inline:hint]`)で「どこで止まっているか」が見える状態まで整えた上で、25.1c 以降の別タスクとして原因究明・修正を進める。 - Ny selfhost 経路とは別に、Stage‑B (`compiler_stageb.hako`) 側の失敗が selfhost CLI の canary に見えてきている。`[plugin/missing] vm providers not loaded: ["FileBox", "ConsoleBox", "ArrayBox", "MapBox", "StringBox", "IntegerBox"]` はあくまで「プラグイン版コア Box が見つからない」という警告であり、Program(JSON v0) emit の必須条件ではない(core‑ro モードではプラグイン無しでもコンパイラ本体は動ける設計)。現状の Stage‑B 失敗は、プラグイン不足ではなく、別の構文/using/Stage‑3 周りのエラーが rc=1 を返している可能性が高く、これは selfhost CLI フェーズとは独立に compiler_stageb.hako 側のバグとして追いかける予定。 Update (2025-11-14 — 21.8 kickoff: MatI64/IntArrayCore builder integration) - Context: - 21.5: AotPrep/CollectionsHot v1 + microbench整備まで完了(linidx/maplin ≒ C=100%)。arraymap/matmul は次フェーズ送り。 - 21.6: NyRT IntArrayCore + Hako IntArrayCore/MatI64/matmul_core スケルトン実装まで完了(builder 経路未対応)。 - Current goal: - Hakorune selfhost chain(Stage‑B → MirBuilder → ny‑llvmc(crate))に IntArrayCore/MatI64 を統合し、`matmul_core` ベンチを EXE ラインで実行できるようにする。 - 実装は Claude Code 担当、このホストは仕様・構造・診断の整理に専念。 Planned tasks (for Claude Code) 1) Fix MatI64 visibility in Stage‑B / MirBuilder - Reproduce provider error: `[mirbuilder/parse/error] undefined variable: MatI64` from `env.mirbuilder.emit` when compiling a small test using `using nyash.core.numeric.matrix_i64 as MatI64`. - Wire `nyash.core.numeric.matrix_i64` / `nyash.core.numeric.intarray` modules into the resolver/prelude so that Stage‑B/MirBuilder can see MatI64 and IntArrayCore like other core boxes. 2) Make `tools/hakorune_emit_mir.sh` emit MIR(JSON) for `matmul_core` - With `HAKO_APPLY_AOT_PREP=1 NYASH_AOT_COLLECTIONS_HOT=1 NYASH_LLVM_FAST=1 NYASH_MIR_LOOP_HOIST=1 NYASH_JSON_ONLY=1`, emit MIR(JSON) for the `matmul_core` case in microbench and ensure no undefined‑variable errors. 3) Finish `matmul_core` bench EXE path - Confirm `tools/perf/microbench.sh --case matmul_core --backend llvm --exe --runs 1 --n 64` builds EXE and runs, logging ratio vs the matching C implementation. 4) Keep defaults stable - No behaviour changes for existing code/benches; IntArrayCore/MatI64 integration is additive and behind explicit use. Update (2025-11-14 — CollectionsHot rewrite expansion, waiting for Claude Code) - Status: pending (waiting on Claude Code to land rewrite coverage improvements) - Scope: AotPrep CollectionsHot — expand Array/Map get/set/has rewrite to externcall by strengthening receiver type resolution. - Done (this host): - Stage‑3 local hint added in builder (Undefined variable: local → guide to set NYASH_PARSER_STAGE3=1 / HAKO_PARSER_STAGE3=1). - 2‑arg lastIndexOf removed across .hako (prefix + 1‑arg pattern) — AotPrep no longer trips PyVM. - CollectionsHot: fixpoint type_table, on‑the‑fly phi peek, backward scan, CH trace logs, push rewrite working. - Bench (arraymap, 10s budget): externcall>0 is observed; boxcall remains in loop; ratio still high. - Waiting (Claude Code tasks): 1) Implement tmap_backprop (receiver type from call‑site signals), iterate to small fixpoint (max 2 rounds). 2) Integrate resolve_recv_type_backward into decision order (after phi peek), widen key/index heuristics. 3) Emit gated logs: "[aot/collections_hot] backprop recv= => arr|map via method=" (NYASH_AOT_CH_TRACE=1). 4) Update README with decision order and NYASH_AOT_CH_BACKPROP toggle (default=1). - Acceptance: - PREP.json contains nyash.array.get_h/set_h and/or nyash.map.get_h(hh)/set_h(hh); boxcall count decreases; jsonfrag=0. - Bench diag shows externcall>1 (push + at least one of get/set); build/exe succeeds. - How to verify quickly: - ORIG: HAKO_APPLY_AOT_PREP=0 NYASH_JSON_ONLY=1 tools/hakorune_emit_mir.sh /tmp/arraymap_min.hako tmp/arraymap_orig.json - PREP: HAKO_APPLY_AOT_PREP=1 NYASH_AOT_COLLECTIONS_HOT=1 NYASH_LLVM_FAST=1 NYASH_MIR_LOOP_HOIST=1 NYASH_JSON_ONLY=1 tools/hakorune_emit_mir.sh /tmp/arraymap_min.hako tmp/arraymap_prep.json - Bench: NYASH_SKIP_TOML_ENV=1 NYASH_DISABLE_PLUGINS=1 tools/perf/microbench.sh --case arraymap --exe --budget-ms 10000 - Optional logs: NYASH_AOT_CH_TRACE=1 HAKO_SELFHOST_TRACE=1 …/hakorune_emit_mir.sh Update (2025-11-12 — Optimization pre-work and bench harness) - Implemented (opt‑in, defaults OFF) - Ret block purity verifier: NYASH_VERIFY_RET_PURITY=1 → Return直前の副作用命令をFail‑Fast(Const/Copy/Phi/Nopのみ許可)。構造純化の安全弁として維持。 - strlen FAST 強化: newbox(StringBox,const) だけでなく const ハンドルからの length() も即値畳み込み(NYASH_LLVM_FAST=1時)。 - Kernel hint: nyrt_string_length に #[inline(always)] を付与(AOT呼び出しのオーバーヘッド抑制)。 - FAST_INT ゲート: NYASH_LLVM_FAST_INT=1 で BinOp/Compare が同一ブロックSSA(vmap)を優先利用し、resolver/PHIの局所化コストを回避(文字列連結は除外)。 - length キャッシュ(llvmlite 最低限): NYASH_LLVM_FAST=1 時、文字列リテラル由来ハンドルに対する length()/len の i64 即値を resolver.length_cache に格納し、ループ内で再利用。 - Added - Bench harness 拡張(tools/perf/microbench.sh): branch/call/stringchain/arraymap/chip8/kilo を追加。各ケースは C 参照付きで ratio を自動算出。 - Bench doc: benchmarks/README.md に一覧・実行例を追加。 - Preliminary results(LLVM/EXE, ノイズ抑制: NYASH_SKIP_TOML_ENV=1 NYASH_DISABLE_PLUGINS=1) - 良好: call / stringchain / kilo → ratio < 100%(Nyash側が軽い) - 要改善: branch / arraymap / chip8 → ratio ≈ 200%(Cの約1/2速度) Compiler health(E0308対応) - PHI 挿入のコールサイトを監査し、`insert_phi_at_head(&mut MirFunction, ...)` へ統一(`current_function.as_mut()` 経由で渡す)。`cargo check` は通過済み。 - `tools/ny_mir_builder.sh --emit exe` 実行時にワークスペース再ビルドが走る環境では、必要に応じて `NYASH_LLVM_SKIP_BUILD=1` を指定し、既存の `ny-llvmc` / `nyash_kernel` ビルド成果物を用いる運用を併記。 - Next actions(AOT集中; 既定OFFのまま段階適用) 1) ループ不変の簡易ホイスティング(strlen/比較/分母mod など) 2) FAST_INT の適用範囲精緻化(不要cast/extendの抑制、CFG保存のまま) 3) array/map のホットパス検討(AOT経路のみ・診断OFF) 4) 再ベンチ(branch/arraymap/chip8 を再測)、目標: ratio ≤ 125%(Cの8割) 5) 既定OFFで挙動不変・Ret純化ガード緑維持・小差分リバーシブルを堅持 Toggles(再掲) - NYASH_LLVM_FAST=1 … strlen FAST + literal length キャッシュ - NYASH_LLVM_FAST_INT=1 … i64 ホットパス(同一BB SSA 優先) - NYASH_VERIFY_RET_PURITY=1 … Ret 純化ガード(開発ガード) - NYASH_LLVM_SKIP_BUILD=1 … ny_mir_builder.sh の再ビルド抑止(既存バイナリ再利用) - NYASH_MIR_DEV_IDEMP=1 … MIR normalize/dev 用の再実行安定化(idempotence)メタ。既定OFF(診断専用) - HAKO_MIR_NORMALIZE_PRINT=1 … AotPrep(.hako) 側で print→externcall(env.console.log) を正規化(CFG不変・既定OFF) - HAKO_MIR_NORMALIZE_REF=1 … AotPrep(.hako) 側で ref_get/ref_set→boxcall(getField/setField) を正規化(CFG不変・既定OFF) - HAKO_SILENT_TAGS=0|1 … v2ランナーのタグ静音トグル(1=静音:既定、0=生ログ) Wrap‑up (this session) - Rust/Hako ownership clarified(docs/development/normalization/ownership.md)。Hako=意味論正規化、Rust=構造/安全。 - Runtime autoload for using.dylib(guarded)を Runner 初期化に集約。箱名は nyash_box.toml から推論して登録。 - Builder/VM safety: 受信ローカライズを強化(LocalSSA/pin/after‑PHIs/tail)。未定義受信は同一BBの直近 NewBox で構造回復(dev 安全弁)に限定。 - PluginInvoke→BoxCall の過剰な書換えを停止(意味論は Hako 側の methodize に集約)。 - カナリア: - phase217_methodize_canary.sh → PASS(rc=5)。 - phase217_methodize_json_canary.sh → v1 + mir_call present(Method が優先、Global は経過容認)。 - phase217_methodize_json_strict.sh を追加(selfhost‑only 仕上げ用ゲート、現状は Stage‑B child パース修正が必要)。 ## Phase 21.5 — Optimization Checklist(進行管理) - [x] パス分割(AotPrep: StrlenFold / LoopHoist / ConstDedup / CollectionsHot / BinopCSE) - [x] CollectionsHot: Array/Map の boxcall→externcall(既定OFF・トグル) - [x] Map key モード導入(`NYASH_AOT_MAP_KEY_MODE={h|i64|hh|auto}`) - [x] LoopHoist v1: compare/mod/div 右辺 const の前出し(参照 const を先頭へ) - [x] BinopCSE v1: `+/*` の同一式を再利用、`copy` で伝播 - [x] VERIFY ガード常時ON(`NYASH_VERIFY_RET_PURITY=1`)で測定 - [x] ベンチ新規(`linidx`/`maplin`)追加・実測を README に反映 - [x] LoopHoist v2: `+/*` 右項 const の連鎖前出し、fix‑point(≤3周)の安全適用(定数 binop 折畳み+hoist 実装) - [x] BinopCSE v2: 線形 `i*n` の共通化強化(copy 連鎖の正規化・左右交換可の正規化) - [x] CollectionsHot v2: Array/Map index/key の式キー共有(同一ブロック短窓で get/set の a0 を統一) - [x] Map auto 精緻化: `_is_const_or_linear` の再帰判定強化(copy 追跡+div/rem の定数片を線形扱い) - [x] Rust normalize.rs の借用修正(E0499/E0502解消)+ dev idempotence メタ追加(既定OFF) - [x] 正規化の .hako 化(新箱でモジュール化):NormalizePrint / NormalizeRef を AotPrep から opt-in で呼び出し - [ ] Idempotence: 置換済みマーク(devメタ)で再実行の結果不変を担保 - [ ] ベンチ更新: `arraymap`/`matmul`/`sieve`/`linidx`/`maplin` EXE 比率 ≤ 125%(arraymap/matmul優先) ### 21.5 引き継ぎメモ(ベンチ&観測) - 新規トグル/修正 - `NYASH_LLVM_DUMP_MIR_IN=/tmp/xxx.json`(AOT 入力MIRダンプ) - dump_mir.sh: provider/selfhost-first + min fallback で実MIRダンプを安定化 - microbench: `PERF_USE_PROVIDER=1` で jsonfrag 強制を解除(実MIRでの突合せ用) - ベンチ現状(EXE, C=100%) - arraymap: 150–300%(分散あり) / matmul: 300% / sieve: 200% / linidx: 100% / maplin: 200% - 次のアクション 1) arraymap/matmul の実MIR(provider or `NYASH_LLVM_DUMP_MIR_IN`)で index SSA 共有の崩れを特定 2) CollectionsHot v2.1: 同一ブロック短窓 get→set で a0 の一致を強制(式キー統一の取りこぼし追加) 3) BinopCSE 小窓 fix‑point 拡張(隣接ブロックまでの `i*n+k` 共有; 制御不変・既定OFF) 4) 再ベンチ(arraymap/matmul/maplin)→ `benchmarks/README.md` に 日付/トグル/ratio ≤ 125% を追記 5) provider emit の失敗パターンを継続調査(emit ラッパの fallback/guard を追加調整) Decisions - 既定挙動は変更しない(dev では methodize トグルON、CI/ユーザ既定は従来維持)。 - Rust 層は正規化を持たず、構造のみ(SSA/PHI/LocalSSA/安全弁)。Hako が mir_call(Method) のSSOT。 Rust normalize.rs sunset plan(記録) - 目的: normalize.rs の責務を .hako 側へ移し、Rust 側は既定OFF→撤去へ。 - 段階: - 1) dev カナリア期間は `HAKO_MIR_NORMALIZE_*`(PRINT/REF/ARRAY)を opt-in で運用(既定OFF)。 - 2) AotPrep 経由の normalize が十分に安定後、dev/quick で既定ONへ昇格(CI は段階移行)。 - 3) Rust 側 normalize は env で明示 ON のみ許可(互換ガードを残す)。 - 4) 既定ON 状態で 2 週安定を確認後、Rust normalize のビルド配線を外し、最終撤去。 - 付随: 新規/更新トグルは env 一覧へ追記し、昇格時にデフォルト化→古いトグルは段階的に非推奨化とする。 Follow‑ups (carried to backlog) - Stage‑B child の "Unexpected token FN" 修正(selfhost‑first/strict ゲート用)。 - Provider 出力の callee を Method へ寄せ、Global 経過容認を段階縮小。 - core_bridge の methodize ブリッジは bring‑up 用。Hako 既定化後に撤去。 # Next Active Task — Phase 21.16(Pre‑Optimization / 最適化前フェーズへ戻す) Intent - 正規化の骨格が揃った段階で、最適化前の安定化に戻す(意味論は不変、構造/観測の強化)。 Scope(当面の作業) 1) Optimizer 前段の安定化(構造のみ) - normalize_legacy/ref_field_access は構造変換の範囲に留める(意味論を変えない)。 - NYASH_MIR_DISABLE_OPT/HAKO_MIR_DISABLE_OPT で最適化全休のゲートを尊重(既存)。 2) Baseline/観測 - quick/integration の rc/出力をゴールデン更新(mir_call 既定はまだOFF)。 - crate_exec タイムボックスを EXE テストへ段階横展開。 - プラグイン parity の軽量観測(autoload ガード有効時)。 3) テスト整備 - 受信未定義の負テスト追加(Builder で防止)。dev 安全弁を将来的にOFFにできる状態を作る。 - v1 + unified の canary は dev のみ strict を維持(CI は現状どおり)。 Exit criteria(21.16) - Optimizer OFF でも quick/integration/plugins が安定緑。 - 受信ローカライズの穴が負テストで検知可能(dev 安全弁に依存しない)。 - v1/unified は dev プロファイルで常時確認可能(既存トグルで担保)。 Handoff Summary (ready for restart) - Delegate v1 fixed (provider‑first): tools/hakorune_emit_mir.sh now prefers env.mirbuilder.emit to emit MIR(JSON v1). Legacy CLI converter kept as fallback with NYASH_JSON_SCHEMA_V1=1/NYASH_MIR_UNIFIED_CALL=1. - Selfhost‑first stabilized for mini cases: HAKO_SELFHOST_TRY_MIN=1 in dev profile; min runner (BuilderRunnerMinBox.run) is used when builder fails. - Methodize canaries: - phase217_methodize_canary.sh → compile‑run rc=5 PASS(semantics) - phase217_methodize_json_canary.sh → schema_version present + mir_call present(Method preferred; Global tolerated for now) - Dev one‑gun toggles (enable_mirbuilder_dev_env.sh): HAKO_STAGEB_FUNC_SCAN=1, HAKO_MIR_BUILDER_FUNCS=1, HAKO_MIR_BUILDER_CALL_RESOLVE=1, NYASH_JSON_SCHEMA_V1=1, NYASH_MIR_UNIFIED_CALL=1, HAKO_SELFHOST_TRY_MIN=1. --- Update (2025-11-15 — Phase 25 / 25.1 handoff: numeric_core & Stage0/Stage1 bootstrap) - Context: - Phase 21.8 の imports 導線まで完了し、`matmul_core` EXE/LLVM 統合と numeric runtime AOT は Phase 25 に移管済み。 - Phase 25 では Ring0/Ring1 分離と Numeric ABI(IntArrayCore/MatI64)設計を docs に固定済み。 - このホストでは numeric_core パスと Stage0/Stage1 設計の「土台」までを整備し、実際の BoxCall→Call 降ろしと自己ホストバイナリ構築は次ホスト(Claude Code)に委譲する。 - Done (this host): - Docs/設計: - Phase 25 README を Numeric ABI + BoxCall→Call 方針に合わせて更新(numeric は Hako 関数 Call、ExternCall は rt_mem_* 等のみ)。 - `docs/development/runtime/NUMERIC_ABI.md` に IntArrayCore/MatI64 の関数契約を整理(実体は Hako 関数、必要になれば FFI にも載せられる)。 - `docs/development/runtime/system-hakorune-subset.md` に runtime/numeric core 用言語サブセットを定義。 - `lang/src/runtime/numeric/README.md` に IntArrayCore/MatI64 の Box API と numeric core の分離構造を記述。 - `docs/development/runtime/ENV_VARS.md` に `NYASH_AOT_NUMERIC_CORE` / `NYASH_AOT_NUMERIC_CORE_TRACE` を追記。 - Phase 25.1 用 README 追加(Stage0=Rust bootstrap / Stage1=Hakorune selfhost バイナリの構想と配置案)。 - Numeric runtime: - `lang/src/runtime/numeric/mat_i64_box.hako` で `MatI64.mul_naive` を `NyNumericMatI64.mul_naive` へ分離(Box=API/所有権、NyNumericMatI64=ループ本体)。 - AotPrep numeric_core パス(MVP土台): - `lang/src/llvm_ir/boxes/aot_prep/passes/numeric_core.hako` を追加。 - MatI64 由来の const/new/copy/phi から `tmap` を構築(`rN -> MatI64`)。 - `BoxCall(MatI64, "mul_naive", ...)` を検出し、`Call("NyNumericMatI64.mul_naive", [recv, args...])` に書き換えるロジックを実装(現状は AotPrep 統合が失敗しているため未実運用)。 - TRACE ON 時に type table / 変換件数 / skip 理由をログ出力。 - `lang/src/llvm_ir/aot_prep.hako` に numeric_core パスを統合(`NYASH_AOT_NUMERIC_CORE=1` で `AotPrepPass_NumericCore.run` を実行)。 - `lang/src/llvm_ir/hako_module.toml` に `aot_prep.passes.numeric_core = "boxes/aot_prep/passes/numeric_core.hako"` を追加。 - `tools/hakorune_emit_mir.sh`: - AotPrep(run_json) 呼び出しに `NYASH_AOT_NUMERIC_CORE` / `TRACE` をパススルー。 - `_prep_stdout` から `[aot/numeric_core]` 行を拾って stderr に透過(TRACE ON 時)。 - VM step budget: - Rust VM(`src/backend/mir_interpreter/exec.rs`)において、`HAKO_VM_MAX_STEPS` / `NYASH_VM_MAX_STEPS` = 0 を「上限なし」と解釈するように変更。 - AotPrep(run_json) 実行時に `HAKO_VM_MAX_STEPS=0` / `NYASH_VM_MAX_STEPS=0` をデフォルト指定(無限ループに注意しつつ、現状の長大 JSON でも落ちにくくする目的)。 - 現状の問題(Claude Code への引き継ぎポイント): - `AotPrepBox.run_json` 統合経路が、selfhost VM 実行中に `vm step budget exceeded (max_steps=1000000)` で失敗しており、AotPrep 全体が rc=1 → `tools/hakorune_emit_mir.sh` が元の MIR(JSON) にフォールバックしている。 - このため numeric_core の BoxCall→Call 変換は最終 MIR には反映されていない(PREP 後の JSON にも `boxcall` が残る)。 - Rust VM 側は 0=unbounded 対応済みだが、selfhost VM 経路のどこかが依然として 1_000_000 ステップ上限で走っている可能性が高い。 - numeric_core の JSON パースで `_seek_object_end` の使い方に問題がある兆候: - `build_type_table` / `build_copy_map` で JSON 全体に対して `{` をスキャンして `_seek_object_end` を呼んでいるため、ルート `{` から呼ばれた場合に JSON 全体末尾まで飛ぶ。 - 結果として「1 命令オブジェクト」ではなく「functions ブロック全体」を inst として扱ってしまい、`dst=0` と `"MatI64"` が同じ巨大文字列内に混在 → 型判定や BoxCall 検出が誤動作する。 - CollectionsHot は `find_block_span`+命令配列スライスを使っているため問題が顕在化していないが、numeric_core 側では命令単位スキャンの前処理が足りていない。 - TODO(次ホスト向け指示): 1) `AotPrepNumericCoreBox` を単体で安定化する: - `AotPrepNumericCoreBox.run` を直接呼ぶテストで、MatI64.new/mul_naive/at を含む MIR(JSON) に対して BoxCall→Call 変換が正しく行われることを確認。 - `_seek_object_end` を「命令オブジェクトの `{`」に対してのみ呼ぶ形にリファクタ(`"\"op\":\"...\""` の位置から `lastIndexOf("{")` でオブジェクト先頭を求めるなど)。 2) AotPrep(run_json) 経路の VM 実装と Step budget を特定し、`HAKO_VM_MAX_STEPS=0` / `NYASH_VM_MAX_STEPS=0` が実際に効いているかを確認。 3) 統合テスト: - `NYASH_AOT_NUMERIC_CORE=1 NYASH_AOT_NUMERIC_CORE_TRACE=1 HAKO_APPLY_AOT_PREP=1` で `tools/hakorune_emit_mir.sh tmp/matmul_core_bench.hako ...` を実行し、PREP 後 MIR に `call("NyNumericMatI64.mul_naive", ...)` が含まれ、対応する `boxcall` が消えていること。 - VM/LLVM 両ラインで `matmul_core` の戻り値が従来と一致していること(小さい n=4,8 程度でOK)。 4) Numeric core 関連のエラー表示強化: - `NYASH_AOT_NUMERIC_CORE_TRACE=1` 時に、type table が空/変換 0 件/skip 理由(型不一致など)を必ずログ出しすることで、「静かにフォールバックする」状態を避ける。 Next Steps (post‑restart) 1) Selfhost‑first child parse fix(Stage‑B): resolve the known “Unexpected token FN” in compiler_stageb chain; target [builder/selfhost‑first:ok] without min fallback. 2) Provider output callee finishing: prefer Method callee so JSON canary asserts Method strictly (now Global allowed temporarily). 3) Consolidate remaining legacy converter usage to provider where possible; keep defaults unchanged. 4) Docs: 21.7 checklist updated; core_bridge methodize remains diagnostic‑only (OFF) with a removal plan once Hako methodize is default. # New Active Task — Phase 21.6(Dual‑Emit Parity & C‑line Readiness) Intent - Provider(Rust)と Selfhost(Hako)で同一の MIR(JSON) を出力できることを確認し、生成時間を計測・比較する。AOT(ny‑llvmc/crate)も O0 既定で安定させる。 What’s done (this session) - Perf ツール追加: - MIR emit bench: `tools/perf/bench_hakorune_emit_mir.sh` - AOT bench: `tools/perf/bench_ny_mir_builder.sh` - 構造比較: `tools/perf/compare_mir_json.sh` - Dual emit + 比較 + ベンチ: `tools/perf/dual_emit_compare.sh` - Docs 整備: - `docs/guides/perf/benchmarks.md`(手順/トグル) - README/README.ja にパフォーマンス導線を追記 - `docs/ENV_VARS.md` にベンチ関連のトグルを追加 - 小最適化(意味論不変): - Builder の不要 clone / finalize 二重呼び出し削減 - VM console 出力の to_string の枝刈り(String/StringBox/Null 先出し) - VM 受信未定義の負テストを 3 本追加(Array/Map/String)。fail‑fast を監視 Known issue / Action - Provider 経路(tools/hakorune_emit_mir.sh の provider‑first)が一部環境で `Program→MIR delegate failed` になることがある。 - 原因: Stage‑B 実行の stdout にログが混在し JSON 抽出が空になるケース。 - 対策(次実装): ラッパを tmp 経由の CLI 変換(`--program-json-to-mir`)へフォールバックさせる安全化。selfhost‑first も明示トグルで維持。 Plan (next after restart) 1) tools/hakorune_emit_mir.sh を安全化(Stage‑B→tmp→CLI 変換フォールバック)。stderr/JSON 分離を強化 2) 代表 4 ケース(json_pp / json_query_min / json_lint / json_query)で dual‑emit を 5 回実行し、21.6 表に p50/Parity を記入 3) Parity 不一致はカテゴリ化(callee 種別/順序/PHI/メタ)して修正元を特定(provider か selfhost) 4) AOT(ny‑llvmc)O0 の 3 回ベンチを取得、必要なら O1 スポットも取得 Tracking - 記録台帳: `docs/development/roadmap/phases/phase-21.6/README.md` の表へ随時追記(チェックボックス方式) Phase 21.6 wrap-up - Parser(Stage‑B) ループJSONの保守フォールバックで壊れ形のみ復元(正常形は素通り) - 代表E2E(return/binop/loop/call)PASS(call は関数化: "Main.add" → Global 関数呼び出し) - VM/LLVM にユーザー関数呼び出しを追加実装(VMのGlobal dispatch、LLVMのarity補正/事前定義) - docs 追加: phase-21.6-solidification、canaries 整備 Next — Phase 21.7 (Normalization & Unification) - 目的: Global("Box.method") ベースの関数化正規化から、段階的に Method 化(静的シングルトン受信)へ統一 - 既定は変更しない。dev トグルで methodize→canary 緑→既定化の順 - 命名とarityの正規化は最適化前に完了させる - Added always-on quick runner: `tools/smokes/v2/run_quick.sh`(fast, SKIP-safe) - Includes Stage‑B Program(JSON) shape and loop_scan (!= with else Break/Continue) canaries. - Hardened MirBuilder internals: replaced JSON hand scans with `JsonFragBox` in core paths (Return/If/Loop/Method utils). - Added opt‑in registry canaries(structure/tag observation only; remain optional). - Added MirBuilderMin (bring‑up minimal builder): `hako.mir.builder.min` - Purpose: tiny using set to avoid heavy prelude in this host; emits `[mirbuilder/min:*]` tags. - New canaries (PASS): builder_min_method_arraymap_{get,push,set,len}_canary_vm.sh - Added direct-lower canary (PASS): registry_optin_method_arraymap_direct_canary_vm.sh - Phase2034 canaries: migrated several rc‑based checks to content checks - If family: varint/varvar/nested/then-follow → now print MIR and assert '"op":"compare"'+'"op":"branch"' - Return family: var_local/bool/float/string/binop_varint/logical → now print MIR and assert minimal tokens - Removed nested command substitution in `mirbuilder_canary_vm.sh`; switched to content assertion - Registry(get) Full path: exercised fast path (JsonFrag‑only) via `HAKO_MIR_BUILDER_REGISTRY_ONLY=return.method.arraymap` and pinned canary to registry tag only Update (today) - Selfhost builder child defaults: when `HAKO_MIR_BUILDER_LOOP_FORCE_JSONFRAG=1`, auto-enable normalizer+purify for child (`HAKO_MIR_BUILDER_JSONFRAG_NORMALIZE=1`, `HAKO_MIR_BUILDER_JSONFRAG_PURIFY=1`) — dev-only, defaults unchanged. - Normalizer tag passthrough: `HAKO_MIR_BUILDER_NORMALIZE_TAG` is now forwarded to selfhost child; remains quiet by default. - strlen FAST path (crate harness): Python lowering now calls neutral kernel symbol `nyrt_string_length(i8*, i64)` when `NYASH_LLVM_FAST=1`. - NyRT kernel: added `nyrt_string_length` and legacy alias `nyash.string.length_si` implementations (byte length, mode reserved). - Canary: added `tools/smokes/v2/profiles/quick/core/phase2034/emit_boxcall_length_canary_vm.sh` to assert `--emit-mir-json` contains `boxcall length`. - Stage‑B parser loop JSON: added conservative fallback in `ParserControlBox.parse_loop` to recover empty body and `rhs:Int(0)` regressions; new canary `tools/dev/stageb_loop_json_canary.sh` PASS(dev補助・既定挙動不変)。 Additional updates (dev-only, behavior unchanged by default) - VM counters wired: `inst_count`(non‑phi), `compare_count`(Compare), `branch_count`(Branch) - Print with `NYASH_VM_STATS=1` as `[vm/stats] inst=… compare=… branch=…` - Microbench harness: fixed ratio print noise(heredoc→one‑liner)。 - EXE canaries: crate backend bring‑up hardened - Added `enable_exe_dev_env` helper and applied to representative EXE tests - Enabled `NYASH_LLVM_VERIFY=1`/`NYASH_LLVM_VERIFY_IR=1` for deterministic cases - Promoted `return42` canary to FAIL on mismatch (was SKIP) Action items(21.7) 1) docs: phase-21.7-normalization/README.md, CHECKLIST.md(追加済み) 2) MirBuilder(dev): HAKO_MIR_BUILDER_METHODIZE=1 で Global("Box.method") → Method(receiver=singleton) 3) VM: Method 経路の静的シングルトンを ensure_static_box_instance で安定化(既存機能の活用) 4) LLVM: mir_call(Method) を既存 unified lowering で実施、必要なら receiver の型/引数整合を補助 5) canary: methodize OFF/ON 両方で rc=5 を維持、method callee を観測(dev) 6) 既定化と撤去計画: 緑維持後、methodize を既定ON → Global 互換は当面維持 Phase 21.6 tasks (bug‑first, default OFF aids) 1) Parser(Stage‑B) loop JSON canaryを緑に維持(tools/dev/stageb_loop_json_canary.sh) 2) Delegate MirBuilder 経路で最小ループの MIR(JSON) → EXE(rc=10)(tools/dev/phase216_chain_canary.sh) 3) VM/EXE パリティを1件追加(最小ループ)し、差分が出たらFail‑Fastで停止 4) 代表ケース(return/binop/method/loop)を少数固定し、自己ホスト導線は hakorune スクリプトのみで回す 5) 最適化(21.5)は全停止。全カナリアが緑になってから再開(docs/phase‑21.6参照) Constraints / Guardrails - quick remains green; new toggles default OFF(`NYASH_LLVM_FAST` / `NYASH_VM_FAST`)。 - Changes small, reversible; acceptance = EXE parity + speedup in benches. Phase references - 21.6: docs/development/roadmap/phases/phase-21.6-solidification/{README.md,CHECKLIST.md} - 21.7: docs/development/roadmap/phases/phase-21.7-normalization/{README.md,CHECKLIST.md} --- Stage‑B → MirBuilder → ny‑llvmc(crate EXE)— Pre‑Optimization Goal Status (2025‑11‑11) - Loop JsonFrag → crate EXE canary: PASS(rc=10) - Root fix: PHI プレースホルダの一元化(前宣言→再利用→配線) - 前宣言: tagging.setup_phi_placeholders で ensure_phi + predeclared_ret_phis に保存 - 再利用: resolver/compare/ret/values が builder の global vmap を参照して同一SSAを読む - 配線: wiring.finalize_phis が前宣言PHIのみを配線、重複/空PHIを抑止 - 代表スクリプト: tools/smokes/v2/profiles/quick/core/phase2100/stageb_loop_jsonfrag_crate_exe_canary_vm.sh(rc=10) - 並行確認 - emit boxcall(v0): 維持(PASS) - strlen FAST(crate): 維持(PASS, rc=5) Phase 21.5 — Optimization folder - New docs: docs/development/roadmap/phases/phase-21.5-optimization/ (README.md, CHECKLIST.md) - New perf wrappers: tools/perf/phase215/{bench_loop.sh, bench_strlen.sh, bench_box.sh, run_all.sh} - Usage example: RUNS=5 TIMEOUT=120 tools/perf/phase215/run_all.sh Rollback 手順(最小) - 万一差戻しが必要な場合: 1) instruction_lower の phi で一時的に ensure_phi を復活(今回撤去したローカル生成を戻す) 2) tagging の predeclared_ret_phis 保存を OFF(行削除) 3) utils/values の global vmap 参照を削除(resolve_i64_strict を元に) 4) 影響範囲は src/llvm_py/* のみ(ny-llvmc ラッパーは無変更) Notes(ライン確認) - ny-llvm 本線(crate)は、ny-llvmc → tools/llvmlite_harness.py → src/llvm_py/llvm_builder.py という導線。 - 今回の PHI 一元化は src/llvm_py 配下のため、crate(ny-llvmc)経路に直接効く(ハーネスは内部)。 - tools/ny_mir_builder.sh は既定で BACKEND=crate を選択し、ny-llvmc を呼ぶ(llvmlite 直選択は明示時のみ)。 - Goal (pre‑21.5 optimization): build EXE via crate backend (ny‑llvmc) from Stage‑B Program(JSON) → MirBuilder MIR(JSON) before focusing on perf. Make EXE self‑hosting reliable on this host. - Why now - VM self‑host is green. EXE canaries (return/compare/binop/phi/externcall) are green. - Loop/strlen general cases fail in crate EXE due to builder output mixing `newbox/MapBox` (loop) and missing FAST path (strlen). Fix these first to unlock fair “execute‑only” microbench. - Plan (small, reversible, default‑OFF) 1) Loop JSONFrag purification (no MapBox/newbox) - Ensure `HAKO_MIR_BUILDER_LOOP_JSONFRAG=1` route emits pure control‑flow MIR only (const/compare/branch/phi/ret). - Acceptance: MIR(JSON) for minimal loop contains no `newbox|MapBox`; crate EXE build PASS; add canary to assert absence and EXE RC parity. 2) strlen FAST path (opt‑in) - ny‑llvmc lowering (FAST=1): `externcall nyrt_string_length(i8*, i64)` (returns i64; no boxing). - Add `nyrt_string_length` to `crates/nyash_kernel` (minimal impl; byte/char mode param reserved). - Acceptance: FAST=1 で crate EXE RC=5("nyash".length); FAST=0 挙動不変。 3) Selfhost EXE wrapper (dev helper) - Script (plan): `tools/selfhost_exe_stageb.sh` - Stage‑B Program(JSON) emit → MirBuilder to MIR(JSON) via `tools/hakorune_emit_mir.sh` - Build EXE via `tools/ny_mir_builder.sh --emit exe` (force `NYASH_LLVM_BACKEND=crate`) - Optional: run + RC parity check vs VM 4) Canaries / Runner - Loop JSONFrag no‑MapBox check (FAIL 基準) - strlen FAST EXE RC check(FAST=1 のみタグ観測/既定OFFで静音) - EXE parity: minimal Stage‑B sample VM↔EXE RC 一致 5) Acceptance & Docs - quick 代表(EXE混在)は `--timeout 120` 推奨で緑維持(既定は変更しない) - CURRENT_TASK/README に切替手順とフラグ記載(ロールバック容易) - Toggles / Scripts - `HAKO_MIR_BUILDER_LOOP_JSONFRAG=1`(Loop を JSONFrag 直組立に固定) - `HAKO_MIR_BUILDER_JSONFRAG_NORMALIZE=1`(任意) - `NYASH_LLVM_BACKEND=crate` / `NYASH_NY_LLVM_COMPILER=target/release/ny-llvmc` / `NYASH_EMIT_EXE_NYRT=target/release` - Helper: `tools/hakorune_emit_mir.sh`(Stage‑B→MIR)、`tools/ny_mir_builder.sh --emit exe`(crate で obj/exe) - Done (recent) - EXE canaries hardened(enable_exe_dev_env 適用・検証ON・代表は FAIL 基準へ昇格) - VM runtime counters(`NYASH_VM_STATS=1`) - microbench `--exe` 実装(ビルド1回→EXEをRUNS回実行)。現状、loop/strlen の一般形は crate 未対応で EXE 失敗 → 上記 1)/2) で解消予定。 2025‑11‑12 Updates(PHI grouping fix, ret‑after guards, provider hooks) - LLVM Python backend(llvmlite harness/crate 経由) - Return 合成 PHI を常にブロック先頭に配置(PHI グルーピング違反の根治)。 - lowering 入口(boxcall/mir_call/safepoint)で terminator 後の誤挿入を防止(継続BBへ移動)。 - builder 側でブロック命令列は最初の terminator(ret/branch/jump)で打ち切る。 - JsonFrag 正規化・純化(dev) - purify=1 で newbox/boxcall/externcall/mir_call を除去、ret 以降を打ち切り。 - provider-first フック(dev) - HAKO_MIR_NORMALIZE_PROVIDER=1 で provider 出力 MIR にも正規化を適用可能。 - HAKO_MIR_BUILDER_LOOP_FORCE_JSONFRAG=1 を provider-first にも適用(最小ループ MIR を直返し)。 Verified - selfhost-first + JsonFrag 正規化+purify: llvmlite=OK / ny‑llvmc=OK(EXE生成) - provider-first + FORCE_JSONFRAG: ny‑llvmc=OK(EXE生成) Open - provider-first の通常出力に対する純化強化(ret ブロックの副作用禁止を徹底)。 - strlen(FAST) の適用強化(resolver マーク補強 → IR に nyrt_string_length を反映)。 - Rust→.hako Normalize 移行計画(Self‑Host First / Freeze準拠) - 方針 - 正規化/置換系は Rust 側から .hako(AotPrep/MirBuilder 直下の新規箱)へ段階移行する。 - Rust 層は最小シーム+安全ガード(互換維持・借用修正・診断)に限定。既定挙動は不変。 - 現状 - 実装済み(opt‑in、既定OFF): NormalizePrintBox(print→externcall)、NormalizeRefBox(ref_get/ref_set→boxcall)。 - Rust 側 normalize.rs は借用修正のみ。dev 用 idempotence トグル(NYASH_MIR_DEV_IDEMP=1)を追加(既定OFF)。 - これから(段階) 1) .hako 正規化のカナリア整備(出力形状トークン検証+VM/EXE RC パリティ)。 2) Rust 側の同等パスは「既定OFF」を明文化し、.hako 側が有効な場合は二重適用を避ける運用に統一(最終的に Rust 側の normalize はOFF運用)。 3) 代表ケースが緑になった段階で、.hako 側をデフォルト化(dev/bench ラッパでON)。 4) 安定期間後、Rust 側の当該パスを撤去(環境変数は deprecate → 警告 → 削除の順)。 - 環境変数の扱い(増えたトグルの将来) - いまは opt‑in(既定OFF)。デフォルト化タイミングで .hako 側トグルはON に寄せ、Rust 側の旧トグルは非推奨化。 - 最終的に Rust 側トグルは削除(ドキュメントも更新)。.hako 側は必要最小のみ残す。 - Next (actionable) - Implement loop JSONFrag purification (no MapBox/newbox) and add canary - Add strlen FAST lowering + `nyrt_string_length` (kernel) + EXE canary - Wire `tools/selfhost_exe_stageb.sh` and record one EXE parity check - Then resume 21.5 optimization and run microbench with `--exe`(execute‑only timing) MirBuilder/JsonFrag note - JsonFrag path is for structure observation only (minimal MIR). Semantics remain prioritized by the default path. Keep it default OFF and tag‑gated. Builder toggles are centralized in `hako.mir.builder.internal.builder_config` to reduce scattered `env.get` calls in lowers. Toggles (dev) - `NYASH_VM_FAST=1`(VM micro fast paths: new StringBox, String.length/size) - `NYASH_LLVM_FAST=1`(ny-llvmc AOT lowering fast path; default OFF) - `HAKO_MIR_BUILDER_SKIP_LOOPS=1`(skip loop lowers in MirBuilderBox; default OFF) - `HAKO_MIR_BUILDER_REGISTRY_ONLY=`(restrict registry for diagnostics; default unset) Next (short) - Extend MirBuilderMin to accept minimal compare/binop (structure only) and add 1–2 min canaries. - Keep full MirBuilder path unchanged (opt‑in, still SKIP on this host); gradually replace Box‑heavy bits with JsonFrag‑only output. Next after restart — Focused checklist - Min Builder(if/compare: Var cases) - [x] lower_if_compare_varint_box.hako: then/else Return(Int) を境界限定で抽出(then→else手前、else→ブロック内) - [x] lower_if_compare_varvar_box.hako: 同上の境界検出を追加 - [x] canary PASS 化: `builder_min_if_compare_varint_canary_vm.sh` / `builder_min_if_compare_varvar_canary_vm.sh` - [x] try_lower 順序の最終確認(var 系 → intint) - [x] fold 系の取り込み(Min): varint/binints を追加しタグ観測(`[mirbuilder/min:if.compare.fold.*]`) - MirBuilder(フル経路の軽量化・段階) - [x] compare/fold(IntInt/VarInt/VarVar)を境界限定へ置換(inline/Lower 双方) - [x] registry: Min 経路での canary PASS 化(`[min|registry]` 許容) - [x] 重い using の原因箇所から Box 依存を JsonFrag のテキスト組立へ置換(点で進める) - **調査完了**: method系lower(array/map)は既にJsonFrag置換済み(文字列結合でMIR JSON生成) - **残存Box使用**: 3箇所のみ(loop系lowerでLoopFormBox.build2()へのopts渡し用 `new MapBox()`) - **Test結果**: phase2034 全29テスト PASS、phase2160 registry 全7テスト PASS - [x] registry:return.method.arraymap(get)を Full(JsonFrag) へ固定し、canary を registry 単独 PASS に更新 - [x] registry:return.method.arraymap(set/push/len)も順次 Full に移植(Min 許容を段階撤去) - [x] loop lowers は必要時のみ `HAKO_MIR_BUILDER_SKIP_LOOPS=1` を使用(既定OFF) - **現状**: loop系lowerは最小MapBox使用のみ、スキップ不要 - Runtime(ファイルプロバイダ) - [x] FileBox を ring‑1 常備(core‑ro)として登録(panic 経路の撤廃; plugin‑only は従来通り) - [x] ENV 追補の確認: MODE/ALLOW_FALLBACK/JSON_ONLY の説明を ENV_VARS.md に整合 Env tips(bring‑up) - Auto + このホスト: `NYASH_JSON_ONLY=1` か `NYASH_FILEBOX_ALLOW_FALLBACK=1` で JSON パイプを静音&安定化 - registry 診断: `HAKO_MIR_BUILDER_REGISTRY_ONLY=return.method.arraymap` で 1 件に絞る Progress — 22.1 MirBuilder 緑化(Bring‑up 導線) - Return 系の JSON 文字列出力へ統一(Int/Float/String/VarInt/VarVar) - If 系(varint/varvar/intint/fold)の then/else 抽出を配列境界限定化 - Min Builder 強化(fold 取り込み+タグ出力) - テスト整理: - include を using へ全面置換 - dev トグルを test_runner に集約(`enable_mirbuilder_dev_env`) - registry canary は当面 `[min|registry]` 許容でパス計画→段階で registry 単独に収束 - phase2034: rc 依存 canary を内容トークン検証へ移行(完了) - 対応済: if(compare eq/le/ge/ne/varint/varvar/nested/then-follow), return(var_local/bool/float/string/binop_varint/logical) - 備考: core_exec 系は rc 検証維持(意味検証のため) Next (pre‑Optimization — MirBuilder build line復活まで) 1) phase2034 の ENV 直書きを `enable_mirbuilder_dev_env` に置換(集約) 2) registry 直経路の軽量化(JsonFrag 置換)を 1 箇所ずつ移植(array/map 周辺から) 3) MirBuilder‑first 導線(tools/hakorune_emit_mir.sh)をトグルで有効化(既定OFF) 4) FAIL_FAST=1/ny‑compiler=既定 の条件で緑維持を確認し、dev トグルを段階撤去 5) tests/NOTES_DEV_TOGGLES.md を追加(dev トグルの意味・使い所・撤去方針) Loop 化の小ステップ(構造→置換) - [x] 最小シーム化: Loop lowers(simple / sum_bc / count_param)の MapBox 生成・set を `loop_opts_adapter` に退避(置換点の集約) - [x] トグル検証: `HAKO_MIR_BUILDER_SKIP_LOOPS=1` の canary を追加(ON=回避、OFF=通常) - [x] JsonFrag 置換(opt-in): `loop_opts_adapter.build2(opts)` で JsonFrag ベースの最小 MIR(JSON) を出力(タグ `[mirbuilder/internal/loop:jsonfrag]`) - [x] 残り 2 件へ水平展開(simple/sum_bc/count_param の3種を対応済・挙動不変/既定OFF) Next(Loop/JsonFrag polish) - [ ] JsonFragの精度引上げ(phi整列・ret値の正規化・const宣言の整理)— 既定OFFのまま小刻み導入(参照: docs/checklists/mirbuilder_jsonfrag_defaultization.md) - progress: Normalizer シーム導入済み(pass-through→最小実装)。phiを先頭集約、ret値の明示、constの重複排除/先頭寄せを追加(devトグル下)。 - progress: const 正規化は i64 に加え f64/String を軽量カバー(signature ベースの dedupe)。 - progress: f64 値の出力正規化(小数表記の冗長ゼロを削除、整数は .0 付与)を実装、カナリアで確認。 - progress: f64 指数・-0.0 に対応。共通ユーティリティへ切り出し(JsonNumberCanonicalBox)。 - [ ] canary helper の共通化(MIR抽出/トークン検証/一貫したSKIPタグ)— 共通lib: tools/smokes/v2/lib/mir_canary.sh - progress: loop トグル canary に導入(phase2034/mirbuilder_internal_loop_skip_toggle_canary_vm.sh)。順次水平展開。 - progress: loop_*_jsonfrag 系3件へ適用(simple/sum_bc/count_param)。 - progress: Normalizer検証カナリアを追加(重複なし): - 冪等: tools/smokes/v2/profiles/quick/core/phase2034/mirbuilder_jsonfrag_normalizer_idempotent_canary_vm.sh - cross-block no-dedupe: tools/smokes/v2/profiles/quick/core/phase2034/mirbuilder_jsonfrag_normalizer_const_crossblock_no_dedupe_canary_vm.sh - rcパリティ: if/loop/binop(3件) - f64 exponent/negzero: tools/smokes/v2/profiles/quick/core/phase2034/mirbuilder_jsonfrag_normalizer_const_f64_exponent_negzero_canary_vm.sh - f64 bigexp: tools/smokes/v2/profiles/quick/core/phase2034/mirbuilder_jsonfrag_normalizer_const_f64_bigexp_canary_vm.sh - phi many incomings: tools/smokes/v2/profiles/quick/core/phase2034/mirbuilder_jsonfrag_normalizer_phi_many_incomings_order_canary_vm.sh - phi multistage merge: tools/smokes/v2/profiles/quick/core/phase2034/mirbuilder_jsonfrag_normalizer_phi_multistage_merge_order_canary_vm.sh - [ ] タグ静音トグル(既定静音) - progress: `HAKO_MIR_BUILDER_NORMALIZE_TAG=1` の時のみタグ出力(既定は静音)。 - [ ] 正規化ロジックの共通化 - progress: `lang/src/shared/json/utils/json_number_canonical_box.hako` を新設し、f64正規化/トークン読取を共通化。 - [ ] dev一括トグル - progress: `enable_mirbuilder_dev_env` に Normalizer 注入導線を追加(`SMOKES_DEV_NORMALIZE=1`/コメントで profile 切替例)。 - [ ] quick の timeout 推奨を明記 - progress: `tools/smokes/v2/run.sh` の Examples に `--timeout 120` の案内を追加。 Phase 21.5(Optimization readiness) - 状態: Normalizer を本線(MirBuilderBox/Min)に既定OFFで配線、quick 代表セット(Normalizer ON)でパリティ確認済み。 - 推奨: quick 全体を Normalizer ON で回す場合は `--timeout 120` を使用(EXE/AOT系の安定化)。 - 次アクション: rcパリティの面を拡大→default 候補フラグ(既定OFF)で段階導入→緑維持で default 化判断。 - [ ] 既定化の条件整理(代表canary緑・タグ観測・既定経路とのdiff=なし・戻し手順)をチェックリスト化(docs/checklists/mirbuilder_jsonfrag_defaultization.md) - progress: チェックリストと Rollback 手順を docs に明記済み。 追加カナリア(Normalizer) - 直接検証: tools/smokes/v2/profiles/quick/core/phase2034/mirbuilder_jsonfrag_normalizer_direct_canary_vm.sh - 複数ブロック/phi順序: tools/smokes/v2/profiles/quick/core/phase2034/mirbuilder_jsonfrag_normalizer_multiblock_phi_order_canary_vm.sh - JsonFrag+Normalize(tag): tools/smokes/v2/profiles/quick/core/phase2034/mirbuilder_internal_loop_simple_jsonfrag_normalize_canary_vm.sh - JsonFrag+Normalize(tag・OFF確認): tools/smokes/v2/profiles/quick/core/phase2034/mirbuilder_internal_loop_simple_jsonfrag_nonormalize_no_tag_canary_vm.sh - 冪等性: tools/smokes/v2/profiles/quick/core/phase2034/mirbuilder_jsonfrag_normalizer_idempotent_canary_vm.sh - cross-block no-dedupe: tools/smokes/v2/profiles/quick/core/phase2034/mirbuilder_jsonfrag_normalizer_const_crossblock_no_dedupe_canary_vm.sh - f64 canonicalize: tools/smokes/v2/profiles/quick/core/phase2034/mirbuilder_jsonfrag_normalizer_const_f64_canonicalize_canary_vm.sh - phi nested merge: tools/smokes/v2/profiles/quick/core/phase2034/mirbuilder_jsonfrag_normalizer_phi_nested_merge_order_canary_vm.sh - rcパリティ: if/loop/binop(3件) # Current Task — Phase 21.10(LLVM line – crate backend print EXE) Status (22.3 wrap) - 22.3 締め: 最小Cランタイム(設計)/Cシンボル整合(nyash.console.*→nyash_console_*)を反映。 - Hako-first MIR emit は wrapper 経由で安定(Stage‑B 出力の RC 混入を抑止、Hako→失敗時は Rust CLI にフォールバック)。 - 緑条件は quick 代表セット + phase2231 canary(rc=42)で確認済み。 Next (this phase) — 22.x continuation 1) TLV配線(既定OFF)+ parityカナリア - 既存の `nyash-tlv`(optional / feature `tlv-shim`)を `src/runtime/plugin_ffi_common.rs` に薄く配線。 - 制御: feature + `HAKO_TLV_SHIM=1`(トレース `HAKO_TLV_SHIM_TRACE{,_DETAIL}`)。 - 受け入れ: ON/OFF で実行/rc 同一(parity)+ トレース観測が可能。 2) SSOTメッセージ・相対推定の整形 + 代表カナリアの常時化 - 曖昧時のメッセージ統一(件数+先頭N、legacy委譲の明記)。 - cwd vs using_paths 優先の明文化・軽量canaryを quick 常時化。 3) ビルダーの JsonFragBox / PatternUtilBox 採用(差分小さい箇所から) - 手書きスキャンの置換を段階導入。If/Compare VarInt / Return BinOp VarVar 周辺を優先。 4) C‑core 一点通し(Map.set)+ parity維持(既定OFF) - feature+ENV で no‑op 経路を通し、ON/OFF parity をカナリアで検証。 目的(このフェーズで到達するゴール) - Hako Parser(MVP)で AST JSON v0 を出力し、Analyzer の一次入力に採用(text は fallback 維持)。 - 代表ルール(HC001/002/003/010/011/020)を AST 入力で正確化。 - JSON(LSP) 出力を用意し、エディタ統合の下地を整備。 This document is intentionally concise (≤ 500 lines). Detailed history and per‑phase plans are kept under docs/private/roadmap/. See links below. Focus (now) - 🎯 Parser/Analyzer の骨格と I/F を先に - tools/hako_parser/* に Tokenizer/Parser/AST emit/CLI を実装(MVP) - Analyzer は AST JSON を優先入力に切替(Text fallback は保持) - 代表ルールの AST 化と LSP 出力、簡易テスト基盤を確立 Update (today) - docs/private/roadmap/phases/phase-21.4/PLAN.md を追加(優先順の実行計画) - tools/hako_parser/* の MVP スケルトン確認(CLI/Emitter/Parser/Tokenizer) - tools/hako_check/tests/README.md と run_tests.sh を追加(テスト雛形) - Runner: plugin_guard 導入(vm/vm_fallback から共通化) - String API: size() を length() のエイリアスとして VM で受理 - Analyzer CLI: --format/--debug/--source-file を順不同で処理 - Analyzer IR: AST 空時の methods をテキスト走査でフォールバック - HC021/HC031: 実装完了。PHI 調査は一旦収束(AST path は既定OFF、`--force-ast` でオン)。 - CLI: `--rules`/`--skip-rules` を追加し、ルール単体/組合せ検証を高速化。`--no-ast` 既定化。 - Runtime: `NYASH_SCRIPT_ARGS_HEX_JSON` を導入(HEX経由で改行・特殊文字を安全搬送)。 - File I/O: FileBox provider 設計(SSOT + 薄いラッパ + 選択ポリシー)を文書化(docs/development/runtime/FILEBOX_PROVIDER.md)。 - ENV: `NYASH_FILEBOX_MODE=auto|core-ro|plugin-only` を追加(ENV_VARS.md)。Analyzer/CI は core‑ro 相当で運用。 Quick update — Green Conditions & Toggles(quick) - Green baseline(quick) - Builder: Hako registry/internal = ON(既定)。必要時のみ `=0` でOFF。 - hv1 inline PRIMARY = ON(直列も緑)。必要時のみ `HAKO_PHASE2100_ENABLE_HV1=0`。 - S3 reps: 任意(`NYASH_LLVM_S3=1` かつ LLVM18 環境時)。未満は自動SKIP。 - EXE‑first: 任意(`SMOKES_ENABLE_SELFHOST=1`)。重いのでデフォルトOFF。 - TLV smoke: 常時(nyash-tlv のみを -p でビルド/テスト)。本体未配線でも安全。 Toggles quicklist - Builder: `HAKO_MIR_BUILDER_INTERNAL=0/1`(既定=1), `HAKO_MIR_BUILDER_REGISTRY=0/1`(既定=1) - hv1: `HAKO_PHASE2100_ENABLE_HV1=0/1`(既定=1) - S3: `NYASH_LLVM_S3=0/1`(既定=auto; LLVM18検出でON) - EXE‑first: `SMOKES_ENABLE_SELFHOST=1`(既定OFF) - TLV: `--features tlv-shim` + `HAKO_TLV_SHIM=1`(既定OFF/配線は無害な identity) - Using SSOT: `HAKO_USING_SSOT=1`(MVP は現行解決ロジックを経由しつつタグ出力) - ENV consolidation(既定不変) - NY compiler: 主 `NYASH_USE_NY_COMPILER`、alias `NYASH_DISABLE_NY_COMPILER`/`HAKO_DISABLE_NY_COMPILER`(受理+警告、一度だけ) - LLVM opt: 主 `NYASH_LLVM_OPT_LEVEL`、alias `HAKO_LLVM_OPT_LEVEL`(受理+警告、一度だけ) - Gate‑C: 主 `NYASH_GATE_C_CORE`、alias `HAKO_GATE_C_CORE`(受理+警告、一度だけ) 22.1 progress (today) - TLV配線(最小導線・既定OFF) - 追加: ルート `Cargo.toml` に `nyash-tlv`(optional)と feature `tlv-shim` - 追加: `src/runtime/plugin_ffi_common.rs` に `maybe_tlv_roundtrip()` を実装し、`encode_args()` の末尾で呼び出し(ENV `HAKO_TLV_SHIM=1` かつ feature 有効時のみ動作) - スモーク: `tools/tlv_roundtrip_smoke.sh` を SKIP→常時 PASS に変更(`-p nyash-tlv` 固定) - Resolver/Using SSOT(薄い導線・トグル) - 追加: `HAKO_USING_SSOT=1` 時に SSOT ブリッジを呼び出し(modules のみを ctx として渡す)。未解決時は既存ロジックにフォールバック - ctx: `{ modules, using_paths, cwd }`(MVPは modules のみ有効) - トレース: `NYASH_RESOLVE_TRACE=1` で `[using/ssot]` タグを出力 - スモーク: `tools/smokes/v2/profiles/quick/core/phase2211/using_ssot_parity_canary_vm.sh` を追加(ON/OFF で出力同一を検証) 22.1 next (follow‑up tasks) - SSOT ctx 拡張(段階導入・既定不変) - [ ] Bridge→Hako 箱で `using_paths`/`cwd` を活用した相対推定のMVP(IOはRunner側で制御)。 - [ ] Runner 側の ctx 渡しを拡張し、パス推定に必要な情報(呼出元ディレクトリ、プロファイル)を追加。 - 受け入れ: パリティcanary(modules命名あり)維持 + 代表ケースで `using_paths` 提示時に解決成功(既定OFF/トグルONのみ)。 - TLV shim 観測タグ(既定OFF・安全) - [x] `HAKO_TLV_SHIM_TRACE=1` で shim 経由のコールに `[tlv/shim:.]` を出力(既定は `MapBox.set` のみ)。 - [x] `HAKO_TLV_SHIM_FILTER=MapBox.set` などで対象コールを限定(カンマ区切り可)。 - 受け入れ: canary で `MapBox.set` の単発コール時にタグが現れる(feature有効+ENV時)、既定OFFではログ増加なし。 22.1 exit (criteria) - SSOT(relative 推定の仕上げ) - Unique: `phase2211/ssot_relative_unique_canary_vm.sh` が常時 PASS(cwd 優先、短時間で終了)。 - Ambiguous+strict: `phase2211/ssot_relative_ambiguous_strict_canary_vm.sh` が PASS(strict=1 時は legacy 委譲)。 - Recursion guard: `HAKO_USING_SSOT_HAKO=1` を含む実行でも無限再帰は発生しない(子プロセスへ SSOT を強制OFF+INVOKING=1)。 - TLV/Extern(観測統合) - `HAKO_CALL_TRACE=1` で plugin/extern 双方に `[call:.]` が観測可能。 - `HAKO_CALL_TRACE_FILTER` で method 名/`.` の双方が機能(例: `MapBox.set,env.console.log`)。 - 既定挙動は不変(新機能はすべてトグルOFFで無影響)。 22.2 progress (today) — Core Thinning I - Docs/plan: docs/private/roadmap/phases/phase-22.2/PLAN.md(T0/T1/T2・ABI契約・受け入れ規準) - C-core crate(設計): crates/nyash_c_core(feature c-core=OFF 既定) - 導線(既定OFF): cwrap/c-core タグ&ENV。対象は MapBox.set / ArrayBox.push / ArrayBox.get / ArrayBox.size(len/length)。 - Parity canaries(ON/OFF 完全一致): - phase2220/c_core_map_set_parity_canary_vm.sh → PASS - phase2220/c_core_array_push_parity_canary_vm.sh → PASS - phase2220/c_core_array_len_length_parity_canary_vm.sh → PASS - Exit(22.2): 既定OFFで挙動不変/ON/OFF parityが緑/失敗時フォールバック(Rust経路) Next — Phase 22.3 (Kernel Minimal C Runtime) - Docs skeleton added: docs/private/roadmap/phases/phase-22.3/PLAN.md - No behavior change; future toggle: NYASH_KERNEL_C_MIN (reserved). - Crate present: `crates/nyash_kernel_min_c` (staticlib) with `nyash_console_log` and a few handle stubs. - Canary: `tools/smokes/v2/profiles/quick/core/phase2230/kernel_min_c_build_canary.sh` → PASS(ビルドのみ、未リンク) - Note: LLVM extern lowering maps `nyash.console.*` → `nyash_console_*` for C linkage (dots→underscores). LLVM line (21.10 prework) - Added backend selector to tools/ny_mir_builder.sh via `NYASH_LLVM_BACKEND=llvmlite|crate|native` (default llvmlite). - Added crate path canaries: - obj (dummy): phase2100/s3_backend_selector_crate_obj_canary_vm.sh → PASS - exe (dummy): phase2100/s3_backend_selector_crate_exe_canary_vm.sh → PASS - exe (print): phase2100/s3_backend_selector_crate_exe_print_canary_vm.sh → SKIP(llvmlite未導入環境では自動SKIP/名称整合は済) - Extern lowering updated: `nyash.console.*` is emitted as `nyash_console_*` to match C symbols (`nyash-kernel-min-c`). Next — Phase 21.5 (Optimization Prep) - Docs: Added plan at `docs/private/roadmap/phases/phase-21.5/PLAN.md`(C≒80% を目標) - C baselines: `benchmarks/c/bench_box_create_destroy_small.c`, `benchmarks/c/bench_method_call_only_small.c` - Perf harness: - `tools/perf/bench_compare_c_vs_hako.sh ` → `[bench] name=.. c_ms=.. ny_ms=.. ratio=..` を出力(median)。 - `tools/perf/run_all_21_5.sh` で2本まとめ実行(warmup=2, repeat=7)。 - 既定不変: スクリプトは任意実行。ビルド未済み時はヒント表示で SKIP。 Baseline records (new) - Recorder: `tools/perf/record_baselines.sh [warmup] [repeat]` - 出力先: `benchmarks/baselines/.latest.json` と追記 `benchmarks/baselines/.ndjson` - 含まれる値: `c_ms`, `py_ms`, `ny_vm_ms`(AOTは現状0固定)。ホスト名/時刻/試行回数も保存。 - 使い方: `cargo build --release && bash tools/perf/record_baselines.sh all` - 今後: これらの C/Python/NY VM 値をターゲットとして最適化を進める(比率の改善を目標管理)。 Note (21.6 / Stage‑B include) - VM の include は未対応。Stage‑B → MirBuilder を VM 直で実行する経路は既定OFF(検証は opt‑in)。 - Program(JSON) → MIR(JSON) は Rust CLI 変換(Gate‑C)を既定とし、wrapper は失敗時に委譲して安定化する。 Hakorune‑primary(検証手順・短縮) - 目的: verify_mir_rc の primary を hakovm 側に切替えて最小セットを検証する。 - 手順(推奨は単発・軽量): - env: `HAKO_VERIFY_PRIMARY=hakovm` を付与して対象スクリプトを実行 - 代表: phase2160 の registry opt‑in canary を個別に実行(Fail‑Fast が必要な箇所は canary 内で `NYASH_FAIL_FAST=0` を注入済) - 既定は Gate‑C 維持。切替は opt‑in のテスト/開発用途に限定。 phase2160/run_all(self‑host canaries) - 今は“任意実行”。quick 常時には含めない(軽さ優先/ホスト依存は SKIP 保護)。 Perf options - `PERF_SUBTRACT_STARTUP=1` で VM/AOT の起動コスト(ret0)を差し引き(ネットのループ時間近似)。 - `PERF_AOT=1` で bench_compare に AOT 行を追加(MIR emit/link が失敗する環境では自動スキップ)。 Roadmap links (21.5→21.7) - 21.5 — Unicode & Provider Polish(現行計画): docs/private/roadmap/phases/phase-21.5/PLAN.md - 21.6 — Hako MIR Builder MVP & Registry(opt‑in): docs/private/roadmap/phases/phase-21.6/PLAN.md - 21.7 — VM mir_call state & Primary Flip(guarded): docs/private/roadmap/phases/phase-21.7/PLAN.md - 21.8 — Hako Check: Refactor & QuickFix(MVP): docs/private/roadmap/phases/phase-21.8/PLAN.md Footing update (A→B→C, today) — 仕様と入口をまず固定 - A. 仕様/インターフェース(hako_check 診断 I/F と出力規約) - 診断スキーマ(型付き)を明文化: `{rule, message, line, severity?, quickFix?}`。 - 互換性: ルールが文字列を `out.push("[HCxxx] ...")` で返す場合も受理(CLI 側で string→diag 変換)。 - 抑制ルール: HC012 > HC011(Box 全体が dead の場合、個別メソッドの unreachable は抑制)。 - 既定の閾値: HC012=warning、HC011=info(CLI 側で override 可能に)。 - Quiet/JSON: `NYASH_JSON_ONLY=1`(JSON/LSP 生成時は冗長ログ抑止)、plugin_guard 出力は stderr のみ。 - B. AST 拡張(解析に必要な最小メタ) - `parser_core.hako`: `boxes[].span_line`(定義開始行)、`methods[].arity`(引数個数)、`is_static` を bool で統一。 - `tokenizer.hako`: 行・桁の位置情報を維持(ブロックコメント除去後も一貫)。 - C. Analyzer 適用(初期化の堅牢化と AST 優先) - `analysis_consumer.hako`: `_ensure_array(ir, key)` を導入し、`methods/calls/boxes` へ `push` 前に必ず確保。 - AST 取り込みを優先(`boxes/uses/includes` と `*_arr` の二系統に両対応)、欠落時のみ簡易テキスト走査にフォールバック。 - CLI: ルール出力をそのまま透過(typed diag を優先、string は変換)、HC012>HC011 の抑制を集約段で適用。 Acceptance(Footing A→B→C) - A: `tools/hako_check/run_tests.sh` が `--format json-lsp` で純 JSON を返し、HC012/HC011 混在入力で抑制が働く。 - B: `parser_core.hako` の AST に `span_line`/`arity` が入り、ダンプで確認可能(最小ケース2件)。 - C: `analysis_consumer.hako` が未初期化 IR に対しても `push` で落ちず、AST 経路で HC011/HC012 が緑。 Status (HC rules) - 10/11 pass, 1 skipped: HC011/012/013/014/015/016/018/021/022/031 = PASS、HC017 = SKIP(UTF‑8 byte-level 支援待ち) - CLI: `--rules`/`--skip-rules` で単体/組合せ検証を高速化、JSON_ONLY で純出力。 Phase 21.7 — VM mir_call state & Primary Flip(green) - T0(最小・安定化) - length state(per‑receiver可): size/len/push, Map.set(new-key) 実装済み(Hakorune VM + Rust hv1_inline 両ルート)。 - フラグ: HAKO_VM_MIRCALL_SIZESTATE=1(既定OFF), HAKO_VM_MIRCALL_SIZESTATE_PER_RECV=1(任意)。 - T1(検証導線) - Primary 切替(verify_mir_rc)配線済み(既定=hakovm)。 - Canary 拡充(phase2170/*): push×N、alias、per‑recv差分、flow跨ぎ。Map dup-key 非増分・value_state set→get も緑化。 - 実行: bash tools/smokes/v2/profiles/quick/core/phase2170/run_all.sh → 全PASS。 Phase 21.8 — Hako Check: Refactor & QuickFix(MVP) - T0 QuickFix(--fix-dry-run, text-scope) - HC002 include→using(安全置換)/HC003 using 非引用→引用化/HC016 未使用 alias 行削除/HC014 空スタブ提案。 - 統一diff(---/+++/@@)で標準出力。既定OFF(dry-run時のみ)。 - T1 AST Rename(同一ファイル) - --rename-box /--rename-method を追加。 - 定義は AST span 行で安全置換、呼出は `.(` を置換。--fix-dry-run で diff 出力。 - T2 Plan 出力 - --fix-plan で refactor_plan.json と sed 雛形(apply_script)を出力(手動レビュー想定)。 - 既定挙動は不変。適用は別フェーズ(write-capable provider)で検討。 Phase 21.9 — De‑Rust(Non‑Plugin)Checklist - [x] Docs: Roadmap – docs/development/strategies/de-rust-roadmap.md(原則/ゲート/リバータブル) - [x] Docs: Gap Analysis – docs/development/strategies/de-rust-gap-analysis.md(Phase1/2の具体) - [x] Script: Phase‑0 archive helper – tools/de_rust/archive_rust_llvm_backend.sh(RESTORE.md 自動生成) - [x] Phase‑0: Rust LLVM backend を archive/ へ移動(既定ビルド影響なし・リバータブル) - [ ] hv1_inline opt‑out トグル(HAKO_VERIFY_DISABLE_INLINE=1)追加(任意) - [ ] TLV C shim(FFI)雛形+往復テスト(最小) - [ ] MIR Interpreter の診断化(Primary=Hakovm を確認、envで明示切替) - [ ] Resolver/Using SSOT ドキュメントを運用ガイド化(Runner/Analyzer 一致) - [x] LLVM harness: object 出力(tmp/nyash_llvm_run.o)確認 - [ ] LLVM link: NyRT 静的ライブラリ(crates/nyash_kernel)ビルド → EXE リンクの確認 CI Integration(end of phase) - [ ] Add optional CI job: selfhost EXE-first smoke - Steps: install LLVM18; prebuild nyash(llvm)/ny-llvmc/nyash_kernel; run `tools/exe_first_smoke.sh` and `tools/exe_first_runner_smoke.sh`. - Policy: non-blocking initially(`continue-on-error` or separate optional workflow); promote later when stable. - [ ] Fix legacy CI workflow bug(old workflow failing) - Audit existing `.github/workflows/*` for broken steps/env; update to use `hakorune` binary and new env toggles. - Ensure LLVM/S3 gates respect environment (skip when LLVM18 absent). Remaining (21.4) 1) Hako Parser MVP 実装(tokenizer/parser_core/ast_emit/cli)【微修整】 2) Analyzer AST 入力の安定化(必要時のみ AST を使用) 3) 代表ルール AST 化(HC001/002/003/010/011/020) 4) `--format json-lsp` 追加ケース(OK/NG/edge) 5) テスト駆動(tests//)を 3 ルール分用意 6) 限定 `--fix`(HC002/003/500) 7) DOT エッジ ON(calls→edges, cluster by box) 8) FileBox provider 実装(リング0/1/選択ポリシー)と最小スモーク追加(core‑ro/auto/plugin-only)【COMPLETE】 Remaining (21.4 → 21.5 handoff, concise) - A. Parser/Analyzer まわり - [ ] Hako Parser MVP 微修整(tokenizer/parser_core/ast_emit/cli) - [ ] Analyzer AST 入力安定化(必要時のみ AST、_needs_ast/_needs_ir 調整) - [ ] 代表ルール AST 化(HC001/002/003/010/011/020) - [ ] json-lsp 追加ケース(OK/NG/edge) - [ ] テスト駆動(tests// を3ルール分) - [ ] 限定 --fix(HC002/HC003/HC500) - B. DOT 改善 - [ ] calls→edges 検証と代表追加ケース(cluster は既存を維持) - C. Ring1/Plugins polish(未了のみ) - [ ] Using/modules SSOT 確認(modules優先→相対推定→not found=警告/verbose詳細) - [x] Capability introspection(FileBox provider caps(read/write) を Shim から参照→未サポート操作は Fail‑Fast) - 実装: `src/runtime/provider_lock.rs:get_filebox_caps()` を追加、`src/boxes/file/mod.rs` で caps.write を参照し明示エラー - [ ] Provider modes スモークの継続(auto/core‑ro/plugin‑only + failure injection) Phase 21.6 — Hako MIR Builder MVP & Registry(COMPLETE) - [x] Registry 経路(opt‑in)を MirBuilderBox に実装(既定OFF) - [x] registry 専用 canary 一式を PASS(Return/Int, If/Compare[Int/Int|Var/Int|Var/Var], Return(Binary Int/Int), Return(Logical OR/AND Var/Var)) - [x] PatternUtilBox の find_local_* を“次の Local まで”で安全化 - [x] MirBuilderBox チェーン fallback を厳格化(Binary/IntInt, Return/Int) - Return(BinOp Var/Int) は registry が先に一致(rc=42) - Logical AND(Var/Var) は JSON v0 bool=0/1 に合わせて一致(rc=0) 受け入れ(21.6) - [x] phase2111 の registry canary 全緑 - [x] 既定OFF・互換維持(トグルON時のみ影響) Phase 21.7 — VM mir_call state & Primary Flip(kickoff) - 目的: VM に最小 state(Array/Map length)を導入し、primary 切替(core|hakovm)で Core と同値検証(既定OFF)。 - スコープ(T0→T1) - T0: state map(受信者ID合成・length管理)、size/len 実値、push で length++、get/set は安定タグ維持 - T1: HAKO_VERIFY_PRIMARY=core|hakovm 配線と canary(push→size 増分、primary=hakovm でも rc一致) - トグル/既定 - HAKO_VM_MIRCALL_STUB=1(既定ON: 非対象は0返し+タグ) - HAKO_VERIFY_PRIMARY=core(既定) - Checklist — Ring1/Plugins polish(このフェーズで完了) - [x] Env 統一(二重解消): `NYASH_FILEBOX_MODE`/`NYASH_DISABLE_PLUGINS` に一本化し、 旧 `NYASH_USE_PLUGIN_BUILTINS` / `NYASH_PLUGIN_OVERRIDE_TYPES` は非推奨(互換ブリッジは維持) - [x] 初期化順のSSOT: `register_builtin_filebox`(feature)→ dynamic登録(toml)→ provider選択→ FILEBOX_PROVIDER 設定(vm/vm_fallback 共通) - [x] Provider 登録口の一本化: static/dynamic/builtin を同じ ProviderFactory 登録APIに集約(select は registry のみ) - [x] FileBox 公開の一本化: `basic/file_box.rs` を再エクスポート/委譲化し、公開は BoxShim(委譲)に揃える(重複実装撤去) - [ ] Using/modules のSSOT確認: modules優先→相対ファイル推定→not found(警告; verboseで詳細)を維持 - [x] JSON_ONLY 監査: json-lsp時は stdout 純JSON・ログは stderr の規約を plugin_guard/loader を含む全経路で確認 - [x] AST/IR ゲート最終化: `_needs_ast`/`_needs_ir` の方針を docs と実装で一致させる(ASTは最小; 既定 no-ast) - [ ] Capability introspection: FILEBOX_PROVIDER の `caps(read/write)` を BoxShim から取得・Fail‑Fastの可否を明示 - [x] スモーク追加: core‑ro(open/read/close)/auto(フォールバック)/plugin-only(厳格)/analyzer(json-lsp純出力) の代表ケース - [x] Docs 同期: FILEBOX_PROVIDER.md / ENV_VARS.md / hako_check README を最終状態に更新 - [x] フォールバック保証: プラグインのロード失敗だけでなく「create_box 失敗時」にも ring1/core‑ro へ自動フォールバック(auto モード)。plugin‑only では Fail‑Fast。 - [x] 失敗時スモーク: ArrayBox の plugin が存在するが creation に失敗するケースを再現し、ring1/core‑ro で生成できることを確認。 Follow‑ups(Analyzer polish) - [x] HC012 JSON 安定化(using alias 依存排除、itoa ローカル化) - [x] HC017 一時 disable(UTF‑8バイト操作対応後に復活) - [x] using の不要宣言削除(Str aliasの掃除:使用ファイル以外から撤去) - [x] ルール実行エラーの可視化(stderr ログを明確に:rule名・ファイル名・行) - [x] テスト運用のENVまとめを README に明示(Disable Plugins / FactoryPolicy / Disable NyCompiler / JSON_ONLY) Phase 21.4 — Completion - FileBox SSOT(provider_lock / provider_registry / CoreRo / BoxShim / feature builtin-filebox): COMPLETE - Analyzer 安定化(HC012 修復、HC017 skip、ENV明文化、json-lsp純出力): COMPLETE Phase 22 — Proposed Focus - Unicode Support(HC017 復活): ByteArrayBox / UTF‑8 encode/decode helpers / 文字プロパティ - Plugin 完全化: dynamic plugin(.so)での create_box 安定化、bid/registry の暫定停止解除 - ENV Migration 完了: 旧ENV 警告の全面展開→削除 - Error Logging 強化: error() extern 経由の統一ロギング、ルール/テキスト系への横展開 Completed — FileBox Provider Wiring(C: Feature と静的/動的の選択を1本化) - 目的: File I/O を SSOT 抽象(FileIo)+ 薄いラッパ(FileBoxShim)+ provider_registry で一本化し、静的/動的/コアRO の選択を ENV で制御する。 - 完了内容: - provider_lock: `FILEBOX_PROVIDER` を追加し、グローバルに選択結果を保持 - vm 起動時に `read_filebox_mode_from_env` → `select_file_provider` で provider を決定・登録 - CoreRoFileIo を read‑only で実装(thread‑safe) - FileBox を provider 経由の委譲へ寄せ、basic/file_box.rs は deprecate 化 - Cargo.toml に `builtin-filebox` feature を追加 - Docs/ENV を同期(FILEBOX_PROVIDER.md / ENV_VARS.md) - 既知の非関連課題(別タスク扱い): - hako_check/cli.hako の parse error(line表示の不整合)。FileBox配線とは無関係。HC012 JSON安定化の一環で対応予定。 Next (handoff to Claude Code) - HC012 JSON 安定化(cli.hako) - json‑lsp時は stdout を純JSON、ログは stderr の規約徹底(fmt判定ガードの再確認) - parse error の発生箇所を修正(構文境界/コメント/Stage‑3トグル周り) - `NYASH_JSON_ONLY=1 ./tools/hako_check.sh --format json-lsp tools/hako_check/tests/HC012_dead_static_box` が純JSONを返すこと - Analyzer run_tests 全緑の維持(--rules/--skip-rules で個別検証可能) 8) FileBox provider 実装(リング0/1/選択ポリシー)と最小スモーク追加(core‑ro/auto/plugin-only) Roadmap (A→B→C) — 必ずこの順序で進める - A. HC011 をまず緑にする(AST 非依存の安全経路)【COMPLETE】 - 実装: `--no-ast` 追加、IR に `source` 格納、methods/calls のテキスト走査フォールバック、整形 JSON-LSP - 受け入れ: `tools/hako_check/run_tests.sh` → [TEST/OK] HC011_dead_methods 緑(期待JSON一致) - 影響範囲: tools/hako_check/{cli,analysis_consumer,rules/rule_dead_methods}.hako(既定は AST、`--no-ast` で切替) - B. plugin_guard の仕上げと一貫化 - 目的: すべての runner モードで不足プラグイン報告を共通APIに統一(strict/quiet のポリシー遵守) - 受け入れ条件: vm/vm_fallback 以外に残る ad-hoc 出力が 0、メッセージは stderr のみ(quiet 時) - C. AST/Tokenizer の精緻化(AST 経路へ戻す) - 目的: parser_core/tokenizer を強化して `boxes[].methods[]` を安定抽出、HC011 を AST 入力で PASS - 受け入れ条件: `HAKO_CHECK_NO_AST=0`(既定)で run_tests.sh が緑、methods/calls 数が IR デバッグに出力される Open Issues (Map semantics) - Map.get の戻り値セマンティクス未確定 - 現状: kernel 側の get_h の値/存在判定の定義が曖昧。reps は has を優先して固定(rc=1)。 - 決めたいこと: get_h の戻り(値 or sentinel)/キー不存在時の扱い(0/-1/None 相当)/rc への反映規約。 - 提案: reps を2段階で導入(has→get)。get は「存在しない場合は 0(未使用値)」を一旦の規約とし、将来 Option 風のタグに拡張可能にする。 - ランタイムシンボルの最小集合の確認 - nyash.map.{birth_h,set_h,size_h,has_h,get_h} が kernel に存在することを常時確認(link 失敗時は Fail‑Fast)。 - 決定性とハッシュ - いまは size 決定性を優先(hash はオプション)。TargetMachine へ移行後に `NYASH_HASH_STRICT=1` を既定 ON に切替予定。 Near‑term TODO(21.4 準備) - tokenizer: 文字列/数値/識別子/記号/位置情報 - parser_core: using/box/static method/assign/簡易block - ast_emit: boxes/uses/methods/calls(min) を JSON 化 - cli: ファイル→AST JSON - Analyzer: AST→IR 変換の経路を優先 - 代表ルールの AST 実装と LSP 出力の雛形 Next (21.2 — TBD) - 21.1 の安定化を維持しつつ、C‑API の純API移行(ny‑llvmc 経由を段階縮小)計画を作成 - reps の決定性(3×)を phase2100 aggregator にも追加検討 - Hako‑first 方針(Rust変更最小化) - Rust は Kernel/ABI(シンボル/リンク)に集中。解釈/解決は Hako 側の Adapter/Policy に段階移行。 - dev は Adapter 登録や by‑name fallback を許容(トグル)、prod は Adapter 必須(Fail‑Fast)。 Next Steps (immediate) 1) A(仕上げ): HC012 line 精度(span_line)/ README 追随 / CLI I/F最終確認 2) B(Parser強化): tokenizer 文字列エスケープ/位置情報、parser_core 複数行・alias 抽出 3) C(可視化): DOT 改善(box cluster / 孤立ノード)と quick スモーク追加 Context Compression Notes - A(診断I/F+抑制)は実装済み。文字列診断→型付き変換あり。 - B(AST: span_line/is_static=bool)は実装済み。methods.arity は既に出力。 - C は ensure_array と calls arity 推定を反映。残は AST優先の徹底と HC012 line 精度。 - HC021/HC031 は完了。PHI は AST パス限定で再発可能性があるため、当面 `--no-ast` 既定(`--force-ast` で明示オン)。 - ルール検証は `--rules`/`--skip-rules` で二分探索可能。 TODO (short-term, non-HC0) - AST-first intake: minimize text fallback; ensure analyzer never uses FileBox in tests. - DOT edges: keep unique edges; add box clusters (optional, post-21.4). - Quiet JSON: enforce NYASH_JSON_ONLY=1 in wrappers; stderr-only plugin hints. - HC015 prep: rely on inferred call arity for arity mismatch rule later. Rules Backlog(候補・優先提案) - HC012: Dead Static Box — 定義のみで参照/呼出ゼロの static box を検出 - HC013: Duplicate Method — 同一 box 内の重複メソッド名/arity を検出 - HC014: Missing Entrypoint — Main.main/0 不在を警告(プロファイル可) - HC015: Arity Mismatch (MVP) — 明確な `Name.method()` 呼び出しの引数個数不一致を検出(0/1の最小版) - HC016: Unused Using/Alias — `using ... as Alias` の未使用を検出 - HC017: Non‑ASCII Quotes — “ ” ‘ ’ 等の fancy quotes を検出し ASCII へ置換提案 - HC018: Top‑level local in prelude — 先頭 `local` を検出(merge 前提のクリーンアップ漏れ) - HC021: Analyzer IO Safety — CLI 経路での FileBox 使用を警告(`--source-file` 利用を提案) - HC022: Stage‑3 Gate — while/for を含む .hako を Nyash VM へ流す危険の検出(gate フラグ提示) - HC031: Brace Heuristics — `{`/`}` の粗い不整合検出(早期警告) 5) `--format json-lsp` の最小実装(既存配線に診断配列を流し込む) Previous Achievement - ✅ Phase 20.44 COMPLETE(provider emit/codegen reps 緑) - ✅ Phase 20.45‑46: PRIMARY 切替のための品質・整流(env_bool・MethodAliasPolicy・MirBuilder prefer reps の整備) - ✅ Phase 20.48 COMPLETE(Deterministic Bootstrap & Parity: run_all 緑 / repeat 3回一致) - ✅ Phase 20.49 COMPLETE(SSOT & hv1 inline 最小:phase2049/run_all 緑、S3 reps ゲート整備) Next Steps (ordered) 1) repeat reps: TypeOp を追加(済) 2) PRIMARY reps: Array/Map 三受信者の独立性(追加済) 3) S3 reps を1本追加(3ブロック系、LLVM18 検出で自動実行) 4) README(20.48)へ Quick Verify の項目拡張(typeop_check/cast と multi‑recv を追記済) Close Ready(20.48) - 条件: - s1s2s3_repeat_*(const/compare/logical/typeop)が3回一致 - PRIMARY reps(If/Logical/Loop/Array/Map/TypeOp)が PASS(no‑fallback) - run_all(phase2048)が緑(S3 は LLVM18 環境で自動、NYASH_LLVM_S3=0 で明示無効) Hotfix Plan — Using/Prelude Unification (Self‑Host) - Problem: .hako を NyashParser に通す経路でパース落ち(Invalid expression)。 - Decision: プレリュードは“テキスト統合(merge_prelude_text)”に一本化。AST マージは撤退。 - Resolver 入口は共通(alias/modules/packages/builtin)。 - 以降はメインの言語に応じて実行器へ渡す(Hako→Hakorune VM / MIR→Core)。 - NyashParser は Nyash コードのみ。Hako は Nyash VM 経路に入れない(Fail‑Fast)。 Action Items (20.38) - P1 C‑ABI ブリッジ(既定OFF) - Hako provider→Rust extern_provider へ最小接続(emit/codegen)。 - ハーネスのタグ用シム(test_runner)を撤去できる状態にする。 - P2 v1 Dispatcher IR 完了+φテーブル堅牢化 - V1SchemaBox.get_function_ir を構造IRで返却(blocks/phi_table)。 - ループは IR 反復に完全切替、φ は entry 適用(命令ループから除去)。 - 複数φ/複数incoming/空白改行混在を canary で固定。 - P3 Verify 既定整流(完了) - v1→Hakorune を既定ON、Core は診断 fallback。末尾数値抽出で rc を一意化。 - include ポリシー quick=ERROR を維持(ドキュメントと一致)。 - P4 Resolver/alias 仕上げ - lang/src/vm/** の alias を監査し、直参照を払拭。normalize/trace ログは最小に整流。 - P5 Docs 反映 - phase‑20.38 のトグル/受け入れ条件/撤去予定のシムを反映。φ entry SSOT は IR 完了後に更新。 - extern タグ用シムの現状と撤去条件(hv1 inline 安定後に除去)を明記。 Acceptance(phase 21.2) - HAKO_CAPI_PURE=1 で reps(ternary=44 / map=1)が PASS、各3回一致(obj/rc)。 - 21.1 reps(C‑API fallback)と既存 llvmlite 経路は緑維持。 New (21.1 wiring) - Rust provider 切替の実装(src/host_providers/llvm_codegen.rs) - `NYASH_LLVM_USE_CAPI=1` + `HAKO_V1_EXTERN_PROVIDER_C_ABI=1` で C‑API 経路を有効化。 - `libhako_llvmc_ffi.so` を dlopen し、`hako_llvmc_compile_json` を呼び出して `.o` を生成。 - plugins feature 未有効時は明示エラー(Fail‑Fast)。 --- # Next Task — Phase 20.49(Resolver SSOT & Compiler Bring‑up) 目的(このフェーズで到達するゴール) - using/プレリュード統合の SSOT を dev/prod で確定(include は prod で非対応) - dev では toml なしの最短導線(相対パス using / preinclude)で“すぐ動く”を保証 - コンパイラ自走に必要な hv1 inline の最小カバレッジを reps で固定 Focus(20.49) - Resolver/Runner: using 解決と prelude 統合の一本化(dev/prod トグルを明文化) - Reps: using/alias/nested prelude の代表追加(dev/prod 両系) - hv1 inline: 命令/extern の最小セットを reps から埋める(不足は段階実装) - S3(任意): ternary / map set→size 等のE2E代表を `NYASH_LLVM_S3=1` で実行 Acceptance(20.49) - dev: toml無し一発経路でコンパイラ一式の v1 生成が成功(S1/S2 繰り返し一致) - prod: alias/modules 経路のみで run_all が緑(include=ERROR) - hv1 inline: 代表で本体必要最小命令/extern が緑 Changes (recent) - Core executor: v1 優先実行(schema_version 検出時)。 - hv1 mir_call handler: per‑recv size state 実装+trace。 - test_runner: HAKO_VERIFY_V1_FORCE_HAKOVM=1 を追加(hv1 ラッパーで v1 実行)。 - hv1 inline reps: 代表を整備(per‑recv second は暫定 rc=1)。 Changes (this pass) - 20.44 を ✅ COMPLETE にマーク - 20.47/20.48 のフェーズ文書を追加(自己ホストの工程と受け入れを明文化) - 拡張子統一(.hako/.nyash 等価): 仕様の明文化 + 実装反映 - Fail‑Fast(Hako in Nyash VM)既定OFF(HAKO_FAIL_FAST_ON_HAKO_IN_NYASH_VM=1 のみON) - using はテキスト・プレリュード統合を既定に(AST統合は任意) - using 解決は .hako 優先→.nyash 次点。using.paths に lang/src を追加 - ドキュメント更新: docs/guides/source-extensions.md を等価性ポリシーに刷新 - runner: env_bool 横展開(common_util/strip.rs, modes/pyvm.rs, modes/common.rs, hv1_inline.rs) - vm: MirCallV1HandlerBox trace の受信者IDログ修正 - quick/core phase2036: v1_minivm_size_stub_off_canary_vm を修正 - using をパス指定から alias(`using selfhost.vm.entry as MiniVmEntryBox`)へ切替 - `NYASH_PREINCLUDE=1` を注入してプレリュードをテキスト統合(prod プロファイルの path using 限制を回避) - 結果: rc=0 で PASS(スタブ時の size=0 が Mini‑VM の rc に反映) - quick/core phase2047: Using alias 代表を追加 - tools/smokes/v2/profiles/quick/core/phase2047/using_alias_selfhost_vm_entry_canary_vm.sh(PASS) - alias 解決の実行確認(cross‑box static call → rc=0) - tools/smokes/v2/profiles/quick/core/phase2047/using_alias_string_helpers_canary_vm.sh(PASS) - shared/helpers の alias 解決を実行確認(静的呼び出し) - Self‑Hosting S1/S2(builder 直行) - gen: tools/selfhost/gen_v1_from_builder.sh(emit_return_int2(42) → v1 JSON 出力) - canary: tools/smokes/v2/profiles/quick/core/phase2047/selfhost_s1_s2_from_builder_canary_vm.sh(PASS) - provider 雛形: tools/selfhost/gen_v1_from_provider.sh(C‑ABI 連携は段階導入) - Provider v1 強制(最終化) - src/host_providers/mir_builder.rs: emit前後で v1 を強制(NYASH_JSON_SCHEMA_V1=1 一時設定 + 読み戻し時の v1 ラップ) - hv1 inline 実装の強化 - Array と Map の per‑receiver サイズ状態を分離(独立マップ: arr/map) - MapBox: set→size を rc で検証可能(first=1/second=0 reps と整合) - Docs 更新 - phase‑20.48 の README に “Quick Verify” セクションを追加(run_all と S3 トグルの手順) - canary 追加: tools/smokes/v2/profiles/quick/core/phase2047/provider_v1_shape_canary_vm.sh(PASS) - SSOT の徹底(strip.rs 連携) - src/runner/modes/common_util/resolve/strip.rs: is_path 判定と dev-file 候補判定を SSOT に寄せ(path_util) - S1/S2 拡張 reps(builder) - gen: tools/selfhost/gen_v1_from_builder_compare_{cfg,ret}.sh - canary: tools/smokes/v2/profiles/quick/core/phase2047/selfhost_s1_s2_from_builder_compare_{cfg,ret}_canary_vm.sh(PASS/環境で整合) - S3 reps(llvmlite, NyRTリンク, 実行) - phase2047/s3_link_run_llvmlite_compare_{cfg,ret}_canary_vm.sh(rc=1) - phase2047/s3_link_run_llvmlite_const42_canary_vm.sh(rc=42) - phase2047/s3_link_run_llvmlite_branch_ret_44_canary_vm.sh(rc=44) - 生成器: tools/selfhost/gen_v1_from_builder_branch_ret_44.sh - PRIMARY no‑fallback reps(hv1 inline) - phase2047/primary_no_fallback_v1_const_rc_canary_vm.sh(rc=42) - phase2047/primary_no_fallback_v1_compare_branch_rc_canary_vm.sh(rc=1) - phase2047/primary_no_fallback_v1_jump_rc_canary_vm.sh(rc=7) - S1/S2 拡張 reps(builder) - gen: tools/selfhost/gen_v1_from_builder_compare_{cfg,ret}.sh - canary: tools/smokes/v2/profiles/quick/core/phase2047/selfhost_s1_s2_from_builder_compare_{cfg,ret}_canary_vm.sh(PASS/環境で整合) - S3 代表(llvmlite, NyRTリンク, 実行) - phase2047/s3_link_run_llvmlite_compare_cfg_canary_vm.sh(NYASH_LLVM_S3=1 で有効、SKIPガードあり) - Self‑Hosting S1/S2 実行例(雛形)を追加 - tools/selfhost/examples/gen_v1_const42.sh(最小 v1 を出力) - `tools/selfhost/bootstrap_s1_s2.sh --cmd1 'bash tools/selfhost/examples/gen_v1_const42.sh' --cmd2 'bash tools/selfhost/examples/gen_v1_const42.sh'` → PASS(正規化ハッシュ一致) // Loop compares normalization (Step‑1) - Loop lowers(simple/count_param/sum_bc): Compare 受理を拡張し Lt 形へ正規化。 - i < L / i <= L は既存通り(<= は L+1)。 - L > i / L >= i は左右スワップで受理(>= は L+1)。 - i != L は init=0, step=1 の単純カウントに限り i < L と同値として受理。 - Canaries: phase2039 に追加(swapped > / >=, !=)し、Core verify で PASS を確認。 // Step‑2/3 generalization (count_param) - step 一般化: Int 2,3,… と Local Var 由来の step を受理。'-' は負の step に正規化(Add + 負値)。 - 降順対応: i > / i >= limit を cmp=Gt/Ge で build2 へ伝達。 - init/limit 起源の拡大: Local Var(Int)由来を逆引きで受理。 - Canaries: step=2 / step(Local) / 降順('-')/ limit(Local) / init(Local) を追加し PASS。 // Step‑4(部分) break/continue 検出の堅牢化(sum_bc) - 'i==X' に加え 'X==i' も受理。専用カナリー(swapped equals) PASS。 - If(var != X) else [Break] の最小サブセットを受理(loop_scan_box へ委譲)。専用カナリー PASS。 - If(var != Y) else [Continue] は検出実装あり(inline)が未検証→次段で helper へ移設しつつ canary 追加予定。 What’s green (20.34) - Loop/PHI unify (phi_core) in JSON v0 bridge — unified path used (toggle exposed). - Program(JSON v0) PHI‑trace canaries — PASS. - Core exec canaries (builder → emit → Core) — now routed and PASS: - mirbuilder_internal_core_exec_canary_vm (rc=10) - mirbuilder_internal_loop_core_exec_canary_vm (rc=3) - mirbuilder_internal_loop_count_param_core_exec_canary_vm (rc=6) - mirbuilder_internal_loop_sum_bc_core_exec_canary_vm (rc=8) Recent changes (summary) - Added MIR JSON v0 loader (minimal): src/runner/mir_json_v0.rs - Supports const/compare/branch/jump/phi/ret/copy - Promoted --mir-json-file to “execute + exit(rc)” - v1 → try_parse_v1_to_module; v0 → minimal loader; executes via Core interpreter - rc mapping unified in execute_mir_module_quiet_exit - verify_mir_rc improvements (tools/smokes/v2/lib/test_runner.sh) - Core primary: MIR(JSON) uses --mir-json-file, Program(JSON v0) uses --json-file - Mini‑VM(hakovm)rc==1 ヒューリスティックを削除し、経路評価を素直化(v1はCore、v0はhakovmに整流) - Hako JSON reader minor fix - lang/src/vm/core/json_v0_reader.hako: r# raw を通常文字列に統一(Hako生文字列の互換性向上) - MIR JSON v1 bridge extended - parse_const_value now handles f64/float, bool, string, and handle(StringBox) → ConstValue::String - Direct extern names supported in VM interpreter: env.mirbuilder.emit, env.codegen.emit_object - New v1 canaries (Core route) - tools/smokes/v2/profiles/quick/core/phase2035/v1_method_string_indexof_canary_vm.sh - tools/smokes/v2/profiles/quick/core/phase2035/v1_extern_mirbuilder_emit_canary_vm.sh - tools/smokes/v2/profiles/quick/core/phase2035/v1_method_string_substring_1arg_canary_vm.sh - tools/smokes/v2/profiles/quick/core/phase2035/v1_method_string_substring_2args_canary_vm.sh - tools/smokes/v2/profiles/quick/core/phase2035/v1_array_push_size_canary_vm.sh - (map) tools/smokes/v2/profiles/quick/core/phase2035/v1_map_set_get_size_canary_vm.sh - Note: returns size (1) for rc stability; get-path validated structurally - 20.38 extern bring-up (Hakorune primary) - Hakorune provider tags: prints `[extern/c-abi:mirbuilder.emit]` / `[extern/c-abi:codegen.emit_object]` when `HAKO_V1_EXTERN_PROVIDER_C_ABI=1`(既定OFF) - Core extern provider: when `HAKO_V1_EXTERN_PROVIDER=1`, `env.mirbuilder.emit` / `env.codegen.emit_object` return empty string (stub) to keep rc=0(verify fallbackの安定化) - Dispatcher(FLOW): minor cleanup to avoid stray scanning code; ret-path returns value and does not emit trailing prints - Canaries: phase2038 emit/codegen → PASS(タグ+rc=0 を固定)。phi 追加ケース(then→jump combo3)も PASS。 Open (pending) - SSOT helpers(binop_lower / loop_common)の導入と呼び出し置換(Builder/Bridge)。 - Continue ‘!=’ else の builder 経路の MIR 生成整流(rc=8 固定化)。 - P1〜P4 の実装・緑化(上記 Action Items)。 Active toggles (debug/verify) - HAKO_VERIFY_PRIMARY=hakovm|core(既定 hakovm、Coreは診断) - HAKO_V1_DISPATCHER_FLOW=1(v1 FLOW 実行) - HAKO_V1_EXTERN_PROVIDER=1(Hako extern provider 有効) - HAKO_V1_EXTERN_PROVIDER_C_ABI=1(タグ/ブリッジ実験。既定OFF) - HAKO_V1_PHI_STRICT=1 / HAKO_V1_PHI_TOLERATE_VOID=1(φポリシー) - NYASH_RESOLVE_TRACE=1 / NYASH_RESOLVE_NORMALIZE=1(resolver dev) How to run (quick) - Build: `cargo build --release` - Program v0 PHI‑trace (debug): - `SMOKES_ENABLE_DEBUG=1 bash tools/smokes/v2/profiles/quick/core/phase2034/program_v0_if_phi_trace_vm.sh` - `SMOKES_ENABLE_DEBUG=1 bash tools/smokes/v2/profiles/quick/core/phase2034/program_v0_loop_phi_trace_vm.sh` - Core exec canaries(20.34 緑対象): - `bash tools/smokes/v2/profiles/quick/core/phase2034/mirbuilder_internal_core_exec_canary_vm.sh` - `bash tools/smokes/v2/profiles/quick/core/phase2034/mirbuilder_internal_loop_core_exec_canary_vm.sh` - `bash tools/smokes/v2/profiles/quick/core/phase2034/mirbuilder_internal_loop_count_param_core_exec_canary_vm.sh` - `bash tools/smokes/v2/profiles/quick/core/phase2034/mirbuilder_internal_loop_sum_bc_core_exec_canary_vm.sh` Mini‑VM policy(20.34) - 実装は維持(alias/ret/phi 最小系を今後整える)。ただし quick の canary は Core へ寄せて緑化。 - 20.36 で verify primary を hakovm に段階的に切替、Mini‑VM green を進める。 Next (20.35 — scoped; behavior unchanged) 1) MIR JSON v1 loader expansion(Method/Extern/BoxCall — 最小) - callee.type=Method → BoxCall 復元(box_name/method/receiver/args) - callee.type=Extern → ExternCall 復元(env.get/env.codegen.emit_object/env.mirbuilder.emit/console.log など) - effects 未指定は PURE 既定、WRITE 系は最小でフラグ化(実害ゼロ) - v1 canary 追加(string indexOf/substring、array push/size、map set/get/size、extern env.get) 2) Using/alias の推移解決の堅牢化(深さ/循環/キャッシュ) - 実装済み(DFS 深さ上限=10、循環検知、キャッシュ)。strict では曖昧解決をエラー扱い。 3) ドキュメント:今回の経路(Core/verify)を roadmap に反映(DONE) Structure cleanups (20.35 A→B→C) - A) v1 mir_call 両対応(flat/nested): 実装済(ローダで互換吸収)。 - B) Extern provider 単一点化: 実装済(handlers/extern_provider.rs)。calls.rs/externals.rs から委譲。 - C) Const パース共通化: 実装済(src/runner/mir_json/common.rs)。まず v1 から採用(v0 は次段)。 Next (20.36 — verify primary → hakovm, preinclude removal, C‑ABI scaffold) - Verify primary 切替(段階): hakovm → Core fallback - preinclude 非推奨化(quick から撤去) - Mini‑VM の最小状態(len/size/push の簡易 state)を flag ガードで導入(デフォルトOFF)— 導入済 - 受信者別サイズ管理フラグ `HAKO_VM_MIRCALL_SIZESTATE_PER_RECV=1` を導入(canary 追加済) - HAKO_VM_MIRCALL_SIZESTATE=1 は緑化済(push 2回→size=2)。次は受信者別管理を flag で導入: HAKO_VM_MIRCALL_SIZESTATE_PER_RECV=1 - C‑ABI 設計(docs + ヘッダ雛形) Known open items(tracked to 20.36) - Mini‑VM: using/alias の推移解決(selfhost.vm.helpers.* 連鎖) - Mini‑VM: ret/phi の最小ケースで rc が確実に数値化されるよう整備(継続確認) Next (20.37 — v1 Dispatcher & Phi) 1) V1SchemaBox: get_function_ir(JSON→IR) を拡張(blocks/insts/phi_table を一括) 2) NyVmDispatcherV1Box: IR反復へ切替(スキャナ依存の最終撤去)、今は二重化(IR優先/scan後退互換) 3) Resolver/inline: AST prelude マージで推移usingを一次収束(Claude codeで進行)、ランナーは既存fallback維持 Next (Hotfix — Using/Prelude Unification) 1) vm.rs: using_ast 経路を `merge_prelude_text` に一本化(ASTマージ撤去) 2) vm.rs: Hako 構文検出で Hakorune VM へ切替(NyashParser をバイパス) 3) strip.rs: `.hako` の AST パース抑止と診断ガイド 4) verify: extern canary を PASS 化(末尾 rc 抽出の安定化) Docs: - docs/development/architecture/phi-entry-in-hako.md に φ entry 設計のSSOTを記載(不変条件/flags/テスト) Next (20.38 — extern provider & C‑ABI) 1) HakoruneExternProviderBox を拡張(warn/error/emit の最小タグ/空文字挙動)— 完了 2) HAKO_V1_EXTERN_PROVIDER=1 の canary 追加(構造緑固定)— 完了 3) C‑ABI 導線のPoC接続(emit/codegen、既定OFF)— 完了(タグ+rc=0) 4) hv1 inline 安定化(残): -c 経路の using resolver に modules.workspace を強制ロードするか、dispatcher の using を dev 限定で path 化。 5) include 撤去の計画(dev → 本線): - まず stub カナリーの include は撤去済み(rc=0 のみ確認)。 - hv1 inline カナリーの prelude include は暫定(dev専用)。-c/alias 安定後に alias へ移行して include を撤去する。 - ランナー側では merge_prelude_text を既定経路とし、include は quick=ERROR のポリシーを維持。 Roadmap links(per‑phase docs) - Index: docs/private/roadmap/README.md - Phase 20.34: docs/private/roadmap/phases/phase-20.34/README.md - Phase 20.35: docs/private/roadmap/phases/phase-20.35/README.md - Phase 20.36: docs/private/roadmap/phases/phase-20.36/README.md Appendix — Toggle quick reference - NYASH_MIR_UNIFY_LOOPFORM=1|0 … Loop/PHI 統一(既定ON) - HAKO_VERIFY_PRIMARY=hakovm|core … verify 実行経路(今は core 優先で緑化) - NYASH_VM_TRACE_PHI=1 … VM PHI 適用トレース - HAKO_PHI_VERIFY=1 | NYASH_PHI_VERIFY=1 … ビルダー側の PHI inputs 検証 - HAKO_VM_PHI_STRICT=0(互換:NYASH_VM_PHI_STRICT=0) … 実行時 PHI 厳格 OFF(開発時のみ) Updates (2025-11-04) - hv1 inline: alias-only route stabilized (no include/preinclude). vm.rs wrapper now uses `using selfhost.vm.hv1.dispatch` and relaxes fail-fast for child. - Verify harness: include+preinclude fallback for v1 removed in `verify_mir_rc`; alias-only hv1 is the standard path. - Concat-safety (hv1 scope): replaced `"" + ` coercions with `StringHelpers.int_to_str(...)` in `lang/src/vm/hakorune-vm/dispatcher_v1.hako` and `lang/src/vm/boxes/mir_call_v1_handler.hako`. # Handoff — 20.43 Kickoff (15h progress) Focus (next) - Start Phase 20.43: MIR generation coverage for call/method/newbox/load/store/typeop, with minimal Array/Map bridge (structure-first, no behavior change). What’s landed this session (DONE) - NewBox → Constructor (minimal lower) - Added: `lang/src/mir/builder/internal/lower_newbox_constructor_box.hako` - Wired in: `lang/src/mir/builder/MirBuilderBox.hako` (try_lower early) and alias in `nyash.toml`. - Direct canary (PASS): `tools/smokes/v2/profiles/quick/core/phase2043/lower_newbox_constructor_direct_core_exec_canary_vm.sh`. - Method(size) → structural MIR (Array) - Added: `lang/src/mir/builder/internal/lower_method_array_size_box.hako` + alias in `nyash.toml`. - Direct structural canary (PASS): `tools/smokes/v2/profiles/quick/core/phase2043/lower_method_array_size_direct_struct_canary_vm.sh`. - Method(push) → structural MIR (Array) - Added: `lang/src/mir/builder/internal/lower_method_array_push_box.hako` + alias in `nyash.toml`. - Direct structural canary (PASS): `tools/smokes/v2/profiles/quick/core/phase2043/lower_method_array_push_direct_struct_canary_vm.sh`. - New → Constructor (direct) and Method(size/push) canaries all green under phase‑2043. - Array get/set - Added: `lang/src/mir/builder/internal/lower_method_array_get_set_box.hako` + alias. - Direct structural canary (PASS): `tools/smokes/v2/profiles/quick/core/phase2043/lower_method_array_get_set_direct_struct_canary_vm.sh`. - Map size/get/set - Added: `lang/src/mir/builder/internal/lower_method_map_size_box.hako`, `lower_method_map_get_set_box.hako` + aliases. - Direct structural canaries (PASS): `lower_method_map_size_direct_struct_canary_vm.sh`, `lower_method_map_get_set_direct_struct_canary_vm.sh`. - Load/Store(最小) - Added: `lang/src/mir/builder/internal/lower_load_store_local_box.hako` + alias。 - Direct structural canary (PASS): `lower_load_store_local_direct_struct_canary_vm.sh`。 - TypeOp Check(最小) - Added: `lang/src/mir/builder/internal/lower_typeop_check_box.hako` + alias。 - Direct structural canary (PASS): `lower_typeop_check_direct_struct_canary_vm.sh`。 - TypeOp Cast(最小) - Added: `lang/src/mir/builder/internal/lower_typeop_cast_box.hako` + alias。 - Direct structural canary (PASS): `lower_typeop_cast_direct_struct_canary_vm.sh`。 - Builder internal route stabilized for simple New → Core via runner_min - Added: `lang/src/mir/builder/internal/runner_min_box.hako` + alias。 - `verify_program_via_builder_to_core` uses runner_min first, with markers + optional full MirBuilder fallback. - Harness improvements - Builder output extraction with markers `[MIR_OUT_BEGIN]/[MIR_OUT_END]` in `tools/smokes/v2/lib/test_runner.sh`. - Debug tails for stdout/stderr when `HAKO_MIR_BUILDER_DEBUG=1`. - Enabled using for inline runs: `NYASH_ENABLE_USING=1` / `HAKO_ENABLE_USING=1`. Open items / blockers - Builder (internal/delegate) inline route still unstable for JSON capture; `phase2043/program_new_array_delegate_struct_canary_vm.sh` fails (no JSON in stdout). - Plan: switch builder to write MIR to a temp file (FileBox) and let harness read it; or adopt provider route in 20.44 (`env.mirbuilder.emit`). - Remaining lowers for 20.43 not yet added: method(push/get/set/len), load/store (local), typeop(is/as) minimal; builder wiring after direct lowers pass. Next-up checklist (20.43) 1) MirBuilder wiring: 上記 direct lowers を `MirBuilderBox` から段階採用(Return系フォールバック前)→ 一部(Array/Map/LoadStore/TypeOp)採用済み。 2) New(Map) は Constructor lower で既に生成可能(direct PASS)。Builder経路へ採用。 3) TypeOp: `Cast` 採用済(構造lower→canary→配線)。 4) Builder route 安定化(internal):lower ラッパー側で MIR を `/tmp` に保存→ハーネスが読む(pipe 揺れを回避)。 5) Delegate route(20.44 に接続):`env.mirbuilder.emit` を provider 経由に切替(構造は共通)。 6) Delegate route (optional): use provider `env.mirbuilder.emit` (20.44 scope) to make canaries robust. How to run - All new phase 20.43 canaries: - `bash tools/smokes/v2/run.sh --profile quick --filter phase2043` - Single tests: - NewBox direct: `tools/smokes/v2/profiles/quick/core/phase2043/lower_newbox_constructor_direct_core_exec_canary_vm.sh` - Method(size) direct: `tools/smokes/v2/profiles/quick/core/phase2043/lower_method_array_size_direct_struct_canary_vm.sh` Toggles (dev) - Inline Hako: `HAKO_FAIL_FAST_ON_HAKO_IN_NYASH_VM=0 NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1` - Builder internal: `HAKO_MIR_BUILDER_INTERNAL=1` (and `HAKO_MIR_BUILDER_DEBUG=1` for tails) Pointers - New lowers: `lang/src/mir/builder/internal/lower_newbox_constructor_box.hako`, `lang/src/mir/builder/internal/lower_method_array_size_box.hako` - Wiring: `lang/src/mir/builder/MirBuilderBox.hako` (try_lower order) and `nyash.toml` aliases - Harness: `tools/smokes/v2/lib/test_runner.sh` (marker extraction / debug tails) --- Update (2025-11-15 — Stage1 CLI emit調査メモ) - Stage‐B emit を拡張(FuncScannerBox/Stage‐B 本体)して `static box` メソッドを defs に追加。暗黙 `me` もパラメータへ補完。 - Rust 側 JSON v0 ブリッジに `ExprV0::Null` variant を追加し、Stage‐B が吐く Null リテラルを受理。 - `launcher.hako` の `while` を `loop` 構文へ置換(Stage‐B パーサ互換)。 - Stage1 CLI の Program(JSON) は attr付き defs まで含むようになったが、selfhost builder (MirBuilderBox on VM)がまだ HakoCli 全体を lowering できず stub MIR を返している。provider 経由では 62KB 超の MIR(JSON) が得られるので Phase 25.1a ではこちらを利用。 Update (2025-11-17 — Phase 25.1d: Rust MIR me-call recursion fix & Stage‑B stack overflow原因特定) - 状況: - `tools/test_stageb_min.sh` の Test2(`compiler_stageb.hako -- --source stageb_min_sample.hako`)で発生していた stack overflow / Segfault は、Rust MIR builder 層の無限再帰が原因だったことが判明。 - backtrace および `logs/stageb_min_full.log` から、次の 3 関数がループしていることが確認できた: - `try_build_me_method_call`(`src/mir/builder/calls/build.rs`) - `try_handle_me_direct_call`(`src/mir/builder/builder_calls.rs`) - `handle_me_method_call`(`src/mir/builder/method_call_handlers.rs`) → `try_build_me_method_call` → `handle_me_method_call` → `try_handle_me_direct_call` → 再び `try_build_me_method_call` という三角ループで Rust スタックを消費していた。 - 対応(Rust 層): - `src/mir/builder/calls/build.rs` の `try_build_me_method_call` から「3-a) Static box fast path」として `handle_me_method_call` を即呼び出すパスを削除し、相互再帰を解消。 - これにより `try_build_me_method_call` は「enclosing box 名を見て、既に lower 済みの `./Arity` を Global call に差し替える」経路だけを担うようになった(インスタンス Box 向けの 1 パスのみ)。 - `src/mir/builder.rs` / `src/mir/builder/lifecycle.rs` に `NYASH_MIR_COMPILE_TRACE=1` 用の compile trace を追加し、 - `lower_root` の static box 降ろし時に `[mir-compile] lower static box ` をログ出力できるようにした(デフォルト OFF)。 - 観測結果(修正後): - `NYASH_MIR_COMPILE_TRACE=1` で Test2 を再実行したところ: - `BundleResolver` / `ParserBox` 関連の static box 群 / `StageBArgsBox` / `StageBBodyExtractorBox` / `StageBDriverBox` / `ParserStub` 等、すべての static box が `[mir-compile] lower static box ...` ログ付きで正常に MIR に lower されることを確認。 - `Main` の `build_static_main_box` も `Before/After lower_static_method_as_function` のデバッグログ付きで完走している。 - stack overflow / Segfault は消え、最終的なエラーは: - `❌ VM error: Invalid instruction: extern function: Unknown: env.set/2` となっており、Rust VM/MIR 層ではなく Nyash側の `env.set` extern 定義不足(Stage‑B 再入ガードに env を使っている部分)だけが残っている状態まで収束した。 - 今後のタスク(Phase 25.1d 続き): - Stage‑B の再入ガードを `env.set/2` ではなく Box 内 state(フィールド)で持たせるか、あるいは `env.set/2` を Stage‑B 実行環境向けに Rust 側 extern として提供するかを検討・実装する。 - `NYASH_MIR_COMPILE_TRACE` ログを活用して、今後も MIR builder 側の深い再帰や相互再帰を早期に検知できるようにする(特に Stage‑B / ParserBox 周辺の me 呼び出し)。 Update (2025-11-17 — Phase 25.1e kickoff: LoopForm PHI v2 migration) - 状況: - Local 変数宣言(`local a = ...`)まわりの SSA は Rust MirBuilder 側で修正済み。 - `build_local_statement` は初期化式を評価したあと、新しい ValueId を払い出し `Copy` 命令でローカルに値を写すようになっている。 - `src/tests/mir_locals_ssa.rs` で `local a,b,c` パターンを固定し、Const/NewBox とローカル変数レジスタが分離されることを確認済み(`%0 const 1` → `%4 copy %0` など)。 - Stage‑B / Stage‑1 / selfhost で残っている赤ログの多くは、loop/if 合流点での PHI 生成ロジックに起因している: - `mir_stage1_using_resolver_full_collect_entries_verifies` 内の `_find_from` ループで: - `Value %24 / %25 / %26 defined multiple times: first in block bb53, again in block bb54` - `Merge block bb54 uses predecessor-defined value %28/%29/%27 from block bb59/bb61 without Phi` など、header/merge ブロックで PHI dst と既存値の ValueId が衝突/Phi 不足が報告されている。 - Stage‑B 最小ハーネス(Test2)でも、legacy LoopBuilder + loop_phi + local_ssa の交差部分で UseBeforeDef/未定義レジスタが露出するケースが残っている。 - LoopBuilder には現在 2 経路が混在している: - legacy 経路: `build_loop_legacy` + `phi_core::loop_phi::prepare_loop_variables_with/ seal_incomplete_phis_with/ build_exit_phis_with` - LoopForm v2 経路: `build_loop_with_loopform` + `LoopFormBuilder` + `LoopFormOps` + `phi_core::{loop_phi,if_phi}` - LocalSSA (`ssa::local`) や pinned 変数(`__pin$*@recv`)の扱いがこの二重構造の上に乗っており、責務境界が曖昧になっている。 - 既に入れてある構造修正: - `LoopBuilder::prepare_loop_variables` で、preheader 時点の `variable_map` をそのまま PHI 対象にせず、 - ループキャリア変数(body 内で再代入されるもの)と - pinned 変数(`__pin$*`) のみを PHI 対象にフィルタリングするように変更。 - これにより、`text_len` / `pattern_len` のようなループ不変ローカルにまで PHI を張ることを避け、ValueId の二重定義/UseBeforeDef が起きにくい形に寄せた。 - 新フェーズ 25.1e の目的: - Loop/PHI 生成の SSOT を LoopForm v2(`LoopFormBuilder` + `phi_core::loop_phi/if_phi`)側に寄せ、legacy 経路は v2 の薄いラッパに縮退させる。 - `NYASH_LOOPFORM_PHI_V2=1` を使って、Stage‑B / Stage‑1 / selfhost 用テストの中で v2 経路を段階導入し、`mir_stage1_using_resolver_full_collect_entries_verifies` や Stage‑B 最小ハーネスで見えている PHI 不整合を構造的に解消する。 - 25.1e では挙動変更を避けるため、デフォルトは現状どおり legacy 経路のままにしつつ、v2 のみ opt‑in で試験運用し、緑になったところから徐々に責務を移す。 - やること(25.1e TODO メモ): - LoopForm v2 テストモード: - `mir_stage1_using_resolver_full_collect_entries_verifies` に `NYASH_LOOPFORM_PHI_V2=1` 用のサブテストを追加し、v2 経路の SSA/PHI 状態を検証する。 - Stage‑B 最小ループ(`_find_from` 相当)を切り出した Hako を v2 経路で `MirVerifier` にかける Rust テストを追加。 - LoopForm/legacy の責務切り分け: - LoopForm v2 の「どの変数に PHI を張るか」のルール(パラメータ+キャリア+pinned のみ)をドキュメント化し、legacy 側から重複する PHI 生成ロジックを段階的に削る。 - 現状の赤ログをロードマップに反映: - `docs/development/roadmap/phases/phase-25.1e/README.md` を追加済み。LoopForm PHI v2 移行フェーズのゴール/方針/タスク粒度をここに集約。 - 25.1e 本体では、「local SSA は緑」「LoopForm v2 経路で Stage‑1 / Stage‑B の代表ループが MirVerifier 緑になる」ことを目標に、小さなテスト+小さな修正で Loop/PHI 周りを仕上げる。 - Rust 側の現状: - MirBuilder / LoopBuilder 側で見えていたローカル SSA 違反・Stage‑B ArgsBox まわりの未定義レシーバ・me-call 再帰バグなどは、25.1d までの修正+今回の StringBox plugin 実装で一通り解消済み。 - `build_local_statement` によるローカル SSA fix(`src/mir/builder/stmts.rs`)。 - `CalleeBoxKind` + `CalleeGuardBox` による Stage‑B / Stage‑1 静的 Box と runtime Box の分離(Method callee の構造ガード)。 - `LoopBuilder::do_break` の snapshot + `jump_with_pred` + unreachable ブロックへの遷移は Rust MIR 側で正常に動作しており、LoopForm v2 の exit PHI 生成も Rust 側では仕様どおり。 - `tools/test_stageb_min.sh` の Test1/Test3 や `mir_locals_ssa.rs` など、Rust ミラー系の代表テストでは Undefined Value / SSA 違反は出ていない。 - 一方で、Stage‑B Test2(`compiler_stageb.hako` 経由)に `NYASH_VM_VERIFY_MIR=1` を付けて実行すると、Rust MIR 側でまだ SSA/PHI が崩れている関数が複数残っていることが分かった: - 代表例: `ParserStringScanBox.scan_with_quote/3`, `ParserExprBox.parse_compare2/3`, `ParserExprBox.parse_expr2/3`, `ParserExprBox.parse_sum2/3`, `FuncScannerBox._trim/1`, `FuncScannerBox._strip_comments/1`, `FuncScannerBox._find_matching_brace/2`, `JsonFragBox._decode_escapes/1`, `LocalSSA._block_insts_end/2` など。 - これらはすべて Rust 側の LoopBuilder + LoopForm v2 でコンパイルされた Hako の Box 群であり、`loopssa.hako` が no-op であるかどうかとは独立に、 header/exit の predecessor セットと PHI inputs の対応がずれているために `phi pred mismatch at ValueId(..)` が Rust VM 実行中に露出している。 - `.hako` 側 LoopSSA(`lang/src/compiler/builder/ssa/loopssa.hako`): - 現時点では `stabilize_merges()` が no-op stub のままで、Stage‑1 JSON v0 / MIR(JSON v0) に対する exit PHI 生成ロジックはまだ未実装。 - ここは「Stage‑0/Stage‑1 の JSON ブリッジ経路を LoopForm v2 の SSOT に揃える」ための別タスクとして扱う(25.1e 後半〜25.1f 想定): - `.hako` 側 LoopSSA には、Rust 側 LoopForm v2 と同じ Carrier/Pinned 規約・ヘッダ/exit 形を JSON レベルで再現するロジックを実装する。 - ただし、Stage‑B Test2 の現在の `phi pred mismatch` は Rust MIR ループの問題として先に 25.1e で根治し、その後で `.hako` LoopSSA を同じ規約に寄せる二段構えにする。