Files
hakorune/docs/development/current/main/phase173-jsonparser-loop-recheck.md
nyash-codex 290e97c54c feat(joinir): Phase 173 - JsonParser P5 expansion with _skip_whitespace
- Task 173-1: JsonParser loop inventory recheck
  - Observed 6 loops: _trim (2 loops, already working), _skip_whitespace,
    _parse_string, _parse_array, _unescape_string
  - Created comprehensive observation report with Trim similarity ratings
  - Discovered that JsonParser._trim already uses P5 pipeline successfully

- Task 173-2: Selected _skip_whitespace as Trim-equivalent pattern
  - Perfect structural match with Trim (100% identical)
  - Independent helper method, easy to test
  - Frequently used in JsonParser (7 call sites)

- Task 173-3: Design doc for P5 pipeline extension to JsonParser
  - Confirmed existing TrimLoopHelper works without modification
  - No charAt() support needed (_skip_whitespace uses substring())
  - Documented data flow and risk analysis

- Task 173-4: Successfully converted _skip_whitespace to JoinIR
  - Created test case: local_tests/test_jsonparser_skip_whitespace.hako
  - Added routing whitelist: JsonParserTest._skip_whitespace/3
  - Pattern detection SUCCESS:
    * LoopBodyLocal 'ch' detected
    * Carrier promotion to 'is_ch_match'
    * Trim pattern recognized
    * JoinIR generation successful
  - Verified P5 pipeline works for both static box methods and helper methods

- Task 173-5: Documentation updates
  - phase173-jsonparser-loop-recheck.md: Loop observation report
  - phase173-jsonparser-p5-design.md: P5 extension design
  - phase173-jsonparser-p5-impl.md: Implementation results
  - CURRENT_TASK.md: Phase 173 completion record

Key achievement: Proven that Trim P5 pipeline is fully generic -
works for both TrimTest (static box method) and JsonParser (helper method).
LoopBodyLocal carrier promotion is production-ready for Trim-like patterns.

