Files
hakorune/CURRENT_TASK.md
nyash-codex f74b7d2b04 📦 Hotfix 1 & 2: Parameter ValueId Reservation + Exit PHI Validation (Box-First Theory)
**箱理論に基づく根治的修正**:

## 🎯 Hotfix 1: Parameter ValueId Reservation (パラメータ ValueId 予約)

### 根本原因
- MirFunction counter が params.len() を考慮していなかった
- local variables が parameter ValueIds を上書き

### 箱理論的解決
1. **LoopFormContext Box**
   - パラメータ予約を明示的に管理
   - 境界をはっきりさせる

2. **MirFunction::new() 改善**
   - `initial_counter = param_count.max(1)` でパラメータ予約
   - Parameters are %0, %1, ..., %N-1

3. **ensure_counter_after() 強化**
   - パラメータ数 + 既存 ValueIds 両方を考慮
   - `min_counter = param_count.max(max_id + 1)`

4. **reserve_parameter_value_ids() 追加**
   - 明示的な予約メソッド(Box-First)

## 🎯 Hotfix 2: Exit PHI Predecessor Validation (Exit PHI 検証)

### 根本原因
- LoopForm builder が存在しないブロックを PHI predecessor に追加
- 「幽霊ブロック」問題

### 箱理論的解決
1. **LoopFormOps.block_exists() 追加**
   - CFG 存在確認メソッド
   - 境界を明確化

2. **build_exit_phis() 検証**
   - 非存在ブロックをスキップ
   - デバッグログ付き

### 実装ファイル
- `src/mir/function.rs`: Parameter reservation
- `src/mir/phi_core/loopform_builder.rs`: Context + validation
- `src/mir/loop_builder.rs`: LoopFormOps impl
- `src/mir/builder/stmts.rs`: Local variable allocation

### 業界標準準拠
-  LLVM IR: Parameters are %0, %1, ...
-  SSA Form: PHI predecessors must exist in CFG
-  Cytron et al. (1991): Parameter reservation principle

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 06:39:45 +09:00

