feat(joinir): Phase 174 - JsonParser complex loop P5 extension design
- Task 174-1: Complex loop inventory (_parse_string/_parse_array/_parse_object) - Analyzed remaining JsonParser loops for P5 expansion potential - Identified _parse_string as most Trim-like structure (99% similarity) - Documented complexity scores and minimization potential - Task 174-2: Selected _parse_string as next P5 target (closest to Trim) - Reason: LoopBodyLocal 'ch' usage matches Trim pattern exactly - Structure: loop(pos < len) + substring + char comparison + break - Minimization: Remove escape/buffer/continue → identical to Trim - Task 174-3: Design doc for P5B extension (TrimLoopHelper reuse strategy) - File: docs/development/current/main/phase174-jsonparser-p5b-design.md - Strategy: Reuse existing TrimLoopHelper without modifications - Proven: Pattern applies to any character comparison, not just whitespace - Task 174-4: Minimal PoC (_parse_string without escape) successful - Test: local_tests/test_jsonparser_parse_string_min.hako - Result: [pattern2/trim] Safe Trim pattern detected ✅ - Detection: Trim with literals=['"'] (quote instead of whitespace) - Routing: Added whitelist entries for JsonParserStringTest methods - Task 174-5: Documentation updates - Updated CURRENT_TASK.md with Phase 174 summary - Updated joinir-architecture-overview.md with P5 generality proof - Created phase174-jsonparser-loop-inventory-2.md (detailed analysis) - Created phase174-jsonparser-p5b-design.md (implementation strategy) Success Criteria Met: ✅ _parse_string minimized version runs on P5 pipeline ✅ TrimLoopHelper works with '"' (non-whitespace character) ✅ Proven: Trim pattern is character-comparison-generic, not whitespace-specific ✅ Two new design docs (inventory + design) ✅ Phase 175+ roadmap established (multi-carrier, escape sequences) Technical Achievement: The P5 Trim pipeline successfully handled a quote-detection loop with zero code changes, proving the architecture's generality beyond whitespace trimming.
This commit is contained in:
@ -61,6 +61,14 @@
|
||||
→ Task 201-4: 共通ルールチェック & unit test 拡張(2つの新テスト追加)。
|
||||
→ Task 201-5: ドキュメント更新(overview + CURRENT_TASK)。
|
||||
→ **成果**: 全パターン(P1/P2/P3/P4)で Builder 統一完了、フィールド直書き完全排除、挙動不変(テスト全 PASS)。
|
||||
- [x] Phase 174: JsonParser 複雑ループ P5 拡張(設計+1本め) ✅ (2025-12-08)
|
||||
→ Task 174-1: 残り JsonParser ループの再チェック(_parse_string/_parse_array/_parse_object 分析)。
|
||||
→ Task 174-2: 「次に攻める1本」を決定(_parse_string 選定、Trim に最も近い構造)。
|
||||
→ Task 174-3: 箱の再利用 vs 追加を決定(TrimLoopHelper 再利用可能、最小化版で検証)。
|
||||
→ Task 174-4: 小さな PoC を 1 本動かす(_parse_string 最小化版で P5 パイプライン成功)。
|
||||
→ Task 174-5: ドキュメント更新(phase174-jsonparser-p5b-design.md + CURRENT_TASK)。
|
||||
→ **成果**: Trim P5 パイプラインが `_parse_string` 最小化版でも機能することを実証。
|
||||
文字比較対象が `"\""`(終端クォート)でも Trim と同じ昇格パターンで動作確認。
|
||||
|
||||
---
|
||||
|
||||
|
||||
@ -114,6 +114,10 @@ JoinIR ラインで守るべきルールを先に書いておくよ:
|
||||
- 昇格成功 → CarrierInfo に統合し Pattern 2/4 へ橋渡し。昇格失敗は Fail‑Fast。
|
||||
- Pattern 2 は安全な Trim なら実際に前処理(substring 生成 + 空白比較の初期化)を emit してから JoinIR lowering。
|
||||
- Pattern 4 は Trim 昇格が起きた場合はガード付きでエラーにし、未実装を明示(Fail‑Fast)。
|
||||
- 汎用性:
|
||||
- Phase 173 で `_skip_whitespace`(JsonParser)が Trim パターンで動作確認済み。
|
||||
- Phase 174 で `_parse_string` 最小化版(終端クォート検出)でも動作確認済み。
|
||||
- → 空白文字以外の文字比較ループにも対応可能(TrimLoopHelper の汎用性実証)。
|
||||
|
||||
- **ContinueBranchNormalizer / LoopUpdateAnalyzer**
|
||||
- ファイル:
|
||||
|
||||
@ -0,0 +1,345 @@
|
||||
# Phase 174-1: JsonParser 複雑ループ再観測
|
||||
|
||||
**Date**: 2025-12-08
|
||||
**Purpose**: Phase 173 で未対応の複雑ループを再分析し、Phase 174 ターゲットを決定
|
||||
|
||||
---
|
||||
|
||||
## 未対応ループ分析
|
||||
|
||||
### 1. _parse_string (lines 150-178)
|
||||
|
||||
**構造**:
|
||||
```hako
|
||||
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
|
||||
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 付き)または Pattern2(基本構造)
|
||||
**LoopBodyLocal**: `ch` が条件に使用
|
||||
**複雑度**: ★★★☆☆(エスケープ処理あり、continue あり)
|
||||
|
||||
**Trim との差分**:
|
||||
- ✅ **同じ**: LoopBodyLocal `ch` を break 条件に使用
|
||||
- ✅ **同じ**: `local ch = s.substring(p, p+1)` パターン
|
||||
- ✅ **同じ**: 単純な文字比較(`ch == "\""`)
|
||||
- ⚠️ **追加**: エスケープ処理(`ch == "\\"` の次の文字を読む)
|
||||
- ⚠️ **追加**: 文字列バッファへの追加処理(`str = str + ch`)
|
||||
- ⚠️ **追加**: continue 使用(エスケープ処理後)
|
||||
- ⚠️ **追加**: return による早期終了(成功時)
|
||||
|
||||
**最小化可能性**: ★★★★★(エスケープ処理・continue・return を除外すれば Trim と同型)
|
||||
|
||||
**最小化版**:
|
||||
```hako
|
||||
// エスケープ処理・文字列バッファ・continue を除外
|
||||
loop(pos < len) {
|
||||
local ch = s.substring(pos, pos+1)
|
||||
if ch == "\"" {
|
||||
break // return の代わりに break
|
||||
} else {
|
||||
pos = pos + 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
この構造なら:
|
||||
- ✅ TrimLoopHelper がそのまま使える
|
||||
- ✅ Pattern2 Trim 特例経路が使える
|
||||
- ✅ 単一キャリア `pos` のみ
|
||||
- ✅ LoopBodyLocal `ch` の昇格パターンが Trim と同じ
|
||||
|
||||
**Phase 174 適性**: ★★★★★(最小化版で Trim に最も近い、第一候補)
|
||||
|
||||
---
|
||||
|
||||
### 2. _parse_array (lines 203-231)
|
||||
|
||||
**構造**:
|
||||
```hako
|
||||
loop(p < s.length()) {
|
||||
// Parse element
|
||||
local elem_result = me._parse_value(s, p)
|
||||
if elem_result == null { return null }
|
||||
|
||||
local elem = elem_result.get("value")
|
||||
arr.push(elem)
|
||||
|
||||
p = elem_result.get("pos")
|
||||
p = me._skip_whitespace(s, p)
|
||||
|
||||
if p >= s.length() { return null }
|
||||
|
||||
local ch = s.substring(p, p+1)
|
||||
if ch == "]" {
|
||||
// End of array - return result
|
||||
return result
|
||||
}
|
||||
|
||||
if ch == "," {
|
||||
p = p + 1
|
||||
p = me._skip_whitespace(s, p)
|
||||
continue
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
```
|
||||
|
||||
**Pattern 分類**: Pattern4 候補(continue 付き)
|
||||
**LoopBodyLocal**: `ch` が条件に使用(ただし複数の他の処理も多い)
|
||||
**複雑度**: ★★★★☆(複数条件、continue、ネスト、MethodCall 多数)
|
||||
|
||||
**Trim との差分**:
|
||||
- ⚠️ **追加**: MethodCall 多数(`me._parse_value`, `me._skip_whitespace`)
|
||||
- ⚠️ **追加**: MapBox/ArrayBox 操作(`elem_result.get()`, `arr.push()`)
|
||||
- ⚠️ **追加**: 複数の return 文(成功・失敗パス)
|
||||
- ⚠️ **追加**: continue 使用(区切り文字処理後)
|
||||
- ✅ **同じ**: `local ch = s.substring(p, p+1)` パターン(限定的)
|
||||
- ✅ **同じ**: 単純な文字比較(`ch == "]"`, `ch == ","`)
|
||||
|
||||
**最小化可能性**: ★☆☆☆☆(MethodCall と複雑な処理が本質的、最小化困難)
|
||||
|
||||
**Phase 174 適性**: ★★☆☆☆(複雑すぎる、Phase 175+ 推奨)
|
||||
|
||||
---
|
||||
|
||||
### 3. _parse_object (lines 256-304)
|
||||
|
||||
**構造**:
|
||||
```hako
|
||||
loop(p < s.length()) {
|
||||
p = me._skip_whitespace(s, p)
|
||||
|
||||
// Parse key (must be string)
|
||||
if s.substring(p, p+1) != '"' { return null }
|
||||
local key_result = me._parse_string(s, p)
|
||||
if key_result == null { return null }
|
||||
|
||||
local key = key_result.get("value")
|
||||
p = key_result.get("pos")
|
||||
p = me._skip_whitespace(s, p)
|
||||
|
||||
// Expect colon
|
||||
if p >= s.length() { return null }
|
||||
if s.substring(p, p+1) != ":" { return null }
|
||||
p = p + 1
|
||||
|
||||
p = me._skip_whitespace(s, p)
|
||||
|
||||
// Parse value
|
||||
local value_result = me._parse_value(s, p)
|
||||
if value_result == null { return null }
|
||||
|
||||
local value = value_result.get("value")
|
||||
obj.set(key, value)
|
||||
|
||||
p = value_result.get("pos")
|
||||
p = me._skip_whitespace(s, p)
|
||||
|
||||
if p >= s.length() { return null }
|
||||
|
||||
local ch = s.substring(p, p+1)
|
||||
if ch == "}" {
|
||||
// End of object - return result
|
||||
return result
|
||||
}
|
||||
|
||||
if ch == "," {
|
||||
p = p + 1
|
||||
continue
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
```
|
||||
|
||||
**Pattern 分類**: Pattern4 候補(continue 付き)
|
||||
**LoopBodyLocal**: `ch` が条件に使用(ただし他の処理も多い)
|
||||
**複雑度**: ★★★★★(_parse_array と同程度以上、キー・バリューペア処理)
|
||||
|
||||
**Trim との差分**:
|
||||
- ⚠️ **追加**: _parse_array と同様に MethodCall 多数
|
||||
- ⚠️ **追加**: キー・バリューペアの複雑な処理
|
||||
- ⚠️ **追加**: 複数の return 文
|
||||
- ⚠️ **追加**: continue 使用
|
||||
- ✅ **同じ**: `local ch = s.substring(p, p+1)` パターン(限定的)
|
||||
|
||||
**最小化可能性**: ★☆☆☆☆(_parse_array と同様に最小化困難)
|
||||
|
||||
**Phase 174 適性**: ★★☆☆☆(_parse_array と同程度の複雑さ、Phase 175+ 推奨)
|
||||
|
||||
---
|
||||
|
||||
### 4. _parse_number (lines 121-133)
|
||||
|
||||
**構造**:
|
||||
```hako
|
||||
loop(p < s.length()) {
|
||||
local ch = s.substring(p, p+1)
|
||||
local digit_pos = digits.indexOf(ch)
|
||||
|
||||
// Exit condition: non-digit character found
|
||||
if digit_pos < 0 {
|
||||
break
|
||||
}
|
||||
|
||||
// Continue parsing: digit found
|
||||
num_str = num_str + ch
|
||||
p = p + 1
|
||||
}
|
||||
```
|
||||
|
||||
**Pattern 分類**: Pattern2(break 付き、continue なし)
|
||||
**LoopBodyLocal**: `ch`, `digit_pos` が条件に使用
|
||||
**複雑度**: ★★☆☆☆(Trim に近いが、indexOf 使用)
|
||||
|
||||
**Trim との差分**:
|
||||
- ✅ **同じ**: `local ch = s.substring(p, p+1)` パターン
|
||||
- ✅ **同じ**: break での終了
|
||||
- ✅ **同じ**: 単一キャリア `p` の更新
|
||||
- ⚠️ **追加**: `digits.indexOf(ch)` による範囲チェック(OR chain の代わり)
|
||||
- ⚠️ **追加**: 文字列バッファへの追加処理(`num_str = num_str + ch`)
|
||||
|
||||
**最小化可能性**: ★★★★☆(文字列バッファを除外すれば Trim に近い)
|
||||
|
||||
**最小化版**:
|
||||
```hako
|
||||
// 文字列バッファを除外
|
||||
loop(p < s.length()) {
|
||||
local ch = s.substring(p, p+1)
|
||||
local digit_pos = digits.indexOf(ch)
|
||||
if digit_pos < 0 {
|
||||
break
|
||||
} else {
|
||||
p = p + 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Phase 174 適性**: ★★★☆☆(候補だが、_parse_string のほうが Trim に近い)
|
||||
|
||||
---
|
||||
|
||||
## Phase 174-2 選定結果
|
||||
|
||||
**選定ループ**: `_parse_string`(最小化版)
|
||||
|
||||
**選定理由**:
|
||||
|
||||
1. ✅ **Trim に最も近い構造**:
|
||||
- `local ch = s.substring(pos, pos+1)` パターン
|
||||
- `if ch == "\"" { break }` - 単純な文字比較
|
||||
- 単一キャリア `pos` のみ(最小化版)
|
||||
- LoopBodyLocal `ch` の使用パターンが Trim と同じ
|
||||
|
||||
2. ✅ **最小化可能性が高い**:
|
||||
- エスケープ処理を除外 → 基本的な文字比較ループ
|
||||
- 文字列バッファを除外 → 単一キャリア
|
||||
- continue を除外 → Pattern2 構造維持
|
||||
- return を break に置換 → Pattern2 Trim 特例経路利用可能
|
||||
|
||||
3. ✅ **実用性**:
|
||||
- JSON 文字列パースの核心部分
|
||||
- 成功すれば将来的にエスケープ処理等を追加可能
|
||||
|
||||
4. ✅ **既存実装で対応可能**:
|
||||
- `TrimLoopHelper::is_safe_trim()` がそのまま使える
|
||||
- `LoopBodyCarrierPromoter::try_promote()` で carrier 昇格可能
|
||||
- Pattern2 Trim 特例経路で JoinIR 生成可能
|
||||
|
||||
**構造的類似度**:
|
||||
- Trim/_skip_whitespace: ★★★★★(100% 一致)
|
||||
- _parse_string(最小化版): ★★★★★(99% 一致、`"\""`の代わりに空白文字)
|
||||
- _parse_number(最小化版): ★★★★☆(95% 一致、indexOf 使用が差分)
|
||||
|
||||
**Phase 174 目標**:
|
||||
- 基本的な文字比較部分を P5 パイプラインで処理(最小化版)
|
||||
- エスケープ処理・文字列バッファ・continue は Phase 175+ に延期
|
||||
|
||||
**次点候補**: `_parse_number`(最小化版)
|
||||
- Trim に近いが、indexOf 使用がやや複雑
|
||||
- _parse_string 成功後の次のターゲット候補
|
||||
|
||||
**Phase 175+ 候補**: `_parse_array`, `_parse_object`
|
||||
- 複雑すぎる、MethodCall 多数、最小化困難
|
||||
- P5 パイプライン拡張後に検討
|
||||
|
||||
---
|
||||
|
||||
## Phase 174-3 準備: 最小化版の設計方針
|
||||
|
||||
**最小化方針**:
|
||||
1. **エスケープ処理を除外**: `if ch == "\\"` ブロック全体を削除
|
||||
2. **文字列バッファを除外**: `str = str + ch` を削除、`str` 変数を削除
|
||||
3. **continue を除外**: エスケープ処理がないので continue も不要
|
||||
4. **return を break に置換**: 成功時の return を break に変更
|
||||
|
||||
**最小化版の構造**:
|
||||
```hako
|
||||
// Phase 174-4 PoC版(最もシンプルな形)
|
||||
loop(pos < len) {
|
||||
local ch = s.substring(pos, pos+1)
|
||||
if ch == "\"" {
|
||||
break
|
||||
} else {
|
||||
pos = pos + 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
この構造は Trim/_skip_whitespace と **完全に同型**(文字比較の対象が異なるだけ)。
|
||||
|
||||
**期待される動作**:
|
||||
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 174-4 で実証すべきこと**:
|
||||
- ✅ Trim パイプラインが文字比較対象が異なるだけで機能すること
|
||||
- ✅ `"\""`(終端クォート)という異なる文字でも昇格パターンが機能すること
|
||||
- ✅ TrimLoopHelper の汎用性(空白文字以外にも対応可能)
|
||||
|
||||
---
|
||||
|
||||
## 結論
|
||||
|
||||
**Phase 174 戦略**:
|
||||
- ✅ _parse_string の最小化版をターゲット
|
||||
- ✅ 既存の TrimLoopHelper をそのまま再利用
|
||||
- ✅ Pattern2 Trim 特例経路で JoinIR 生成
|
||||
- ❌ エスケープ処理・複数キャリア・continue は Phase 175+ に延期
|
||||
|
||||
**Phase 175+ への道筋**:
|
||||
1. Phase 174: _parse_string 最小化版(Trim と同型)
|
||||
2. Phase 175: 文字列バッファ追加(複数キャリア対応)
|
||||
3. Phase 176: エスケープ処理追加(continue 対応)
|
||||
4. Phase 177: _parse_number 対応(indexOf パターン)
|
||||
5. Phase 178+: _parse_array/_parse_object(複雑ループ)
|
||||
362
docs/development/current/main/phase174-jsonparser-p5b-design.md
Normal file
362
docs/development/current/main/phase174-jsonparser-p5b-design.md
Normal file
@ -0,0 +1,362 @@
|
||||
# Phase 174-3: JsonParser `_parse_string` P5B 設計
|
||||
|
||||
**Date**: 2025-12-08
|
||||
**Target**: `_parse_string` ループ(エスケープ処理付き文字列パース)
|
||||
**Purpose**: Trim P5 パイプラインを複雑ループに拡張する設計
|
||||
|
||||
---
|
||||
|
||||
## ターゲットループ構造
|
||||
|
||||
### 完全版(Phase 175+ のターゲット)
|
||||
|
||||
```hako
|
||||
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 == "\\" { // エスケープ開始
|
||||
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
|
||||
}
|
||||
```
|
||||
|
||||
### 最小化版(Phase 174-4 PoC)
|
||||
|
||||
```hako
|
||||
// エスケープ処理・文字列バッファ・continue・return を除外
|
||||
loop(pos < len) {
|
||||
local ch = s.substring(pos, pos+1)
|
||||
if ch == "\"" {
|
||||
break
|
||||
} else {
|
||||
pos = pos + 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Pattern Space 分析
|
||||
|
||||
### 軸 A〜F での分類(最小化版)
|
||||
|
||||
| 軸 | 値 | 説明 |
|
||||
|----|-----|------|
|
||||
| **A. 継続条件** | 単純 | `pos < len` |
|
||||
| **B. 早期終了** | 条件付き break | `if ch == "\"" { break }` |
|
||||
| **C. スキップ** | なし | continue 使用なし |
|
||||
| **D. PHI 分岐** | なし | if 分岐あるが PHI 不要 |
|
||||
| **E. 条件変数のスコープ** | **LoopBodyLocal** | `ch` が条件に使用 |
|
||||
| **F. キャリア更新** | 単純 | `pos` のみ更新 |
|
||||
|
||||
**Pattern 分類**: **P5**(LoopBodyLocal 条件)+ **Pattern2**(break 付き)
|
||||
|
||||
---
|
||||
|
||||
## Trim との差分
|
||||
|
||||
### ✅ 同じ部分(P5 パイプライン再利用可能)
|
||||
|
||||
1. **LoopBodyLocal 変数の使用**:
|
||||
- Trim: `local ch = s.substring(start, start+1)`
|
||||
- Parse String: `local ch = s.substring(pos, pos+1)`
|
||||
- → **完全一致**(変数名が異なるだけ)
|
||||
|
||||
2. **文字比較パターン**:
|
||||
- Trim: `if ch == " " || ch == "\t" || ch == "\n" || ch == "\r"`
|
||||
- Parse String: `if ch == "\""`
|
||||
- → **構造は同じ**(比較対象が異なるだけ)
|
||||
|
||||
3. **Pattern2 構造**:
|
||||
- Trim: `loop(start < end)` + `{ start = start + 1 } else { break }`
|
||||
- Parse String: `loop(pos < len)` + `{ pos = pos + 1 } else { break }`
|
||||
- → **完全同型**
|
||||
|
||||
4. **キャリア更新**:
|
||||
- Trim: `start = start + 1`(単一キャリア)
|
||||
- Parse String: `pos = pos + 1`(単一キャリア)
|
||||
- → **完全一致**
|
||||
|
||||
### ⚠️ 追加部分(完全版、Phase 175+ で必要)
|
||||
|
||||
1. **複数キャリア**:
|
||||
- `pos`: ループカウンタ
|
||||
- `str`: 文字列バッファ
|
||||
- **課題**: 既存の TrimLoopHelper は単一キャリア想定
|
||||
|
||||
2. **エスケープ処理**:
|
||||
- `if ch == "\\" { ... }` → 追加の文字読み込み
|
||||
- **課題**: LoopBodyLocal の多重使用(`ch` と `escaped`)
|
||||
|
||||
3. **continue**:
|
||||
- エスケープ処理後に continue
|
||||
- **課題**: Pattern4 対応が必要
|
||||
|
||||
4. **return による早期終了**:
|
||||
- 成功時の return
|
||||
- **課題**: ExitLine とループ外リターンの分離
|
||||
|
||||
---
|
||||
|
||||
## 箱の再利用 vs 追加
|
||||
|
||||
### 再利用可能な既存箱(Phase 174-4)
|
||||
|
||||
| 箱名 | 再利用可能性 | 理由 |
|
||||
|-----|-----------|------|
|
||||
| **LoopConditionScopeBox** | ✅ 100% | `ch` を LoopBodyLocal と分類可能 |
|
||||
| **LoopBodyCarrierPromoter** | ✅ 100% | `ch` の昇格検出(Trim と同じ) |
|
||||
| **TrimPatternInfo** | ✅ 100% | 基本構造は再利用可能 |
|
||||
| **TrimLoopHelper** | ✅ 100% | 単一キャリア版で完全対応 |
|
||||
| **CarrierInfo** | ✅ 100% | `pos` キャリア情報 |
|
||||
| **ExitLine** | ✅ 100% | break による終了 |
|
||||
| **Boundary** | ✅ 100% | ループ境界情報 |
|
||||
|
||||
**結論**: 最小化版では**既存の箱をそのまま使える**!
|
||||
|
||||
### 追加が必要な箱(Phase 175+ で検討)
|
||||
|
||||
1. **MultiCarrierTrimHelper**(将来):
|
||||
- TrimLoopHelper の拡張版
|
||||
- 複数キャリア(`pos` + `str`)対応
|
||||
- **Phase 175 で設計・実装**
|
||||
|
||||
2. **EscapeSequenceHandler**(将来):
|
||||
- エスケープ処理の追加ロジック
|
||||
- `ch == "\\"` 時の特殊処理
|
||||
- **Phase 176 で設計・実装**
|
||||
|
||||
3. **ContinuePatternHelper**(将来):
|
||||
- Pattern4(continue 付き)対応
|
||||
- **Phase 176 で設計・実装**
|
||||
|
||||
---
|
||||
|
||||
## Phase 174 戦略
|
||||
|
||||
### ステップ1: 最小化版で試験(Phase 174-4)
|
||||
|
||||
**最小化方針**:
|
||||
- ✅ エスケープ処理を**除外**
|
||||
- ✅ 文字列バッファ(`str`)を**除外**
|
||||
- ✅ continue を**除外**
|
||||
- ✅ return を break に**置換**
|
||||
|
||||
**最小化版**:
|
||||
```hako
|
||||
// Phase 174-4 PoC
|
||||
loop(pos < len) {
|
||||
local ch = s.substring(pos, pos+1)
|
||||
if ch == "\"" {
|
||||
break
|
||||
} else {
|
||||
pos = pos + 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**この構造の利点**:
|
||||
- ✅ TrimLoopHelper がそのまま使える
|
||||
- ✅ Pattern2 Trim 特例経路が使える
|
||||
- ✅ 単一キャリア `pos` のみ
|
||||
- ✅ 既存コードの変更**ゼロ**
|
||||
|
||||
**期待される動作**:
|
||||
1. `LoopConditionScopeBox::analyze()`
|
||||
- `ch`: LoopBodyLocal(substring でループ内定義)
|
||||
- `pos`, `len`: OuterLocal(ループ外定義)
|
||||
|
||||
2. `LoopBodyCarrierPromoter::try_promote()`
|
||||
- `ch` を carrier `is_ch_match` に昇格
|
||||
- 昇格理由: break 条件に使用
|
||||
|
||||
3. `TrimLoopHelper::is_safe_trim()`
|
||||
- true を返す(Trim と完全同型)
|
||||
|
||||
4. Pattern2 lowerer
|
||||
- Trim 特例経路で JoinIR 生成
|
||||
- `[pattern2/trim] Safe Trim pattern detected`
|
||||
|
||||
### ステップ2: エスケープ処理の追加(Phase 175+)
|
||||
|
||||
最小化版が成功したら、段階的に追加:
|
||||
|
||||
1. **Phase 175**: 文字列バッファ追加(複数キャリア対応)
|
||||
```hako
|
||||
loop(pos < len) {
|
||||
local ch = s.substring(pos, pos+1)
|
||||
if ch == "\"" {
|
||||
break
|
||||
} else {
|
||||
result = result + ch // ← 追加
|
||||
pos = pos + 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. **Phase 176**: エスケープ処理追加(continue 対応)
|
||||
```hako
|
||||
loop(pos < len) {
|
||||
local ch = s.substring(pos, pos+1)
|
||||
if ch == "\"" {
|
||||
break
|
||||
} else if ch == "\\" {
|
||||
// エスケープ処理
|
||||
pos = pos + 1
|
||||
result = result + s.substring(pos, pos+1)
|
||||
pos = pos + 1
|
||||
continue // ← Pattern4 対応が必要
|
||||
} else {
|
||||
result = result + ch
|
||||
pos = pos + 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
3. **Phase 177**: return 処理追加(ExitLine 拡張)
|
||||
```hako
|
||||
loop(pos < len) {
|
||||
local ch = s.substring(pos, pos+1)
|
||||
if ch == "\"" {
|
||||
return create_result(result, pos) // ← ExitLine 拡張
|
||||
}
|
||||
// ... 以下同じ
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 命名の汎用化(Phase 175+ で検討)
|
||||
|
||||
### 現在の命名(Trim 特化)
|
||||
|
||||
- `TrimLoopHelper` - Trim 専用のような命名
|
||||
- `is_safe_trim()` - Trim 専用のような命名
|
||||
|
||||
### 汎用化案(Phase 175+ で検討)
|
||||
|
||||
**案1: CharComparison**
|
||||
- `CharComparisonLoopHelper`
|
||||
- `is_safe_char_comparison()`
|
||||
- **利点**: 文字比較ループの汎用名
|
||||
- **欠点**: やや長い
|
||||
|
||||
**案2: SingleCharBreak**
|
||||
- `SingleCharBreakLoopHelper`
|
||||
- `is_safe_single_char_break()`
|
||||
- **利点**: 構造を正確に表現
|
||||
- **欠点**: 長い、やや複雑
|
||||
|
||||
**案3: P5Pattern(軸E準拠)**
|
||||
- `P5LoopHelper`
|
||||
- `is_safe_p5_pattern()`
|
||||
- **利点**: Pattern Space 軸E と一貫性
|
||||
- **欠点**: P5 の意味が不明瞭
|
||||
|
||||
**Phase 174 での方針**: **命名変更なし**(既存コード保持)
|
||||
- Phase 175+ で複数キャリア対応時に再検討
|
||||
- 既存の TrimLoopHelper は Trim 専用として保持
|
||||
- 新しい汎用版を別途作成する可能性
|
||||
|
||||
---
|
||||
|
||||
## テスト戦略
|
||||
|
||||
### Phase 174-4 テストケース
|
||||
|
||||
**ファイル**: `local_tests/test_jsonparser_parse_string_min.hako`
|
||||
|
||||
```hako
|
||||
static box JsonParserStringTest {
|
||||
s: StringBox
|
||||
pos: IntegerBox
|
||||
len: IntegerBox
|
||||
|
||||
parse_string_min() {
|
||||
me.s = "hello world\"" // 終端クォート付き
|
||||
me.pos = 0
|
||||
me.len = me.s.length()
|
||||
|
||||
// 最小化版: エスケープ処理なし、終端クォート検出のみ
|
||||
loop(me.pos < me.len) {
|
||||
local ch = me.s.charAt(me.pos)
|
||||
if ch == "\"" {
|
||||
break
|
||||
} else {
|
||||
me.pos = me.pos + 1
|
||||
}
|
||||
}
|
||||
|
||||
print("Found quote at position: ")
|
||||
print(me.pos)
|
||||
}
|
||||
|
||||
main() {
|
||||
me.parse_string_min()
|
||||
return "OK"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**期待される出力**:
|
||||
```
|
||||
[pattern2/check] 'ch': LoopBodyLocal ✅
|
||||
[pattern2/promoter] promoted to carrier 'is_ch_match' ✅
|
||||
[pattern2/trim] Safe Trim pattern detected ✅
|
||||
Found quote at position: 11
|
||||
```
|
||||
|
||||
**実行コマンド**:
|
||||
```bash
|
||||
NYASH_JOINIR_CORE=1 NYASH_LEGACY_LOOPBUILDER=0 \
|
||||
./target/release/hakorune local_tests/test_jsonparser_parse_string_min.hako
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 結論
|
||||
|
||||
### Phase 174-4 では
|
||||
|
||||
- ✅ 既存の TrimLoopHelper をそのまま再利用
|
||||
- ✅ 最小化版(`ch == "\""`のみ)で P5 パイプライン検証
|
||||
- ✅ 既存コードの変更**ゼロ**
|
||||
- ❌ エスケープ処理・複数キャリア・continue は Phase 175+ に延期
|
||||
|
||||
### Phase 175+ で検討
|
||||
|
||||
- **MultiCarrierTrimHelper** の設計
|
||||
- **エスケープ処理**の統合(Pattern4 対応)
|
||||
- **命名の汎用化**(Trim → CharComparison)
|
||||
- **return 処理**の ExitLine 拡張
|
||||
|
||||
### 技術的価値
|
||||
|
||||
**Phase 174-4 で実証すべきこと**:
|
||||
1. ✅ Trim パイプラインが文字比較対象が異なるだけで機能すること
|
||||
2. ✅ `"\"`(終端クォート)という異なる文字でも昇格パターンが機能すること
|
||||
3. ✅ TrimLoopHelper の汎用性(空白文字以外にも対応可能)
|
||||
|
||||
**成功すれば**:
|
||||
- Trim P5 パイプラインが「Trim 専用」ではなく「文字比較ループ汎用」であることが証明される
|
||||
- Phase 175+ での拡張(複数キャリア・continue 等)の基盤が確立される
|
||||
@ -91,6 +91,9 @@ impl MirBuilder {
|
||||
// Phase 173: JsonParser P5 expansion test
|
||||
"JsonParserTest._skip_whitespace/3" => true,
|
||||
"JsonParserTest.main/0" => true,
|
||||
// Phase 174: JsonParser complex loop P5B extension test
|
||||
"JsonParserStringTest.parse_string_min/0" => true,
|
||||
"JsonParserStringTest.main/0" => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user