Changes:
- src/mir/builder/control_flow/joinir/routing.rs: Add JsonParserTest whitelist
- docs/development/current/main/*173*.md: 3 new documentation files
- CURRENT_TASK.md: Phase 173 completion entry
2025-12-08 10:13:34 +09:00

11 KiB
Raw Blame History

Phase 173-1: JsonParser ループ再観測

Date: 2025-12-08 Purpose: Trim P5 パイプラインを JsonParser に展開するための予備調査


観測対象ループ

1. _trim - Leading Whitespace

File: tools/hako_shared/json_parser.hako Lines: 330-337

loop(start < end) {
    local ch = s.substring(start, start+1)
    if ch == " " || ch == "\t" || ch == "\n" || ch == "\r" {
        start = start + 1
    } else {
        break
    }
}

Pattern 分類: Pattern2 (break付き) LoopBodyLocal: ch (substring定義、break条件で使用) Trim 類似度: ★★★★★ (完全同型 - 既に実装済み)

JoinIR 実行結果: SUCCESS

[pattern2/check] Analyzing condition scope: 3 variables
[pattern2/check]   'ch': LoopBodyLocal
[pattern2/promoter] LoopBodyLocal 'ch' promoted to carrier 'is_ch_match'
[pattern2/trim] Safe Trim pattern detected, implementing lowering
[joinir/pattern2] Generated JoinIR for Loop with Break Pattern (Phase 170-B)

状態: Phase 171 で既に P5 パイプライン実装済み


2. _trim - Trailing Whitespace

File: tools/hako_shared/json_parser.hako Lines: 340-347

loop(end > start) {
    local ch = s.substring(end-1, end)
    if ch == " " || ch == "\t" || ch == "\n" || ch == "\r" {
        end = end - 1
    } else {
        break
    }
}

Pattern 分類: Pattern2 (break付き) LoopBodyLocal: ch (substring定義、break条件で使用) Trim 類似度: ★★★★★ (完全同型 - 既に実装済み)

JoinIR 実行結果: SUCCESS

[pattern2/check] Analyzing condition scope: 3 variables
[pattern2/check]   'ch': LoopBodyLocal
[pattern2/promoter] LoopBodyLocal 'ch' promoted to carrier 'is_ch_match'
[pattern2/trim] Safe Trim pattern detected, implementing lowering
[joinir/pattern2] Generated JoinIR for Loop with Break Pattern (Phase 170-B)

状態: Phase 171 で既に P5 パイプライン実装済み


3. _skip_whitespace

File: tools/hako_shared/json_parser.hako Lines: 310-321

_skip_whitespace(s, pos) {
    local p = pos
    loop(p < s.length()) {
        local ch = s.substring(p, p+1)
        if ch == " " || ch == "\t" || ch == "\n" || ch == "\r" {
            p = p + 1
        } else {
            break
        }
    }
    return p
}

Pattern 分類: Pattern2 (break付き) LoopBodyLocal: ch (substring定義、break条件で使用) Trim 類似度: ★★★★★ (Trim の leading whitespace と完全同型)

構造的特徴:

  • loop(p < s.length()) - 長さチェックTrim の start < end と同等)
  • local ch = s.substring(p, p+1) - 1文字抽出完全一致
  • if ch == " " || ch == "\t" || ch == "\n" || ch == "\r" - 空白判定(完全一致)
  • p = p + 1 vs break - 進行 vs 脱出(完全一致)

JoinIR 実行可能性: 既存の Trim パイプラインで即座に対応可能

  • TrimLoopHelper::is_safe_trim() が true を返すはず
  • LoopBodyCarrierPromoter::try_promote() で carrier 昇格成功するはず

Phase 173-2 での選定: ★★★★★ 第一候補Trim と完全同型)


4. _parse_string

File: tools/hako_shared/json_parser.hako Lines: 150-178

loop(p < s.length()) {
    local ch = s.substring(p, p+1)

    if ch == '"' {
        // End of string
        local result = new MapBox()
        result.set("value", me._unescape_string(str))
        result.set("pos", p + 1)
        result.set("type", "string")
        return result
    }

    if ch == "\\" {
        // Escape sequence (workaround: flatten to avoid MIR nested-if bug)
        local has_next = 0
        if p + 1 < s.length() { has_next = 1 }

        if has_next == 0 { return null }

        str = str + ch
        p = p + 1
        str = str + s.substring(p, p+1)
        p = p + 1
        continue
    }

    str = str + ch
    p = p + 1
}

Pattern 分類: Pattern4 候補continue付き LoopBodyLocal: ch (substring定義、複数条件で使用) Trim 類似度: ★★☆☆☆ (構造が複雑)

構造的差異:

  • local ch = s.substring(p, p+1) - Trim と同じ
  • 複数の条件分岐(ch == '"', ch == "\\"
  • return 文での早期終了
  • continue での反復継続
  • 中間状態の蓄積(str = str + ch

LoopBodyLocal 使用: ch を複数箇所で使用 Phase 173 での対応: ⚠️ 除外複雑すぎる、Phase 174+ で検討)


5. _parse_array

File: tools/hako_shared/json_parser.hako Lines: 189-230+

loop(p < s.length()) {
    // Parse value
    local val_result = me._parse_value(s, p)
    if val_result == null { return null }

    local val = val_result.get("value")
    arr.push(val)
    p = val_result.get("pos")

    p = me._skip_whitespace(s, p)

    if p < s.length() {
        local next_ch = s.substring(p, p+1)
        if next_ch == "," {
            p = p + 1
            p = me._skip_whitespace(s, p)
            continue
        }
        if next_ch == "]" {
            // End of array
            p = p + 1
            local result = new MapBox()
            result.set("value", arr)
            result.set("pos", p)
            result.set("type", "array")
            return result
        }
    }

    return null
}

Pattern 分類: Pattern4 候補continue付き LoopBodyLocal: next_ch (substring定義、条件で使用) Trim 類似度: ★☆☆☆☆ (構造が大きく異なる)

構造的差異:

  • MethodCall 多数(me._parse_value, me._skip_whitespace
  • 複数の return 文(成功・失敗パス)
  • 配列操作(arr.push(val)
  • MapBox からの値取得
  • local next_ch = s.substring(p, p+1) - Trim と同じパターン
  • if next_ch == "," - 単純な等価比較

LoopBodyLocal 使用: next_ch のみ(限定的) Phase 173 での対応: ⚠️ 除外構造が複雑、Phase 175+ で検討)


6. _unescape_string

File: tools/hako_shared/json_parser.hako Lines: 373-410+

loop(i < s.length()) {
    local ch = s.substring(i, i+1)

    // Workaround: flatten to avoid MIR nested-if bug
    local is_escape = 0
    local has_next = 0

    if ch == "\\" { is_escape = 1 }
    if i + 1 < s.length() { has_next = 1 }

    local process_escape = 0
    if is_escape == 1 {
        if has_next == 1 {
            process_escape = 1
        }
    }

    if process_escape == 1 {
        // ... complex escape handling
    }

    result = result + ch
    i = i + 1
}

Pattern 分類: Pattern1 候補break/continue なし) LoopBodyLocal: ch, is_escape, has_next, process_escape Trim 類似度: ☆☆☆☆☆ (全く異なる)

構造的差異:

  • break/continue なし(自然終了のみ)
  • 複数の LoopBodyLocal 変数
  • ネストした条件分岐
  • エスケープシーケンス処理

Phase 173 での対応: 除外Pattern1、LoopBodyLocal の問題なし)

JoinIR 実行結果: FAILED

[ERROR] ❌ MIR compilation error: [joinir/freeze] Loop lowering failed:
JoinIR does not support this pattern, and LoopBuilder has been removed.

失敗理由: Pattern1 でも JoinIR 未対応の構造ありPhase 173 対象外)


選定候補

Phase 173-2 で選ぶべきループ: _skip_whitespace

選定理由:

  1. Trim と完全同型: 既存の P5 パイプラインがそのまま使える

    • local ch = s.substring(p, p+1) パターン
    • if ch == " " || ch == "\t" || ch == "\n" || ch == "\r" 空白判定
    • break での終了
  2. 独立した関数: 他の複雑なロジックに依存しない

  3. 実用的: JsonParser で頻繁に使われる7箇所で呼び出し

  4. テスト容易: 単純な入出力でテスト可能

  5. 既存実装の活用:

    • TrimLoopHelper::is_safe_trim() - そのまま使える
    • LoopBodyCarrierPromoter::try_promote() - そのまま使える
    • Pattern2 lowerer - Trim 特例経路がそのまま機能する

次点候補: なし他のループは複雑すぎるか、LoopBodyLocal 問題がない)


重要な発見

JsonParser の _trim は既に P5 対応済み!

Phase 171 で実装した Trim パイプラインが、JsonParser の _trim メソッドで 既に完全動作 していることを確認:

[pattern2/trim] Safe Trim pattern detected, implementing lowering
[joinir/pattern2] Generated JoinIR for Loop with Break Pattern (Phase 170-B)

これは、Phase 173 の目的が達成済みであることを意味する。

🎯 Phase 173 の真の価値

既存実装の検証: Trim パイプラインが JsonParser でも機能することを実証

  • TrimLoopHelper の汎用性確認
  • Pattern2 Trim 特例の堅牢性確認
  • LoopBodyLocal 昇格の実用性確認

次のステップ: _skip_whitespace で独立関数パターンの検証

  • Trim は static box のメソッド内ループ
  • _skip_whitespace は helper method 内ループ
  • 両方で機能すれば、P5 パイプラインの汎用性が完全証明される

次のステップ (Phase 173-2)

選定ループ: _skip_whitespace

選定基準確認:

  • LoopBodyLocal 変数を break 条件に使用
  • substring でループ内定義
  • OR chain での比較(空白文字判定)
  • Pattern2 構造break 付き、continue なし)

期待される動作:

  1. LoopConditionScopeBox::analyze() - ch を LoopBodyLocal として検出
  2. LoopBodyCarrierPromoter::try_promote() - carrier is_ch_match に昇格
  3. TrimLoopHelper::is_safe_trim() - true を返す
  4. Pattern2 lowerer - Trim 特例経路で JoinIR 生成

Phase 173-4 で実装: ミニテストケースでの動作確認


Phase 173-2 選定結果

選定ループ: _skip_whitespace (line 310-321)

選定理由:

  1. Trim と完全同型: 構造が完全に一致

    • loop(p < s.length()) ← Trim の loop(start < end) と等価
    • local ch = s.substring(p, p+1) ← 完全一致
    • if ch == " " || ch == "\t" || ch == "\n" || ch == "\r" ← 完全一致
    • { p = p + 1 } else { break } ← Trim の start = start + 1 と同パターン
  2. 独立関数: helper method として独立(テスト容易)

  3. 実用性: JsonParser で 7箇所で使用される頻出パターン

  4. 既存実装で対応可能:

    • TrimLoopHelper::is_safe_trim() がそのまま使える
    • LoopBodyCarrierPromoter::try_promote() で carrier 昇格可能
    • Pattern2 Trim 特例経路で JoinIR 生成可能
  5. 検証価値:

    • _trim メソッド内ループで既に成功static box method
    • 🎯 _skip_whitespace で helper method パターンを検証
    • → 両方成功すれば P5 パイプラインの汎用性が完全証明される

次点候補: なし

理由:

  • _parse_string - 複雑すぎるreturn/continue 混在、Phase 174+
  • _parse_array - MethodCall 多数、構造複雑Phase 175+
  • _unescape_string - Pattern1、LoopBodyLocal 問題なし(対象外)

Phase 173-3 での設計方針: 既存の Trim パイプラインをそのまま活用