1684 lines
156 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Current Task — Phase 21.8 / 25 / 25.1 / 25.2Numeric 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 & StageB path)
- Status: Rust MIR ビルダー側の SSA/PHI と StageB 最小ハーネスまわりを重点的にデバッグ中。スタックオーバーフロー系は Rust 側の再帰バグを潰しきって、いまは「StageB 経由 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/StageB など複数 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 をログ出力するようにし、StageB (`compiler_stageb.hako`) のどの box までコンパイルできているかを追跡しやすくした。
- StageB 最小ハーネスの現状:
- `tools/test_stageb_min.sh`:
- Test1`stageb_min_sample.hako` を直接 VM 実行): RC=0 で PASS。
- Test3同ソースを直接 MIR verify: MirVerifier 緑SSA/PHI エラーなし)。
- Test2`compiler_stageb.hako` 経由の StageB パス): 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 実装というより、StageB / UsingResolver / BundleResolver 周辺での receiver 推論・コピー挿入・メタデータ伝播の問題とみられる。
- Next steps25.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 未定義にならない」ことを追加で固定する。
- StageB/Stage1 ほかの 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 修正と StageB パスの現状)を反映済み。
- `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 製 hakoruneStage0 ブートストラップ」「Hakorune コードで構成された selfhost バイナリStage1」という二段構え方針を導入。
- Decisions:
- Stage0Rust bootstrap binary: プロセス起動・FFI・VM/LLVM コアのみを担当し、ランタイムロジックや数値コアは持たない。
- Stage1Hakorune selfhost binary: StageB / 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:
- Stage0Rust CLI:
- `cargo build --release``target/release/nyash` を Stage0 ブートストラップとして扱う(名称は将来 `hakorune-bootstrap` へ移行予定)。
- `Makefile``stage0-release` ターゲットを追加Rust 側のみをビルドする専用ターゲット)。
- Stage1Hakorune 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=nyashRust CLI, Stage1=hakorunetools/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` が StageB / 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` を追加し、StageB が出力する `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 CLIlauncher.hako:
- `lang/src/runner/launcher.hako``HakoCli` dispatcher を実装し、`Main.main(args)` を Stage1 エントリとして固定。
- コマンド実装Phase 25.1 実装範囲):
- `hakorune emit program-json [-o <out>] [--quiet] <source.hako>`:
- `FileBox``<source.hako>` を読み取り、`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 <program.json>] [-o <out>] [--quiet] [<source.hako>]`:
- `--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 <out>] [--quiet] <source.hako>`:
- `.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] <cmd>: not implemented yet` を表示し、9093 の固定コードで終了)。
- 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 CLIlauncher.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→MIRenv.mirbuilder.emitも修復済み。
- Current symptoms (after first fixes):
- `tools/hakorune_emit_mir.sh lang/src/runner/launcher.hako /tmp/launcher_mir.json`:
- StageB: `[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 を排除、
によって Stage3 パース/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を Stage3 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 では扱わず、タグ付き FailFast で検知するPHI ノード生成は既存 LoopForm/LowerLoop helper に一元化)。
- 新規: Stage3 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 経由。Stage3 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` 依存が排除された。Stage3 VM 経路で `BoxTypeInspectorBox.kind` / `is_map` / `is_array` が MapBox / ArrayBox を正しく認識し、小さな Hako テストで env.box_introspect.kind provider 経路が endtoend で動作することを確認済み。次は LoopOptsBox.build2 / JsonEmitBox._quote 等の残差に適用して multi-carrier LoopForm の selfhost-first を復旧する。
- docs: `docs/development/roadmap/phases/phase-25.1b/README.md` を design deepdive 版に更新し、FuncLoweringBox / MirBuilderBox の現状把握と拡張方針FailFast ポリシー・LoopForm/PHI ポリシー・Step0〜6 の実装順序などを整理済み。Step0FailFast/観測導線)は 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` から段階的に呼び出せるようにした。Step3LoopForm対応も 2025-11-15 実装完了:`FuncBodyBasicLowerBox._try_lower_loop` から `LowerLoopSumBcBox`/`LowerLoopSimpleBox` を呼び、LoopForm正規化済みループをMIRに落とす導線を確立、PHI/キャリア処理は既存Loop lowersに完全委譲、制約外は `[builder/funcs:unsupported:loopform]` でFail-Fast。Step4MethodCall/ExternCall パリティ)は Rust 層 (`builder_calls.rs` / extern handler) と StageB Program(JSON) の形を読み解いた設計メモに基づき、`FuncBodyBasicLowerBox._try_lower_return_method` による ArrayBox.size/getparams ベース 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 にはまだ適用していない)。さらに StageB 側の func_scan トグル(`HAKO_STAGEB_FUNC_SCAN`は「未設定なら既定ON、`\"0\"` のときだけ OFF」とするように compiler_stageb.hako を変更し、StageB を直接叩いたときに env 立て忘れで defs が欠落するバグを構造的に防ぐようにした。***
- LoopForm 複雑ケースについては、「Rust 側の LoopForm/PHI 実装をオラクルとし、同じ .hako を provider-first と selfhost-first の両方で通す」方針を docs に追記。LoopForm/PHI のロジック自体は Hako 側では `lower_loop_*_box.hako` 群に閉じ込め、FuncLowering/MirBuilder 本体は `_rebind` 呼び出しのみを行う。Rust は StageB/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 — StageB using resolver alias 化 & 環境導線)
- StageB 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`) に置き換え、Stage3 パーサが string literal using を弾いていた問題を解消。
- `tools/hakorune_emit_mir.sh` では `nyash.toml` `[modules]` を Python で読み取り `name=path``HAKO_STAGEB_MODULES_LIST``|||` 区切り)として export 済み。StageB 側では `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 として抽出するようにした。これにより StageB 経由で生成された 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 解析の重複を解消しつつ Stage3 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 に揃え、StageB から box 定義が Program(JSON) に落ちるようにする。
- selfhost builder Runner (`try_selfhost_builder`) は引き続き opt-in。StageB 改修により 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 EXEny-llvmc 経由で生成されたバイナリ)が提供する `emit program-json` / `emit mir-json` の I/O 挙動は、llvmlite ハーネス(`NYASH_LLVM_USE_HARNESS=1` 経路)の挙動に揃える。
- 具体的には:
- stdout: JSON をそのまま吐く(`Result: 0` のようなハーネス用メッセージは既定OFFverbose専用に寄せる、エラー時は JSON ではなく明示的なエラーメッセージ非0 exit code。
- exit code: Rust CLI / llvmlite ハーネスと同じく、0=成功、非0=失敗Stage1 CLI 側の 9093 番台コードと整合)。
- 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 は「StageB / Bridge / MirBuilder への IntArrayCore/MatI64 導線imports」まで完了とし、EXE/LLVM ベンチ統合は Phase 25 に移管する。
- Done in 21.8:
- BridgeEnv に `imports: HashMap<String,String>` フィールドを追加し、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 <input.hako> <out.json>`
- 常に `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 実装までの経路を Stage3 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 以降の構造タスクとして整理予定。
- 追加メモStageB / selfhost CLI canary 周りの現状把握):
- `tools/smokes/v2/profiles/quick/core/phase251/selfhost_cli_run_basic_vm.sh` で使っている簡易 HakoCli.run サンプルに対しては、以前は StageB (`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` から静的 BoxHakoCli など)も user factory 経由で生成できるようにしたplugins disabled でも HakoCli の NewBox 自体は成功する)。
- Ifblock 側の 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` がエラーメッセージに含まれるようになり、StageB / StageB 用最小ハーネス内の `ParserBox.length()` 呼び出しが recv 未定義で落ちていることを特定できるようになったNYASH_VM_TRACE/NYASH_VM_TRACE_EXEC 未設定時でも場所が分かる)。
- なお、StageB を selfhost CLI サンプルに対して実行した際に現時点で見えている残存課題は次の 3 点:
- 1) `if args { ... }` まわりの truthy 判定ArrayBox を boolean 条件に使っている部分)の扱いに起因する型エラーであり、これは SSA ではなく「条件式の型truthy 規約」をどう定義するかという別問題として扱うPhase 25.1c 以降の型システム整理タスクで扱う想定)。
- 2) StageB 用最小ハーネス(`lang/src/compiler/tests/stageb_min_sample.hako` + `tools/test_stageb_min.sh` の Test2を StageB 経由で実行した際に、以前は `❌ 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 の再帰ルートではなく、StageB 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 系の自己再帰は構造的に防止されている。StageB 経路の 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 modulekind=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)` の StageB/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`Stage3 キーワード)エラーが出ていることを確認。これは Ny selfhost の parser/Stage3/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 経路とは別に、StageB (`compiler_stageb.hako`) 側の失敗が selfhost CLI の canary に見えてきている。`[plugin/missing] vm providers not loaded: ["FileBox", "ConsoleBox", "ArrayBox", "MapBox", "StringBox", "IntegerBox"]` はあくまで「プラグイン版コア Box が見つからない」という警告であり、Program(JSON v0) emit の必須条件ではないcorero モードではプラグイン無しでもコンパイラ本体は動ける設計)。現状の StageB 失敗は、プラグイン不足ではなく、別の構文/using/Stage3 周りのエラーが 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 chainStageB → MirBuilder → nyllvmc(crate))に IntArrayCore/MatI64 を統合し、`matmul_core` ベンチを EXE ラインで実行できるようにする。
- 実装は Claude Code 担当、このホストは仕様・構造・診断の整理に専念。
Planned tasks (for Claude Code)
1) Fix MatI64 visibility in StageB / 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 StageB/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 undefinedvariable 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):
- Stage3 local hint added in builder (Undefined variable: local → guide to set NYASH_PARSER_STAGE3=1 / HAKO_PARSER_STAGE3=1).
- 2arg lastIndexOf removed across .hako (prefix + 1arg pattern) — AotPrep no longer trips PyVM.
- CollectionsHot: fixpoint type_table, onthefly 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 callsite 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=<vid> => arr|map via method=<mname>" (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 (optin, defaults OFF)
- Ret block purity verifier: NYASH_VERIFY_RET_PURITY=1 → Return直前の副作用命令をFailFastConst/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 が同一ブロックSSAvmapを優先利用し、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 resultsLLVM/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 healthE0308対応
- 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 actionsAOT集中; 既定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=生ログ)
Wrapup (this session)
- Rust/Hako ownership clarifieddocs/development/normalization/ownership.md。Hako=意味論正規化、Rust=構造/安全。
- Runtime autoload for using.dylibguardedを Runner 初期化に集約。箱名は nyash_box.toml から推論して登録。
- Builder/VM safety: 受信ローカライズを強化LocalSSA/pin/afterPHIs/tail。未定義受信は同一BBの直近 NewBox<Box> で構造回復dev 安全弁)に限定。
- PluginInvoke→BoxCall の過剰な書換えを停止(意味論は Hako 側の methodize に集約)。
- カナリア:
- phase217_methodize_canary.sh → PASSrc=5
- phase217_methodize_json_canary.sh → v1 + mir_call presentMethod が優先、Global は経過容認)。
- phase217_methodize_json_strict.sh を追加selfhostonly 仕上げ用ゲート、現状は StageB 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 の連鎖前出し、fixpoint≤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: 150300%(分散あり) / matmul: 300% / sieve: 200% / linidx: 100% / maplin: 200%
- 次のアクション
1) arraymap/matmul の実MIRprovider or `NYASH_LLVM_DUMP_MIR_IN`)で index SSA 共有の崩れを特定
2) CollectionsHot v2.1: 同一ブロック短窓 get→set で a0 の一致を強制(式キー統一の取りこぼし追加)
3) BinopCSE 小窓 fixpoint 拡張(隣接ブロックまでの `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 一覧へ追記し、昇格時にデフォルト化→古いトグルは段階的に非推奨化とする。
Followups (carried to backlog)
- StageB child の "Unexpected token FN" 修正selfhostfirst/strict ゲート用)。
- Provider 出力の callee を Method へ寄せ、Global 経過容認を段階縮小。
- core_bridge の methodize ブリッジは bringup 用。Hako 既定化後に撤去。
# Next Active Task — Phase 21.16PreOptimization / 最適化前フェーズへ戻す)
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 criteria21.16
- Optimizer OFF でも quick/integration/plugins が安定緑。
- 受信ローカライズの穴が負テストで検知可能dev 安全弁に依存しない)。
- v1/unified は dev プロファイルで常時確認可能(既存トグルで担保)。
Handoff Summary (ready for restart)
- Delegate v1 fixed (providerfirst): 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.
- Selfhostfirst 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 → compilerun rc=5 PASSsemantics
- phase217_methodize_json_canary.sh → schema_version present + mir_call presentMethod preferred; Global tolerated for now
- Dev onegun 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 ABIIntArrayCore/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 (postrestart)
1) Selfhostfirst child parse fixStageB: resolve the known “Unexpected token FN” in compiler_stageb chain; target [builder/selfhostfirst: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 diagnosticonly (OFF) with a removal plan once Hako methodize is default.
# New Active Task — Phase 21.6DualEmit Parity & Cline Readiness
Intent
- ProviderRustと SelfhostHakoで同一の MIR(JSON) を出力できることを確認し、生成時間を計測・比較する。AOTnyllvmc/crateも O0 既定で安定させる。
Whats 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。failfast を監視
Known issue / Action
- Provider 経路tools/hakorune_emit_mir.sh の providerfirstが一部環境で `Program→MIR delegate failed` になることがある。
- 原因: StageB 実行の stdout にログが混在し JSON 抽出が空になるケース。
- 対策(次実装): ラッパを tmp 経由の CLI 変換(`--program-json-to-mir`へフォールバックさせる安全化。selfhostfirst も明示トグルで維持。
Plan (next after restart)
1) tools/hakorune_emit_mir.sh を安全化StageB→tmp→CLI 変換フォールバック。stderr/JSON 分離を強化
2) 代表 4 ケースjson_pp / json_query_min / json_lint / json_queryで dualemit を 5 回実行し、21.6 表に p50/Parity を記入
3) Parity 不一致はカテゴリ化callee 種別/順序/PHI/メタして修正元を特定provider か selfhost
4) AOTnyllvmcO0 の 3 回ベンチを取得、必要なら O1 スポットも取得
Tracking
- 記録台帳: `docs/development/roadmap/phases/phase-21.6/README.md` の表へ随時追記(チェックボックス方式)
Phase 21.6 wrap-up
- Parser(StageB) ループJSONの保守フォールバックで壊れ形のみ復元正常形は素通り
- 代表E2Ereturn/binop/loop/callPASScall は関数化: "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 StageB 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 optin registry canariesstructure/tag observation only; remain optional.
- Added MirBuilderMin (bringup 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 rcbased 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 (JsonFragonly) 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`.
- StageB 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` PASSdev補助・既定挙動不変
Additional updates (dev-only, behavior unchanged by default)
- VM counters wired: `inst_count`nonphi, `compare_count`Compare, `branch_count`Branch
- Print with `NYASH_VM_STATS=1` as `[vm/stats] inst=… compare=… branch=…`
- Microbench harness: fixed ratio print noiseheredoc→oneliner
- EXE canaries: crate backend bringup 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 items21.7
1) docs: phase-21.7-normalization/README.md, CHECKLIST.md追加済み
2) MirBuilderdev: 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 (bugfirst, default OFF aids)
1) Parser(StageB) 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件追加最小ループし、差分が出たらFailFastで停止
4) 代表ケースreturn/binop/method/loopを少数固定し、自己ホスト導線は hakorune スクリプトのみで回す
5) 最適化21.5は全停止。全カナリアが緑になってから再開docs/phase21.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}
---
StageB → MirBuilder → nyllvmccrate EXE— PreOptimization Goal
Status (20251111)
- Loop JsonFrag → crate EXE canary: PASSrc=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.shrc=10
- 並行確認
- emit boxcallv0: 維持PASS
- strlen FASTcrate: 維持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 配下のため、crateny-llvmc経路に直接効くハーネスは内部
- tools/ny_mir_builder.sh は既定で BACKEND=crate を選択し、ny-llvmc を呼ぶllvmlite 直選択は明示時のみ)。
- Goal (pre21.5 optimization): build EXE via crate backend (nyllvmc) from StageB Program(JSON) → MirBuilder MIR(JSON) before focusing on perf. Make EXE selfhosting reliable on this host.
- Why now
- VM selfhost 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 “executeonly” microbench.
- Plan (small, reversible, defaultOFF)
1) Loop JSONFrag purification (no MapBox/newbox)
- Ensure `HAKO_MIR_BUILDER_LOOP_JSONFRAG=1` route emits pure controlflow 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 (optin)
- nyllvmc 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`
- StageB 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 noMapBox check (FAIL 基準)
- strlen FAST EXE RC checkFAST=1 のみタグ観測既定OFFで静音
- EXE parity: minimal StageB 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`StageB→MIR、`tools/ny_mir_builder.sh --emit exe`crate で obj/exe
- Done (recent)
- EXE canaries hardenedenable_exe_dev_env 適用・検証ON・代表は FAIL 基準へ昇格)
- VM runtime counters`NYASH_VM_STATS=1`
- microbench `--exe` 実装ビルド1回→EXEをRUNS回実行。現状、loop/strlen の一般形は crate 未対応で EXE 失敗 → 上記 1)/2) で解消予定。
20251112 UpdatesPHI grouping fix, retafter guards, provider hooks
- LLVM Python backendllvmlite harness/crate 経由)
- Return 合成 PHI を常にブロック先頭に配置PHI グルーピング違反の根治)。
- lowering 入口boxcall/mir_call/safepointで terminator 後の誤挿入を防止継続BBへ移動
- builder 側でブロック命令列は最初の terminatorret/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 / nyllvmc=OKEXE生成
- provider-first + FORCE_JSONFRAG: nyllvmc=OKEXE生成
Open
- provider-first の通常出力に対する純化強化ret ブロックの副作用禁止を徹底)。
- strlen(FAST) の適用強化resolver マーク補強 → IR に nyrt_string_length を反映)。
- Rust→.hako Normalize 移行計画SelfHost First / Freeze準拠
- 方針
- 正規化/置換系は Rust 側から .hakoAotPrep/MirBuilder 直下の新規箱)へ段階移行する。
- Rust 層は最小シーム+安全ガード(互換維持・借用修正・診断)に限定。既定挙動は不変。
- 現状
- 実装済みoptin、既定OFF: NormalizePrintBoxprint→externcall、NormalizeRefBoxref_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 → 警告 → 削除の順)。
- 環境変数の扱い(増えたトグルの将来)
- いまは optin既定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`executeonly 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 taggated. 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=<name>`restrict registry for diagnostics; default unset
Next (short)
- Extend MirBuilderMin to accept minimal compare/binop (structure only) and add 12 min canaries.
- Keep full MirBuilder path unchanged (optin, still SKIP on this host); gradually replace Boxheavy bits with JsonFragonly output.
Next after restart — Focused checklist
- Min Builderif/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/foldIntInt/VarInt/VarVarを境界限定へ置換inline/Lower 双方)
- [x] registry: Min 経路での canary PASS 化(`[min|registry]` 許容)
- [x] 重い using の原因箇所から Box 依存を JsonFrag のテキスト組立へ置換(点で進める)
- **調査完了**: method系lowerarray/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.arraymapgetを Full(JsonFrag) へ固定し、canary を registry 単独 PASS に更新
- [x] registry:return.method.arraymapset/push/lenも順次 Full に移植Min 許容を段階撤去)
- [x] loop lowers は必要時のみ `HAKO_MIR_BUILDER_SKIP_LOOPS=1` を使用既定OFF
- **現状**: loop系lowerは最小MapBox使用のみ、スキップ不要
- Runtimeファイルプロバイダ
- [x] FileBox を ring1 常備coreroとして登録panic 経路の撤廃; pluginonly は従来通り)
- [x] ENV 追補の確認: MODE/ALLOW_FALLBACK/JSON_ONLY の説明を ENV_VARS.md に整合
Env tipsbringup
- 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 緑化Bringup 導線)
- 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 (preOptimization — MirBuilder build line復活まで)
1) phase2034 の ENV 直書きを `enable_mirbuilder_dev_env` に置換(集約)
2) registry 直経路の軽量化JsonFrag 置換)を 1 箇所ずつ移植array/map 周辺から)
3) MirBuilderfirst 導線tools/hakorune_emit_mir.shをトグルで有効化既定OFF
4) FAIL_FAST=1/nycompiler=既定 の条件で緑維持を確認し、dev トグルを段階撤去
5) tests/NOTES_DEV_TOGGLES.md を追加dev トグルの意味・使い所・撤去方針)
Loop 化の小ステップ(構造→置換)
- [x] 最小シーム化: Loop lowerssimple / 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
NextLoop/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/binop3件
- 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.5Optimization 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/binop3件
# Current Task — Phase 21.10LLVM line crate backend print EXE
Status (22.3 wrap)
- 22.3 締め: 最小Cランタイム設計/Cシンボル整合nyash.console.*→nyash_console_*)を反映。
- Hako-first MIR emit は wrapper 経由で安定StageB 出力の RC 混入を抑止、Hako→失敗時は Rust CLI にフォールバック)。
- 緑条件は quick 代表セット + phase2231 canaryrc=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) Ccore 一点通しMap.set+ parity維持既定OFF
- feature+ENV で noop 経路を通し、ON/OFF parity をカナリアで検証。
目的(このフェーズで到達するゴール)
- Hako ParserMVPで 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 perphase 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 は corero 相当で運用。
Quick update — Green Conditions & Togglesquick
- Green baselinequick
- Builder: Hako registry/internal = ON既定。必要時のみ `=0` でOFF。
- hv1 inline PRIMARY = ON直列も緑。必要時のみ `HAKO_PHASE2100_ENABLE_HV1=0`。
- S3 reps: 任意(`NYASH_LLVM_S3=1` かつ LLVM18 環境時。未満は自動SKIP。
- EXEfirst: 任意(`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
- EXEfirst: `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`(受理+警告、一度だけ)
- GateC: 主 `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 (followup tasks)
- SSOT ctx 拡張(段階導入・既定不変)
- [ ] Bridge→Hako 箱で `using_paths`/`cwd` を活用した相対推定のMVPIOはRunner側で制御
- [ ] Runner 側の ctx 渡しを拡張し、パス推定に必要な情報(呼出元ディレクトリ、プロファイル)を追加。
- 受け入れ: パリティcanarymodules命名あり維持 + 代表ケースで `using_paths` 提示時に解決成功既定OFF/トグルONのみ
- TLV shim 観測タグ既定OFF・安全
- [x] `HAKO_TLV_SHIM_TRACE=1` で shim 経由のコールに `[tlv/shim:<Box>.<method>]` を出力(既定は `MapBox.set` のみ)。
- [x] `HAKO_TLV_SHIM_FILTER=MapBox.set` などで対象コールを限定(カンマ区切り可)。
- 受け入れ: canary で `MapBox.set` の単発コール時にタグが現れるfeature有効ENV時、既定OFFではログ増加なし。
22.1 exit (criteria)
- SSOTrelative 推定の仕上げ)
- Unique: `phase2211/ssot_relative_unique_canary_vm.sh` が常時 PASScwd 優先、短時間で終了)。
- Ambiguous+strict: `phase2211/ssot_relative_ambiguous_strict_canary_vm.sh` が PASSstrict=1 時は legacy 委譲)。
- Recursion guard: `HAKO_USING_SSOT_HAKO=1` を含む実行でも無限再帰は発生しない(子プロセスへ SSOT を強制OFFINVOKING=1
- TLV/Extern観測統合
- `HAKO_CALL_TRACE=1` で plugin/extern 双方に `[call:<target>.<method>]` が観測可能。
- `HAKO_CALL_TRACE_FILTER` で method 名/`<target>.<method>` の双方が機能(例: `MapBox.set,env.console.log`)。
- 既定挙動は不変新機能はすべてトグルOFFで無影響
22.2 progress (today) — Core Thinning I
- Docs/plan: docs/private/roadmap/phases/phase-22.2/PLAN.mdT0/T1/T2・ABI契約・受け入れ規準
- C-core crate設計: crates/nyash_c_corefeature c-core=OFF 既定)
- 導線既定OFF: cwrap/c-core タグENV。対象は MapBox.set / ArrayBox.push / ArrayBox.get / ArrayBox.size(len/length)。
- Parity canariesON/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
- Exit22.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 → SKIPllvmlite未導入環境では自動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 <key>` → `[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 <bench|all> [warmup] [repeat]`
- 出力先: `benchmarks/baselines/<bench>.latest.json` と追記 `benchmarks/baselines/<bench>.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 / StageB include)
- VM の include は未対応。StageB → MirBuilder を VM 直で実行する経路は既定OFF検証は optin
- Program(JSON) → MIR(JSON) は Rust CLI 変換GateCを既定とし、wrapper は失敗時に委譲して安定化する。
Hakoruneprimary検証手順・短縮
- 目的: verify_mir_rc の primary を hakovm 側に切替えて最小セットを検証する。
- 手順(推奨は単発・軽量):
- env: `HAKO_VERIFY_PRIMARY=hakovm` を付与して対象スクリプトを実行
- 代表: phase2160 の registry optin canary を個別に実行FailFast が必要な箇所は canary 内で `NYASH_FAIL_FAST=0` を注入済)
- 既定は GateC 維持。切替は optin のテスト/開発用途に限定。
phase2160/run_allselfhost 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 & Registryoptin: docs/private/roadmap/phases/phase-21.6/PLAN.md
- 21.7 — VM mir_call state & Primary Flipguarded: docs/private/roadmap/phases/phase-21.7/PLAN.md
- 21.8 — Hako Check: Refactor & QuickFixMVP: 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 > HC011Box 全体が dead の場合、個別メソッドの unreachable は抑制)。
- 既定の閾値: HC012=warning、HC011=infoCLI 側で 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 の抑制を集約段で適用。
AcceptanceFooting 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 = SKIPUTF8 byte-level 支援待ち)
- CLI: `--rules`/`--skip-rules` で単体/組合せ検証を高速化、JSON_ONLY で純出力。
Phase 21.7 — VM mir_call state & Primary Flipgreen
- T0最小・安定化
- length stateperreceiver可: 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、perrecv差分、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 & QuickFixMVP
- T0 QuickFix--fix-dry-run, text-scope
- HC002 include→using安全置換HC003 using 非引用→引用化HC016 未使用 alias 行削除HC014 空スタブ提案。
- 統一diff---/+++/@@で標準出力。既定OFFdry-run時のみ
- T1 AST Rename同一ファイル
- --rename-box <Old> <New>--rename-method <Box> <Old> <New> を追加。
- 定義は AST span 行で安全置換、呼出は `<Box>.<Method>(` を置換。--fix-dry-run で diff 出力。
- T2 Plan 出力
- --fix-plan で refactor_plan.json と sed 雛形apply_scriptを出力手動レビュー想定
- 既定挙動は不変。適用は別フェーズwrite-capable providerで検討。
Phase 21.9 — DeRustNonPluginChecklist
- [x] Docs: Roadmap docs/development/strategies/de-rust-roadmap.md原則/ゲート/リバータブル)
- [x] Docs: Gap Analysis docs/development/strategies/de-rust-gap-analysis.mdPhase1/2の具体
- [x] Script: Phase0 archive helper tools/de_rust/archive_rust_llvm_backend.shRESTORE.md 自動生成)
- [x] Phase0: Rust LLVM backend を archive/ へ移動(既定ビルド影響なし・リバータブル)
- [ ] hv1_inline optout トグルHAKO_VERIFY_DISABLE_INLINE=1追加任意
- [ ] TLV C shimFFI雛形往復テスト最小
- [ ] 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 Integrationend 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 bugold 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/<rule>/)を 3 ルール分用意
6) 限定 `--fix`HC002/003/500
7) DOT エッジ ONcalls→edges, cluster by box
8) FileBox provider 実装リング0/1/選択ポリシーと最小スモーク追加corero/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/<rule>/ を3ルール分
- [ ] 限定 --fixHC002/HC003/HC500
- B. DOT 改善
- [ ] calls→edges 検証と代表追加ケースcluster は既存を維持)
- C. Ring1/Plugins polish未了のみ
- [ ] Using/modules SSOT 確認modules優先→相対推定→not found=警告/verbose詳細
- [x] Capability introspectionFileBox provider caps(read/write) を Shim から参照→未サポート操作は FailFast
- 実装: `src/runtime/provider_lock.rs:get_filebox_caps()` を追加、`src/boxes/file/mod.rs` で caps.write を参照し明示エラー
- [ ] Provider modes スモークの継続auto/corero/pluginonly + failure injection
Phase 21.6 — Hako MIR Builder MVP & RegistryCOMPLETE
- [x] Registry 経路optinを MirBuilderBox に実装既定OFF
- [x] registry 専用 canary 一式を PASSReturn/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 Flipkickoff
- 目的: VM に最小 stateArray/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 配線と canarypush→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 から取得・FailFastの可否を明示
- [x] スモーク追加: corero(open/read/close)/auto(フォールバック)/plugin-only(厳格)/analyzer(json-lsp純出力) の代表ケース
- [x] Docs 同期: FILEBOX_PROVIDER.md / ENV_VARS.md / hako_check README を最終状態に更新
- [x] フォールバック保証: プラグインのロード失敗だけでなく「create_box 失敗時」にも ring1/corero へ自動フォールバックauto モード。pluginonly では FailFast。
- [x] 失敗時スモーク: ArrayBox の plugin が存在するが creation に失敗するケースを再現し、ring1/corero で生成できることを確認。
FollowupsAnalyzer polish
- [x] HC012 JSON 安定化using alias 依存排除、itoa ローカル化)
- [x] HC017 一時 disableUTF8バイト操作対応後に復活
- [x] using の不要宣言削除Str aliasの掃除使用ファイル以外から撤去
- [x] ルール実行エラーの可視化stderr ログを明確にrule名・ファイル名・行
- [x] テスト運用のENVまとめを README に明示Disable Plugins / FactoryPolicy / Disable NyCompiler / JSON_ONLY
Phase 21.4 — Completion
- FileBox SSOTprovider_lock / provider_registry / CoreRo / BoxShim / feature builtin-filebox: COMPLETE
- Analyzer 安定化HC012 修復、HC017 skip、ENV明文化、json-lsp純出力: COMPLETE
Phase 22 — Proposed Focus
- Unicode SupportHC017 復活): ByteArrayBox / UTF8 encode/decode helpers / 文字プロパティ
- Plugin 完全化: dynamic plugin.soでの create_box 安定化、bid/registry の暫定停止解除
- ENV Migration 完了: 旧ENV 警告の全面展開→削除
- Error Logging 強化: error() extern 経由の統一ロギング、ルール/テキスト系への横展開
Completed — FileBox Provider WiringC: 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 を readonly で実装threadsafe
- 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 errorline表示の不整合。FileBox配線とは無関係。HC012 JSON安定化の一環で対応予定。
Next (handoff to Claude Code)
- HC012 JSON 安定化cli.hako
- jsonlsp時は stdout を純JSON、ログは stderr の規約徹底fmt判定ガードの再確認
- parse error の発生箇所を修正(構文境界/コメント/Stage3トグル周り
- `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/選択ポリシーと最小スモーク追加corero/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 失敗時は FailFast
- 決定性とハッシュ
- いまは size 決定性を優先hash はオプション。TargetMachine へ移行後に `NYASH_HASH_STRICT=1` を既定 ON に切替予定。
Nearterm TODO21.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 の安定化を維持しつつ、CAPI の純API移行nyllvmc 経由を段階縮小)計画を作成
- reps の決定性3×を phase2100 aggregator にも追加検討
- Hakofirst 方針Rust変更最小化
- Rust は Kernel/ABIシンボル/リンク)に集中。解釈/解決は Hako 側の Adapter/Policy に段階移行。
- dev は Adapter 登録や byname fallback を許容トグル、prod は Adapter 必須FailFast
Next Steps (immediate)
1) A仕上げ: HC012 line 精度span_line/ README 追随 / CLI I/F最終確認
2) BParser強化: tokenizer 文字列エスケープ/位置情報、parser_core 複数行・alias 抽出
3) C可視化: DOT 改善box cluster / 孤立ノード)と quick スモーク追加
Context Compression Notes
- A診断I/F抑制は実装済み。文字列診断→型付き変換あり。
- BAST: 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: NonASCII Quotes — “ ” 等の fancy quotes を検出し ASCII へ置換提案
- HC018: Toplevel local in prelude — 先頭 `local` を検出merge 前提のクリーンアップ漏れ)
- HC021: Analyzer IO Safety — CLI 経路での FileBox 使用を警告(`--source-file` 利用を提案)
- HC022: Stage3 Gate — while/for を含む .hako を Nyash VM へ流す危険の検出gate フラグ提示)
- HC031: Brace Heuristics — `{`/`}` の粗い不整合検出(早期警告)
5) `--format json-lsp` の最小実装(既存配線に診断配列を流し込む)
Previous Achievement
- ✅ Phase 20.44 COMPLETEprovider emit/codegen reps 緑)
- ✅ Phase 20.4546: PRIMARY 切替のための品質・整流env_bool・MethodAliasPolicy・MirBuilder prefer reps の整備)
- ✅ Phase 20.48 COMPLETEDeterministic Bootstrap & Parity: run_all 緑 / repeat 3回一致
- ✅ Phase 20.49 COMPLETESSOT & 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) README20.48)へ Quick Verify の項目拡張typeop_check/cast と multirecv を追記済)
Close Ready20.48
- 条件:
- s1s2s3_repeat_*const/compare/logical/typeopが3回一致
- PRIMARY repsIf/Logical/Loop/Array/Map/TypeOpが PASSnofallback
- run_allphase2048が緑S3 は LLVM18 環境で自動、NYASH_LLVM_S3=0 で明示無効)
Hotfix Plan — Using/Prelude Unification (SelfHost)
- 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 経路に入れないFailFast
Action Items (20.38)
- P1 CABI ブリッジ既定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 反映
- phase20.38 のトグル/受け入れ条件/撤去予定のシムを反映。φ entry SSOT は IR 完了後に更新。
- extern タグ用シムの現状と撤去条件hv1 inline 安定後に除去)を明記。
Acceptancephase 21.2
- HAKO_CAPI_PURE=1 で repsternary=44 / map=1が PASS、各3回一致obj/rc
- 21.1 repsCAPI 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` で CAPI 経路を有効化。
- `libhako_llvmc_ffi.so` を dlopen し、`hako_llvmc_compile_json` を呼び出して `.o` を生成。
- plugins feature 未有効時は明示エラーFailFast
---
# Next Task — Phase 20.49Resolver SSOT & Compiler Bringup
目的(このフェーズで到達するゴール)
- using/プレリュード統合の SSOT を dev/prod で確定include は prod で非対応)
- dev では toml なしの最短導線(相対パス using / preincludeで“すぐ動く”を保証
- コンパイラ自走に必要な hv1 inline の最小カバレッジを reps で固定
Focus20.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` で実行
Acceptance20.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: perrecv size state 実装trace。
- test_runner: HAKO_VERIFY_V1_FORCE_HAKOVM=1 を追加hv1 ラッパーで v1 実行)。
- hv1 inline reps: 代表を整備perrecv second は暫定 rc=1
Changes (this pass)
- 20.44 を ✅ COMPLETE にマーク
- 20.47/20.48 のフェーズ文書を追加(自己ホストの工程と受け入れを明文化)
- 拡張子統一(.hako/.nyash 等価): 仕様の明文化 + 実装反映
- FailFastHako in Nyash VM既定OFFHAKO_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 が MiniVM の rc に反映)
- quick/core phase2047: Using alias 代表を追加
- tools/smokes/v2/profiles/quick/core/phase2047/using_alias_selfhost_vm_entry_canary_vm.shPASS
- alias 解決の実行確認crossbox static call → rc=0
- tools/smokes/v2/profiles/quick/core/phase2047/using_alias_string_helpers_canary_vm.shPASS
- shared/helpers の alias 解決を実行確認(静的呼び出し)
- SelfHosting S1/S2builder 直行)
- gen: tools/selfhost/gen_v1_from_builder.shemit_return_int2(42) → v1 JSON 出力)
- canary: tools/smokes/v2/profiles/quick/core/phase2047/selfhost_s1_s2_from_builder_canary_vm.shPASS
- provider 雛形: tools/selfhost/gen_v1_from_provider.shCABI 連携は段階導入)
- Provider v1 強制(最終化)
- src/host_providers/mir_builder.rs: emit前後で v1 を強制NYASH_JSON_SCHEMA_V1=1 一時設定 + 読み戻し時の v1 ラップ)
- hv1 inline 実装の強化
- Array と Map の perreceiver サイズ状態を分離(独立マップ: arr/map
- MapBox: set→size を rc で検証可能first=1/second=0 reps と整合)
- Docs 更新
- phase20.48 の README に “Quick Verify” セクションを追加run_all と S3 トグルの手順)
- canary 追加: tools/smokes/v2/profiles/quick/core/phase2047/provider_v1_shape_canary_vm.shPASS
- SSOT の徹底strip.rs 連携)
- src/runner/modes/common_util/resolve/strip.rs: is_path 判定と dev-file 候補判定を SSOT に寄せpath_util
- S1/S2 拡張 repsbuilder
- 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.shPASS/環境で整合)
- S3 repsllvmlite, NyRTリンク, 実行)
- phase2047/s3_link_run_llvmlite_compare_{cfg,ret}_canary_vm.shrc=1
- phase2047/s3_link_run_llvmlite_const42_canary_vm.shrc=42
- phase2047/s3_link_run_llvmlite_branch_ret_44_canary_vm.shrc=44
- 生成器: tools/selfhost/gen_v1_from_builder_branch_ret_44.sh
- PRIMARY nofallback repshv1 inline
- phase2047/primary_no_fallback_v1_const_rc_canary_vm.shrc=42
- phase2047/primary_no_fallback_v1_compare_branch_rc_canary_vm.shrc=1
- phase2047/primary_no_fallback_v1_jump_rc_canary_vm.shrc=7
- S1/S2 拡張 repsbuilder
- 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.shPASS/環境で整合)
- S3 代表llvmlite, NyRTリンク, 実行)
- phase2047/s3_link_run_llvmlite_compare_cfg_canary_vm.shNYASH_LLVM_S3=1 で有効、SKIPガードあり
- SelfHosting 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 (Step1)
- Loop lowerssimple/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 を確認。
// Step2/3 generalization (count_param)
- step 一般化: Int 2,3,… と Local Var 由来の step を受理。'-' は負の step に正規化Add + 負値)。
- 降順対応: i > / i >= limit を cmp=Gt/Ge で build2 へ伝達。
- init/limit 起源の拡大: Local VarInt由来を逆引きで受理。
- Canaries: step=2 / step(Local) / 降順('-'/ limit(Local) / init(Local) を追加し PASS。
// Step4部分 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 追加予定。
Whats green (20.34)
- Loop/PHI unify (phi_core) in JSON v0 bridge — unified path used (toggle exposed).
- Program(JSON v0) PHItrace 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
- MiniVMhakovmrc==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=0verify 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 helpersbinop_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=1v1 FLOW 実行)
- HAKO_V1_EXTERN_PROVIDER=1Hako 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=1resolver dev
How to run (quick)
- Build: `cargo build --release`
- Program v0 PHItrace (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 canaries20.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`
MiniVM policy20.34
- 実装は維持alias/ret/phi 最小系を今後整える)。ただし quick の canary は Core へ寄せて緑化。
- 20.36 で verify primary を hakovm に段階的に切替、MiniVM green を進める。
Next (20.35 — scoped; behavior unchanged)
1) MIR JSON v1 loader expansionMethod/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, CABI scaffold)
- Verify primary 切替(段階): hakovm → Core fallback
- preinclude 非推奨化quick から撤去)
- MiniVM の最小状態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
- CABI 設計docs + ヘッダ雛形)
Known open itemstracked to 20.36
- MiniVM: using/alias の推移解決selfhost.vm.helpers.* 連鎖)
- MiniVM: 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 & CABI)
1) HakoruneExternProviderBox を拡張warn/error/emit の最小タグ/空文字挙動)— 完了
2) HAKO_V1_EXTERN_PROVIDER=1 の canary 追加(構造緑固定)— 完了
3) CABI 導線の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 linksperphase 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 `"" + <int>` 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).
Whats 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 phase2043.
- 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 安定化internallower ラッパー側で MIR を `/tmp` に保存→ハーネスが読むpipe 揺れを回避)。
5) Delegate route20.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調査メモ)
- StageB emit を拡張FuncScannerBox/StageB 本体)して `static box` メソッドを defs に追加。暗黙 `me` もパラメータへ補完。
- Rust 側 JSON v0 ブリッジに `ExprV0::Null` variant を追加し、StageB が吐く Null リテラルを受理。
- `launcher.hako` の `while` を `loop` 構文へ置換StageB パーサ互換)。
- 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 & StageB 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 済みの `<Box>.<method>/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 <Name>` をログ出力できるようにした(デフォルト 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 定義不足StageB 再入ガードに env を使っている部分)だけが残っている状態まで収束した。
- 今後のタスクPhase 25.1d 続き):
- StageB の再入ガードを `env.set/2` ではなく Box 内 stateフィールドで持たせるか、あるいは `env.set/2` を StageB 実行環境向けに Rust 側 extern として提供するかを検討・実装する。
- `NYASH_MIR_COMPILE_TRACE` ログを活用して、今後も MIR builder 側の深い再帰や相互再帰を早期に検知できるようにする(特に StageB / 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` など)。
- StageB / Stage1 / 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 不足が報告されている。
- StageB 最小ハーネス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` を使って、StageB / Stage1 / selfhost 用テストの中で v2 経路を段階導入し、`mir_stage1_using_resolver_full_collect_entries_verifies` や StageB 最小ハーネスで見えている PHI 不整合を構造的に解消する。
- 25.1e では挙動変更を避けるため、デフォルトは現状どおり legacy 経路のままにしつつ、v2 のみ optin で試験運用し、緑になったところから徐々に責務を移す。
- やること25.1e TODO メモ):
- LoopForm v2 テストモード:
- `mir_stage1_using_resolver_full_collect_entries_verifies` に `NYASH_LOOPFORM_PHI_V2=1` 用のサブテストを追加し、v2 経路の SSA/PHI 状態を検証する。
- StageB 最小ループ(`_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 経路で Stage1 / StageB の代表ループが MirVerifier 緑になる」ことを目標に、小さなテスト+小さな修正で Loop/PHI 周りを仕上げる。
- Rust 側の現状:
- MirBuilder / LoopBuilder 側で見えていたローカル SSA 違反・StageB ArgsBox まわりの未定義レシーバ・me-call 再帰バグなどは、25.1d までの修正+今回の StringBox plugin 実装で一通り解消済み。
- `build_local_statement` によるローカル SSA fix`src/mir/builder/stmts.rs`)。
- `CalleeBoxKind` + `CalleeGuardBox` による StageB / Stage1 静的 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 違反は出ていない。
- 一方で、StageB 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 のままで、Stage1 JSON v0 / MIR(JSON v0) に対する exit PHI 生成ロジックはまだ未実装。
- ここは「Stage0/Stage1 の JSON ブリッジ経路を LoopForm v2 の SSOT に揃える」ための別タスクとして扱う25.1e 後半〜25.1f 想定):
- `.hako` 側 LoopSSA には、Rust 側 LoopForm v2 と同じ Carrier/Pinned 規約・ヘッダ/exit 形を JSON レベルで再現するロジックを実装する。
- ただし、StageB Test2 の現在の `phi pred mismatch` は Rust MIR ループの問題として先に 25.1e で根治し、その後で `.hako` LoopSSA を同じ規約に寄せる二段構えにする。