Files
hakorune/docs/development/current/main/phase245-jsonparser-parse-number-joinir-integration.md
nyash-codex d4597dacfa feat(joinir): Phase 245C - Function parameter capture + test fix
Extend CapturedEnv to include function parameters used in loop conditions,
enabling ExprLowerer to resolve variables like `s` in `loop(p < s.length())`.

Phase 245C changes:
- function_scope_capture.rs: Add collect_names_in_loop_parts() helper
- function_scope_capture.rs: Extend analyze_captured_vars_v2() with param capture logic
- function_scope_capture.rs: Add 4 new comprehensive tests

Test fix:
- expr_lowerer/ast_support.rs: Accept all MethodCall nodes for syntax support
  (validation happens during lowering in MethodCallLowerer)

Problem solved: "Variable not found: s" errors in loop conditions

Test results: 924/924 PASS (+13 from baseline 911)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-11 13:13:08 +09:00

91 lines
6.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

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

Status: Active → Close-out
Scope: JsonParser `_parse_number` のループを Pattern2break 付き)で JoinIR 経路に載せるための設計決定メモ。
# Phase 245-EX: JsonParser `_parse_number` の JoinIR 統合1 本目)
## 1. 目的 / スコープ
- 目的: `_parse_number` のループを、既存の Pattern2 + ExprLowerer/ConditionEnv/CarrierUpdateEmitter で JoinIR 経路に載せる。
- スコープ: このフェーズでは `_parse_number` のみ。`_atoi` / `_atof_loop` / `_parse_array` など他ループは後続フェーズ。
- 明示: **扱うのは `p` の header / break / 更新のみ。`num_str` には手を出さない**(文字列連結キャリアは Phase 245B 以降で検討)。
## 2. 現状の挙動と既存フェーズの整理
- ループ概要tools/hako_shared/json_parser.hako より):
- ループ変数: `p`(文字走査位置)
- ヘッダ条件: `p < s.length()`
- body 計算: `ch = s[p]`; `digit_pos = digits.indexOf(ch)`
- break 条件: `digit_pos < 0`(非 digit で脱出)
- 更新: `p = p + 1`; 数値文字列の累積(`num_str = num_str + ch` 相当)あり
- 参考フェーズ:
- ループ全体の設計/在庫: `phase181-jsonparser-loop-roadmap.md`, `phase174-jsonparser-loop-inventory-2.md`
- digit_pos / ConditionEnv 系: `phase200-A/B/C`, `phase224-digitpos-condition-normalizer.md`, `phase224-digitpos-promoter-design.md`
- ExprLowerer/ScopeManager: `phase230-expr-lowerer-design.md`, `phase236-exprlowerer-integration.md`, `phase237-exprlowerer-condition-catalog.md`, `phase238-exprlowerer-scope-boundaries.md`
- 既にカバーされている要素:
- header 条件 `p < len` は ExprLowerer/ConditionEnv で扱える想定Phase 230/236 系)
- break 条件 `digit_pos < 0` は digitpos 正規化経路で扱う前提Phase 224 系)
- キャリア更新 `p = p + 1` は Pattern2/CarrierUpdateEmitter で許容
- まだ本番経路に載っていない部分:
- 数値文字列の累積(`num_str`)の扱いを今回どうするか(キャリアに入れるか、今回は p 更新のみに絞るか)を決める必要あり。
## 3. ターゲット JoinIR パターン / 箱構成
- パターン: **Pattern2 (Break)** を基本とし、必要なら LoopBodyLocal 昇格P5 相当の body-local 扱い)を併用。
- ループ変数・キャリア・body-local・captured の対応表:
- loop var: `p`
- carriers: `p` は必須。`num_str` は今回の Phase では **任意**(下記の許可範囲で決める)。
- condition inputs: `p`, `s.length()`, `digit_pos`
- break 条件: `digit_pos < 0`
- body-local/captured: `s`, `digits` は captured 扱いで読み取りのみ。
- 経由させる箱:
- ConditionEnv + ExprLowererheader 条件 / break 条件)
- MethodCallLowerer`digits.indexOf(ch)`
- CarrierUpdateEmitter`p = p + 1`、必要なら `num_str` 更新)
## 4. 条件式・更新式パターンの許可範囲
- ヘッダ条件: `p < s.length()` は ExprLowerer/ConditionEnv の既存カバー範囲で扱うYES 前提)。
- break 条件: `digit_pos < 0` を digitpos 正規化経路Phase 224 系に乗せる。Compare/Jump で Pattern2 に合流すること。
- 更新式:
- 必須: `p = p + 1` を CarrierUpdateEmitter で扱う。
- 任意: `num_str = num_str + ch`
- もし ExprLowerer/CarrierUpdate が文字列連結キャリアを安全に扱えるなら、キャリアとして含める。
- 難しければ本フェーズは `p` の更新と break 条件の JoinIR 化に限定し、`num_str` は後続フェーズで扱うと明示。
- 線引き:
- **今回扱う**: header 条件、break 条件、`p` 更新。`num_str` 更新は「可能なら扱う、無理なら後続」と書き分ける。原則として **Phase 245-EX では `num_str` をキャリアに載せない**
- **後続に回す**: `_parse_array` / `_parse_object` / `_unescape_string` / if-sum/continue を含む Pattern3/4 の適用。
## 5. 期待する検証方法(テスト観点)
- 既存テストで固定したいもの:
- JsonParser の数値解析系スモーク(ファイル名/ケース名があれば列挙)。
- 例: `"123"` → 数値として成功 / `"123a"` → 非 digit で break して期待どおりのパース失敗/戻り値になること。
- 必要なら追加する最小ケース(例):
- 入力: `"42"` → 正常に数値化num_str が "42"し、p が len に一致。
- 入力: `"7z"``z` で break、num_str が "7" で止まり、エラー/戻り値が従来と一致。
- JoinIR レベル確認ポイント:
- header 条件が Compare + Jump で Pattern2 のヘッダに乗っていること。
- break 条件 `digit_pos < 0` が ConditionEnv/ExprLowerer 経由で JoinIR の break ブロックに接続していること。
- `p` の更新が CarrierUpdateEmitter で扱われ、LoopHeader PHI / ExitLine と矛盾しないこと。
## 6. 非目標 / 今回はやらないこと
- `_parse_array` / `_parse_object` / `_unescape_string` など他ループへの展開は本フェーズ外。
- continue/if-sum を含む Pattern3/4 への適用は別フェーズ。
- JsonParser 全体の設計変更や API 変更は行わない。ループ部分の JoinIR 経路追加/切り替えに限定。
## 7. コード側 Phase 245-EX への引き継ぎメモ
- 対象ループ: `_parse_number`
- パターン: Pattern2 (Break) + 必要に応じて body-local 昇格P5 相当)
- 変数の役割:
- loop var: `p`
- carriers: `p`(必須)、`num_str`(可能なら含める/後続に回すかをここで決める)
- condition inputs: `p`, `s.length()`, `digit_pos`
- break 条件: `digit_pos < 0`
- captured: `s`, `digits`
- 許可された式:
- header: `p < s.length()`
- break: `digit_pos < 0`
- 更新: `p = p + 1`(必須)、`num_str = num_str + ch`(扱うかどうかを本メモで明記)
- 検証:
- 使うテストケース(既存/追加と期待する挙動RC/ログ)を本メモに列挙しておく。
## 8. 完了メモPhase 245-EX 締め)
- `_parse_number` の p ヘッダ条件(`p < s.length()`・break 条件(`digit_pos < 0`)・更新(`p = p + 1`)を Pattern2 + ExprLowerer/CarrierUpdateEmitter 経路に載せた。
- 既存の挙動確認: `cargo test --release phase245_json_parse_number -- --nocapture` を実行し、RC/ログともに従来からの差分なしnum_str 未導入のため外部挙動不変)。
- 次フェーズ245Bで扱うもの: `num_str` をキャリアに載せるかどうか、更新式の許容範囲、固定すべきテストを設計する。