Files
hakorune/docs/development/current/main/phase43-norm-canon-p2-mid.md
nyash-codex ed8e2d3142 feat(joinir): Phase 248 - Normalized JoinIR infrastructure
Major refactoring of JoinIR normalization pipeline:

Key changes:
- Structured→Normalized→MIR(direct) pipeline established
- ShapeGuard enhanced with Pattern2 loop validation
- dev_env.rs: New development fixtures and env control
- fixtures.rs: jsonparser_parse_number_real fixture
- normalized_bridge/direct.rs: Direct MIR generation from Normalized
- pattern2_step_schedule.rs: Extracted step scheduling logic

Files changed:
- normalized.rs: Enhanced NormalizedJoinModule with DevEnv support
- shape_guard.rs: Pattern2-specific validation (+300 lines)
- normalized_bridge.rs: Unified bridge with direct path
- loop_with_break_minimal.rs: Integrated step scheduling
- Deleted: step_schedule.rs (moved to pattern2_step_schedule.rs)

New files:
- param_guess.rs: Loop parameter inference
- pattern2_step_schedule.rs: Step scheduling for Pattern2
- phase43-norm-canon-p2-mid.md: Design doc

Tests: 937/937 PASS (+6 from baseline 931)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-12 03:15:45 +09:00

10 KiB
Raw Blame History

Status: Planned
Scope: Phase 43NORMCANONP2MID — JsonParser 本命 P2_parse_number / _atoi 本体 / _atof_loop)を Normalized 基準に寄せるための事前設計メモ。 Update (Phase 43-A): _atoi 本体を Program(JSON) フィクスチャ jsonparser_atoi_real で dev Normalized→MIR(direct) 経路に載せ、Structured 直経路との VM 出力一致を確認済み(符号あり/なしの簡易パスまで対応。canonical 化は後続で検討)。 Update (Phase 43-C): _parse_number 本体を Program(JSON) フィクスチャ jsonparser_parse_number_real で dev Normalized→MIR(direct) 経路に載せ、Structured 直経路との VM 出力一致を dev テストで固定num_str は現状仕様のまま据え置き)。

Phase 43NORMCANONP2MID 設計メモJsonParser P2Mid 向け Normalized 拡張)

0. ゴールと前提

  • ゴール
    • JsonParser の本命 P2 ループP2Midを、既存の Normalized インフラの延長で扱えるようにするための設計方針を固める。
    • 特に _parse_number / _atoi 本体 / _atof_loop について、
      • どのキャリア・bodylocal を EnvLayout に載せるか
      • どの JpInst / JpOp パターンが追加で必要か
      • StepScheduleBox / DigitPos / NumberAccumulation との責務分担 を整理する。
  • 前提
    • P2CoreP2 ミニ + JP skip_ws mini/real + JP atoi miniは Phase 41 までで Normalized→MIR(direct) が canonical 済み。
    • P2Mid は JoinIR(Structured) までは載っているが Normalized は未対応 の状態Phase 245/246 系)。
    • 本メモは「設計レベル」で止め、実装・テスト追加は後続フェーズ43 実装回)で扱う。

1. 対象ループと P2Mid クラスの整理

  • 対象とする P2MidJsonParser 側)
    • _parse_number(数値文字列の収集 + digit_pos break
    • _atoi 本体(範囲チェック + digit_pos + NumberAccumulation
    • _atof_loop(構造的には _atoi と同型の浮動小数点版)
  • すべて Pattern2 Break で、既に JoinIR(Structured) には載っている:
    • _parse_number → Phase 245EX で header / break / p 更新を Pattern2 に統合済み(num_str は当面対象外)。
    • _atoi → Phase 246EX で DigitPos dual 値 + NumberAccumulation パターンとして JoinIR 経路に統合済み。
    • _atof_loop → 設計上 _atoi と同型とみなし、P2Mid クラスに含める。
  • P2Core との差分
    • P2 ミニ / skip_ws / atoi ミニに比べて:
      • Carrier の本数(p + result + 場合によっては num_str)が増える。
      • bodylocal / Derived Carrierdigit_pos, is_digit_pos, digit_value 等)の依存関係が複雑。
      • 一部で文字列連結(num_str = num_str + ch)や Range チェック("0" <= ch <= "9")が入る。

2. Normalized IR に必要な拡張EnvLayout / JpInst / JpOp

2.1 EnvLayout / フィールド設計

  • P2Mid で EnvLayout に載せる候補
    • LoopState キャリア
      • _parse_number: p(必須)、num_strPhase 43 では オプション、まず p 単独で正規化する案も許容)。
      • _atoi 本体 / _atof_loop: i, resultNumberAccumulation キャリア)。
    • Condition 専用 / FromHost
      • len / s / digits などの不変値は ParamRole::Condition として EnvLayout 側に持たない(現状どおり)。
    • Derived LoopStateDigitPos 系)
      • P2Core で既に導入済みの digit_value / is_digit_pos と同じ方針:
        • EnvLayout に「FromHost ではない LoopState キャリア」として載せる。
        • host_slot を持たず、ExitBinding には出さない(ループ内部完結キャリア)。

