Phase 33 NORM canon test: enforce normalized dev route for P1/P2/JP mini
This commit is contained in:
@ -1106,7 +1106,65 @@ Normalized JoinIR では、制御構造を次の 3 要素だけで表現する
|
||||
これにより、現在 JoinIR 層で苦労している「PHI 配線」「exit_bindings/jump_args 整合性」「評価順のねじれ」は、
|
||||
Normalized JoinIR 側では「Env フィールドの更新順」と「どの継続を呼ぶか」に還元される想定だよ。
|
||||
|
||||
### 3.3 Phase 26-H のフェーズ分割(案)
|
||||
### 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 のフェーズ分割(案)
|
||||
|
||||
この正規化レイヤを一度に入れるのは重いので、Phase 26-H ラインとして小さく段階分けして進める方針だよ。
|
||||
(番号は仮で、実際の Phase 番号は current の進行に合わせて調整する想定)
|
||||
@ -1136,6 +1194,41 @@ Normalized JoinIR 側では「Env フィールドの更新順」と「どの継
|
||||
各サブフェーズでは「既存意味論を変えない」「Fail-Fast 原則を維持する」「新旧経路の比較テストを先に用意する」をガードとして運用するよ。
|
||||
詳細な API/型設計は、Phase 26-H.A/B の中で `EnvLayoutBox` / `LoopStepSynthesizer` / `JpVerifier` 等の箱として段階的に固めていく想定。
|
||||
|
||||
### 3.4 Phase 27-CLEAN – Pattern2–4 の軽量整理
|
||||
### 3.5 Phase 27-CLEAN – Pattern2–4 の軽量整理
|
||||
|
||||
- Pattern2〜4/loop_with_break_minimal まわりで可視性・ログ・補助関数を整理し、joinir_dev フラグ配下のデバッグログに寄せる。意味論は変えずに「読みやすさ」「追いやすさ」を優先するクリーンアップフェーズだよ。
|
||||
|
||||
### 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 相当の役割を担わせている。
|
||||
|
||||
@ -0,0 +1,65 @@
|
||||
Status: Active
|
||||
Scope: Phase 26‑H.C ― Normalized JoinIR (Pattern1) を MIR に落とす最小ブリッジの設計と比較テスト計画(dev専用)。
|
||||
|
||||
# Phase 26‑H.C 指示書 — Normalized→MIR ブリッジ(Pattern1 最小)+比較テスト
|
||||
|
||||
## ゴール
|
||||
- Normalized JoinIR(NormalizedModule)から MIR への「本物のブリッジ」を、Pattern1 最小ケースだけで実装する。
|
||||
- Structured→MIR と Structured→Normalized→MIR の結果が一致することをテストで確認する(dev 専用、CLI はまだ触らない)。
|
||||
|
||||
## A. Normalized→Structured or Normalized→MIR の経路方針
|
||||
- Option 1: Normalized→Structured→既存 MIR ブリッジ
|
||||
- 長所: 既存の JoinIR→MIR パイプラインを再利用できる。
|
||||
- 短所: フェーズが一段増える(Normalized→Structured が joinir→joinir の一歩になる)。
|
||||
- Option 2: Normalized→MIR を直接作るミニブリッジ(Pattern1 限定) **←今回これを優先**
|
||||
- 長所: TailCall/Env をそのまま MIR に落とす感触を掴める。
|
||||
- 短所: 一部ロジックが JoinIR→MIR と重複する。
|
||||
- どちらを選んでも「Pattern1 最小ケース限定」「テスト専用 helper」とする(本番パスへは配線しない)。今回は Option 2 で進め、必要があれば Option 1 のスケルトンも残す。
|
||||
|
||||
## B. Normalized→Structured ミニ変換(Option 1 採用時のメモ)
|
||||
- 追加場所: `src/mir/join_ir/normalized.rs`
|
||||
- API 例: `pub fn normalize_pattern1_to_structured(norm: &NormalizedModule) -> JoinModule`
|
||||
- 制約: `norm.phase == JoinIrPhase::Normalized`、関数は 1 つ(loop_step + 仮の k_exit 程度)を想定。
|
||||
- 変換の要点:
|
||||
- EnvLayout の fields から JoinFunction の params を再構成(最小なら1引数でも可)。
|
||||
- `JpInst::Let` → `JoinInst::Compute(MirLikeInst::Const/BinOp/UnaryOp/Compare)` に戻す。
|
||||
- TailCallFn/TailCallKont/If を Pattern1 が生成していた `JoinInst::Call/Jump/Ret` 相当に戻す。
|
||||
- `NormalizedModule.entry` を `JoinModule.entry` に写す。
|
||||
- `NormalizedModule.structured_backup` は比較用に残すが、ブリッジでは本体から再構成する。
|
||||
|
||||
## C. Normalized→MIR ミニブリッジ(今回の主経路: Option 2)
|
||||
- 追加ファイル案: `src/mir/join_ir/lowering/normalized_pattern1_to_mir.rs`
|
||||
- API 例:
|
||||
```rust
|
||||
pub fn lower_normalized_pattern1_to_mir(norm: &NormalizedModule) -> crate::mir::Module { ... }
|
||||
```
|
||||
- 最低限やること:
|
||||
- EnvLayout の 1 フィールドを MIR のループ変数に対応させる。
|
||||
- `JpFunction` 本体を 1 ブロック or 小ブロック列に変換(Let→MIR Assign/Compute、TailCallFn→ループ末尾 Jump 等)。
|
||||
- Pattern1 の `loop_min_while` 相当が生成していた MIR と構造的に一致するかをテストで確認。
|
||||
- ガード: dev/テスト専用 helper から明示的に呼ぶ。ランナー/CLI には配線しない。
|
||||
|
||||
## D. 比較用テストの追加
|
||||
- テストファイル案: `tests/normalized_pattern1_bridge.rs`
|
||||
- シナリオ:
|
||||
1. Structured JoinIR (Pattern1: loop_min_while 相当) を既存 lowerer で生成。
|
||||
2. そのコピーを `normalize_pattern1_minimal` に通し NormalizedModule を得る。
|
||||
3. 既存経路: Structured → 既存 JoinIR→MIR ブリッジ → 実行 or MIR dump。
|
||||
4. 新経路: Structured → Normalized → (C のブリッジ)→ MIR → 実行 or MIR dump。
|
||||
5. 比較:
|
||||
- 実行結果一致(RC + stdout)。
|
||||
- 余裕があれば MIR の基本ブロック数や命令種も比較し、構造乖離がないことを確認。
|
||||
- テスト名例:
|
||||
- `test_normalized_pattern1_minimal_roundtrip`
|
||||
- `test_normalized_pattern1_exec_result_matches_structured`
|
||||
|
||||
## E. ガードと完了条件
|
||||
- ガード:
|
||||
- 新ブリッジはテスト専用(ランナー/CLI からは呼ばない)。
|
||||
- JoinModule.phase が Structured のままでも既存経路は従来どおり動作。
|
||||
- Normalized 経路は dev/テスト専用 helper からのみ呼ぶ。
|
||||
- 完了条件:
|
||||
- NormalizedModule から MIR を生成する経路(Option 2)が 1 本通る。
|
||||
- Pattern1 最小ケースで Structured→MIR と Structured→Normalized→MIR が同じ結果になるテストが緑。
|
||||
- 既存 `cargo test --release` が 0 FAIL のまま。
|
||||
|
||||
Reference in New Issue
Block a user