joinir: clean pattern visibility and refactor pattern2 pipeline

This commit is contained in:
nyash-codex
2025-12-11 19:11:26 +09:00
parent 463a6240fb
commit 59a985b7fa
16 changed files with 1141 additions and 812 deletions

View File

@ -1032,3 +1032,110 @@ JoinIR は Rust 側だけでなく、将来的に .hako selfhost コンパイラ
- 根本原因: carrier 検出ロジックの name heuristic が脆弱
- **次フェーズ**: Carrier 検出修正Phase 219
- 詳細: phase218-jsonparser-if-sum-min.md
---
## 3. JoinIR → JoinIR 正規化レイヤ(構想 / Phase 26-H ライン)
### 3.1 Structured JoinIR と Normalized JoinIR概念レベル
JoinIR ラインは、今後は「同じ JoinIR をフェーズごとに正規化していく」二段構成で扱う想定だよ:
- **Structured JoinIR現行層**
- Pattern15 / CarrierInfo / ConditionEnv / UpdateEnv / Boundary / ExitLine までを終えた状態。
- while/if/break/continue/return がまだ「構造」として残っていてよい層。
- いまの JoinIR loweringPattern lowerer 群)が出力しているものはここ。
- **Normalized JoinIRJoinIR / 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) // Pattern15, CarrierInfo, ConditionEnv/UpdateEnv, Boundary/ExitLine
↓ JoinIR パス A: 正規化JoinIR → JoinIR
JoinIR(Normalized) // 関数 + 継続 + Env のみTailCall-only
↓ JoinIR→MIR bridge
MIR
```
型レベルでは、次の二案のどちらかで扱う想定だよ(詳細は今後の Phase で選択):
- **案① 型を分ける**
- `JoinModuleRaw`Structured、`JoinModuleCps`Normalizedを別型にする。
- BridgeJoinIR→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 フィールドの更新順」と「どの継続を呼ぶか」に還元される想定だよ。
### 3.3 Phase 26-H のフェーズ分割(案)
この正規化レイヤを一度に入れるのは重いので、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 Pattern24 / 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` 等の箱として段階的に固めていく想定。
### 3.4 Phase 27-CLEAN Pattern24 の軽量整理
- Pattern2〜4/loop_with_break_minimal まわりで可視性・ログ・補助関数を整理し、joinir_dev フラグ配下のデバッグログに寄せる。意味論は変えずに「読みやすさ」「追いやすさ」を優先するクリーンアップフェーズだよ。