2025-12-08 04:00:44 +09:00
# JoinIR Architecture Overview (2025‑ 12‑ 08)
2025-12-07 21:02:20 +09:00
このドキュメントは、JoinIR ライン全体( Loop/If lowering, ExitLine, Boundary, 条件式 lowering) の
「箱」と「契約」を横串でまとめた設計図だよ。selfhost / JsonParser / hako_check など、
どの呼び出し元から見てもここを見れば「JoinIR 層の責務と流れ」が分かるようにしておく。
変更があったら、Phase ドキュメントではなく **このファイルを随時更新する** 方針。
---
2025-12-12 06:06:39 +09:00
## 0. 読み方ガイド( Reader's Guide)
このファイルは情報量が多いので、「何を知りたいか」で読む場所を分けると楽だよ:
2025-12-13 03:47:54 +09:00
- 注意: 本文のセクション番号は歴史的経緯で重複することがあるため、参照は「見出し名」を基本にする。
2025-12-12 06:06:39 +09:00
- **不変条件だけ押さえたいとき**
- セクション `1. 不変条件( Invariants) ` を読む。
- JoinIR 全体で絶対に守るルール( ValueId 領域 / PHI 契約 / Fail‑ Fast) がここにまとまっている。
- **箱ごとの責務と流れを掴みたいとき**
- セクション `2. 主な箱と責務` を読む。
- LoopPattern / Pattern lowerer / ConditionEnv / ExitLine / Boundary など、構造箱・判定箱・生成箱の入口がここ。
- **Normalized JoinIR( JoinIR→JoinIR 正規化)を知りたいとき**
2025-12-13 03:47:54 +09:00
- 見出し `JoinIR 第1章: 基盤完成サマリ` と
小節 `Structured vs Normalized` ( Structured/Normalized の関係)を読む。
2025-12-12 06:06:39 +09:00
- 詳細な完成サマリは `PHASE_43_245B_NORMALIZED_COMPLETION.md` にまとまっているので、そちらも合わせて参照してね。
- **JsonParser/selfhost のループ状況を見たいとき**
2025-12-13 03:47:54 +09:00
- 見出し `JoinIR 第1章: 基盤完成サマリ` 内の JsonParser/selfhost 表と、`phase181-jsonparser-loop-roadmap.md` を見る。
2025-12-12 06:06:39 +09:00
- **各 Phase ごとの細かい経緯・ログが欲しいとき**
- `docs/development/current/main/phase*-*.md` 系の Phase ドキュメントを読む。
- 本ファイルの `3.x` にある Phase ロードマップは「索引」としての位置づけで、詳細は各 Phase doc 側が SSOT だよ。
---
2025-12-13 03:47:54 +09:00
## 0.1 用語( routing / fallback / fail-fast)
本文では「fallback」という単語が文脈でぶれやすいので、先に用語を固定する:
- **routing**: JoinIR Core 内での正規な経路選択( Pattern ルータ、if-sum mode ↔ legacy P3 など)。理由が分かる形でログ/タグを付ける。
- **soft fallback**: 任意箱( pre-validation / optional optimizer) が失敗したときに、同等意味論の別 JoinIR 経路へ退避すること( JoinIR Core 外へは出ない)。
- **prohibited fallback**: 非 JoinIR への退避(例: LoopBuilder) ・サイレント退避・契約違反の握りつぶし。
2025-12-07 21:02:20 +09:00
## 1. 不変条件( Invariants)
JoinIR ラインで守るべきルールを先に書いておくよ:
1. **JoinIR 内部は JoinIR ValueId だけ**
2025-12-13 03:47:54 +09:00
- JoinIR lowering が発行する `JoinInst` の `ValueId` は JoinValueSpace の領域( Param/Local) のみを使う。
- `alloc_param()` ( Param 100– 999) / `alloc_local()` ( Local 1000+)が SSOT。
- 多くの lowerer が使う `alloc_value()` は「実装上の別名( Local を増やす)」として扱う(概念上は `alloc_local()` )。
- Rust/MIR 側の ValueId( 例: `builder.variable_map` ) は、JoinInst の operand としては持ち込まない。
- 例外(ただし JoinInst には出現しない): LoopHeader PHI dst は merge(MIR) 段階で確保される MIR ValueId で、JoinValueSpace は `reserve_phi()` で衝突防止のマークだけを行う。
2025-12-07 21:02:20 +09:00
2. **host ↔ join の橋渡しは JoinInlineBoundary 系だけ**
- host から JoinIR への入力(ループ変数 / 条件専用変数)は
- `JoinInlineBoundary.join_inputs + host_inputs`
- `JoinInlineBoundary.condition_bindings` ( ConditionBinding)
だけで接続する。
- 出力(キャリアの出口)は `JoinInlineBoundary.exit_bindings` に一本化する。
2025-12-08 04:00:44 +09:00
3. **LoopHeader PHI を SSA の単一源泉にする**
- ループ変数とキャリアは **LoopHeaderPhiBuilder/LoopHeaderPhiInfo** でヘッダ PHI を作り、これを「現在値」の SSOT にする。
- exit 用の PHI も組むが、変数再接続や expr_result 収集はヘッダ PHI を経由して行う( SSA‑ undef 防止)。
4. **式としての戻り値とキャリア更新を分離する**
2025-12-07 21:02:20 +09:00
- 「ループが式として値を返す」ケース(例: `let r = loop_min_while(...)` )の出口は **exit_phi_builder** が扱う。
- 「ループが状態更新だけする」ケース(例: `trim` の `start/end` )の出口は **ExitLine( ExitMeta / ExitBinding / ExitLineReconnector) ** だけが扱う。
2025-12-13 18:46:07 +09:00
- promoted carriers( 例: DigitPos/Trim の `ConditionOnly` )は exit PHI から除外し、ExitLineReconnector は LoopState のみを reconnect する( Phase 81 で E2E 検証)。
- 参照: `docs/development/current/main/phase81-pattern2-exitline-contract.md`
2025-12-07 21:02:20 +09:00
2025-12-08 04:00:44 +09:00
5. **ループ制御 vs 条件式の分離**
2025-12-07 21:02:20 +09:00
- ループの「形」( Pattern1– 4, LoopFeatures) は control-flow 専用の箱が担当。
- 条件式(`i < len && (ch == " " || ch == "\t")` 等)は **BoolExprLowerer / condition_to_joinir** が担当し、
ループパターンは boolean ValueId だけを受け取る。
2025-12-08 04:00:44 +09:00
6. **Fail‑ Fast**
2025-12-07 21:02:20 +09:00
- JoinIR が対応していないループパターン / if パターンは、必ず `[joinir/freeze]` 等で明示的にエラーにする。
2025-12-08 04:00:44 +09:00
- LoopBuilder 等へのサイレントフォールバックは禁止。
2025-12-07 21:02:20 +09:00
2025-12-08 18:36:13 +09:00
7. **Param の役割( ParamRole) を分ける**
- JoinIR 側で扱うパラメータは概念的に 3 種類に分かれる:
- 条件専用( Condition param) : 継続条件や break 条件だけに使う値
- キャリア( Carrier param) : ループ状態( pos/result など)として更新される値
- 式結果( Expr param) : ループが式として返す値
- ExitLine / Header PHI / InstructionRewriter は **Carrier param だけ** を対象にし、Condition/Expr param は上書きしない。
- 現状は ConditionBinding/ExitMeta/JoinFragmentMeta で役割を区別しており、将来 ParamRole enum として明示する予定。
8. **LoopHeader PHI dst は予約領域(上書き禁止)**
2025-12-09 16:19:08 +09:00
- LoopHeaderPhiBuilder が生成したヘッダ PHI の dst ValueId は「現在のループ値」の SSOT として扱い、
2025-12-08 18:36:13 +09:00
BoundaryInjector や InstructionRewriter が `Copy` などで二度書きすることを禁止する。
- merge ラインでは「ヘッダ PHI dst に対する新しい定義が出てきたら debug モードで panic する」ことで契約違反を早期検出する。
2025-12-09 16:19:08 +09:00
9. **ParamRole の不変条件( Phase 200-A 追加)**
- **Condition 役のパラメータは「PHI dst にしてはいけない」**
- 理由: 条件専用変数はループ内で更新されない(例: `digits` in `_atoi()` )
- LoopHeaderPhiBuilder は Condition 役の変数に対して header PHI を生成しない
- **Condition 役のパラメータは「ExitLine の対象にも入れない」**
- 理由: 条件専用変数はループ外で使われない(ループ内でのみ参照)
- ExitLineReconnector は Condition 役の変数を exit_bindings から除外
- **ParamRole の分類**:
- `LoopParam` : ループ制御変数(例: `i` in `loop(i < len)` )→ header PHI + exit_bindings
2025-12-10 00:01:53 +09:00
- `Condition` : 条件専用変数(例: `digits` in `digits.indexOf(ch)` )→ condition_bindings のみ
- `Carrier` : 状態更新変数(例: `sum` , `count` )→ header PHI + exit_bindings
- `ExprResult` : ループ戻り値 → exit_phi_builder で処理
10. **JoinIR Core は常時 ON**
2025-12-13 03:47:54 +09:00
- LoopBuilder は物理削除済み。JoinIR を OFF にする経路や prohibited fallback( 非 JoinIR への退避)は存在しない。
2025-12-10 00:01:53 +09:00
- `NYASH_JOINIR_CORE` は deprecated( 0 を指定しても警告して無視) 。JoinIR の OFF トグルは提供しない。
2025-12-09 16:19:08 +09:00
2025-12-10 08:58:37 +09:00
11. **Phase 220: P3 if-sum の ConditionEnv 統合完了**
- **LoopBuilder へのフォールバック経路は Phase 187 で完全削除済み**。
- **P3 if-sum には ConditionPatternBox + ConditionEnv が必須**:
- 単純条件(`var CmpOp literal` )のみ if-sum mode へルーティング( Phase 219-fix) 。
2025-12-13 03:47:54 +09:00
- 複雑条件(`i % 2 == 1` 等)は legacy P3 経路へ routing( JoinIR Core 内)。
2025-12-10 08:58:37 +09:00
- **Phase 220-D で loop 条件の変数サポート完了**:
- `loop(i < len)` のような変数条件を ConditionEnv で解決。
- `extract_loop_condition()` を ValueOrLiteral 対応に拡張。
- **Phase 220 で if-sum の expr-result exit contract が P2 と揃った**:
- ExprResultResolver Box で expr_result routing を統一化( Phase 221-R) 。
- phase212_if_sum_min.hako → RC=2 達成。
2025-12-13 03:47:54 +09:00
12. **Lexical scope( Phase 68) を host 側で実在化する**
- JoinIR の正当性は「上流の束縛モデル」が壊れていないことを前提にする。
- MIR builder は `{...}` ( Program) / `ScopeBox` を lexical scope として扱い、`local` shadowing を正しく復元する。
- “未宣言名への代入はエラー” を SSOT( quick-reference/LANGUAGE_REFERENCE) に揃えて Fail-Fast 化する。
- 参照:
- `docs/development/current/main/phase67-mir-var-identity-survey.md`
- `docs/reference/language/variables-and-scope.md`
- 次の焦点( Phase 73+) :
- JoinIR lowering の `ScopeManager` を「名前ベース」から「BindingId ベース」に段階移行し、shadowing/束縛同一性を JoinIR 側でも安全に扱えるようにする。
- 参照: `docs/development/current/main/phase73-scope-manager-design.md`
2025-12-13 17:26:15 +09:00
- promoted carriers( DigitPos/Trim) の “synthetic name” 問題を BindingId で接続する( dev-only) :
- 参照: `docs/development/current/main/phase78-bindingid-promoted-carriers.md`
- 次の配線計画( P3/P4 拡張):
- 参照: `docs/development/current/main/phase80-bindingid-p3p4-plan.md`
2025-12-13 03:47:54 +09:00
13. **Ownership/Relay( Phase 56– 71) : carrier/capture/relay を契約化する( dev-only) **
- `OwnershipPlan` は carriers/captures/relay_writes の SSOT として使い、混線を Fail-Fast で検出する。
- multihop relay は plan 層では受理できるが、runtime 側で未対応の間は標準タグで Fail-Fast に落とす( Phase 70-A) 。
- 標準タグ: `[ownership/relay:runtime_unsupported]`
- `OwnershipPlanValidator` を箱として隔離し、Pattern lowerer 側から再利用できる形にする( Phase 71-Pre) 。
- 参照:
- `docs/development/current/main/phase56-ownership-relay-design.md`
- `docs/development/current/main/phase65-ownership-relay-multihop-design.md`
- `docs/development/current/main/phase70-relay-runtime-guard.md`
2025-12-07 21:02:20 +09:00
---
2025-12-09 19:39:01 +09:00
## 1.9 ValueId Space Management (Phase 201)
JoinIR の ValueId 割り当ては **JoinValueSpace** で一元管理され、3つの領域に分離されているよ:
### 1.9.1 ValueId 空間のダイアグラム
```
JoinValueSpace Memory Layout:
2025-12-13 03:47:54 +09:00
0 100 1000 LOCAL_MAX
2025-12-09 19:39:01 +09:00
├──────────┼──────────┼──────────────────────────┤
│ PHI │ Param │ Local │
│ Reserved│ Region │ Region │
└──────────┴──────────┴──────────────────────────┘
PHI Reserved (0-99):
2025-12-13 03:47:54 +09:00
- LoopHeader PHI dst 用の「予約マーカー領域」( JoinValueSpace 側の契約)
- `reserve_phi(dst)` で「この MIR ValueId を PHI dst として予約した」というマークだけを行う( JoinValueSpace は PHI dst を割り当てない)
- 注: 実際の PHI dst は host MirBuilder が割り当てるため、0-99 に入ることは “保証” ではない( Phase 72 観測: `docs/development/current/main/phase72-phi-reserved-observation.md` )
2025-12-09 19:39:01 +09:00
Param Region (100-999):
- alloc_param() で割り当て
- 使用箇所: ConditionEnv, CarrierInfo.join_id, CapturedEnv
2025-12-13 03:47:54 +09:00
Local Region (1000..=LOCAL_MAX):
2025-12-09 19:39:01 +09:00
- alloc_local() で割り当て
- 使用箇所: Pattern lowerers (Const, BinOp, etc.)
```
### 1.9.2 JoinValueSpace の役割
- **単一の真実源 (SSOT)**: すべての JoinIR ValueId 割り当てを一箇所で管理
- **領域分離**: Param ID、Local ID、PHI dst が決して重複しない
- **契約検証**: デバッグモードで違反を早期検出
- **後方互換性**: 既存 API は継続動作
2025-12-13 03:47:54 +09:00
- 注意: `LOCAL_MAX` はデバッグ/検証用の上限。概念上は Local 領域は拡張可能で、必要なら上限を増やす。
2025-12-09 19:39:01 +09:00
### 1.9.3 各コンポーネントと ValueId 領域の対応表
| コンポーネント | 使用領域 | 割り当て方法 | 用途 |
|--------------|---------|------------|------|
| ConditionEnv | Param (100-999) | `alloc_param()` | ループ条件変数の JoinIR ValueId |
| CarrierInfo.join_id | Param (100-999) | `alloc_param()` | キャリア変数の JoinIR ValueId |
| CapturedEnv | Param (100-999) | `alloc_param()` | 関数スコープ変数の JoinIR ValueId |
| Pattern 1 lowerer | Local (1000+) | `alloc_local()` | 中間値( Const, Compare, etc.) |
| Pattern 2 lowerer | Local (1000+) | `alloc_local()` | 中間値( Const, BinOp, etc.) |
| Pattern 3 lowerer | Local (1000+) | `alloc_local()` | 中間値( PHI, Select, etc.) |
| Pattern 4 lowerer | Local (1000+) | `alloc_local()` | 中間値( Select, BinOp, etc.) |
| LoopHeaderPhiBuilder | PHI Reserved (0-99) | `reserve_phi()` | PHI dst ID 保護(上書き防止) |
### 1.9.4 設計原則
1. **領域の固定境界**
- 明確な境界( 100, 1000) で領域を分離
- デバッグが容易( ValueId を見ればどの領域か一目瞭然)
- アロケータ間の調整不要
2. **reserve_phi() vs alloc_phi()**
2025-12-13 03:47:54 +09:00
- LoopHeader PHI dst は merge(MIR) 段階で確保される **MIR 側 ValueId** ( JoinInst の ValueId とは世界が違う)。
- JoinValueSpace は PHI dst を「割り当てる」箱ではなく、`reserve_phi(dst)` で予約マークし、JoinIR Param/Local の割当と衝突しないようにする。
- `reserve_phi()` はマーカーのみ(「この ID を JoinIR 側で上書き/再利用するな」という契約)。
2025-12-09 19:39:01 +09:00
3. **value_id_ranges.rs との関係**
- `value_id_ranges.rs` : **モジュールレベルの分離** ( min_loop, skip_ws 等の各モジュールに大きな固定範囲を割り当て)
- `JoinValueSpace` : **lowering 内部の分離** ( param vs local vs PHI)
- 両者は相補的な役割
2025-12-10 00:01:53 +09:00
### 1.9.5 Phase 205: 領域契約の検証強化
**追加された Box-First 機能**:
1. **衝突検出( debug-only) **
- 全ての割り当てられた ValueId を追跡(`allocated_ids: HashSet<u32>` )
- 重複割り当てを即座に検出し panic( Fail-Fast 原則)
- `check_collision()` で実装
2. **領域検証( debug-only) **
- `verify_region(id, expected_region)` で ValueId が期待される領域にいるか検証
- 違反時は明確なエラーメッセージと修正ヒントを提供
- 例: "ValueId(500) is in Param region, expected Local. Hint: Use alloc_local() for JoinIR values"
3. **RegionVerifier Box**
- 場所: `src/mir/builder/control_flow/joinir/merge/mod.rs::verify_valueid_regions()`
- 責務: merge 時に boundary と loop_info の ValueId 領域契約を検証
- 検証項目:
- 全ての `boundary.join_inputs` が Param 領域( 100-999) にいる
- 全ての `condition_bindings[].join_value` が Param 領域にいる
2025-12-13 03:47:54 +09:00
- 全ての `carrier_phis[].phi_dst` が「JoinIR 側の Param/Local と衝突しない」こと
- 現状は “偶発的な非衝突( MirBuilder が低番、JoinValueSpace が 100+)” で安定している( Phase 72 観測: `docs/development/current/main/phase72-phi-reserved-observation.md` )。
- 検証強化の是非は Phase 72 を SSOT にして別フェーズで決める(ここで前提を固定しない)。
2025-12-10 00:01:53 +09:00
4. **明示的な領域定数**
```rust
pub const PHI_RESERVED_MIN: u32 = 0;
pub const PHI_RESERVED_MAX: u32 = 99;
pub const PARAM_MIN: u32 = 100;
pub const PARAM_MAX: u32 = 999;
pub const LOCAL_MIN: u32 = 1000;
pub const LOCAL_MAX: u32 = 100000;
```
**Fail-Fast 原則の実装**:
- 領域違反は即座に panic( デバッグモード)
- フォールバックやサイレント修正は一切行わない
- エラーメッセージに具体的な修正方法を含める
詳細は `src/mir/join_ir/lowering/join_value_space.rs` と `phase205-valueid-regions-design.md` を参照。
2025-12-09 19:39:01 +09:00
---
2025-12-07 21:02:20 +09:00
## 2. 主な箱と責務
### 2.1 Loop 構造・検出ライン
- **LoopFeatures / LoopPatternKind / router**
- ファイル:
- `src/mir/loop_pattern_detection.rs`
- `src/mir/builder/control_flow/joinir/patterns/router.rs`
2025-12-08 04:00:44 +09:00
- `src/mir/builder/control_flow/joinir/patterns/ast_feature_extractor.rs`
2025-12-07 21:02:20 +09:00
- 責務:
2025-12-08 04:00:44 +09:00
- AST から break/continue/if‑ else PHI などの特徴を抽出( ast_feature_extractor) 。
- `classify(&LoopFeatures)` で Pattern1– 4 に分類し、テーブル駆動の `LOOP_PATTERNS` でルーティング。
- ルータ順序は P4(continue) → P3(if‑ phi) → P1(simple) → P2(break) で固定(優先度フィールドはデバッグ用)。
2025-12-07 21:02:20 +09:00
- **Pattern Lowerers (Pattern1– 4)**
- ファイル例:
2025-12-08 04:00:44 +09:00
- `pattern1_minimal.rs` ( Simple while)
- `pattern2_with_break.rs` ( break 付き / Trim 昇格パスを含む)
- `pattern3_with_if_phi.rs` ( if‑ phi キャリア)
- `pattern4_with_continue.rs` ( continue を Select で表現)
2025-12-07 21:02:20 +09:00
- 責務:
- LoopScopeShape / AST / LoopFeatures を入力として JoinIR の `JoinModule` を構築。
- `JoinFragmentMeta{ expr_result, exit_meta }` を返し、出口情報を ExitLine に渡す。
- host/MIR の ValueId は一切扱わない( JoinIR ローカルの ValueId のみ)。
2025-12-08 04:00:44 +09:00
- **Scope / Env Builders**
- `loop_scope_shape_builder.rs` : ループ本体ローカルの収集、LoopScopeShape 統一生成。
- `condition_env_builder.rs` : 条件専用変数の環境と ConditionBinding を一括構築。
2025-12-07 21:02:20 +09:00
- **CommonPatternInitializer** (Phase 33-22)
- ファイル: `src/mir/builder/control_flow/joinir/patterns/common_init.rs`
- 責務:
- 全 Pattern 共通の初期化ロジック統一化(ループ変数抽出 + CarrierInfo 構築)。
2025-12-08 04:00:44 +09:00
- 全パターンで boundary.loop_var_name を確実に設定し、SSA‑ undef を防ぐ。
2025-12-07 21:02:20 +09:00
2025-12-08 19:51:04 +09:00
- **PatternPipelineContext** (Phase 179-B)
- ファイル: `src/mir/builder/control_flow/joinir/patterns/pattern_pipeline.rs`
- 責務:
- 全 Pattern の前処理結果を格納する「解析済みコンテキスト箱」。
- CommonPatternInitializer + LoopScopeShapeBuilder の結果を統一的に保持。
- Pattern 1-4 の共通データ( loop_var_name, loop_var_id, carrier_info, loop_scope) を提供。
- Pattern 2/4 専用データ( condition_env, carrier_updates, trim_helper) は Option< T > で保持。
- **Analyzer-only dependencies**: 解析ロジックのみ依存、JoinIR emission ロジックは含まない。
2025-12-08 21:09:00 +09:00
- **TrimLoopLowerer (P5 Dedicated Module)** (Phase 180)
- ファイル: `src/mir/builder/control_flow/joinir/patterns/trim_loop_lowering.rs`
- 責務:
- Trim/CharComparison (Pattern 5) 専用の lowering ロジックを一箇所に集約。
- Pattern2/4 から呼ばれ、LoopBodyLocal 変数を carrier に昇格し、Trim パターンの break 条件を置き換える。
- TrimPatternValidator/TrimPatternLowerer を内部で利用し、carrier 初期化コード生成・条件式置換を実行。
- 入力:
- MirBuilder, LoopScopeShape, loop_cond, break_cond, body, loop_var_name, carrier_info, alloc_join_value
- 出力:
- `Some(TrimLoweringResult)` : Trim パターン検出・lowering 成功時(置換後条件、更新 carrier_info、condition_bindings)
- `None` : Trim パターンでない場合(通常ループ処理に戻る)
- `Err` : Trim パターン検出したが lowering 失敗時
- 使用元:
- Pattern2 (pattern2_with_break.rs): Trim/P5 ロジックを完全委譲(~160 行削減)
- Pattern4 (pattern4_with_continue.rs): 将来の Phase 172+ で Trim lowering 実装時に利用予定
2025-12-08 19:51:04 +09:00
- デザイン原則:
- Pure analysis container( 前処理結果のみ保持、emission なし)
- Pattern-specific variants( Option< T > でパターン固有データ管理)
- Single source of truth( 全パターンが同じ前処理経路を使用)
2025-12-07 21:02:20 +09:00
- **JoinIRConversionPipeline** (Phase 33-22)
- ファイル: `src/mir/builder/control_flow/joinir/patterns/conversion_pipeline.rs`
- 責務:
- JoinIR → MIR 変換フロー統一化( JoinModule → MirModule → merge_joinir_mir_blocks) 。
2025-12-08 04:00:44 +09:00
- JoinIR/MIR の関数数・ブロック数をログ出力し、全パターンが同じ入口でマージする。
2025-12-07 21:02:20 +09:00
### 2.2 条件式ライン(式の箱)
2025-12-08 04:00:44 +09:00
- **BoolExprLowerer / condition_to_joinir**
- ファイル:
- `src/mir/join_ir/lowering/bool_expr_lowerer.rs`
- `src/mir/join_ir/lowering/condition_to_joinir.rs`
2025-12-07 21:02:20 +09:00
- 責務:
2025-12-08 04:00:44 +09:00
- 通常の if/while 条件を MIR Compare/BinOp/UnaryOp へ lowering。
- ループ lowerer 用の「AST 条件 → JoinIR Compute 命令列」を ConditionEnv とセットで構築。
2025-12-07 21:02:20 +09:00
2025-12-08 04:00:44 +09:00
- **ConditionEnv/ConditionBinding + ConditionEnvBuilder**
- ファイル:
- `src/mir/join_ir/lowering/condition_env.rs`
- `src/mir/builder/control_flow/joinir/patterns/condition_env_builder.rs`
2025-12-07 21:02:20 +09:00
- 責務:
2025-12-08 04:00:44 +09:00
- 変数名→JoinIR ValueId の環境を組み立て、host↔join の橋渡しを ConditionBinding に明示する。
- Pattern 2 では break 条件の全変数をスキャンし、JoinInlineBoundary.condition_bindings に渡す。
2025-12-07 21:02:20 +09:00
2025-12-07 23:09:25 +09:00
- **LoopConditionScopeBox( Phase 170-D 実装済み)**
- ファイル: `src/mir/loop_pattern_detection/loop_condition_scope.rs`
2025-12-07 21:29:19 +09:00
- 責務:
2025-12-08 04:00:44 +09:00
- 条件式の各変数を LoopParam / OuterLocal / LoopBodyLocal に分類。
- 関数パラメータ誤分類バグは `condition_var_analyzer.rs` の修正で解消済み( OuterLocal として扱う)。
2025-12-07 23:09:25 +09:00
2025-12-10 09:29:32 +09:00
- **ConditionPatternBox( Phase 219-fix / Phase 222 拡張完了)**
2025-12-10 08:58:37 +09:00
- ファイル: `src/mir/join_ir/lowering/condition_pattern.rs`
- 責務:
- if 条件の複雑度を判定( SimpleComparison vs Complex) 。
2025-12-10 09:29:32 +09:00
- **Phase 222**: 条件を正規化( var on left の canonical form) 。
- `normalize_comparison()` で左右反転をサポート:
- `0 < i` → `i > 0` (literal < var → var > literal)
- `i > j` (var CmpOp var) - そのまま受理
2025-12-10 08:58:37 +09:00
- 複雑条件(`i % 2 == 1` 、MethodCall 等)は false を返し、legacy P3 経路へルーティング。
- 使用箇所:
- PatternPipelineContext.is_if_sum_pattern() で条件複雑度をチェック。
2025-12-13 03:47:54 +09:00
- P3 if-sum mode は単純比較のみ受理し、複雑条件は legacy P3 route へ routing( JoinIR Core 内)。
2025-12-10 08:58:37 +09:00
2025-12-10 19:08:18 +09:00
- **MethodCallLowerer( Phase 224-B / 224-C / 225 実装完了)**
2025-12-10 17:59:24 +09:00
- ファイル: `src/mir/join_ir/lowering/method_call_lowerer.rs`
- 責務:
- AST MethodCall ノードを JoinIR BoxCall に lowering( メタデータ駆動) 。
2025-12-10 19:08:18 +09:00
- CoreMethodId の `is_pure()` , `allowed_in_condition()` , `allowed_in_init()` などのメタでホワイトリスト判定。
- Phase 224-B: 引数なしメソッド(`length()` 等)対応。
- Phase 224-C: 引数付きメソッド(`substring(i,j)` , `indexOf(ch)` 等)対応。
- Phase 225: body-local init 用の MethodCall lowering も完全に CoreMethodId メタ駆動に統一(メソッド名ハードコード/Box 名ハードコードを削除)。
2025-12-10 17:59:24 +09:00
- 設計原則:
- **メソッド名ハードコード禁止**: CoreMethodId メタデータのみ参照。
- **Fail-Fast**: ホワイトリストにないメソッドは即座にエラー。
- **Box-First**: 単一責任("このMethodCallをJoinIRにできるか? ")だけを担当。
- 使用箇所:
- `condition_lowerer.rs` の `lower_value_expression()` から呼び出し。
2025-12-10 19:08:18 +09:00
- `loop_body_local_init.rs` の init lowering からも呼び出され、body‑ local init での substring/indexOf などを lowering。
- Pattern 2/3/4 のループ条件式や body‑ local init で `s.length()` , `s.substring(...)` , `digits.indexOf(ch)` 等をサポート可能(メタ条件を満たす範囲で)。
2025-12-10 17:59:24 +09:00
2025-12-08 04:00:44 +09:00
- **LoopBodyCarrierPromoter( Phase 171-C-2 実装済み)**
2025-12-07 23:09:25 +09:00
- ファイル: `src/mir/loop_pattern_detection/loop_body_carrier_promoter.rs`
- 責務:
2025-12-08 04:00:44 +09:00
- LoopBodyLocal を Trim パターンとして bool キャリアへ昇格( substring + equality 連鎖を検出)。
- 昇格成功 → CarrierInfo に統合し Pattern 2/4 へ橋渡し。昇格失敗は Fail‑ Fast。
- Pattern 2 は安全な Trim なら実際に前処理( substring 生成 + 空白比較の初期化)を emit してから JoinIR lowering。
- Pattern 4 は Trim 昇格が起きた場合はガード付きでエラーにし、未実装を明示( Fail‑ Fast) 。
2025-12-08 13:08:44 +09:00
- 汎用性:
- Phase 173 で `_skip_whitespace` ( JsonParser) が Trim パターンで動作確認済み。
- Phase 174 で `_parse_string` 最小化版(終端クォート検出)でも動作確認済み。
- → 空白文字以外の文字比較ループにも対応可能( TrimLoopHelper の汎用性実証)。
2025-12-08 04:00:44 +09:00
2025-12-10 16:21:01 +09:00
- **LoopBodyCondPromoter( Phase 223-3 + 223.5 + 224 実装完了)**
2025-12-10 15:00:20 +09:00
- ファイル: `src/mir/loop_pattern_detection/loop_body_cond_promoter.rs`
- 責務:
- ループ条件( header/break/continue) に出てくる LoopBodyLocal を carrier に昇格する統一 API。
2025-12-10 16:21:01 +09:00
- Pattern 2/Pattern 4 両対応の薄いコーディネーター箱( detection は専門 Promoter に委譲)。
2025-12-13 03:47:54 +09:00
- **Phase 224: Two-tier strategy** - A-3 Trim → A-4 DigitPos の二段階 routing( 昇格箱の順序を固定) 。
2025-12-10 15:00:20 +09:00
- Phase 223-3 実装内容:
- `extract_continue_condition()` : body 内の if 文から continue 条件を抽出。
- `try_promote_for_condition()` : LoopBodyCarrierPromoter を使った昇格処理。
- Pattern4 への統合完了: LoopBodyLocal 条件の昇格成功時に lowering を続行(以前は Fail-Fast) 。
2025-12-10 16:21:01 +09:00
- Phase 223.5 実装内容:
- Pattern2 への統合完了: header/break 条件を分析し昇格を試みる。
2025-12-10 22:48:45 +09:00
- **ScopeManager / ExprLowerer( Phase 231 パイロット実装完了)**
- ファイル:
- `src/mir/join_ir/lowering/scope_manager.rs`
- `src/mir/join_ir/lowering/expr_lowerer.rs`
- 責務:
- **ScopeManager trait**: 変数参照を統一的に扱う trait( ConditionEnv / LoopBodyLocalEnv / CapturedEnv / CarrierInfo を統合)。
- **Pattern2ScopeManager**: Pattern2 専用の薄いラッパー( promoted_loopbodylocals 対応含む)。
- **ExprLowerer**: 式 lowering を1箇所に集約( Phase 231: Condition context のみ、General context は将来実装)。
- Phase 231 実装内容:
2025-12-13 03:47:54 +09:00
- Pattern2 break 条件の **pre-validation** として ExprLowerer を試行( soft fallback を前提にした検証ルート)。
- 簡単な条件式(`i >= 5` など)を正常に検証し、未対応は UnsupportedNode エラーとして上位 router が legacy route を選ぶ。
2025-12-10 22:48:45 +09:00
- 箱化・モジュール化の原則に準拠( ScopeManager は trait、ExprLowerer は再利用可能)。
- 設計原則:
- **Box-First**: ScopeManager は trait-based "box" で変数解決を抽象化。
2025-12-13 03:47:54 +09:00
- **Fail-Safe**: 未対応 AST ノ ードは明示的エラーとして扱い、JoinIR Core 内の routing で安全に退避する。
2025-12-10 22:48:45 +09:00
- **Incremental Adoption**: Phase 231 は検証専用、Phase 232+ で実際の lowering 置き換え予定。
- 使用箇所:
- `pattern2_with_break.rs` の break 条件 lowering 前に pre-validation として実行。
- 将来は Pattern1/Pattern3/Pattern4 にも拡大予定( Phase 232) 。
- **DigitPosConditionNormalizer( Phase 224-E 実装完了)**
- ファイル: `src/mir/join_ir/lowering/digitpos_condition_normalizer.rs`
- 責務:
- digit_pos 条件を正規化(`digit_pos < 0` → `!is_digit_pos` )。
- Pattern2 の break 条件 lowering 前に呼び出され、promoted variable の条件を bool 形式に変換。
2025-12-10 16:21:01 +09:00
- Phase 224 実装内容( Core Implementation Complete ⚠️):
- **Two-tier promotion**: Step1 で A-3 Trim 試行 → 失敗なら Step2 で A-4 DigitPos 試行 → 両方失敗で Fail-Fast。
- **DigitPosPromoter 統合**: cascading indexOf パターン( substring → indexOf → comparison) の昇格をサポート。
- **Unit test 完全成功**: 6/6 PASS( promoter 自体は完璧動作)。
2025-12-10 18:45:04 +09:00
- **残りの制約**: body-local init の MethodCall( `substring` 等)の lowering は Phase 193/224-B/C のスコープ外で、今後の Phase で対応。
2025-12-10 15:00:20 +09:00
- 設計原則:
2025-12-10 16:21:01 +09:00
- **Thin coordinator**: 専門 Promoter( LoopBodyCarrierPromoter / DigitPosPromoter) に昇格ロジックを委譲。
2025-12-10 15:00:20 +09:00
- **Pattern-agnostic**: Pattern2 (break) / Pattern4 (continue) の統一入口として機能。
2025-12-10 16:21:01 +09:00
- **Fail-Fast with clear routing**: A-3 → A-4 順で試行し、両方失敗なら明示的エラー。
2025-12-10 15:00:20 +09:00
- 入出力:
- 入力: `ConditionPromotionRequest` ( loop_param_name, cond_scope, break_cond/continue_cond, loop_body)
- 出力: `ConditionPromotionResult::Promoted { carrier_info, promoted_var, carrier_name }` または `CannotPromote { reason, vars }`
2025-12-10 16:21:01 +09:00
- 使用元( Phase 223.5 実装完了、Phase 224 拡張済み):
2025-12-10 15:00:20 +09:00
- Pattern4: promotion-first( 昇格試行 → 成功なら CarrierInfo merge → 失敗なら Fail-Fast)
2025-12-10 16:21:01 +09:00
- Pattern2: promotion-first( 同上、break条件を分析対象とする)
- **DigitPosPromoter( Phase 224 実装完了 ⚠️ Core Complete) **
- ファイル: `src/mir/loop_pattern_detection/loop_body_digitpos_promoter.rs` ( 467 lines)
- 責務:
- **A-4 pattern**: Cascading LoopBodyLocal with indexOf( substring → indexOf → comparison) の昇格。
- **Pattern detection**: `local ch = s.substring(...); local digit_pos = digits.indexOf(ch); if digit_pos < 0 { break }`
- **Comparison operators**: `<` , `>` , `<=` , `>=` , `!=` をサポート( equality `==` は A-3 Trim 領域)。
- **Dependency validation**: indexOf() が別の LoopBodyLocal に依存していることを検証( cascading pattern) 。
- Phase 224 実装内容:
- `try_promote()` : A-4 パターン検出 & bool carrier 昇格(`digit_pos` → `is_digit_pos` )。
- **Unit tests**: 6/6 PASS( basic pattern, non-indexOf rejection, no dependency rejection, comparison operators, equality rejection) 。
2025-12-13 03:47:54 +09:00
- **Integration**: LoopBodyCondPromoter から A-3 Trim 失敗後の二段階 routing で呼ばれる。
2025-12-10 16:21:01 +09:00
- 設計原則:
- **One Box, One Question**: A-4 DigitPos パターン専用( A-3 Trim は LoopBodyCarrierPromoter に残す)。
- **Separation of Concerns**: Trim( equality-based) と DigitPos( comparison-based) を分離。
- **Bool carrier consistency**: A-3 Trim と同じく bool carrier に昇格(`is_digit_pos` )。
- 入出力:
- 入力: `DigitPosPromotionRequest` ( cond_scope, break_cond/continue_cond, loop_body)
- 出力: `DigitPosPromotionResult::Promoted { carrier_info, promoted_var, carrier_name }` または `CannotPromote { reason, vars }`
2025-12-10 22:10:28 +09:00
- **Phase 224-E 完了( AST 条件正規化)**:
- **DigitPosConditionNormalizer Box**: `digit_pos < 0` → `!is_digit_pos` の AST 変換。
- **実装箇所**: `src/mir/join_ir/lowering/digitpos_condition_normalizer.rs` ( 173 lines) 。
- **統合**: Pattern2 で promotion 成功後に自動適用(`pattern2_with_break.rs` line 332-344) 。
- **単体テスト**: 5/5 PASS( happy path, wrong operator/variable/constant, non-binary-op) 。
- **E2E テスト**: `phase2235_p2_digit_pos_min.hako` で型エラー解消確認。
- **回帰テスト**: digitpos (11 tests), trim (32 tests) 全て PASS。
2025-12-11 00:21:29 +09:00
- **digit_pos 正規化ライン**: DigitPosPromoter + CarrierInfo.promoted_loopbodylocals + DigitPosConditionNormalizer で `digit_pos < 0` を bool キャリア `is_digit_pos` ベースの条件(`!is_digit_pos` )に直してから ConditionEnv / ConditionPatternBox / ExprLowerer 系の条件 lowering に渡す。
2025-12-10 16:21:01 +09:00
- 参考:
2025-12-10 22:10:28 +09:00
- 設計ドキュメント: `docs/development/current/main/phase224-digitpos-condition-normalizer.md`
- 実装サマリ: `docs/development/current/main/PHASE_224_SUMMARY.md`
2025-12-10 16:21:01 +09:00
- テストケース: `apps/tests/phase2235_p2_digit_pos_min.hako`
2025-12-10 15:00:20 +09:00
2025-12-08 04:00:44 +09:00
- **ContinueBranchNormalizer / LoopUpdateAnalyzer**
- ファイル:
- `src/mir/join_ir/lowering/continue_branch_normalizer.rs`
- `src/mir/join_ir/lowering/loop_update_analyzer.rs`
- 責務:
- else-continue を then-continue へ正規化し、Select ベースの continue を簡潔にする。
- ループ本体で実際に更新されるキャリアだけを抽出( Pattern 4 で不要キャリアを排除)。
2025-12-07 21:29:19 +09:00
2025-12-09 03:59:53 +09:00
- **LoopBodyLocalEnv / UpdateEnv / CarrierUpdateEmitter( Phase 184, 191統合完了) **
feat(joinir): Phase 184 - Body-local MIR Lowering Infrastructure
Phase 184 implements the foundation for body-local variable support in
update expressions, completing the three-box architecture:
LoopBodyLocalEnv (storage), UpdateEnv (composition), and
CarrierUpdateEmitter (emission).
## Implementation Summary
### Task 184-1: Design Document
- Created phase184-body-local-mir-lowering.md
- Two-Environment System design (ConditionEnv + LoopBodyLocalEnv)
- Box-First design principles documented
### Task 184-2: LoopBodyLocalEnv Implementation
- New file: src/mir/join_ir/lowering/loop_body_local_env.rs (216 lines)
- Storage box for body-local variable name → ValueId mappings
- BTreeMap for deterministic ordering (PHI consistency)
- 7 unit tests: empty env, single/multiple locals, get/contains, iteration
### Task 184-3: UpdateEnv Implementation
- New file: src/mir/join_ir/lowering/update_env.rs (237 lines)
- Composition box for unified variable resolution
- Priority order: ConditionEnv (condition vars) → LoopBodyLocalEnv (body-local)
- 8 unit tests: priority, fallback, not found, combined lookup
### Task 184-4: CarrierUpdateEmitter Integration
- Modified: src/mir/join_ir/lowering/carrier_update_emitter.rs
- Added emit_carrier_update_with_env() (UpdateEnv version)
- Kept emit_carrier_update() for backward compatibility
- 4 new unit tests: body-local variable, priority, not found, const update
- Total 10 tests PASS (6 existing + 4 new)
### Task 184-5: Representative Test Cases
- apps/tests/phase184_body_local_update.hako (Pattern1 baseline)
- apps/tests/phase184_body_local_with_break.hako (Pattern2, Phase 185 target)
### Task 184-6: Documentation Updates
- Updated: docs/development/current/main/joinir-architecture-overview.md
- Updated: CURRENT_TASK.md (Phase 184 completion record)
## Test Results
All 25 unit tests PASS:
- LoopBodyLocalEnv: 7 tests
- UpdateEnv: 8 tests
- CarrierUpdateEmitter: 10 tests (6 existing + 4 new)
Build: ✅ Success (0 errors)
## Design Constraints
Following 箱理論 (Box Theory) principles:
- Single Responsibility: Each box has one clear purpose
- Deterministic: BTreeMap ensures consistent ordering
- Conservative: Pattern5 (Trim) integration deferred to Phase 185
- Fail-Fast: Explicit errors for unsupported patterns
## Scope Limitation
Phase 184 provides the **infrastructure only**:
- ✅ Storage box (LoopBodyLocalEnv)
- ✅ Composition box (UpdateEnv)
- ✅ Emission support (CarrierUpdateEmitter)
- ❌ Pattern2/4 integration (requires body-local collection, Phase 185)
## Next Steps
Phase 185: Pattern2/4 Integration
- Integrate LoopBodyLocalEnv into Pattern2/4 lowerers
- Add body-local variable collection from loop body AST
- Enable full E2E body-local variable support in update expressions
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-08 23:59:19 +09:00
- ファイル:
- `src/mir/join_ir/lowering/loop_body_local_env.rs`
- `src/mir/join_ir/lowering/update_env.rs`
- `src/mir/join_ir/lowering/carrier_update_emitter.rs`
2025-12-09 03:59:53 +09:00
- `src/mir/join_ir/lowering/loop_with_break_minimal.rs` ( Phase 191統合)
feat(joinir): Phase 184 - Body-local MIR Lowering Infrastructure
Phase 184 implements the foundation for body-local variable support in
update expressions, completing the three-box architecture:
LoopBodyLocalEnv (storage), UpdateEnv (composition), and
CarrierUpdateEmitter (emission).
## Implementation Summary
### Task 184-1: Design Document
- Created phase184-body-local-mir-lowering.md
- Two-Environment System design (ConditionEnv + LoopBodyLocalEnv)
- Box-First design principles documented
### Task 184-2: LoopBodyLocalEnv Implementation
- New file: src/mir/join_ir/lowering/loop_body_local_env.rs (216 lines)
- Storage box for body-local variable name → ValueId mappings
- BTreeMap for deterministic ordering (PHI consistency)
- 7 unit tests: empty env, single/multiple locals, get/contains, iteration
### Task 184-3: UpdateEnv Implementation
- New file: src/mir/join_ir/lowering/update_env.rs (237 lines)
- Composition box for unified variable resolution
- Priority order: ConditionEnv (condition vars) → LoopBodyLocalEnv (body-local)
- 8 unit tests: priority, fallback, not found, combined lookup
### Task 184-4: CarrierUpdateEmitter Integration
- Modified: src/mir/join_ir/lowering/carrier_update_emitter.rs
- Added emit_carrier_update_with_env() (UpdateEnv version)
- Kept emit_carrier_update() for backward compatibility
- 4 new unit tests: body-local variable, priority, not found, const update
- Total 10 tests PASS (6 existing + 4 new)
### Task 184-5: Representative Test Cases
- apps/tests/phase184_body_local_update.hako (Pattern1 baseline)
- apps/tests/phase184_body_local_with_break.hako (Pattern2, Phase 185 target)
### Task 184-6: Documentation Updates
- Updated: docs/development/current/main/joinir-architecture-overview.md
- Updated: CURRENT_TASK.md (Phase 184 completion record)
## Test Results
All 25 unit tests PASS:
- LoopBodyLocalEnv: 7 tests
- UpdateEnv: 8 tests
- CarrierUpdateEmitter: 10 tests (6 existing + 4 new)
Build: ✅ Success (0 errors)
## Design Constraints
Following 箱理論 (Box Theory) principles:
- Single Responsibility: Each box has one clear purpose
- Deterministic: BTreeMap ensures consistent ordering
- Conservative: Pattern5 (Trim) integration deferred to Phase 185
- Fail-Fast: Explicit errors for unsupported patterns
## Scope Limitation
Phase 184 provides the **infrastructure only**:
- ✅ Storage box (LoopBodyLocalEnv)
- ✅ Composition box (UpdateEnv)
- ✅ Emission support (CarrierUpdateEmitter)
- ❌ Pattern2/4 integration (requires body-local collection, Phase 185)
## Next Steps
Phase 185: Pattern2/4 Integration
- Integrate LoopBodyLocalEnv into Pattern2/4 lowerers
- Add body-local variable collection from loop body AST
- Enable full E2E body-local variable support in update expressions
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-08 23:59:19 +09:00
- 責務:
- **LoopBodyLocalEnv**: ループ本体で宣言された body-local 変数の名前→ValueId マッピングを管理(箱化設計)。
- **UpdateEnv**: 条件変数( ConditionEnv) と body-local 変数( LoopBodyLocalEnv) を統合した変数解決層。
- Priority order: 1. Condition variables( 高優先度) → 2. Body-local variables( フォールバック)
- **CarrierUpdateEmitter**: UpdateExpr を JoinIR 命令に変換する際、UpdateEnv を使用して body-local 変数をサポート。
- `emit_carrier_update_with_env()` : UpdateEnv 版( Phase 184 新規)
- `emit_carrier_update()` : ConditionEnv 版(後方互換)
2025-12-09 03:59:53 +09:00
- **LoopBodyLocalInitLowerer**: Phase 191 で Pattern2 に統合完了。
- 対応済み init 式: 整数リテラル、変数参照、二項演算(`local digit = i + 1` )
- UpdateEnv の優先順位により ConditionEnv → LoopBodyLocalEnv の順で変数解決
feat(joinir): Phase 184 - Body-local MIR Lowering Infrastructure
Phase 184 implements the foundation for body-local variable support in
update expressions, completing the three-box architecture:
LoopBodyLocalEnv (storage), UpdateEnv (composition), and
CarrierUpdateEmitter (emission).
## Implementation Summary
### Task 184-1: Design Document
- Created phase184-body-local-mir-lowering.md
- Two-Environment System design (ConditionEnv + LoopBodyLocalEnv)
- Box-First design principles documented
### Task 184-2: LoopBodyLocalEnv Implementation
- New file: src/mir/join_ir/lowering/loop_body_local_env.rs (216 lines)
- Storage box for body-local variable name → ValueId mappings
- BTreeMap for deterministic ordering (PHI consistency)
- 7 unit tests: empty env, single/multiple locals, get/contains, iteration
### Task 184-3: UpdateEnv Implementation
- New file: src/mir/join_ir/lowering/update_env.rs (237 lines)
- Composition box for unified variable resolution
- Priority order: ConditionEnv (condition vars) → LoopBodyLocalEnv (body-local)
- 8 unit tests: priority, fallback, not found, combined lookup
### Task 184-4: CarrierUpdateEmitter Integration
- Modified: src/mir/join_ir/lowering/carrier_update_emitter.rs
- Added emit_carrier_update_with_env() (UpdateEnv version)
- Kept emit_carrier_update() for backward compatibility
- 4 new unit tests: body-local variable, priority, not found, const update
- Total 10 tests PASS (6 existing + 4 new)
### Task 184-5: Representative Test Cases
- apps/tests/phase184_body_local_update.hako (Pattern1 baseline)
- apps/tests/phase184_body_local_with_break.hako (Pattern2, Phase 185 target)
### Task 184-6: Documentation Updates
- Updated: docs/development/current/main/joinir-architecture-overview.md
- Updated: CURRENT_TASK.md (Phase 184 completion record)
## Test Results
All 25 unit tests PASS:
- LoopBodyLocalEnv: 7 tests
- UpdateEnv: 8 tests
- CarrierUpdateEmitter: 10 tests (6 existing + 4 new)
Build: ✅ Success (0 errors)
## Design Constraints
Following 箱理論 (Box Theory) principles:
- Single Responsibility: Each box has one clear purpose
- Deterministic: BTreeMap ensures consistent ordering
- Conservative: Pattern5 (Trim) integration deferred to Phase 185
- Fail-Fast: Explicit errors for unsupported patterns
## Scope Limitation
Phase 184 provides the **infrastructure only**:
- ✅ Storage box (LoopBodyLocalEnv)
- ✅ Composition box (UpdateEnv)
- ✅ Emission support (CarrierUpdateEmitter)
- ❌ Pattern2/4 integration (requires body-local collection, Phase 185)
## Next Steps
Phase 185: Pattern2/4 Integration
- Integrate LoopBodyLocalEnv into Pattern2/4 lowerers
- Add body-local variable collection from loop body AST
- Enable full E2E body-local variable support in update expressions
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-08 23:59:19 +09:00
- 設計原則:
- **箱理論**: 各 Box が単一責任を持ち、境界明確。
- **決定性**: BTreeMap 使用で一貫した順序保証( PHI 生成の決定性)。
2025-12-09 04:28:10 +09:00
- **Phase 192完了**: Complex addend( `v = v*10 + f(x)` )は ComplexAddendNormalizer で temp に分解してから NumberAccumulation に載せる。
- `complex_addend_normalizer.rs` : Pure AST transformer( 前処理箱)
- Pattern2 統合完了、emission ライン再利用(変更なし)
- 制約: MethodCall を含む init 式は Phase 193 で対応予定
feat(joinir): Phase 184 - Body-local MIR Lowering Infrastructure
Phase 184 implements the foundation for body-local variable support in
update expressions, completing the three-box architecture:
LoopBodyLocalEnv (storage), UpdateEnv (composition), and
CarrierUpdateEmitter (emission).
## Implementation Summary
### Task 184-1: Design Document
- Created phase184-body-local-mir-lowering.md
- Two-Environment System design (ConditionEnv + LoopBodyLocalEnv)
- Box-First design principles documented
### Task 184-2: LoopBodyLocalEnv Implementation
- New file: src/mir/join_ir/lowering/loop_body_local_env.rs (216 lines)
- Storage box for body-local variable name → ValueId mappings
- BTreeMap for deterministic ordering (PHI consistency)
- 7 unit tests: empty env, single/multiple locals, get/contains, iteration
### Task 184-3: UpdateEnv Implementation
- New file: src/mir/join_ir/lowering/update_env.rs (237 lines)
- Composition box for unified variable resolution
- Priority order: ConditionEnv (condition vars) → LoopBodyLocalEnv (body-local)
- 8 unit tests: priority, fallback, not found, combined lookup
### Task 184-4: CarrierUpdateEmitter Integration
- Modified: src/mir/join_ir/lowering/carrier_update_emitter.rs
- Added emit_carrier_update_with_env() (UpdateEnv version)
- Kept emit_carrier_update() for backward compatibility
- 4 new unit tests: body-local variable, priority, not found, const update
- Total 10 tests PASS (6 existing + 4 new)
### Task 184-5: Representative Test Cases
- apps/tests/phase184_body_local_update.hako (Pattern1 baseline)
- apps/tests/phase184_body_local_with_break.hako (Pattern2, Phase 185 target)
### Task 184-6: Documentation Updates
- Updated: docs/development/current/main/joinir-architecture-overview.md
- Updated: CURRENT_TASK.md (Phase 184 completion record)
## Test Results
All 25 unit tests PASS:
- LoopBodyLocalEnv: 7 tests
- UpdateEnv: 8 tests
- CarrierUpdateEmitter: 10 tests (6 existing + 4 new)
Build: ✅ Success (0 errors)
## Design Constraints
Following 箱理論 (Box Theory) principles:
- Single Responsibility: Each box has one clear purpose
- Deterministic: BTreeMap ensures consistent ordering
- Conservative: Pattern5 (Trim) integration deferred to Phase 185
- Fail-Fast: Explicit errors for unsupported patterns
## Scope Limitation
Phase 184 provides the **infrastructure only**:
- ✅ Storage box (LoopBodyLocalEnv)
- ✅ Composition box (UpdateEnv)
- ✅ Emission support (CarrierUpdateEmitter)
- ❌ Pattern2/4 integration (requires body-local collection, Phase 185)
## Next Steps
Phase 185: Pattern2/4 Integration
- Integrate LoopBodyLocalEnv into Pattern2/4 lowerers
- Add body-local variable collection from loop body AST
- Enable full E2E body-local variable support in update expressions
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-08 23:59:19 +09:00
2025-12-07 21:02:20 +09:00
### 2.3 キャリア / Exit / Boundary ライン
2025-12-09 18:32:03 +09:00
- **Phase 200-B: FunctionScopeCaptureAnalyzer (完了)**
- ファイル: `src/mir/loop_pattern_detection/function_scope_capture.rs`
- 責務: 関数スコープの「実質定数」を検出
- 判定条件:
1. 関数トップレベルで 1 回だけ定義
2. ループ内で再代入なし
3. 安全な初期式(文字列/整数リテラル)のみ
- 結果: CapturedEnv に name, host_id, is_immutable を格納
- **ConditionEnvBuilder v2**:
- 責務: CapturedEnv から ParamRole::Condition として ConditionEnv に追加
- 経路: analyze_captured_vars → build_with_captures → ConditionEnv.captured
- 不変条件: Condition role は Header PHI / ExitLine の対象にならない
- **Pattern 2 統合**: Phase 200-C で完了 ✅
- MirBuilder.fn_body_ast フィールド追加
- LoopPatternContext.fn_body 経由で Pattern 2 lowerer に渡す
- analyze_captured_vars_v2() で構造的ループ検索(ポインタ比較 → AST 構造比較)
- **Phase 200-C: digits.indexOf E2E 連携 (完了)**
- 目的: 200-A/B インフラを実際に Pattern 2 経路に統合
- 実装:
- fn_body を MirBuilder → LoopPatternContext → Pattern 2 に渡す
- analyze_captured_vars_v2() で構造的マッチング( AST Debug 文字列比較)
- digits / s 等の関数ローカル定数が CapturedEnv に正しく捕捉される
- 検証結果:
- capture 検出: ✅ PASS
- E2E 実行: ❌ BLOCKED( テストケースが Pattern 5+ 必要)
- テストケース制約:
- phase200_digits_atoi_min.hako: body-local `pos` を条件 `if pos < 0` で使用
- → Pattern 5 (body-local promotion) が必要
- **Phase 200-D: digits capture "実戦 1 本" 検証 (完了)**
- 目的: capture 経路の E2E 検証( body-local なしのシンプルケース)
- 検証結果:
- capture 検出: ✅ PASS( base, limit, n 等が正しく CapturedEnv に)
- ConditionEnv 統合: ✅ PASS( captured vars が ConditionEnv.captured に追加)
- 実行: ⚠️ 別の制約でブロック( substring 未対応、キャリア更新型問題)
- 成果:
- capture 経路( analyze_captured_vars_v2 → ConditionEnv → Pattern 2) が正常動作
- 関数スコープ定数が正しく検出・統合される
- テストファイル: phase200d_capture_minimal.hako, phase200d_capture_in_condition.hako
2025-12-09 01:09:54 +09:00
- **CarrierInfo / LoopUpdateAnalyzer / CarrierUpdateEmitter**
2025-12-07 21:02:20 +09:00
- ファイル:
- `src/mir/join_ir/lowering/carrier_info.rs`
2025-12-08 04:00:44 +09:00
- `src/mir/join_ir/lowering/loop_update_analyzer.rs`
2025-12-09 01:09:54 +09:00
- `src/mir/join_ir/lowering/carrier_update_emitter.rs`
2025-12-07 21:02:20 +09:00
- 責務:
2025-12-08 04:00:44 +09:00
- ループで更新される変数( carrier) を検出し、UpdateExpr を保持。
- Pattern 4 では実際に更新されるキャリアだけを残す。
2025-12-09 01:09:54 +09:00
- **Phase 188 完了** ✅: String 更新( StringAppendChar/StringAppendLiteral) を UpdateRhs ベースのホワイトリストで受理し、JoinIR BinOp を emit。
- 許可: `UpdateRhs::Const` , `UpdateRhs::Variable` , `UpdateRhs::StringLiteral`
- 拒否: `UpdateRhs::Other` ( method call / nested BinOp 等の複雑パターンのみ)
- Pattern2/4 の can_lower() で選別、carrier_update_emitter.rs で JoinIR 生成
2025-12-07 21:02:20 +09:00
- **ExitMeta / JoinFragmentMeta**
2025-12-08 04:00:44 +09:00
- ファイル: `carrier_info.rs`
2025-12-07 21:02:20 +09:00
- 責務:
2025-12-08 04:00:44 +09:00
- JoinIR lowerer が出口の JoinIR ValueId を記録( expr_result とキャリアを明確に分離)。
2025-12-07 21:02:20 +09:00
2025-12-08 04:00:44 +09:00
- **LoopHeader PHI Builder**
- ファイル:
- `src/mir/builder/control_flow/joinir/merge/loop_header_phi_info.rs`
- `loop_header_phi_builder.rs`
2025-12-07 21:02:20 +09:00
- 責務:
2025-12-08 04:00:44 +09:00
- ループ変数とキャリアの PHI をヘッダブロックに生成し、entry/latch の 2 入力で SSA を確立。
- instruction_rewriter が latch 側を埋めた後に finalize して挿入する。
2025-12-07 21:02:20 +09:00
- **JoinInlineBoundary**
- ファイル: `src/mir/join_ir/lowering/inline_boundary.rs`
2025-12-08 04:00:44 +09:00
- 主フィールド:
2025-12-07 21:02:20 +09:00
- `join_inputs / host_inputs` :ループパラメータの橋渡し
2025-12-08 04:00:44 +09:00
- `condition_bindings` : 条件専用変数の橋渡し( JoinIR ValueId を明示)
- `exit_bindings` : キャリア出口の橋渡し( carrier 名を明示)
- `expr_result` / `loop_var_name` : expr result / ヘッダ PHI 生成用のメタ情報
2025-12-07 21:02:20 +09:00
- 責務:
2025-12-08 04:00:44 +09:00
- 「host ↔ JoinIR」の境界情報の SSOT。各パターン lowerer がここに全て詰めてから merge する。
2025-12-07 21:02:20 +09:00
- **BoundaryInjector**
- ファイル: `src/mir/builder/joinir_inline_boundary_injector.rs`
- 責務:
2025-12-08 04:00:44 +09:00
- `join_inputs` と `condition_bindings` を entry block に Copy で注入し、JoinIR ローカル ID と host ID を接続。
2025-12-07 21:02:20 +09:00
- **ExitLine (ExitMetaCollector / ExitLineReconnector / ExitLineOrchestrator)**
- ファイル:
- `src/mir/builder/control_flow/joinir/merge/exit_line/mod.rs`
- `exit_line/meta_collector.rs`
- `exit_line/reconnector.rs`
- 責務:
2025-12-08 04:00:44 +09:00
- ExitMeta から exit_bindings を構築( Collector) 。
- 変数再接続はヘッダ PHI の dst を使って `builder.variable_map` を更新( Reconnector) 。
2025-12-07 21:02:20 +09:00
- expr 用の PHI には一切触れない( carrier 専用ライン)。
2025-12-10 22:48:45 +09:00
- **ConditionOnly キャリア**: header PHI の entry は CarrierInit( BoolConst(false) 等) を起点にし、ExitLine では variable_map や ExprResult への書き戻しを行わずヘッダ PHI 経由に限定。
2025-12-07 21:02:20 +09:00
2025-12-10 08:58:37 +09:00
- **ExprResultResolver( Phase 221-R 実装済み)**
- ファイル: `src/mir/builder/control_flow/joinir/merge/expr_result_resolver.rs`
- 責務:
- expr_result ValueId を exit_bindings/carrier_phis と照合し、適切な出口値を解決。
- expr_result が carrier の場合: carrier PHI dst を返す(変数再接続と統一)。
- expr_result が非 carrier の場合: remapped ValueId を返す( expr-only の値)。
- 特徴:
- Phase 33 モジュール化パターン準拠( ExitMetaCollector/ExitLineReconnector と同様)。
- 4つのシナリオを unit test でカバー( carrier/non-carrier/None/error) 。
- merge/mod.rs から 64 行を抽出、-37 行のネット削減。
2025-12-08 06:14:03 +09:00
- **JoinInlineBoundaryBuilder( Phase 200-2 / Phase 201 完了)**
2025-12-08 04:35:13 +09:00
- ファイル: `src/mir/join_ir/lowering/inline_boundary_builder.rs`
- 責務:
- JoinInlineBoundary の構築を Builder パターンで統一化。
- フィールド直書きの散乱を防ぎ、inputs/outputs/condition_bindings/exit_bindings/loop_var_name/expr_result の設定を fluent API で実施。
2025-12-08 06:14:03 +09:00
- **Phase 201 で Pattern1/2/3/4 全てに適用完了**(境界情報組み立てを 1 箇所に集約)。
2025-12-08 04:35:13 +09:00
- **JoinIRVerifier( Phase 200-3 追加)**
- ファイル: `src/mir/builder/control_flow/joinir/merge/mod.rs` ( debug_assertions 専用関数)
- 責務:
- LoopHeader PHI / ExitLine 契約をデバッグビルドで検証する門番。
- `verify_loop_header_phis()` : loop_var_name がある場合にヘッダ PHI が存在するか確認。
- `verify_exit_line()` : exit_bindings が exit block に対応しているか確認。
- `verify_joinir_contracts()` : merge_joinir_mir_blocks() の最後で全契約を一括チェック。
- release ビルドでは完全に除去される(`#[cfg(debug_assertions)]` )。
2025-12-09 16:19:08 +09:00
- **FunctionScopeCaptureAnalyzer / CapturedEnv( Phase 200-A 追加)**
- ファイル: `src/mir/loop_pattern_detection/function_scope_capture.rs`
- 責務:
- 関数スコープで宣言され、ループ内で不変な変数("実質定数")を検出。
- 例: `local digits = "0123456789"` in `JsonParser._atoi()`
- CapturedVar: `{ name, host_id, is_immutable }`
- CapturedEnv: 検出された変数のコレクション
- **Phase 200-A**: 型と空実装のみ( skeleton) 。
- **Phase 200-B**: 実際の検出ロジックを実装予定( AST スキャン + 再代入チェック)。
- **ParamRole enum( Phase 200-A 追加)**
- ファイル: `src/mir/join_ir/lowering/inline_boundary_builder.rs`
- 責務:
- JoinInlineBoundary のパラメータ役割を明示的に区別。
- LoopParam / Condition / Carrier / ExprResult の 4 種類。
- **不変条件**:
- **Condition 役**: PHI dst にしてはいけない(ループ内で更新されない)。
- **Condition 役**: ExitLine の対象にも入れない(ループ外で使われない)。
- 理由: 条件専用変数(例: `digits` )はループ内でのみ参照され、不変。
- **Phase 200-A**: enum 定義のみ。
- **Phase 200-B**: ルーティングロジック実装予定( CapturedEnv 統合時)。
- **ConditionEnvBuilder::build_with_captures( Phase 200-A 追加)**
- ファイル: `src/mir/builder/control_flow/joinir/patterns/condition_env_builder.rs`
- 責務:
- 将来 CapturedEnv を受け取り、ConditionEnv に統合する v2 入口。
- **Phase 200-A**: 既存実装に委譲する skeleton。
- **Phase 200-B**: CapturedEnv の変数を condition_bindings に追加する実装予定。
2025-12-07 21:02:20 +09:00
### 2.4 expr result ライン(式としての戻り値)
- **exit_phi_builder**
- ファイル: `src/mir/builder/control_flow/joinir/merge/exit_phi_builder.rs`
- 責務:
2025-12-08 04:00:44 +09:00
- JoinIR fragment が `expr_result` を持つときに exit ブロックへ PHI を生成。
- carrier_inputs も受け取り exit ブロックに PHI を作るが、再接続の SSOT は LoopHeader PHI( ExitLine はヘッダ PHI を使用)。
2025-12-07 21:02:20 +09:00
2025-12-08 04:00:44 +09:00
- **InstructionRewriter**
2025-12-07 21:02:20 +09:00
- ファイル: `instruction_rewriter.rs`
- 責務:
2025-12-08 04:00:44 +09:00
- continuation 関数( k_exit) をスキップし、Return → exit ブロック Jump に変換。
- `JoinFragmentMeta.expr_result` と exit_bindings をヘッダ PHI 経由で収集し、`exit_phi_inputs` / `carrier_inputs` を復活させた( SSA‑ undef 修正済み)。
- tail call を Branch/Jump に書き換えつつ、LoopHeaderPhiInfo に latch 入力を記録する。
2025-12-09 14:56:05 +09:00
- **Select 展開の不変条件( Phase 196) **:
- PHI の入力 ValueId は必ず `remapper.remap_instruction()` で remap 済みの MIR ValueId を使用。
- InstructionRewriter では ValueId の二重 remap を行わない( block ID のみ remap) 。
- 詳細: [phase196-select-bug-analysis.md ](./phase196-select-bug-analysis.md )
2025-12-07 21:02:20 +09:00
---
## 3. JoinIR → MIR 統合の全体フロー
1. Pattern router が AST/LoopFeatures から Pattern1– 4 を選択し、各 lowerer が
`(JoinModule, JoinFragmentMeta)` を生成。
2. `JoinInlineBoundary` が:
- ループ入力( join_inputs/host_inputs)
- 条件変数( condition_bindings)
- キャリア出口( exit_bindings)
を保持。
2025-12-08 04:00:44 +09:00
3. `merge_joinir_mir_blocks` が(マルチ関数対応):
- 全関数の BlockID を再割り当て( block_allocator) し、ValueId はパラメータを除外して収集。
- Boundary の condition/exit Bindings の JoinIR ValueId も remap 対象に追加。
- LoopHeader PHI を生成( loop_header_phi_builder) し、latch 側は instruction_rewriter が埋める。
- instruction_rewriter で関数をマージしつつ Call→Jump に変換、k_exit 関数はスキップ。
- BoundaryInjector で entry block に Copy を注入( join_inputs + condition_bindings) 。
- Header PHI を finalize → exit_phi_builder で expr_result/carrier の exit PHI を構築。
- ExitLineOrchestrator がヘッダ PHI dst を使って variable_map を更新。
- host の現在ブロックから JoinIR entry へ jump を張り、exit ブロックに切り替える。
2025-12-07 21:02:20 +09:00
この全体フローの詳細は `src/mir/builder/control_flow/joinir/merge/mod.rs` と
`phase-189-multi-function-mir-merge/README.md` を参照。
---
2025-12-08 21:41:19 +09:00
## 4. JsonParser / Trim / P5 ループの現在地( Phase 170– 181)
### 4.1 JsonParser ループ空間と P1– P5
Phase 181 で JsonParserBox 内の 11 ループを棚卸しした結果、
構造的には **すべて JoinIR Pattern1– 4 (+ P5) で扱える** ことが分かったよ。
- 既に JoinIR 経路で動作しているもの:
- `_skip_whitespace` ( P2 + P5 Trim)
- `_trim` leading/trailing( P2 + P5 Trim)
- **Phase 182 で P1/P2 パターン検証完了** ✅:
- Pattern1 (Simple): `_match_literal` 系ループで動作確認済み( apps/tests/phase182_p1_match_literal.hako)
- Pattern2 (Break): 整数演算ループで動作確認済み( apps/tests/phase182_p2_break_integer.hako)
- **ブロッカー発見**: 実際の JsonParser ループには 2 つの制約が必要:
1. LoopBodyLocal 変数の扱い(`ch` , `digit_pos` , `pos` など)
- 現状は Trim pattern 専用の carrier 昇格を試みてエラーになる
- P1/P2 では純粋なローカル変数(昇格不要)として扱うべき
2. 文字列連結フィルタ( Phase 178)
- `num_str = num_str + ch` のような string concat を保守的に reject
- JsonParser では必須の操作なので段階的に有効化が必要
2025-12-08 23:43:26 +09:00
- **設計原則**:
- string は「特別扱いのパターン」ではなく、あくまで MirType の 1 種類として扱う。
- Pattern2/4 側で型名や変数名(`"result"` , `"num_str"` など)に依存した分岐は入れない。
- LoopUpdateAnalyzer の `UpdateKind` / `UpdateRhs` で「安全な更新パターン」を列挙し、
そのうち string にも適用可能なものだけを **ホワイトリストで許可**する。
- 実際の lowering は CarrierUpdateLowerer / 式 Lowerer 側で行い、JoinIR のループ形( P1– P4) は増やさない。
2025-12-09 01:54:53 +09:00
3. 数値の桁展開( Phase 190 設計完了)
- `v = v * 10 + digit` のような NumberAccumulation パターンを UpdateKind で whitelist 制御。
- 型制約: Integer のみ許可( String は StringAppendChar 使用)。
- 検出: AST 構造解析( 名前依存禁止) 、Complex パターンは Fail-Fast で reject。
2025-12-08 23:14:10 +09:00
- **Phase 183 で LoopBodyLocal 役割分離完了** ✅:
- **設計**: LoopBodyLocal を 2 カテゴリに分類:
- **Condition LoopBodyLocal**: ループ条件( header/break/continue) で使用 → Trim 昇格対象
- **Body-only LoopBodyLocal**: ループ本体のみで使用 → 昇格不要、pure local 扱い
- **実装**: TrimLoopLowerer に `is_var_used_in_condition()` ヘルパー追加
- 条件で使われていない LoopBodyLocal は Trim 昇格スキップ
- 5 つの unit test で変数検出ロジックを検証
- **テスト**: `apps/tests/phase183_body_only_loopbodylocal.hako` で動作確認
- `[TrimLoopLowerer] No LoopBodyLocal detected` トレース出力で body-only 判定成功
2025-12-09 00:59:38 +09:00
- **次の課題( →Phase 184 で対応)**: body-local 変数の MIR lowering 対応(`local temp` in loop body)
2025-12-08 23:14:10 +09:00
- Phase 183 では "Trim promotion しない" 判定まで完了
2025-12-09 00:59:38 +09:00
- 実際の MIR 生成インフラは Phase 184 で実装済み( Pattern2/4 への統合は次フェーズ)
### 4.2 Body-local 変数の MIR lowering 基盤( Phase 184)
Phase 184 では、「条件には出てこない LoopBodyLocal 変数」を安全に JoinIR→MIR に落とすためのインフラ箱だけを追加したよ。
- **LoopBodyLocalEnv**
- 責務: ループ本体内で `local` 定義された変数の「JoinIR 側 ValueId のみ」を管理する。
- 入力: ループ本体 AST / JoinIR ビルダー。
- 出力: `name -> join_value_id` のマップ。
- 特徴: host 側との対応は持たない。ConditionEnv とは完全に分離された「本体専用ローカル環境」。
- **UpdateEnv**
- 責務: UpdateExpr lowering 時の変数解決順序をカプセル化する。
- 仕様: `ConditionEnv` (条件・キャリア)と `LoopBodyLocalEnv` (本体ローカル)を中で束ねて、
`resolve(name)` で「条件→ローカル」の順に ValueId を返す。
- 利用箇所: CarrierUpdateEmitter / CarrierUpdateLowerer が、変数名ベースで UpdateExpr を JoinIR に落とす時に利用。
- **CarrierUpdateEmitter 拡張**
- 責務: `LoopUpdateSummary` ( UpdateKind) に応じて、int 系キャリア更新を JoinIR 命令に変換する。
- 変更点: 直接 `variable_map` を読むのではなく、`UpdateEnv` 経由で名前解決するように変更。
- 効果: 本体専用の LoopBodyLocal 変数(`temp` 等) を、Pattern2/4 から安全に扱える土台が整った。
このフェーズではあくまで「ストレージ・名前解決・emit の箱」までで止めてあり、
Pattern2/4 への統合(実際に Body-local 更新を使うループを JoinIR 経路に載せる) は次フェーズ( Phase 185 以降)の仕事として分離している。
2025-12-08 21:41:19 +09:00
- 構造的に P1– P4 で対応可能(代表例):
- `_parse_number` / `_atoi` ( P2 Break) - Phase 182 でブロッカー特定済み
- `_match_literal` ( P1 Simple while) - Phase 182 で動作確認済み ✅
- `_parse_string` / `_parse_array` / `_parse_object`
( P2 + P4 + P5 の組み合わせで表現可能なことを設計上確認済み)
- 低優先度だが理論上は P1– P4 からの拡張で吸収可能:
- `_unescape_string` など、複雑な continue / 条件付き更新を含むループ
方針:
2025-12-10 00:01:53 +09:00
- **ループの「形」は P1– P4 から増やさない**。
2025-12-08 21:41:19 +09:00
複雑さ( LoopBodyLocal 条件、OR chain、continue 多用など)は BoolExprLowerer /
ContinueBranchNormalizer / TrimLoopLowerer (P5) といった補助箱側で吸収する。
2025-12-10 00:01:53 +09:00
- JsonParser 側の P5 適用( Trim / `_skip_whitespace` / `_parse_string` 最小版)は実証済み。
2025-12-08 21:41:19 +09:00
残りのループは Phase 17x– 18x で、P1– P4+P5 の組み合わせとして段階的に実装していく。
docs: Phase 221 JsonParser numerical loops deployment
Phase 221: JsonParser 数値ループの実戦投入と制約整理完了
## Task 1: 代表テスト再確認 (E2E)
✅ 3/3 tests PASS:
- phase190_atoi_impl.hako: 12 (P2 NumberAccumulation)
- phase190_parse_number_impl.hako: 123 (P2 NumberAccumulation)
- phase212_if_sum_min.hako: RC=2 (P3 if-sum with variable condition)
## Task 2: JsonParser ミニケース追加
✅ 2/2 additional tests PASS:
- phase200d_capture_minimal.hako: 30 (P2 with captured vars)
- phase200d_digits_accumulate.hako: 0,1,2 (P2 simple accumulation)
## Task 3: 制約の洗い出し記録
### ✅ 実戦 OK (5/9 tests):
- NumberAccumulation (P2) ✅
- if-sum pattern (P3) ✅
- Captured variables (P2) ✅
- Simple accumulation (P2) ✅
### ⚠️ 制約でブロック (4/9 tests):
1. **LoopBodyLocal in condition** (Pattern 5+ required):
- phase200_digits_atoi_min.hako: `pos` in break condition
- phase200_digits_parse_number_min.hako: `digit_pos` in break condition
2. **MethodCall whitelist** (Phase 193 constraint):
- phase200d_digits_simple.hako: `substring` not whitelisted
- Supported: indexOf, get, toString only
3. **if condition pattern** (Phase 219-fix constraint):
- phase218_json_if_sum_min.hako: Variable in if LHS (`i > 0`)
- if-sum mode accepts only `var CmpOp literal`
## Task 4: 設計ドキュメント固定
Updated docs/development/current/main/joinir-architecture-overview.md:
- Section 4.3: JsonParser 実戦カバレッジ (Phase 210 → Phase 221)
- Coverage: 7/13 (54%) → 9/13 (69%)
- Added: 3 constraint categories with concrete examples
- Conclusion: NumberAccumulation + captured const + if-sum 基盤完成 ✨
Updated CURRENT_TASK.md:
- Added Phase 221 summary (実戦 OK, 制約発見, 次の候補)
## 成果サマリー
- **JoinIR 数値ループ基盤**: 実戦投入可能な成熟度に到達
- **5/9 テスト PASS**: NumberAccumulation, if-sum, captured vars 全て動作
- **3 種の既知制約**: LoopBodyLocal in condition, MethodCall whitelist, if condition pattern
- **次の候補**: Pattern 5+ 拡張, if condition 左辺変数対応
2025-12-10 09:03:46 +09:00
### 4.3 JsonParser 実戦カバレッジ( Phase 221 時点)
2025-12-10 00:01:53 +09:00
docs: Phase 221 JsonParser numerical loops deployment
Phase 221: JsonParser 数値ループの実戦投入と制約整理完了
## Task 1: 代表テスト再確認 (E2E)
✅ 3/3 tests PASS:
- phase190_atoi_impl.hako: 12 (P2 NumberAccumulation)
- phase190_parse_number_impl.hako: 123 (P2 NumberAccumulation)
- phase212_if_sum_min.hako: RC=2 (P3 if-sum with variable condition)
## Task 2: JsonParser ミニケース追加
✅ 2/2 additional tests PASS:
- phase200d_capture_minimal.hako: 30 (P2 with captured vars)
- phase200d_digits_accumulate.hako: 0,1,2 (P2 simple accumulation)
## Task 3: 制約の洗い出し記録
### ✅ 実戦 OK (5/9 tests):
- NumberAccumulation (P2) ✅
- if-sum pattern (P3) ✅
- Captured variables (P2) ✅
- Simple accumulation (P2) ✅
### ⚠️ 制約でブロック (4/9 tests):
1. **LoopBodyLocal in condition** (Pattern 5+ required):
- phase200_digits_atoi_min.hako: `pos` in break condition
- phase200_digits_parse_number_min.hako: `digit_pos` in break condition
2. **MethodCall whitelist** (Phase 193 constraint):
- phase200d_digits_simple.hako: `substring` not whitelisted
- Supported: indexOf, get, toString only
3. **if condition pattern** (Phase 219-fix constraint):
- phase218_json_if_sum_min.hako: Variable in if LHS (`i > 0`)
- if-sum mode accepts only `var CmpOp literal`
## Task 4: 設計ドキュメント固定
Updated docs/development/current/main/joinir-architecture-overview.md:
- Section 4.3: JsonParser 実戦カバレッジ (Phase 210 → Phase 221)
- Coverage: 7/13 (54%) → 9/13 (69%)
- Added: 3 constraint categories with concrete examples
- Conclusion: NumberAccumulation + captured const + if-sum 基盤完成 ✨
Updated CURRENT_TASK.md:
- Added Phase 221 summary (実戦 OK, 制約発見, 次の候補)
## 成果サマリー
- **JoinIR 数値ループ基盤**: 実戦投入可能な成熟度に到達
- **5/9 テスト PASS**: NumberAccumulation, if-sum, captured vars 全て動作
- **3 種の既知制約**: LoopBodyLocal in condition, MethodCall whitelist, if condition pattern
- **次の候補**: Pattern 5+ 拡張, if condition 左辺変数対応
2025-12-10 09:03:46 +09:00
Phase 210– 221 で「数値ループ+ if-sum」を実戦投入し、JoinIR インフラが **本番級に動作する** ことを確認したよ:
2025-12-10 00:01:53 +09:00
docs: Phase 221 JsonParser numerical loops deployment
Phase 221: JsonParser 数値ループの実戦投入と制約整理完了
## Task 1: 代表テスト再確認 (E2E)
✅ 3/3 tests PASS:
- phase190_atoi_impl.hako: 12 (P2 NumberAccumulation)
- phase190_parse_number_impl.hako: 123 (P2 NumberAccumulation)
- phase212_if_sum_min.hako: RC=2 (P3 if-sum with variable condition)
## Task 2: JsonParser ミニケース追加
✅ 2/2 additional tests PASS:
- phase200d_capture_minimal.hako: 30 (P2 with captured vars)
- phase200d_digits_accumulate.hako: 0,1,2 (P2 simple accumulation)
## Task 3: 制約の洗い出し記録
### ✅ 実戦 OK (5/9 tests):
- NumberAccumulation (P2) ✅
- if-sum pattern (P3) ✅
- Captured variables (P2) ✅
- Simple accumulation (P2) ✅
### ⚠️ 制約でブロック (4/9 tests):
1. **LoopBodyLocal in condition** (Pattern 5+ required):
- phase200_digits_atoi_min.hako: `pos` in break condition
- phase200_digits_parse_number_min.hako: `digit_pos` in break condition
2. **MethodCall whitelist** (Phase 193 constraint):
- phase200d_digits_simple.hako: `substring` not whitelisted
- Supported: indexOf, get, toString only
3. **if condition pattern** (Phase 219-fix constraint):
- phase218_json_if_sum_min.hako: Variable in if LHS (`i > 0`)
- if-sum mode accepts only `var CmpOp literal`
## Task 4: 設計ドキュメント固定
Updated docs/development/current/main/joinir-architecture-overview.md:
- Section 4.3: JsonParser 実戦カバレッジ (Phase 210 → Phase 221)
- Coverage: 7/13 (54%) → 9/13 (69%)
- Added: 3 constraint categories with concrete examples
- Conclusion: NumberAccumulation + captured const + if-sum 基盤完成 ✨
Updated CURRENT_TASK.md:
- Added Phase 221 summary (実戦 OK, 制約発見, 次の候補)
## 成果サマリー
- **JoinIR 数値ループ基盤**: 実戦投入可能な成熟度に到達
- **5/9 テスト PASS**: NumberAccumulation, if-sum, captured vars 全て動作
- **3 種の既知制約**: LoopBodyLocal in condition, MethodCall whitelist, if condition pattern
- **次の候補**: Pattern 5+ 拡張, if condition 左辺変数対応
2025-12-10 09:03:46 +09:00
- **実戦確認済みループ**( 9/13 loops ≒ 69%) :
2025-12-10 00:01:53 +09:00
- ✅ `_skip_whitespace` (P2 + P5 Trim, Phase 173)
- ✅ `_trim` leading/trailing (P2 + P5 Trim, Phase 171/172)
- ✅ `_match_literal` 最小版 (P1 Simple, Phase 210)
docs: Phase 221 JsonParser numerical loops deployment
Phase 221: JsonParser 数値ループの実戦投入と制約整理完了
## Task 1: 代表テスト再確認 (E2E)
✅ 3/3 tests PASS:
- phase190_atoi_impl.hako: 12 (P2 NumberAccumulation)
- phase190_parse_number_impl.hako: 123 (P2 NumberAccumulation)
- phase212_if_sum_min.hako: RC=2 (P3 if-sum with variable condition)
## Task 2: JsonParser ミニケース追加
✅ 2/2 additional tests PASS:
- phase200d_capture_minimal.hako: 30 (P2 with captured vars)
- phase200d_digits_accumulate.hako: 0,1,2 (P2 simple accumulation)
## Task 3: 制約の洗い出し記録
### ✅ 実戦 OK (5/9 tests):
- NumberAccumulation (P2) ✅
- if-sum pattern (P3) ✅
- Captured variables (P2) ✅
- Simple accumulation (P2) ✅
### ⚠️ 制約でブロック (4/9 tests):
1. **LoopBodyLocal in condition** (Pattern 5+ required):
- phase200_digits_atoi_min.hako: `pos` in break condition
- phase200_digits_parse_number_min.hako: `digit_pos` in break condition
2. **MethodCall whitelist** (Phase 193 constraint):
- phase200d_digits_simple.hako: `substring` not whitelisted
- Supported: indexOf, get, toString only
3. **if condition pattern** (Phase 219-fix constraint):
- phase218_json_if_sum_min.hako: Variable in if LHS (`i > 0`)
- if-sum mode accepts only `var CmpOp literal`
## Task 4: 設計ドキュメント固定
Updated docs/development/current/main/joinir-architecture-overview.md:
- Section 4.3: JsonParser 実戦カバレッジ (Phase 210 → Phase 221)
- Coverage: 7/13 (54%) → 9/13 (69%)
- Added: 3 constraint categories with concrete examples
- Conclusion: NumberAccumulation + captured const + if-sum 基盤完成 ✨
Updated CURRENT_TASK.md:
- Added Phase 221 summary (実戦 OK, 制約発見, 次の候補)
## 成果サマリー
- **JoinIR 数値ループ基盤**: 実戦投入可能な成熟度に到達
- **5/9 テスト PASS**: NumberAccumulation, if-sum, captured vars 全て動作
- **3 種の既知制約**: LoopBodyLocal in condition, MethodCall whitelist, if condition pattern
- **次の候補**: Pattern 5+ 拡張, if condition 左辺変数対応
2025-12-10 09:03:46 +09:00
- ✅ `_atoi` 最小版 (P2 Break, NumberAccumulation, Phase 190)
- ✅ `_parse_number` 最小版 (P2 Break, NumberAccumulation, Phase 190)
- ✅ if-sum 最小版 (P3 IfPHI, variable condition, Phase 212/220)
- ✅ captured vars 最小版 (P2 Break, function-local const, Phase 200-D)
- ✅ digits accumulate 最小版 (P2 Simple accumulation, Phase 200-D)
- **Phase 210– 221 の成果**:
- 8 本すべて JoinIR → MIR → Runtime 完全成功( RC 正常)
- Pattern1/2/3 自動ルーティング正常動作
- NumberAccumulation (Mul+Add), if-sum (if条件付き更新), captured vars すべて正常
- ConditionEnv/ConditionPatternBox/ExprResultResolver 統合完了
- **制約発見ゼロ(基本パス)** - Phase 190/200/220 の統合が完璧に機能
- **Phase 221 制約発見** (2025-12-09):
- ⚠️ **LoopBodyLocal in condition** : break/continue 条件で loop-body-local 変数を使用( Pattern 5+ 必要)
- ⚠️ **MethodCall whitelist** : body-local init で `substring` 未対応( Phase 193: indexOf/get/toString のみ)
2025-12-10 09:29:32 +09:00
- ~~⚠️ **if condition pattern** : if-sum mode は `var CmpOp literal` のみ(`i > 0` は OK、`0 < i` や `i > j` は NG) ~~ → **Phase 222 で解決済み✅**
- **Phase 222 解決済み制約** (2025-12-10):
- ✅ **if condition pattern** : ConditionPatternBox 正規化で左リテラル・変数同士の比較をサポート
- `0 < i` , `len > i` → `i > 0` , `i < len` に正規化
- `i > j` (var CmpOp var) - 直接サポート
- テスト: phase222_if_cond_left_literal_min.hako → RC=2 達成
docs: Phase 221 JsonParser numerical loops deployment
Phase 221: JsonParser 数値ループの実戦投入と制約整理完了
## Task 1: 代表テスト再確認 (E2E)
✅ 3/3 tests PASS:
- phase190_atoi_impl.hako: 12 (P2 NumberAccumulation)
- phase190_parse_number_impl.hako: 123 (P2 NumberAccumulation)
- phase212_if_sum_min.hako: RC=2 (P3 if-sum with variable condition)
## Task 2: JsonParser ミニケース追加
✅ 2/2 additional tests PASS:
- phase200d_capture_minimal.hako: 30 (P2 with captured vars)
- phase200d_digits_accumulate.hako: 0,1,2 (P2 simple accumulation)
## Task 3: 制約の洗い出し記録
### ✅ 実戦 OK (5/9 tests):
- NumberAccumulation (P2) ✅
- if-sum pattern (P3) ✅
- Captured variables (P2) ✅
- Simple accumulation (P2) ✅
### ⚠️ 制約でブロック (4/9 tests):
1. **LoopBodyLocal in condition** (Pattern 5+ required):
- phase200_digits_atoi_min.hako: `pos` in break condition
- phase200_digits_parse_number_min.hako: `digit_pos` in break condition
2. **MethodCall whitelist** (Phase 193 constraint):
- phase200d_digits_simple.hako: `substring` not whitelisted
- Supported: indexOf, get, toString only
3. **if condition pattern** (Phase 219-fix constraint):
- phase218_json_if_sum_min.hako: Variable in if LHS (`i > 0`)
- if-sum mode accepts only `var CmpOp literal`
## Task 4: 設計ドキュメント固定
Updated docs/development/current/main/joinir-architecture-overview.md:
- Section 4.3: JsonParser 実戦カバレッジ (Phase 210 → Phase 221)
- Coverage: 7/13 (54%) → 9/13 (69%)
- Added: 3 constraint categories with concrete examples
- Conclusion: NumberAccumulation + captured const + if-sum 基盤完成 ✨
Updated CURRENT_TASK.md:
- Added Phase 221 summary (実戦 OK, 制約発見, 次の候補)
## 成果サマリー
- **JoinIR 数値ループ基盤**: 実戦投入可能な成熟度に到達
- **5/9 テスト PASS**: NumberAccumulation, if-sum, captured vars 全て動作
- **3 種の既知制約**: LoopBodyLocal in condition, MethodCall whitelist, if condition pattern
- **次の候補**: Pattern 5+ 拡張, if condition 左辺変数対応
2025-12-10 09:03:46 +09:00
- **残りループ** (Phase 222+ で段階的対応予定):
2025-12-10 00:01:53 +09:00
- `_parse_array` , `_parse_object` (MethodCall 複数)
- `_unescape_string` (複雑なキャリア処理)
docs: Phase 221 JsonParser numerical loops deployment
Phase 221: JsonParser 数値ループの実戦投入と制約整理完了
## Task 1: 代表テスト再確認 (E2E)
✅ 3/3 tests PASS:
- phase190_atoi_impl.hako: 12 (P2 NumberAccumulation)
- phase190_parse_number_impl.hako: 123 (P2 NumberAccumulation)
- phase212_if_sum_min.hako: RC=2 (P3 if-sum with variable condition)
## Task 2: JsonParser ミニケース追加
✅ 2/2 additional tests PASS:
- phase200d_capture_minimal.hako: 30 (P2 with captured vars)
- phase200d_digits_accumulate.hako: 0,1,2 (P2 simple accumulation)
## Task 3: 制約の洗い出し記録
### ✅ 実戦 OK (5/9 tests):
- NumberAccumulation (P2) ✅
- if-sum pattern (P3) ✅
- Captured variables (P2) ✅
- Simple accumulation (P2) ✅
### ⚠️ 制約でブロック (4/9 tests):
1. **LoopBodyLocal in condition** (Pattern 5+ required):
- phase200_digits_atoi_min.hako: `pos` in break condition
- phase200_digits_parse_number_min.hako: `digit_pos` in break condition
2. **MethodCall whitelist** (Phase 193 constraint):
- phase200d_digits_simple.hako: `substring` not whitelisted
- Supported: indexOf, get, toString only
3. **if condition pattern** (Phase 219-fix constraint):
- phase218_json_if_sum_min.hako: Variable in if LHS (`i > 0`)
- if-sum mode accepts only `var CmpOp literal`
## Task 4: 設計ドキュメント固定
Updated docs/development/current/main/joinir-architecture-overview.md:
- Section 4.3: JsonParser 実戦カバレッジ (Phase 210 → Phase 221)
- Coverage: 7/13 (54%) → 9/13 (69%)
- Added: 3 constraint categories with concrete examples
- Conclusion: NumberAccumulation + captured const + if-sum 基盤完成 ✨
Updated CURRENT_TASK.md:
- Added Phase 221 summary (実戦 OK, 制約発見, 次の候補)
## 成果サマリー
- **JoinIR 数値ループ基盤**: 実戦投入可能な成熟度に到達
- **5/9 テスト PASS**: NumberAccumulation, if-sum, captured vars 全て動作
- **3 種の既知制約**: LoopBodyLocal in condition, MethodCall whitelist, if condition pattern
- **次の候補**: Pattern 5+ 拡張, if condition 左辺変数対応
2025-12-10 09:03:46 +09:00
- `_atoi` /`_parse_number` 本体( LoopBodyLocal in condition 対応後)
2025-12-10 00:01:53 +09:00
docs: Phase 221 JsonParser numerical loops deployment
Phase 221: JsonParser 数値ループの実戦投入と制約整理完了
## Task 1: 代表テスト再確認 (E2E)
✅ 3/3 tests PASS:
- phase190_atoi_impl.hako: 12 (P2 NumberAccumulation)
- phase190_parse_number_impl.hako: 123 (P2 NumberAccumulation)
- phase212_if_sum_min.hako: RC=2 (P3 if-sum with variable condition)
## Task 2: JsonParser ミニケース追加
✅ 2/2 additional tests PASS:
- phase200d_capture_minimal.hako: 30 (P2 with captured vars)
- phase200d_digits_accumulate.hako: 0,1,2 (P2 simple accumulation)
## Task 3: 制約の洗い出し記録
### ✅ 実戦 OK (5/9 tests):
- NumberAccumulation (P2) ✅
- if-sum pattern (P3) ✅
- Captured variables (P2) ✅
- Simple accumulation (P2) ✅
### ⚠️ 制約でブロック (4/9 tests):
1. **LoopBodyLocal in condition** (Pattern 5+ required):
- phase200_digits_atoi_min.hako: `pos` in break condition
- phase200_digits_parse_number_min.hako: `digit_pos` in break condition
2. **MethodCall whitelist** (Phase 193 constraint):
- phase200d_digits_simple.hako: `substring` not whitelisted
- Supported: indexOf, get, toString only
3. **if condition pattern** (Phase 219-fix constraint):
- phase218_json_if_sum_min.hako: Variable in if LHS (`i > 0`)
- if-sum mode accepts only `var CmpOp literal`
## Task 4: 設計ドキュメント固定
Updated docs/development/current/main/joinir-architecture-overview.md:
- Section 4.3: JsonParser 実戦カバレッジ (Phase 210 → Phase 221)
- Coverage: 7/13 (54%) → 9/13 (69%)
- Added: 3 constraint categories with concrete examples
- Conclusion: NumberAccumulation + captured const + if-sum 基盤完成 ✨
Updated CURRENT_TASK.md:
- Added Phase 221 summary (実戦 OK, 制約発見, 次の候補)
## 成果サマリー
- **JoinIR 数値ループ基盤**: 実戦投入可能な成熟度に到達
- **5/9 テスト PASS**: NumberAccumulation, if-sum, captured vars 全て動作
- **3 種の既知制約**: LoopBodyLocal in condition, MethodCall whitelist, if condition pattern
- **次の候補**: Pattern 5+ 拡張, if condition 左辺変数対応
2025-12-10 09:03:46 +09:00
**結論**:
- JoinIR 数値ループ基盤( NumberAccumulation + captured const + if-sum) は **実戦投入可能な成熟度** に到達 ✨
- **Phase 221 で 3 種の既知制約を整理** - 次フェーズで Pattern 5+ 拡張 / MethodCall whitelist 拡張が候補
2025-12-10 00:01:53 +09:00
2025-12-08 21:41:19 +09:00
---
2025-12-10 22:48:45 +09:00
## 6. Roadmap( JoinIR の今後のゴール)
ここから先の JoinIR の「目指す形」を、箱レベルでざっくり書いておくよ。フェーズ詳細は各 phase ドキュメントに分散させて、このセクションは常に最新の方向性だけを保つ。
### 6.1 直近( Phase 176-177 まわり)
- **P5( Trim/JsonParser 系)ループの複数キャリア対応** ✅ Phase 176 完了 (2025-12-08)
- 完了内容:
- Pattern2 lowerer を全キャリア対応に拡張(ヘッダ PHI / ループ更新 / ExitLine) 。
- CarrierUpdateLowerer ヘルパで UpdateExpr → JoinIR 変換を統一。
- 2キャリア( pos + result) E2E テスト完全成功。
- 技術的成果:
- CarrierInfo / ExitMeta / ExitLine / LoopHeaderPhiBuilder の multi-carrier 対応を Pattern2 lowerer で完全活用。
- Trim pattern の「キャリア = ループ変数」という誤解を解消( loop_var は特殊キャリア)。
- 次のステップ (Phase 177):
- JsonParser `_parse_string` 本体を P2+P5 で通す( pos + result の 2 キャリアで実ループ動作確認)。
### 6.2 中期( selfhost depth‑ 2 / JsonParser 本体)
- **JsonParserBox / Trim 系ループの本線化**
- 目標:
- `_trim` / `_skip_whitespace` / `_parse_string` / `_parse_array` などの主要ループが、すべて JoinIR Pattern1– 4 + P5 で通ること。
- LoopConditionScopeBox + LoopBodyCarrierPromoter + TrimLoopHelper の上で安全に正規化できるループを広げていく。
- 方針:
- 「ループの形」は P1– P4 から増やさず、複雑さは BoolExprLowerer / ContinueBranchNormalizer / P5 系の補助箱で吸収する。
- LoopPatternSpace の P6/P7/P12 候補( break+continue 同時 / 複数キャリア条件更新 / early return) は、実アプリで必要になった順に小さく足す。
- **selfhost depth‑ 2( .hako JoinIR/MIR Frontend) **
- 目標:
- `.hako → JsonParserBox → Program/MIR JSON → MirAnalyzerBox/JoinIrAnalyzerBox → VM/LLVM` の深度 2 ループを、日常的に回せるようにする。
- Rust 側の JoinIR は「JSON を受け取って実行・検証するランナー層」、.hako 側が「JoinIR/MIR を構築・解析する言語側 SSOT」という役割分担に近づける。
- **Phase 230( ExprLowerer / ScopeManager 設計フェーズ)**
- 目標: 条件式 / init 式 / carrier 更新式の lowering を将来ひとつの ExprLowerer + ScopeManager に統合できるよう、既存の散在する lowering/API/Env を設計レベルで整理する(このフェーズではコード変更なし)。
2025-12-11 00:21:29 +09:00
- **Phase 233( loop_update_summary テスト刷新フェーズ)**
- 目標: deprecated `analyze_loop_updates()` 依存のテストを廃止し、`analyze_loop_updates_from_ast()` に揃えたユニットで if-sum 判定ラインの期待値を固定する。
- **Phase 232( Failing Tests の棚卸しフェーズ)**
- 目標: `cargo test --release` で残っている 7 件の FAIL を「どの箱 / どのパターン / どのレイヤ」の問題かで整理し、P0/P1/P2 に分類して次フェーズのターゲットを決める( core バグを見つけるフェーズではなく、未対応領域の可視化フェーズ)。
- **Phase 234( ArrayFilter / Pattern3 設計フェーズ)**
- 目標: ArrayExtBox.filter 系 3 テストを P3 if-PHI の正式対象に含めるか、当面は PoC 領域として Fail-Fast を仕様として維持するかを docs ベースで決める(コード変更なし)。
- **Phase 235( ExprLowerer / ScopeManager パイロット実装 & テスト)**
- 目標: ExprLowerer/ScopeManager の Condition 文脈を小さな範囲でユニットテストしつつ、Pattern2 の break 条件で validation-only の経路として動かし、既存の legacy lowering と挙動が一致することを確認する(本番 lowering の置き換えは後続フェーズ)。
- **Phase 236-EX( ExprLowerer / ScopeManager 本番導入 - Pattern2 break 条件)**
- 目標: Pattern2 の break 条件 lowering を ExprLowerer/ScopeManager 経由の本番経路に切り替え、既存の condition_to_joinir ベース実装と RC / JoinIR 構造 / ログ挙動が一致することを確認する(影響範囲は Pattern2 break 条件のみに限定)。
- **Phase 237-EX( ExprLowerer 条件パターン棚卸しフェーズ)**
- 目標: JsonParser / selfhost のループ条件・break/continue 条件をカタログ化し、ExprLowerer/ScopeManager で優先的に扱うパターンと後回しにするパターンを SSOT 化する(コード変更なし)。
- **Phase 238-EX( ExprLowerer / ScopeManager Scope Boundaries) **
- 目標: ExprLowerer / ScopeManager / ConditionEnv / LoopBodyLocalEnv / UpdateEnv の責務と参照範囲を文書化し、「誰がどこまで見てよいか」を SSOT として固定する(コード変更なし、ガイドライン整備)。***
2025-12-10 22:48:45 +09:00
---
2025-12-08 21:41:19 +09:00
## 5. selfhost / .hako JoinIR Frontend との関係
2025-12-07 21:02:20 +09:00
JoinIR は Rust 側だけでなく、将来的に .hako selfhost コンパイラ側でも生成・解析される予定だよ:
- .hako 側の JsonParser/分析箱は、Program JSON / MIR JSON v1 を読んで JoinIR/MIR を解析する。
- Rust 側 JoinIR ラインの設計変更(特に ValueId/ExitLine/Boundary 周り)は、
**必ずこのファイルを更新してから** .hako 側にも段階的に反映する方針。
「JoinIR の仕様」「箱の責務」「境界の契約」は、このファイルを SSOT として運用していく。
---
## 5. 関連ドキュメント
- `docs/development/current/main/10-Now.md`
- 全体の「いまどこ」を短くまとめたダッシュボード。
- `docs/private/roadmap2/phases/phase-180-joinir-unification-before-selfhost/README.md`
- JoinIR 統一フェーズ全体のロードマップと進捗。
- 各 Phase 詳細:
- 185– 188: Strict mode / LoopBuilder 削除 / Pattern1– 4 基盤
- 189– 193: Multi-function merge / Select bridge / ExitLine 箱化
- 171– 172 / 33‑ 10/13: ConditionEnv, ConditionBinding, JoinFragmentMeta, ExitLineRefactor 等
2025-12-08 03:06:20 +09:00
- `docs/development/current/main/loop_pattern_space.md`
- JoinIR ループパターン空間の整理メモ。
どの軸(継続条件 / break / continue / PHI / 条件変数スコープ / 更新パターン)でパターンを分けるか、
そして P1– P4 / Trim(P5) の位置づけと、今後追加候補のパターン一覧がまとまっている。
2025-12-08 15:17:53 +09:00
---
## 6. Roadmap( JoinIR の今後のゴール)
ここから先の JoinIR の「目指す形」を、箱レベルでざっくり書いておくよ。フェーズ詳細は各 phase ドキュメントに分散させて、このセクションは常に最新の方向性だけを保つ。
### 6.1 直近( Phase 176-177 まわり)
- **P5( Trim/JsonParser 系)ループの複数キャリア対応** ✅ Phase 176 完了 (2025-12-08)
- 完了内容:
- Pattern2 lowerer を全キャリア対応に拡張(ヘッダ PHI / ループ更新 / ExitLine) 。
- CarrierUpdateLowerer ヘルパで UpdateExpr → JoinIR 変換を統一。
- 2キャリア( pos + result) E2E テスト完全成功。
- 技術的成果:
- CarrierInfo / ExitMeta / ExitLine / LoopHeaderPhiBuilder の multi-carrier 対応を Pattern2 lowerer で完全活用。
- Trim pattern の「キャリア = ループ変数」という誤解を解消( loop_var は特殊キャリア)。
- 次のステップ (Phase 177):
- JsonParser `_parse_string` 本体を P2+P5 で通す( pos + result の 2 キャリアで実ループ動作確認)。
### 6.2 中期( selfhost depth‑ 2 / JsonParser 本体)
- **JsonParserBox / Trim 系ループの本線化**
- 目標:
- `_trim` / `_skip_whitespace` / `_parse_string` / `_parse_array` などの主要ループが、すべて JoinIR Pattern1– 4 + P5 で通ること。
- LoopConditionScopeBox + LoopBodyCarrierPromoter + TrimLoopHelper の上で安全に正規化できるループを広げていく。
- 方針:
- 「ループの形」は P1– P4 から増やさず、複雑さは BoolExprLowerer / ContinueBranchNormalizer / P5 系の補助箱で吸収する。
- LoopPatternSpace の P6/P7/P12 候補( break+continue 同時 / 複数キャリア条件更新 / early return) は、実アプリで必要になった順に小さく足す。
- **selfhost depth‑ 2( .hako JoinIR/MIR Frontend) **
- 目標:
- `.hako → JsonParserBox → Program/MIR JSON → MirAnalyzerBox/JoinIrAnalyzerBox → VM/LLVM` の深度 2 ループを、日常的に回せるようにする。
- Rust 側の JoinIR は「JSON を受け取って実行・検証するランナー層」、.hako 側が「JoinIR/MIR を構築・解析する言語側 SSOT」という役割分担に近づける。
- 前提:
- 本ドキュメント( joinir-architecture-overview.md) を .hako 側の JoinIR 実装の参照設計として維持し、仕様変更は必ずここを更新してから .hako にも反映する。
### 6.3 当面やらないこと( Non‑ Goals)
- ループパターンを闇雲に増やすこと
- P1– P4( 構造) + P5( body‑ local 条件を昇格する補助パス)を「骨格」とみなし、
新しいパターンが必要になったときは LoopPatternSpace に追記してから、小さな箱で補う方針。
- LoopBuilder の復活や、JoinIR 以外の別ラインによるループ lowering
- LoopBuilder 系は Phase 186– 187 で完全に削除済み。
ループに関する新しい要件はすべて JoinIR 側のパターン/箱の拡張で扱う。
- JoinIR の中に言語固有のハードコード(特定 Box 名や変数名)を戻すこと
- Trim/JsonParser 系は、構造( パターン) と補助箱( Promoter/Helper) で扱い、
「sum」「ch」など名前ベースの判定は LoopUpdateSummary / TrimLoopHelper の内部に閉じ込める。
この Roadmap は、JoinIR 層の変更や selfhost 深度を進めるたびに更新していくよ。
2025-12-09 03:18:05 +09:00
---
## 7. JoinIR 第1章: 基盤完成サマリ( 2025-12-09 時点)
### 7.1 現在の対応状況
**Pattern サポート**:
| Pattern | 説明 | 状態 |
|---------|------|------|
| P1 Simple | `loop(cond) { body }` | ✅ 完成 |
| P2 Break | `loop(cond) { if(...) break }` | ✅ 完成 |
| P3 If-PHI | `loop { if(...) a else b; use(φ) }` | ✅ 完成 |
| P4 Continue | `loop { if(...) continue }` | ✅ 完成 |
| P5 Trim | LoopBodyLocal → bool carrier 昇格 | ✅ 基本完成 |
**UpdateKind サポート**:
| UpdateKind | 例 | 状態 |
|------------|-----|------|
| CounterLike | `i = i + 1` | ✅ |
| AccumulationLike | `sum = sum + x` | ✅ |
| StringAppendChar | `s = s + ch` | ✅ |
| StringAppendLiteral | `s = s + "lit"` | ✅ |
| NumberAccumulation | `v = v * 10 + digit` | ✅ (Phase 190) |
| Complex | method call 含む | ❌ Fail-Fast |
**アーキテクチャ SSOT ライン**:
- ✅ LoopHeaderPhiBuilder: ループ変数・キャリアの PHI を SSOT で生成
- ✅ ExitLineReconnector: PHI dst → variable_map 接続
- ✅ JoinInlineBoundaryBuilder: 全パターンで Builder パターン統一
- ✅ JoinIRVerifier: デバッグビルドで契約検証
- ✅ ExitLine Contract Verifier: PHI 配線検証( Phase 190-impl-D)
2025-12-09 03:59:53 +09:00
### 7.2 残タスク( Phase 192+ で対応予定)
2025-12-09 03:18:05 +09:00
2025-12-09 03:59:53 +09:00
1. ** ✅ body-local 変数の init + update lowering** → Phase 191 完了
- `local digit = i + 1` のような body-local 変数の JoinIR/MIR 生成完了
- 対応済み: 整数リテラル、変数参照、二項演算
- テスト: `phase191_body_local_atoi.hako` → 期待値 123 ✅
2025-12-09 03:18:05 +09:00
2025-12-09 04:28:10 +09:00
2. ** ✅ Complex addend 対応** → Phase 192 完了
- `v = v * 10 + digits.indexOf(ch)` のような method call を含む NumberAccumulation対応
- ComplexAddendNormalizer で `temp = f(x)` に分解してから NumberAccumulation に載せる実装完了
- テスト: phase192_normalization_demo.hako → 123 ✅
- 制約: MethodCall を含む init 式は Phase 193 で対応予定
2025-12-09 03:18:05 +09:00
2025-12-10 19:08:18 +09:00
3. ** ✅ MethodCall を含む init 式の対応** → Phase 193 完了、Phase 225 でメタ駆動化
2025-12-09 13:22:14 +09:00
- `local digit = digits.indexOf(ch)` のような MethodCall init の lowering 完了
2025-12-09 04:28:10 +09:00
- LoopBodyLocalInitLowerer 拡張( BoxCall emission)
2025-12-10 19:08:18 +09:00
- **Phase 193**: ハードコードされた whitelist: indexOf, get, toString 対応
- **Phase 225**: CoreMethodId メタ駆動化によりハードコード完全削除 ✅
- `SUPPORTED_INIT_METHODS` 定数削除(メソッド名 whitelist)
- Box 名の match 文削除(`indexOf → StringBox` 等のハードコード)
- MethodCallLowerer への委譲により単一責任原則達成
- `allowed_in_init()` メタデータで whitelist 管理
- **substring メソッド追加**: Phase 225 で substring が body-local init で使用可能に
- **コード削減**: -82 行( 158削除 - 76追加)
2025-12-09 13:22:14 +09:00
- 制約: body-local init のみ対応、condition 内の MethodCall は Phase 200+
4. ** ✅ JsonParser 実戦投入( P1/P2/P5 検証)** → Phase 194 完了
- 4/10 ループが JoinIR 経路で動作確認 (40% coverage)
- Target loops: _skip_whitespace, _trim (x2), _match_literal
- Deferred loops: _parse_number, _atoi (ConditionEnv constraint)
- Deferred loops: _parse_string, _unescape_string (complex carriers)
- Deferred loops: _parse_array, _parse_object (multiple MethodCalls)
- 詳細: phase194-loop-inventory.md, phase194-jsonparser-deployment.md
2025-12-09 14:45:04 +09:00
5. **Pattern 3 拡張(複数キャリア対応)** → Phase 195 + 196 完了 ✅
2025-12-09 13:22:14 +09:00
- 目的: P3( If-Else PHI) で 2-3 個の Carrier を同時処理
2025-12-09 14:45:04 +09:00
- **Phase 195**: Lowerer 側完了( multi-carrier PHI 生成: sum + count) ✅
- **Phase 196**: Select 二重 remap バグ修正 ✅
- 根本原因: `instruction_rewriter.rs` で PHI inputs を二重 remap
- 修正: block ID のみ remap、ValueId は既に remap 済み
- **E2E 結果**: phase195_sum_count.hako → 93 ✅
- 詳細: phase196-select-bug-analysis.md
2025-12-09 15:28:49 +09:00
6. ** ✅ JoinIR 実戦適用(軽量ループ検証)** → Phase 197 完了 ✅
- 目的: Phase 196 までの安定基盤を実戦の小さいループで検証
- 対象ループ( 5本) :
1. `_match_literal` (P1) - JsonParser 単純 while ✅
2. `_skip_whitespace` (P2) - JsonParser break パターン ✅
3. `phase195_sum_count.hako` (P3 multi-carrier) ✅
4. `loop_if_phi.hako` (P3 single-carrier) ✅
5. `loop_min_while.hako` (P1 minimal) ✅
- 結果:
- [x] routing 確認: 全ループ whitelisted ✅
- [x] E2E 実行: 4/5 ループで期待値出力、1/5 routing 確認 ✅
- [x] 退行なし: Phase 190-196 テスト全 PASS ✅
- 詳細: phase197-lightweight-loops-deployment.md
2025-12-12 03:15:45 +09:00
7. **JsonParser/selfhost 実戦 JoinIR 適用状況** (2025-12-09 更新 → Phase 42 で棚卸し済み)
2025-12-09 15:28:49 +09:00
| Function | Pattern | Status | Note |
|----------|---------|--------|------|
| `_match_literal` | P1 | ✅ JoinIR OK | Phase 197 検証済み( E2E PASS) |
| `_skip_whitespace` | P2 | ✅ JoinIR OK | Phase 197 routing 確認( whitelisted) |
| `_trim` (leading) | P5 | ✅ JoinIR OK | Phase 173 実証済み |
| `_trim` (trailing) | P5 | ✅ JoinIR OK | Phase 173 実証済み |
| `phase195_sum_count` | P3 | ✅ JoinIR OK | Phase 196 検証済み( multi-carrier) |
| `loop_if_phi` | P3 | ✅ JoinIR OK | Phase 196 検証済み( single-carrier) |
| `loop_min_while` | P1 | ✅ JoinIR OK | Phase 165 基本検証済み |
2025-12-12 03:15:45 +09:00
| `_parse_number` | P2 | ✅ JoinIR OK | Phase 245B-IMPL: P2-Mid( num_str LoopState キャリア)を Structured→Normalized(dev, direct) で固定 |
| `_atoi` | P2 | ✅ JoinIR OK | Phase 246-EX で NumberAccumulation パターンとして統合( P2-Mid、Normalized: mini + real(dev, 符号対応) / canonical 準備中)|
2025-12-09 15:28:49 +09:00
| `_parse_string` | P3 | ⚠️ Deferred | 複雑キャリア( Phase 195+ 拡張後)|
| `_unescape_string` | P3 | ⚠️ Deferred | 複雑キャリア( Phase 195+ 拡張後)|
| `_parse_array` | - | ⚠️ Deferred | 複数 MethodCall( Phase 195+) |
| `_parse_object` | - | ⚠️ Deferred | 複数 MethodCall( Phase 195+) |
2025-12-12 03:15:45 +09:00
**Coverage**: 9/13 ループ JoinIR 対応済み(約 69%)
**Verification**: 代表ループ( P1/P2 Core + Trim/P3) については E2E テストで挙動確認済み。詳細なケースごとの状況は各 Phase ドキュメント( Phase 197/245/246 など)を参照。
2025-12-09 15:28:49 +09:00
8. **JsonParser 残り複雑ループへの適用( Phase 198+, 200+) **
2025-12-09 13:22:14 +09:00
- Phase 200+: ConditionEnv 拡張 (function-scoped variables) → _parse_number, _atoi
2025-12-09 15:28:49 +09:00
- Phase 198+: Pattern 3 拡張 (multi-flag carriers) → _parse_string, _unescape_string
- Phase 198+: MethodCall 拡張 (multiple calls in body) → _parse_array, _parse_object
2025-12-09 13:22:14 +09:00
- selfhost `.hako` コンパイラの全ループを JoinIR で処理 (Phase 210+)
2025-12-10 02:07:28 +09:00
9. **Pattern 3 If-Sum AST ベース実装** → Phase 213-217 完了 ✅
- **Phase 213**: If-sum パターン AST ベース lowerer 実装
- `loop_with_if_phi_if_sum.rs` : AST 抽出 + JoinIR 生成
- Dual-mode 構成: if-sum mode / legacy mode
- **Phase 214**: Dynamic join inputs 対応( hardcoded 3-input 除去)
- **Phase 215**: ExprResult exit contract 確立
- **Phase 216**: Selfhost if-sum production test 検証
- **Phase 217**: Multi-carrier if-sum 動作確認(追加実装ゼロ行)
- 詳細: phase213-if-sum-implementation.md, phase217-if-sum-multi.md
10. **Phase 218: JsonParser If-Sum 適用調査** → 🔍 調査完了
- **目的**: JsonParser-style if-sum パターン (`sum = sum + digit` ) への Pattern 3 適用
- **結果**: パターン認識ギャップを発見
- Phantom `count` carrier が誤検出され、`is_if_sum_pattern()` が false
- AST ベース lowerer は実装済みだが起動されていない
- 根本原因: carrier 検出ロジックの name heuristic が脆弱
- **次フェーズ**: Carrier 検出修正( Phase 219)
- 詳細: phase218-jsonparser-if-sum-min.md
2025-12-11 19:11:26 +09:00
---
## 3. JoinIR → JoinIR 正規化レイヤ(構想 / Phase 26-H ライン)
### 3.1 Structured JoinIR と Normalized JoinIR( 概念レベル)
JoinIR ラインは、今後は「同じ JoinIR をフェーズごとに正規化していく」二段構成で扱う想定だよ:
- **Structured JoinIR( 現行層) **
- Pattern1– 5 / CarrierInfo / ConditionEnv / UpdateEnv / Boundary / ExitLine までを終えた状態。
- while/if/break/continue/return がまだ「構造」として残っていてよい層。
- いまの JoinIR lowering( Pattern lowerer 群)が出力しているものはここ。
- **Normalized JoinIR( JoinIR’ / CPS 風層)**
- 制御構造をすべて「関数+継続+ Env」の形に正規化した状態。
- ループは `loop_step(env, k_exit)` と exit 継続のペア、if は `if_branch(env, k_then, k_else)` + join 継続で表現。
- while/break/continue/return は **TailCallFn/TailCallKont + If** だけに還元され、goto/生の branch は現れない。
- Env は「ループキャリア + DigitPos/num_str などの Derived + captured 変数」を 1 つの struct としてまとめる。
パイプラインのイメージ:
```text
AST
↓
JoinIR(Structured) // Pattern1– 5, CarrierInfo, ConditionEnv/UpdateEnv, Boundary/ExitLine
↓ JoinIR パス A: 正規化( JoinIR → JoinIR)
JoinIR(Normalized) // 関数 + 継続 + Env のみ( TailCall-only)
↓ JoinIR→MIR bridge
MIR
```
型レベルでは、次の二案のどちらかで扱う想定だよ(詳細は今後の Phase で選択):
- **案① 型を分ける**
- `JoinModuleRaw` ( Structured) 、`JoinModuleCps` ( Normalized) を別型にする。
- Bridge( JoinIR→MIR) は `JoinModuleCps` だけを受け取る。
- **案② 型は 1 つ+フェーズフラグ**
- `JoinModule { phase: JoinIrPhase, ... }` として、`phase = Structured / Normalized` をメタデータで持つ。
- JoinIR パスはすべて `fn run(&mut JoinModule)` ( = joinir→joinir) で構成し、
Verifier が「phase=Normalized なら while/if/break/continue/return 禁止」などの不変条件をチェックする。
どちらの案でも本質は同じで、「JoinIR の下に JoinIR’ ( = 正規形フェーズ)を 1 段挟む」という設計、というのがポイントだよ。
### 3.2 Normalized JoinIR の基本モデル(ラフスケッチ)
Normalized JoinIR では、制御構造を次の 3 要素だけで表現する想定だよ:
- **Env( 環境) **
- そのループ/if に必要な情報を 1 つにまとめた struct。
- フィールド種別の例:
- `Carrier` ( LoopState キャリア: i, sum, result, num_state 等)
- `Derived` ( DigitPos 二重値, NumberAccumulation 等)
- `Captured` (外側のローカルや関数パラメータ: s, len 等)
- **Fn( 通常の関数) **
- 典型例: `loop_step(env, k_exit)` / `loop_body(env, k_exit)` 。
- 末尾は常に `TailCallFn` または `TailCallKont` 。
- **Kont( 継続) **
- 典型例: ループ exit 後の処理、if 後の join、関数 return など。
- 末尾は別の Fn/Kont への tail-call。
制御の不変条件( Normalized フェーズ):
1. 制御フローは `TailCallFn` / `TailCallKont` / `If(cond, then_k, else_k, env)` のみで表現する。
2. 各ループは「`loop_step(env, k_exit)` 関数 + `k_exit(env)` 継続」のペアとして現れる( break は必ず k_exit へ TailCall) 。
3. continue は `loop_step` への TailCall として現れる(ヘッダ PHI 相当は Env の書き込み順で表現)。
4. return は専用の `return_kont(env)` への TailCall で表現される。
5. EnvLayoutVerifier( 検証箱) が、常に正しい EnvLayout が使われていることをチェックする。
これにより、現在 JoinIR 層で苦労している「PHI 配線」「exit_bindings/jump_args 整合性」「評価順のねじれ」は、
Normalized JoinIR 側では「Env フィールドの更新順」と「どの継続を呼ぶか」に還元される想定だよ。
2025-12-12 04:40:46 +09:00
#### 3.2.1 P1〜P4 と Normalized ループ形
Normalized JoinIR のゴールは、「P1〜P4 すべてのループを同じループ骨格(`loop_step(env, k_exit)` + 継続)で表現する」ことだよ:
- P1 Simple:
- `loop_step(env, k_exit)` だけを持つ最小形( break/continue なし)。
- 条件が false になったら `k_exit(env)` に TailCall、true なら body を 1 ステップ進めて再び `loop_step` を呼ぶ。
- P2 Break:
- P1 の形に「body 後の break 判定」と `k_exit(env)` への分岐が加わったもの。
- break/continue/return 自体はすべて継続呼び出し(`TailCallKont` / `TailCallFn` )として表現され、型レベルでは P1 の上位互換。
- P3 If‑ PHI:
- ループ本体に `if_branch(env, k_then, k_else)` + join 継続を挟んだ形として表現し、PHI は「Env のフィールド更新順+ join 継続」で表す。
- P4 Continue:
- `continue` は「更新後に `loop_step(env', k_exit)` へ TailCall」するだけの構造として扱い、break/return と同じく継続レベルで閉じる。
設計としては **Normalized IR の型と不変条件は P1〜P4 で共通**で、違いは Structured 層からどのように `loop_step` / 継続を合成するか(`LoopCpsSynthesizer` 側の分岐)だけに閉じ込める前提だよ。
- Phase 26‑ H / 28– 43 では、まず P1/P2( 特に JsonParser の P2-Core/P2-Mid) だけを Normalized に載せて設計を固定した。
- P3/P4 の Normalized 対応は今後のフェーズ( NORM‑ P3 / NORM‑ P4 ライン)で、上の骨格に揃える形で段階的に進める。
この方針により、「先に P1/P2 だけ Normalized を実装しても、後から P3/P4 を同じ器に寄せられる」ことを文書上で保証しておく。
2025-12-11 20:54:33 +09:00
### 3.3 Normalized JoinIR 導入のメリットと初期コスト
Normalized JoinIR を 1 段挟むと、開発の手触りがどう変わるかをここでまとめておくよ。
#### 3.3.1 楽になるポイント
- **デバッグ時の「問いの分離」**
- Structured JoinIR だけで `_parse_number` / `_atoi` を追うときは、常に同時に 4 つくらいの問いを抱えることになる:
1. Pattern 判定は正しいか( P1/P2/P3/P4/P5)
2. CarrierInfo / LoopState / LoopLocalZero / FromHost の設計は妥当か
3. 評価順( header → body-init → break → updates → tail) は正しいか
4. PHI / exit_bindings / jump_args / variable_map の整合は取れているか
- Normalized JoinIR を挟むと、これが層ごとに分割される:
- 上( Structured) : Pattern 判定 + CarrierInfo/Condition/Update の設計
- 中( Normalized) : EnvLayout + step/kont 合成(制御骨格)
- 下( Bridge) : TailCall+ Env から MIR/VM の PHI/branch を作る
- これにより、「これは Pattern/Carrier 問題」「これは Env+ 継続の組み立て問題」「これは Bridge 問題」と、デバッグ時にレイヤ単位で切り分けやすくなる。
- **PHI まわりの思考負荷軽減**
- Structured JoinIR では、LoopHeader PHI / Exit PHI / Select 展開 PHI と、exit_bindings/jump_args/variable_map 再接続が絡み合う。
- Normalized フェーズでは、キャリアや DigitPos/NumberAccumulation などはすべて Env フィールドになり、PHI は JoinIR’ には現れない:
- 「どこから値が来たか?」は「どの Env フィールドがどの順番で更新されたか」を見るだけでよくなる。
- PHI/exit_bindings は Bridge 側の責務として明示的に分離される。
- **while/if/break/continue/return の骨格が共通化される**
- Pattern1– 5 ごとに似たロジックが散らばりがちな現在と違い、Normalized では:
- ループ: `loop_step(env, k_exit)` + `loop_body(env, k_exit)`
- if: 条件判定 → then/else 継続 → join 継続
- break: `TailCallKont(k_exit, env)`
- continue: `TailCallFn(loop_step, env', k_exit)`
- こうした「世界共通のテンプレ」を 1 箱にまとめておけるので、新しい Pattern や JsonParser/selfhost のループを追加するときも、構造箱( Structured) 側だけで頑張ればよくなる。
- **「1箱 = 1質問」を守りやすくなる**
- Structured JoinIR では、PatternLowerer が一時的に「構造+ 評価順+ PHI 配線+ exit_bindings」を抱える瞬間がある。
- Normalized を挟むと:
- Structured: 「どの値を Env に載せるか」を決める箱
- Normalized: 「Env と継続にどう分解するか」を決める箱
- Bridge: 「TailCall+ Env を MIR/VM にどう落とすか」を決める箱
- という分担にできるので、「この箱は何の質問に答えるか」が清潔に保ちやすくなる。
#### 3.3.2 初期コストと注意点
- **新しい IR モデルを 1 セット覚える必要がある**
- Env+ Fn+ Kont+ TailCall の世界観を JoinIR 層の前提として追加することになる。
- 一度定着すれば Structured より思考負荷は下がるが、導入初期は「型・不変条件・ダンプの読み方」に慣れるまで少しコストが乗る。
- **移行期間中は 2 経路の比較が発生する**
- AST → JoinIR(Structured) → MIR
- AST → JoinIR(Structured) → JoinIR(Normalized) → MIR
- の 2 経路をしばらく併走させ、dev で結果比較をするフェーズが必要になる。
- Phase 26-H / 28-NORM-P2 のように「小さいサブセットから比較用にだけ回す」方針で進めることで、コストは制御可能にする。
- **導入フェーズごとに Fail-Fast とテストが必須**
- Structured→Normalized は対応範囲外の Structured JoinModule については必ず Fail-Fast( panic/Err) し、サイレントに正規化を試みない。
- `normalized_dev` feature 配下で、Structured↔Normalized↔Structured の roundtrip と VM 実行結果比較を常に追加していく運用にする。
全体として、短期的には「新しいレイヤと比較テストを抱えるコスト」が増えるけれど、中長期では Pattern2〜4 や JsonParser 系の「評価順+ PHI+ DigitPos/num_str」が絡むループで、デバッグと設計の負荷をかなり下げることを狙った設計だよ。
### 3.4 Phase 26-H のフェーズ分割(案)
2025-12-11 19:11:26 +09:00
この正規化レイヤを一度に入れるのは重いので、Phase 26-H ラインとして小さく段階分けして進める方針だよ。
(番号は仮で、実際の Phase 番号は current の進行に合わせて調整する想定)
1. **Phase 26-H.A – モデル定義と Doc 固定(コード変更最小)**
- JoinIR Architecture Overview( このファイル) に Structured / Normalized の二層構造を明文化(本節)。
- `JoinIrPhase` などのメタ情報だけを追加し、既存 lowering / Bridge の挙動は変えない。
- Normalized JoinIR の不変条件( TailCall-only / EnvLayout 整合性)を Verifier の設計として書き出す。
2. **Phase 26-H.B – 最小サブセットでの JoinIR→JoinIR パス導入**
- Pattern1( 単純 while, break/continue なし)だけを対象にした Normalized パスを実装。
- パイプライン:
- 既存: `JoinIR(Structured) → MIR`
- 新規: `JoinIR(Structured) → JoinIR(Normalized, small subset) → MIR`
- 新規パスは dev フラグの裏側で比較用にのみ使い、E2E で結果が一致することを確認(既定経路は従来のまま)。
3. **Phase 26-H.C – Pattern2– 4 / DigitPos / JsonParser への拡張**
- Pattern2/3/4 と DigitPos / NumberAccumulation / Trim を Normalized パスの対象に広げる。
- JsonParser `_parse_number` / `_atoi` を優先対象にし、JoinIR(Normalized) 経由での実行を dev フラグ付きで有効化。
- JoinIR(Structured) → JoinIR(Normalized) の各ステップに構造テストを追加し、「Env の更新」「継続の呼び出し順」が期待どおりかを固定。
4. **Phase 26-H.D – Normalized JoinIR を canonical route に昇格**
- JoinIR→MIR Bridge が「Normalized フェーズの JoinIR だけ」を受け取るように変更。
- Structured JoinIR → MIR の直接パスは「比較テスト専用」として残すか、段階的に削除。
- selfhost / JsonParser / hako_check の代表ループはすべて Normalized JoinIR 経由で通ることを確認。
各サブフェーズでは「既存意味論を変えない」「Fail-Fast 原則を維持する」「新旧経路の比較テストを先に用意する」をガードとして運用するよ。
詳細な API/型設計は、Phase 26-H.A/B の中で `EnvLayoutBox` / `LoopStepSynthesizer` / `JpVerifier` 等の箱として段階的に固めていく想定。
2025-12-11 20:54:33 +09:00
### 3.5 Phase 27-CLEAN – Pattern2– 4 の軽量整理
2025-12-11 19:11:26 +09:00
- Pattern2〜4/loop_with_break_minimal まわりで可視性・ログ・補助関数を整理し、joinir_dev フラグ配下のデバッグログに寄せる。意味論は変えずに「読みやすさ」「追いやすさ」を優先するクリーンアップフェーズだよ。
2025-12-11 20:54:33 +09:00
### 3.6 Phase 28-NORM-P2 – Normalized JoinIR プロトタイプ拡張( dev-only)
- Phase 26-H で用意した Normalized JoinIR の極小サブセットを、Pattern1 に続いて Pattern2( 最小 break ループ)まで拡張。
- Structured → Normalized → Structured の往復と VM 実行比較を dev フィーチャ (`normalized_dev` + debug) でテスト済み。
- 対象は joinir_min_loop 相当の「ループ変数1つ+ breakのみ」のミニケースに限定し、本番経路( Structured→MIR) は不変。
- normalize_pattern2_minimal は対応外の Structured JoinModule では Fail-Fast するようにガードを追加し、対応範囲をテストで固定。
### 3.7 Phase 29-NORM-P2-APPLY – Pattern2 実ループへの dev 適用
- Phase 34 の fixture `loop_frontend_break.program.json` ( `i/acc/n` のシンプル break ループ)を Structured→Normalized→Structured の往復経路に載せ、VM 実行結果が Structured 直経路と一致することを dev テストで確認。
- `normalize_pattern2_minimal` のガードを 3 パラメータ( loop var + acc + host) まで許容する形に緩めつつ、DigitPos/Trim などの heavy carrier は依然として非対応に固定。
- すべて `normalized_dev` feature + debug_assertions 配下の実験経路に閉じ、本番 Structured→MIR パスの挙動は不変。
### 3.8 Phase 30-NORM-P2-DEV-RUN – runner で Normalized を試走( dev)
- JoinIR runner に dev 専用の `NYASH_JOINIR_NORMALIZED_DEV_RUN=1` スイッチを追加し、Pattern1/2 のミニケースだけ Structured→Normalized→Structured を噛ませてから実行できるようにした(`normalized_dev` feature + debug ビルド限定)。
- runner 経路でも Structured 直実行との stdout/結果が一致することをテスト( loop_min_while と Phase 34 break fixture) で確認。フラグ OFF 時の挙動は従来と同じ。
### 3.9 Phase 31-NORM-JP-MINI – JsonParser ミニ P2 を Normalized dev 経由で試走
- JsonParser 系のシンプルな P2 ループ( skip_whitespace 簡易版)を Structured→Normalized→Structured の dev ランナー経路に載せ、通常経路との実行結果一致を比較。
- `jsonparser_skip_ws_mini.program.json` ( docs/private/roadmap2/phases/normalized_dev/fixtures 配下)由来の JoinModule を使い、`NYASH_JOINIR_NORMALIZED_DEV_RUN=1` + `normalized_dev` + debug 限定で切替可能にした。
- 本番経路( Structured→MIR) は引き続き不変で、Normalized は dev 比較専用のまま。
### 3.10 Phase 32-NORM-CANON-PREP – Normalized 本番導入の下地づくり
- JoinIR→MIR ブリッジに Structured/Normalized の入口を分けた `bridge_joinir_to_mir_*` を用意し、conversion pipeline / VM ランナーがこの 1 箇所で dev roundtrip を切替できるように整理。
- Normalized dev スイッチを `normalized_dev_enabled()` に集約( feature `normalized_dev` + `NYASH_JOINIR_NORMALIZED_DEV_RUN=1` ) 。P1/P2 ミニ + JsonParser mini で env ON/OFF の比較テストを追加し、いつでも canonical route に昇格できる状態を固めた。
### 3.11 Phase 33-NORM-CANON-TEST – P1/P2/JP mini をテスト必須ラインへ
- `bridge_joinir_to_mir` / JoinIR runner は `shape_guard` で P1/P2 ミニ + JsonParser skip_ws mini を検知した場合、`normalized_dev_enabled()` が ON なら必ず Structured→Normalized→Structured の dev roundtrip を経由(正規化失敗は dev panic) 。未対応形状は静かに Structured 直通。
- tests/normalized_joinir_min.rs を Phase 33 前提に拡張し、P1/P2/JP mini の runner/VM 比較テストを env ON で実行。Normalized が壊れればこのスイートが必ず赤になる構造にした( feature OFF の CI は従来どおり無関係)。
- 本番 CLI 挙動は Structured→MIR のまま維持しつつ、Normalized を canonical に昇格させる前段階として dev テストで SSOT 相当の役割を担わせている。
2025-12-11 22:12:46 +09:00
### 3.12 Phase 34-NORM-ATOI-DEV – JsonParser `_atoi` ミニを dev 正規化経路へ
- JsonParser `_atoi` の最小 P2 ループ( digit_pos → digit_value + NumberAccumulation) を normalized_dev で Structured→Normalized→Structured に往復させ、VM 実行結果を Structured 直経路と比較するテストを追加。
- フィクスチャ `jsonparser_atoi_mini.program.json` を `shape_guard::JsonparserAtoiMini` で検知し、dev roundtrip が必ず通るようにした(正規化失敗は dev panic) 。本番 CLI は引き続き Structured→MIR 既定のまま。
### 3.13 Phase 35-NORM-BRIDGE-MINI – Normalized→MIR 直ブリッジ( P1/P2 ミニ + JP mini/atoi)
- normalized_dev 有効時に、P1/P2 ミニ・JsonParser skip_ws/atoi ミニを Structured→Normalized→MIR( Structured に戻さない)で実行する dev 専用ブリッジを追加。
- `bridge_joinir_to_mir` が shape_guard 対応形状では Normalized→MIR 直経路を使い、従来の Structured→MIR と VM 実行結果が一致することを比較テストで固定( env OFF 時は従来経路のまま)。
2025-12-11 22:52:17 +09:00
### 3.14 Phase 36-NORM-BRIDGE-DIRECT – Normalized→MIR を direct 実装に収束( P1/P2 ミニ + JP mini/atoi)
- Normalized ブリッジを direct 実装と Structured 再構成の二段に分離し、shape_guard で direct 対象( P1/P2 ミニ + JsonParser skip_ws/atoi ミニ)だけを Normalized→MIR 直接生成に切り替えた。
- direct 経路は `normalized_bridge::direct` に閉じ込め、非対応形状は `[joinir/normalized-bridge/fallback]` ログ付きで Structured 再構成経路に落とす構造に整理。dev テストでは direct 経路の VM 出力が従来経路と一致することを固定。
2025-12-12 03:15:45 +09:00
### 3.15 Phase 37-NORM-JP-REAL – JsonParser `_skip_whitespace` 本体を dev Normalized で比較
- JsonParser 本体の `_skip_whitespace` ループを Program(JSON) フィクスチャ化し、`shape_guard` で real 版を検知して Structured→Normalized→MIR(direct) の dev 経路に通すように拡張。`extract_value` は `&&` /`||` を BinOp として受け付けるようにした。
- Break パターンのパラメータ推定を柔軟化( loop_var/acc/n が無いケースでも loop_var を優先し、acc が無ければ同一キャリアとして扱う) し、skip_ws real の構造で panic しないようにした。
- tests/normalized_joinir_min.rs に `_skip_whitespace` real フィクスチャの VM 比較テストを追加し、env ON 時は Structured→Normalized→MIR(direct) と Structured 直経路の stdout が一致することを固定( env OFF は既存経路のまま)。
- normalized_dev 用フィクスチャは `docs/private/roadmap2/phases/normalized_dev/fixtures/` に配置し、Program(JSON) から `AstToJoinIrLowerer` で読み込む運用に統一した。
### 3.16 Phase 38-NORM-OBS – Normalized dev ログ/Fail‑ Fast の整備
- Normalized/JoinIR dev 経路のログカテゴリを `[joinir/normalized-bridge/*]` / `[joinir/normalized-dev/shape]` に統一し、`JOINIR_TEST_DEBUG` フラグ下のみ詳細を出すよう静音化。Verifier/Fail‑ Fast メッセージも shape/役割付きに整理してデバッグ観測性を強化。
### 3.17 Phase 40-NORM-CANON-TESTS – テスト側で Normalized を“当たり前”に通す
- `normalized_dev_enabled()` と env ガードを整理し、P1/P2 ミニ + JsonParser skip_ws/atoi ミニ/real の代表テストは「Normalized dev 経路が必ず通る」前提にする(壊れたら normalized_* スイートが赤になる)。
- 既存の Structured 直経路は比較用に維持しつつ、tests/normalized_joinir_min.rs 経路では Structured→Normalized→MIR(direct) が第一観測点になるように整備(本番 CLI は Structured→MIR のまま)。
### 3.18 Phase 41-NORM-CANON-P2-CORE – Pattern2 コアケースの canonical Normalized 化
2025-12-13 03:47:54 +09:00
- Pattern2 のコアセット( P2 ミニ + JsonParser skip_ws/atoi ミニ/real) について、JoinIR→MIR Bridge の既定を Normalized→MIR に寄せ、Structured→MIR は比較テスト用/soft fallback( JoinIR 内) の位置づけにする( Fail‑ Fast ポリシーは維持)。
2025-12-12 03:15:45 +09:00
- `shape_guard` で「Normalized 対応と宣言した P2 コアループ」は常に Normalized 経路を通すようにし、Normalized 側の invariant 破損は dev では panic、本番では明示エラーで早期検出する設計に寄せる。
### 3.19 Phase 42-NORM-P2-INVENTORY – P2 コア/ミドル/ヘビーの棚卸し
- JsonParser / selfhost で **現役の P2 ループ** を洗い出し、次の 3 クラスに整理した:
- **P2-Core**(すでに Normalized canonical なもの)
- test fixture 系: `loop_min_while` P2 ミニ, Phase 34 break fixture (`i/acc/n` )
- JsonParser 系: `_skip_whitespace` mini/real, `_atoi` mini
- これらは Phase 36– 41 で **Structured→Normalized→MIR(direct)** が canonical になっており、`bridge_joinir_to_mir` でも優先的に Normalized 経路が選ばれる。
- **P2-Mid**(次に Normalized を当てる候補)
- JsonParser: `_parse_number` , `_atoi` 本体, `_atof_loop`
- いずれも Pattern2 Break で JoinIR(Structured) には載っており( Phase 245/246 系) 、Normalized への写像は今後の拡張対象として扱う。
- **P2-Heavy**(複数 MethodCall / 複雑キャリアを持つもの)
- JsonParser: `_parse_string` , `_parse_array` , `_parse_object` , `_unescape_string`
- P2/P3/P4 が混在し、複雑なキャリアや MethodCall 多数のため、Phase 43 以降の後続フェーズで設計する。
2025-12-13 03:47:54 +09:00
- P2-Core については Phase 41 で canonical Normalized 化が完了しており、Structured→MIR は比較テスト用 / soft fallback( JoinIR 内)の経路として扱う。
2025-12-12 03:15:45 +09:00
- P2-Mid のうち、Phase 43 ではまず `_parse_number` を第 1 候補、`_atoi` 本体を第 2 候補として扱い、Normalized→MIR(direct) に必要な追加インフラ( EnvLayout 拡張 / JpInst パターン拡張)を段階的に入れていく前提を整理した。
2025-12-12 04:19:06 +09:00
### 3.20 Phase 43-NORM-CANON-P2-MID – JsonParser 本命 P2( _parse_number/_atoi) への適用 ✅ COMPLETE
**完全サマリ**: [PHASE_43_245B_NORMALIZED_COMPLETION.md ](./PHASE_43_245B_NORMALIZED_COMPLETION.md )
2025-12-12 03:15:45 +09:00
- JsonParser `_parse_number` / `_atoi` 本体の Pattern2 ループを、既存インフラ( DigitPos dual 値, LoopLocalZero, StepScheduleBox, ExprLowerer/MethodCall, Normalized ブリッジ)上で Structured→Normalized→MIR(direct) に載せる。
- dev で Structured 直経路との VM 実行結果一致を固定した上で、段階的に「この関数だけ Normalized canonical」とみなすプロファイル/フラグを導入し、最終的に JsonParser P2 の canonical route を Normalized 側に寄せるための足場にする。
- Phase 43-A( dev 専用): `_atoi` 本体を Program(JSON) フィクスチャ `jsonparser_atoi_real` で Structured→Normalized→MIR(direct) に通し、Structured 直経路との VM 出力一致を比較テストで固定(符号あり/なしの簡易パスまで対応。canonical 化は後続フェーズで検討)。
- Phase 43-C( dev 専用): `_parse_number` 本体を Program(JSON) フィクスチャ `jsonparser_parse_number_real` で Structured→Normalized→MIR(direct) に通し、`num_str = num_str + ch` の LoopState キャリアを含めた状態で Structured 直経路との VM 出力一致を比較テストで固定。
2025-12-12 04:19:06 +09:00
### 3.21 Phase 44-SHAPE-CAP – shape_guard の能力ベース化 ✅ COMPLETE (2025-12-12)
**完全サマリ**: [PHASE_43_245B_NORMALIZED_COMPLETION.md ](./PHASE_43_245B_NORMALIZED_COMPLETION.md )
**設計詳細**: [phase44-shape-capabilities-design.md ](./phase44-shape-capabilities-design.md )
- ✅ **ShapeCapabilityKind 導入完了** : P2CoreSimple / P2CoreSkipWs / P2CoreAtoi / P2MidParseNumber の 4 種類
- ✅ **Capability-based API** : `capability_for_shape()` , `is_canonical_shape()` , `is_p2_core_capability()` , `is_supported_by_normalized()`
- ✅ **Shape-level と Capability-level の二層 API** : 正確なマッチング vs 広い能力ファミリ判定
- ✅ **拡張性確保** : 将来の carrier_roles, method_calls フィールド用の struct 設計
- ✅ **既存挙動完全保持** : 937/937 tests PASS
2025-12-12 03:15:45 +09:00
2025-12-12 04:19:06 +09:00
### 3.22 Phase 45-NORM-MODE – JoinIR モードの一本化 ✅ COMPLETE (2025-12-12)
2025-12-12 03:15:45 +09:00
2025-12-12 04:19:06 +09:00
**完全サマリ**: [PHASE_43_245B_NORMALIZED_COMPLETION.md ](./PHASE_43_245B_NORMALIZED_COMPLETION.md )
**設計詳細**: [phase45-norm-mode-design.md ](./phase45-norm-mode-design.md )
2025-12-12 03:15:45 +09:00
2025-12-12 04:19:06 +09:00
- ✅ **JoinIrMode enum 導入完了** : StructuredOnly / NormalizedDev / NormalizedCanonical
- ✅ **current_joinir_mode() 統一** : バラバラだったフラグ/feature を一箇所に集約
- ✅ **Canonical-first routing** : P2-Core canonical shapes は mode 無視で常に Normalized→MIR(direct)
- ✅ **Mode-based 分岐統一** : bridge/runner の pattern matching で一貫した挙動
- ✅ **既存挙動完全保持** : 937/937 tests PASS
2025-12-12 04:40:46 +09:00
### 3.23 Phase 46-NORM-CANON-P2-MID – Normalized Canonical P2-Mid 昇格 ✅ COMPLETE (2025-12-12)
**設計詳細**: [phase46-norm-canon-p2-mid.md ](./phase46-norm-canon-p2-mid.md )
P2-Mid パターン( _atoi real, _parse_number real) を canonical Normalized→MIR(direct) ルートに昇格。
**Canonical set 拡張( Phase 46) **:
- P2-Core: Pattern2Mini, skip_ws mini/real, atoi mini
- **P2-Mid: atoi real, parse_number real** (NEW)
JsonParser _skip_whitespace / _atoi / _parse_number が**すべて canonical Normalized** に。Structured→MIR は P2 ラインにおいてレガシー/比較用途のみ。
**スコープ外**: P3/P4 Normalized 対応( NORM-P3/NORM-P4 フェーズで実施)。
**変更ファイル**:
- `shape_guard.rs` : `is_canonical_shape()` 拡張(+2 パターン)
- `bridge.rs` : コメント更新( Phase 41 → Phase 46)
- `normalized_joinir_min.rs` : canonical set 検証テスト追加
2025-12-12 06:06:39 +09:00
**テスト**: 938/938 PASS
2025-12-12 04:50:26 +09:00
2025-12-12 06:06:39 +09:00
### 3.24 Phase 47-NORM-P3 – Normalized P3 (If-Sum) Support 🏗️ DESIGN + MINIMAL DEV + DIRECT (2025-12-12)
2025-12-12 04:50:26 +09:00
**設計詳細**: [phase47-norm-p3-design.md ](./phase47-norm-p3-design.md )
Pattern3 (if-sum) ループを Normalized JoinIR に対応させる。P2 と同じ ConditionEnv/CarrierInfo/ExitLine インフラを再利用。
**Phase 220 基盤**: P3 if-sum は Phase 220 で ConditionEnv 統合済み(既に P2 と同じ Structured JoinIR foundation を持つ)
**Key difference**: P3 は **conditional carrier updates** ( if 内でのみキャリア更新) vs P2 の unconditional updates before break
2025-12-12 05:07:01 +09:00
**Phase 47-A**: Minimal sum_count( dev-only 正規化・第1ステップ)
2025-12-12 06:06:39 +09:00
- ✅ AST ベース if-sum lowerer( `loop_with_if_phi_if_sum.rs` )で `phase212_if_sum_min.hako` 相当の Structured JoinModule( 3 関数構成)を生成
2025-12-12 05:07:01 +09:00
- ✅ Normalized dev ランナー経路で Structured→Normalized→Structured roundtrip を通し、JoinIR Runner の実行結果が一致することをテストで固定
( `build_pattern3_if_sum_min_structured_for_normalized_dev` + `normalized_pattern3_if_sum_minimal_runner_dev_switch_matches_structured` )
2025-12-12 06:06:39 +09:00
- ✅ StepScheduleBox を汎用化し、P3 用 StepKind( `IfCond` / `ThenUpdates` / `ElseUpdates` )を追加
- ✅ shape_guard に `Pattern3IfSumMinimal` を追加し、構造ベースで P3 最小 if-sum 形状を検出
- ✅ `normalize_pattern3_if_sum_minimal` を通じて P3 最小ケースを Normalized→MIR(direct) パイプラインに載せ、P1/P2 と同じ direct ブリッジで実行結果一致を確認( dev-only)
2025-12-12 04:50:26 +09:00
2025-12-12 07:13:34 +09:00
**Phase 47-B**: Extended dev( sum+count / JsonParser if-sum mini)
- ✅ フィクスチャ追加: `pattern3_if_sum_multi_min` ( sum+count) / `jsonparser_if_sum_min` ( JsonParser 由来)
- ✅ ShapeGuard: `Pattern3IfSumMulti` / `Pattern3IfSumJson` 追加、capability=P3IfSum
- ✅ Normalizer/Bridge: P3 if-sum multi/json を Structured→Normalized→MIR(direct) で dev A/B( Structured と一致)
- ✅ VM Bridge テスト: `normalized_pattern3_if_sum_multi_vm_bridge_direct_matches_structured` / `normalized_pattern3_json_if_sum_min_vm_bridge_direct_matches_structured`
2025-12-12 04:50:26 +09:00
2025-12-12 07:13:34 +09:00
**Phase 47-C**: Canonical promotion( P3 minimal/multi/json → canonical Normalized)
- Canonical set 拡張: P3 if-sum minimal/multi/json を `is_canonical_shape()` に追加、mode/env 無視で Normalized→MIR(direct) ルートを使用
- Bridge/runner: canonical shapes は Structured fallback せず fail-fast( dev logs は normalized-dev プレフィックスに統一)
2025-12-12 04:50:26 +09:00
**スコープ外**: P4 (continue) 対応( NORM-P4 フェーズで実施) 、Complex P3 patterns( 後続フェーズ)
2025-12-12 06:06:39 +09:00
2025-12-12 16:40:20 +09:00
### 3.25 Phase 48-NORM-P4 – Normalized P4 (Continue) 🏗️ DESIGN + PHASE 48-A/B/C CANONICAL COMPLETE (2025-12-12 → 2026-01-XX)
2025-12-12 06:06:39 +09:00
2025-12-12 07:13:34 +09:00
**設計詳細 / 実装サマリ**: [phase48-norm-p4-design.md ](./phase48-norm-p4-design.md )
2025-12-12 06:06:39 +09:00
2025-12-12 07:13:34 +09:00
P4 (continue) は P1/P2/P3 と同じ `loop_step(env, k_exit)` 骨格を使う設計だよ。
**Key insight**: `continue` = 「更新済み Env での `TailCallFn(loop_step, env', k_exit)` 」で表現できる(新しい命令種別は不要)。
2025-12-12 06:06:39 +09:00
**Target loops** (JsonParser):
2025-12-12 07:13:34 +09:00
- ◎ `_parse_array` (skip whitespace) – PRIMARY( Phase 48-A 対象)
- ○ `_parse_object` (skip whitespace) – Extended
- △ `_unescape_string` , `_parse_string` – Later
**Infrastructure reuse**: P2/P3 Normalized の 95% 以上をそのまま再利用
- 共通: EnvLayout / ConditionEnv / CarrierInfo / ExitLine / JpInst
- 追加: StepScheduleBox に `ContinueCheck` step kind を追加
**Phase 48-A( Minimal continue, dev-only) 実装ステータス**:
- Fixture: `pattern4_continue_min.program.json` ( `i == 2` を `continue` でスキップする最小 P4 ループ)
- ShapeGuard: `NormalizedDevShape::Pattern4ContinueMinimal` を追加し、構造ベースで minimal continue 形状を検出
- StepSchedule: `HeaderCond → ContinueCheck → Updates → Tail` の順序を固定
- Normalized lowering: `normalize_pattern4_continue_minimal()` を実装し、P2 正規化ロジックを約 95% 再利用
- テスト:
- Normalized dev スイートに P4 minimal の比較テストを 4 本追加
( Structured→Normalized→MIR(direct) vs Structured→MIR / runner / VM bridge)
- `cargo test --release` ベースで **939/939 tests PASS** ( Phase 48-A 実装時点)
2025-12-12 16:40:20 +09:00
**Phase 48-B( JsonParser continue skip_ws、dev-only) 実装ステータス**:
- Fixtures: `jsonparser_parse_array_continue_skip_ws.program.json` / `jsonparser_parse_object_continue_skip_ws.program.json`
- ShapeGuard: JsonParser continue ループ用の shape を追加( array/object 両方)
- Normalized lowering: `normalize_jsonparser_parse_array_continue_skip_ws` / `_parse_object_...` で Structured→Normalized→MIR(direct) を dev 比較
- テスト: normalized dev スイートに VM bridge 比較テストを追加( Structured 直経路と stdout 一致を確認)
**Phase 48-C( canonical 昇格)実装ステータス**:
- Canonical set 拡張: Pattern4 continue minimal / JsonParser skip_ws array/object を `is_canonical_shape()` に追加
- Bridge/runner: P4 canonical shapes は env 無しでも Normalized→MIR(direct) を必ず通る( Structured fallback 無し、fail-fast)
- テスト: canonical ルート( env OFF) と Structured 直経路の stdout 一致を比較するテストを追加
**Phase 48 doc is SSOT** for P4 Normalized design + 48-A/B/C サマリだよ。
P1〜P4 の代表ループがすべて canonical Normalized パイプラインに載った状態になった。
### 3.26 Phase 49-SELFHOST-NORM-DEPTH2 – Selfhost depth2 Normalized 設計フェーズ( docsのみ)
- SSOT: [phase49-selfhost-joinir-depth2-design.md ](./phase49-selfhost-joinir-depth2-design.md )
- 目的: selfhost ラインでも `.hako → Program/MIR JSON → JoinIR(Structured) → Normalized → MIR → VM/LLVM` の depth2 パイプラインを踏めるように、対象ループ(軽い P2/P3 を 1〜2 本)と適用方針を設計で固定する。
- スコープ: selfhost の P2/P3 軽量ループのみ(トークン走査系 P2・if-sum 系 P3 を候補化) 。heavy ループや P5/Trim 系は Phase 50+ に回す。
- 設計アウトプット: 対象ループ↔Pattern/shape マッピング表、Program JSON/fixture/test 計画、depth2 パイプラインの責務整理(コード変更なし)。
### 3.27 Phase 50-SELFHOST-NORM-DEV – selfhost P2/P3 の dev Normalized 実装
- 対象: selfhost_token_scan_p2( P2 break カウンタループ)/ selfhost_if_sum_p3( P3 if-sum sum+count) の 2 本に限定。
- Fixtures: `selfhost_token_scan_p2.program.json` / `selfhost_if_sum_p3.program.json` を normalized_dev フィクスチャ群に追加。
- ShapeGuard: `SelfhostTokenScanP2` / `SelfhostIfSumP3` 形状を追加し、canonical P2/P3 とは分離( Pattern2/3 minimal に吸われないようガード)。
- Normalizer/Bridge: 既存 Pattern2/3 normalizer を流用して Structured→Normalized→MIR(direct) を dev 実行、構造/VM 出力を Structured 直経路と比較。
- テスト: normalized_joinir_min.rs に selfhost P2/P3 の VM ブリッジ比較テストを追加( normalized_dev 前提) 、shape_guard の検出テストも拡張。