2.2 JpInst / JpOp 側の必要パターン

  • 既存の Normalized が既に扱っているもの
    • Let { dst, op: Const / BinOp / Unary / Compare / BoxCall, args }
    • If { cond, then_target, else_target, env }
    • TailCallFn / TailCallKontloop_step / k_exit のみ)
  • P2Mid で追加検証・明文化が必要なパターン
    • _parse_number
      • substring / indexOf の BoxCall パターンP2Core でも使用済みだが、num_str 周辺の利用を含めてドキュメントで SSOT 化する)。
      • 文字列連結 num_str = num_str + ch
        • 当面は「扱わない」(num_str を Carrier から外す)案
        • もしくは BinOp(Add) として Normalized→MIR 直ブリッジに追加する案 のどちらにするかを Phase 43 実装メモで最終決定する。
    • _atoi 本体 / _atof_loop
      • Range チェック ch < "0" || ch > "9"
        • ExprLowerer / ConditionEnv 側で既に対応済みであれば、Normalized には Compare + BinOp(or) の形で入る。
        • Normalized では追加の JpOp は不要Compare / BinOp を利用)。
      • NumberAccumulation パターン:
        • Structured 側では UpdateRhs::NumberAccumulation として扱っているので、
          • Normalized → MIR 直ブリッジ側で「Mul + Add + digit_value」の形を既に対応済み。
        • Phase 43 では _atoi 本体 / _atof_loop でも同じシーケンスになることを前提とし、JpInst 種別追加は行わない。

3. StepScheduleBox / DigitPos / NumberAccumulation の役割分担

3.1 StepScheduleBox評価順の適用範囲

  • Phase 39 で導入した StepScheduleBoxPattern2 用は、P2Mid に対しても「どの StepKind をどの順番で評価するか」を決める SSOT として使う。
  • _parse_number / _atoi 本体 / _atof_loop では、以下のようなフラグを想定:
    • has_digitpos_body_localDigitPos 二重値を使うか)
    • has_number_accumulation(結果キャリアに Mul+Add があるか)
    • has_bodylocal_breakbreak 条件が bodylocal に依存するか)
  • StepScheduleBox は、これらのフラグだけを見て
    • 標準 P2: [HeaderCond, BreakCheck, BodyInit, Updates, Tail]
    • DigitPos / atoi 系: [HeaderCond, BodyInit, BreakCheck, Updates, Tail] など、評価順のバリエーションを返す「薄い箱」のまま保つ。
  • Pattern2 lowerer / Normalized 変換側は、この StepSchedule に従って
    • header 条件
    • bodylocal initDigitPos / Range check 等)
    • break 条件
    • carrier 更新NumberAccumulation / i++ 等) を「並べるだけ」にし、条件式の詳細や bodylocal の構造には踏み込まない。

3.2 DigitPos / NumberAccumulation との接続

  • DigitPos 系
    • digit_posis_digit_pos / digit_value の二重値設計は、P2Core と同じく「LoopState キャリアFromHost なし)」として EnvLayout に載せる。
    • ExitBinding には出さず、Normalized→MIR 直ブリッジでも Loop 内部だけで完結させる。
    • Break 条件 digit_pos < 0 は Phase 224 の DigitPosConditionNormalizerAST→!is_digit_posを前提にし、Normalized 側は !is_digit_pos という bool 条件だけを受け取る。
  • NumberAccumulation 系
    • Structured 側の LoopUpdateAnalyzer / CarrierUpdateEmitter が result = result * 10 + digit_value パターンを UpdateRhs::NumberAccumulation として検出・JoinIR 生成済み。
    • Normalized→MIR 直ブリッジは、P2Core と同じ Mul + Add シーケンスで MIR を吐く設計を維持し、P2Mid でも追加ロジックを増やさずに流用する。

4. Bridge / ShapeGuard / canonical 切り替え方針

  • ShapeGuard 拡張
    • 既存の P2Core 判定P2 ミニ / skip_ws mini/real / atoi miniに加えて、
      • _parse_number 本体
      • _atoi 本体
      • _atof_loop を P2Mid として検出できる Shape 種別を追加する(例: ShapeKind::JsonparserParseNumber, ShapeKind::JsonparserAtoiCore)。
    • Phase 43 実装フェーズでは、まず P2Mid ループを dev only の Normalized 対象にするcanonical 切り替えは Phase 43 後半〜Phase 44 相当で検討)。
  • Bridge 側の経路
    • bridge_joinir_to_mir の入口で:
      • P2Core: 既に canonical Normalized→MIR(direct)Phase 41 の状態を維持)。
      • P2Mid: normalized_dev_enabled() が true のときに限り Structured→Normalized→MIR(direct) を試し、テストで Structured 直経路と比較。
    • FailFast 方針
      • P2Mid では「Normalized が未対応の領域」がまだ多いため、
        • dev / debug ビルドでは invariant 破壊・未対応命令で panicNormalized 実装の穴を早期検出)。
        • release / canonical OFF 時は Structured→MIR 直経路に落とすサイレントフォールバックではなく「Normalized をそもそも使わない」構成にする)。

5. テストと完了条件Phase 43 実装フェーズ向けメモ)

  • テスト戦略(概要)
    • _parse_number:
      • 代表ケース("42", "7z" など)で
        • Structured→MIR→VM
        • Structured→Normalized→MIR(direct)→VM の stdout / RC を比較する dev テストを追加。
      • num_str をまだ Normalized キャリアに載せない場合でも、「p / break 条件 / DigitPos 周り」が齟齬なく動くことを確認する。
    • _atoi 本体 / _atof_loop:
      • 既存の _atoi mini dev fixture と同じ観点で、NumberAccumulation / DigitPos / Range check が Normalized 経路で再現できるかをチェック。
      • Mini / 本体 / _atof_loop が同じ normalized helper / bridge ロジックを共有できることを確認する。
  • 完了条件Phase 43 実装のためのチェックリスト)
    • EnvLayout / JpInst / JpOp / StepScheduleBox / DigitPos / NumberAccumulation の役割分担が本メモの通りに整理されている。
    • P2Mid_parse_number / _atoi 本体 / _atof_loop)に対して、どこまでを Phase 43 で扱い、どこから先を後続フェーズに回すかの線引きが明文化されている。
    • joinir-architecture-overview.md の Phase 43 セクション3.20)と、この設計メモの内容が矛盾していない。