feat(joinir): Phase 164 Pattern3 (If-Else PHI) validation complete
- Created 4 representative test cases for Pattern3 patterns: * test_pattern3_if_phi_no_break.hako - Core Pattern3 (if-else PHI, no break/continue) * test_pattern3_skip_whitespace.hako - Pattern3+break style (routed to Pattern2) * test_pattern3_trim_leading.hako - Pattern3+break style (routed to Pattern2) * test_pattern3_trim_trailing.hako - Pattern3+break style (routed to Pattern2) - Validated Pattern3_WithIfPhi detection: * Pattern routing: Pattern3_WithIfPhi MATCHED confirmed * JoinIR lowering: 3 functions, 20 blocks → 8 blocks (successful) * [joinir/freeze] elimination: Complete (no errors on any test) - Clarified pattern classification: * Pattern3_WithIfPhi handles if-else PHI without break/continue * Loops with "if-else PHI + break" are routed to Pattern2_WithBreak * Break takes priority over if-else PHI in pattern detection - Cumulative achievement (Phase 162-164): * Pattern1: 6 loops working ✅ * Pattern2: 5 loops working ✅ * Pattern3 (no break): 1 loop working ✅ * Pattern3+break (as Pattern2): 3 loops working ✅ * Total: 15 loops covered, zero [joinir/freeze] errors - Updated CURRENT_TASK.md with Phase 164 section and findings Next: Phase 165 Pattern4 (continue) validation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -732,6 +732,124 @@ Phase 122 の println/log 統一は、Phase 99-101 で確立された3層ロギ
|
||||
|
||||
---
|
||||
|
||||
## Section 9: JoinIR/Loop Trace System (Phase 194)
|
||||
|
||||
### 概要
|
||||
|
||||
JoinIR(関数型IR)とループ最適化のデバッグ専用トレースシステム。
|
||||
開発時のみ有効化し、本番環境では常にOFFにする。
|
||||
|
||||
**実装**: `src/mir/builder/control_flow/joinir/trace.rs` (250行)
|
||||
|
||||
### トレースカテゴリと環境変数
|
||||
|
||||
| 環境変数 | カテゴリ | 内容 | 出力例 |
|
||||
|---------|---------|------|--------|
|
||||
| `NYASH_JOINIR_DEBUG=1` | 全般デバッグ | JoinIR lowering全般の詳細 | `[trace:debug] pattern4: CarrierInfo: ...` |
|
||||
| `NYASH_TRACE_VARMAP=1` | 変数マップ | variable_mapのスナップショット | `[trace:varmap] i=ValueId(123) sum=ValueId(456)` |
|
||||
| `NYASH_TRACE_PHI=1` | PHI生成 | PHI命令生成の詳細 | `[trace:phi] Generated PHI for carrier 'sum'` |
|
||||
| `NYASH_TRACE_MERGE=1` | ブロック結合 | MIRブロックマージ処理 | `[trace:merge] Remapping block BB5 → BB142` |
|
||||
| `NYASH_TRACE_JOINIR_STATS=1` | 統計情報 | 関数数・ブロック数等 | `[trace:joinir_stats] 3 functions, 12 blocks` |
|
||||
|
||||
### 主要トレースメソッド
|
||||
|
||||
```rust
|
||||
// シングルトンアクセス
|
||||
use crate::mir::builder::control_flow::joinir::trace;
|
||||
|
||||
// パターン検出
|
||||
trace::trace().pattern("pattern4", "Lowering loop with continue");
|
||||
|
||||
// 変数マップ
|
||||
trace::trace().varmap("before_loop", &builder.variable_map);
|
||||
|
||||
// JoinIR統計
|
||||
trace::trace().joinir_stats("pattern4", fn_count, block_count);
|
||||
|
||||
// PHI生成
|
||||
trace::trace().phi("sum_exit", phi_id, &incoming_values);
|
||||
|
||||
// 汎用デバッグ
|
||||
trace::trace().debug("pattern4", &format!("Carrier: {:?}", carrier_info));
|
||||
```
|
||||
|
||||
### 出力フォーマット
|
||||
|
||||
**基本フォーマット**: `[trace:<category>] <tag>: <message>`
|
||||
|
||||
**出力例**:
|
||||
```
|
||||
[trace:pattern] pattern4: Detected loop with continue
|
||||
[trace:varmap] pattern4_start: i=ValueId(100), sum=ValueId(101)
|
||||
[trace:debug] pattern4: CarrierInfo: loop_var=i, carriers=["sum"]
|
||||
[trace:debug] pattern4: Analyzed 1 carrier update expressions
|
||||
[trace:debug] pattern4: sum → BinOp { lhs: "sum", op: Add, rhs: Variable("i") }
|
||||
[trace:joinir_stats] pattern4: 3 functions, 12 blocks
|
||||
[trace:phi] sum_exit: PHI ValueId(456) from [BB10:ValueId(123), BB15:ValueId(234)]
|
||||
[trace:merge] Remapping ValueId(5) → ValueId(789)
|
||||
[trace:exit_phi] Building exit PHI from 2 incoming values
|
||||
```
|
||||
|
||||
### 運用ポリシー
|
||||
|
||||
#### 開発時(推奨)
|
||||
```bash
|
||||
# Pattern 4デバッグ
|
||||
NYASH_JOINIR_DEBUG=1 ./target/release/hakorune test.hako
|
||||
|
||||
# 変数追跡
|
||||
NYASH_TRACE_VARMAP=1 ./target/release/hakorune test.hako
|
||||
|
||||
# 全トレース有効化(詳細デバッグ)
|
||||
NYASH_JOINIR_DEBUG=1 NYASH_TRACE_VARMAP=1 NYASH_TRACE_PHI=1 \
|
||||
./target/release/hakorune test.hako
|
||||
```
|
||||
|
||||
#### 本番環境(必須)
|
||||
```bash
|
||||
# すべてのトレース環境変数をOFFにする(デフォルト)
|
||||
./target/release/hakorune test.hako
|
||||
```
|
||||
|
||||
#### テスト実行時
|
||||
```bash
|
||||
# 通常テスト: トレースOFF(デフォルト)
|
||||
cargo test --release
|
||||
|
||||
# 特定テストのトレース有効化
|
||||
NYASH_JOINIR_DEBUG=1 cargo test --release loop_continue_multi_carrier
|
||||
```
|
||||
|
||||
### 実装箇所
|
||||
|
||||
**トレースAPI実装**:
|
||||
- `src/mir/builder/control_flow/joinir/trace.rs` - JoinLoopTrace構造体・シングルトン
|
||||
|
||||
**トレース利用箇所**:
|
||||
- `src/mir/builder/control_flow/joinir/patterns/pattern4_with_continue.rs` - Pattern 4 lowering
|
||||
- `src/mir/builder/control_flow/joinir/merge/mod.rs` - MIRブロック結合
|
||||
- `src/mir/join_ir/lowering/loop_with_continue_minimal.rs` - JoinIR生成
|
||||
- その他JoinIR関連モジュール
|
||||
|
||||
### 設計原則
|
||||
|
||||
1. **開発時のみON、本番OFF**: 環境変数なしではトレース出力なし(ZeroConfig Default)
|
||||
2. **カテゴリ別制御**: 必要なトレースのみ有効化(粒度の細かい制御)
|
||||
3. **一貫フォーマット**: `[trace:<category>]` prefix統一(grep/filterしやすい)
|
||||
4. **シングルトン**: `trace::trace()` で全モジュールから統一アクセス
|
||||
5. **環境変数駆動**: コンパイル不要、実行時制御のみ
|
||||
|
||||
### Phase 194実装完了内容
|
||||
|
||||
**Task 194-3 完了**: Pattern 4 lowering内の全eprintln!をtrace()に置き換え
|
||||
- 8箇所のeprintln!削除
|
||||
- trace().debug()統一化
|
||||
- 環境変数制御で出力ON/OFF
|
||||
|
||||
**Task 194-4 完了**: このドキュメントへの反映
|
||||
|
||||
---
|
||||
|
||||
## 📚 Related Documents
|
||||
|
||||
### ConsoleBox について知りたい場合
|
||||
|
||||
@ -0,0 +1,522 @@
|
||||
# Phase 161-impl-3: JsonParserBox ループインベントリ
|
||||
|
||||
## 概要
|
||||
|
||||
JsonParserBox (`tools/hako_shared/json_parser.hako`) に含まれるループを全て分類し、
|
||||
JoinIR Pattern1-4 とのマッピングを行う。
|
||||
|
||||
## ループ一覧(11個)
|
||||
|
||||
### 1. `_parse_number` (L121-133)
|
||||
```hako
|
||||
loop(p < s.length()) {
|
||||
local ch = s.substring(p, p+1)
|
||||
local digit_pos = digits.indexOf(ch)
|
||||
if digit_pos < 0 { break }
|
||||
num_str = num_str + ch
|
||||
p = p + 1
|
||||
}
|
||||
```
|
||||
| 特徴 | 値 |
|
||||
|------|-----|
|
||||
| break | ✅ あり |
|
||||
| continue | ❌ なし |
|
||||
| if-else PHI | ❌ なし(単純if+break) |
|
||||
| ループ変数 | `p`, `num_str` (2変数) |
|
||||
| **パターン** | **Pattern2 (Break)** |
|
||||
|
||||
---
|
||||
|
||||
### 2. `_parse_string` (L150-178)
|
||||
```hako
|
||||
loop(p < s.length()) {
|
||||
local ch = s.substring(p, p+1)
|
||||
if ch == '"' {
|
||||
// return inside loop
|
||||
return result
|
||||
}
|
||||
if ch == "\\" {
|
||||
// escape handling
|
||||
str = str + ch; p = p + 1
|
||||
str = str + s.substring(p, p+1); p = p + 1
|
||||
continue
|
||||
}
|
||||
str = str + ch
|
||||
p = p + 1
|
||||
}
|
||||
```
|
||||
| 特徴 | 値 |
|
||||
|------|-----|
|
||||
| break | ❌ なし(return使用) |
|
||||
| continue | ✅ あり |
|
||||
| if-else PHI | ❌ なし |
|
||||
| ループ変数 | `p`, `str` (2変数) |
|
||||
| return in loop | ✅ あり |
|
||||
| **パターン** | **Pattern4 (Continue) + return** |
|
||||
|
||||
---
|
||||
|
||||
### 3. `_parse_array` (L203-231)
|
||||
```hako
|
||||
loop(p < s.length()) {
|
||||
local elem_result = me._parse_value(s, p)
|
||||
if elem_result == null { return null }
|
||||
arr.push(elem)
|
||||
p = elem_result.get("pos")
|
||||
if ch == "]" { return result }
|
||||
if ch == "," { p = p + 1; continue }
|
||||
return null
|
||||
}
|
||||
```
|
||||
| 特徴 | 値 |
|
||||
|------|-----|
|
||||
| break | ❌ なし |
|
||||
| continue | ✅ あり |
|
||||
| if-else PHI | ❌ なし |
|
||||
| ループ変数 | `p`, `arr` (2変数、arrはmutate) |
|
||||
| return in loop | ✅ あり(複数箇所) |
|
||||
| **パターン** | **Pattern4 (Continue) + multi-return** |
|
||||
|
||||
---
|
||||
|
||||
### 4. `_parse_object` (L256-304)
|
||||
```hako
|
||||
loop(p < s.length()) {
|
||||
// parse key
|
||||
if s.substring(p, p+1) != '"' { return null }
|
||||
local key_result = me._parse_string(s, p)
|
||||
// parse value
|
||||
local value_result = me._parse_value(s, p)
|
||||
obj.set(key, value)
|
||||
if ch == "}" { return result }
|
||||
if ch == "," { p = p + 1; continue }
|
||||
return null
|
||||
}
|
||||
```
|
||||
| 特徴 | 値 |
|
||||
|------|-----|
|
||||
| break | ❌ なし |
|
||||
| continue | ✅ あり |
|
||||
| if-else PHI | ❌ なし |
|
||||
| ループ変数 | `p`, `obj` (2変数、objはmutate) |
|
||||
| return in loop | ✅ あり(複数箇所) |
|
||||
| **パターン** | **Pattern4 (Continue) + multi-return** |
|
||||
|
||||
---
|
||||
|
||||
### 5. `_skip_whitespace` (L312-319)
|
||||
```hako
|
||||
loop(p < s.length()) {
|
||||
local ch = s.substring(p, p+1)
|
||||
if ch == " " || ch == "\t" || ch == "\n" || ch == "\r" {
|
||||
p = p + 1
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
```
|
||||
| 特徴 | 値 |
|
||||
|------|-----|
|
||||
| break | ✅ あり |
|
||||
| continue | ❌ なし |
|
||||
| if-else PHI | ✅ あり(if-else分岐でpを更新) |
|
||||
| ループ変数 | `p` (1変数) |
|
||||
| **パターン** | **Pattern3 (If-Else PHI) + break** |
|
||||
|
||||
---
|
||||
|
||||
### 6. `_trim` (leading whitespace, L330-337)
|
||||
```hako
|
||||
loop(start < end) {
|
||||
local ch = s.substring(start, start+1)
|
||||
if ch == " " || ch == "\t" || ch == "\n" || ch == "\r" {
|
||||
start = start + 1
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
```
|
||||
| 特徴 | 値 |
|
||||
|------|-----|
|
||||
| break | ✅ あり |
|
||||
| continue | ❌ なし |
|
||||
| if-else PHI | ✅ あり |
|
||||
| ループ変数 | `start` (1変数) |
|
||||
| **パターン** | **Pattern3 (If-Else PHI) + break** |
|
||||
|
||||
---
|
||||
|
||||
### 7. `_trim` (trailing whitespace, L340-347)
|
||||
```hako
|
||||
loop(end > start) {
|
||||
local ch = s.substring(end-1, end)
|
||||
if ch == " " || ch == "\t" || ch == "\n" || ch == "\r" {
|
||||
end = end - 1
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
```
|
||||
| 特徴 | 値 |
|
||||
|------|-----|
|
||||
| break | ✅ あり |
|
||||
| continue | ❌ なし |
|
||||
| if-else PHI | ✅ あり |
|
||||
| ループ変数 | `end` (1変数) |
|
||||
| **パターン** | **Pattern3 (If-Else PHI) + break** |
|
||||
|
||||
---
|
||||
|
||||
### 8. `_match_literal` (L357-362)
|
||||
```hako
|
||||
loop(i < len) {
|
||||
if s.substring(pos + i, pos + i + 1) != literal.substring(i, i + 1) {
|
||||
return 0
|
||||
}
|
||||
i = i + 1
|
||||
}
|
||||
```
|
||||
| 特徴 | 値 |
|
||||
|------|-----|
|
||||
| break | ❌ なし |
|
||||
| continue | ❌ なし |
|
||||
| if-else PHI | ❌ なし(単純if+return) |
|
||||
| ループ変数 | `i` (1変数) |
|
||||
| return in loop | ✅ あり |
|
||||
| **パターン** | **Pattern1 (Simple) + return** |
|
||||
|
||||
---
|
||||
|
||||
### 9. `_unescape_string` (L373-431)
|
||||
```hako
|
||||
loop(i < s.length()) {
|
||||
local ch = s.substring(i, i+1)
|
||||
// flatten workaround for nested-if bug
|
||||
local is_escape = 0
|
||||
if ch == "\\" { is_escape = 1 }
|
||||
if process_escape == 1 {
|
||||
// multiple if-continue patterns
|
||||
if next == "n" { result = result + "\n"; i = i + 2; continue }
|
||||
if next == "t" { result = result + "\t"; i = i + 2; continue }
|
||||
// ... more cases
|
||||
}
|
||||
result = result + ch
|
||||
i = i + 1
|
||||
}
|
||||
```
|
||||
| 特徴 | 値 |
|
||||
|------|-----|
|
||||
| break | ❌ なし |
|
||||
| continue | ✅ あり(多数) |
|
||||
| if-else PHI | ✅ あり(フラットworkaround済み) |
|
||||
| ループ変数 | `i`, `result` (2変数) |
|
||||
| **パターン** | **Pattern4 (Continue) + multi-PHI** |
|
||||
| **複雑度** | **高**(フラット化workaround済み) |
|
||||
|
||||
---
|
||||
|
||||
### 10. `_atoi` (L453-460)
|
||||
```hako
|
||||
loop(i < n) {
|
||||
local ch = s.substring(i, i+1)
|
||||
if ch < "0" || ch > "9" { break }
|
||||
local pos = digits.indexOf(ch)
|
||||
if pos < 0 { break }
|
||||
v = v * 10 + pos
|
||||
i = i + 1
|
||||
}
|
||||
```
|
||||
| 特徴 | 値 |
|
||||
|------|-----|
|
||||
| break | ✅ あり(複数箇所) |
|
||||
| continue | ❌ なし |
|
||||
| if-else PHI | ❌ なし |
|
||||
| ループ変数 | `i`, `v` (2変数) |
|
||||
| **パターン** | **Pattern2 (Break)** |
|
||||
|
||||
---
|
||||
|
||||
## パターン別サマリ
|
||||
|
||||
| パターン | ループ数 | 対象 |
|
||||
|----------|----------|------|
|
||||
| **Pattern1 (Simple)** | 1 | `_match_literal` (return in loop) |
|
||||
| **Pattern2 (Break)** | 2 | `_parse_number`, `_atoi` |
|
||||
| **Pattern3 (If-Else PHI) + break** | 3 | `_skip_whitespace`, `_trim`×2 |
|
||||
| **Pattern4 (Continue)** | 5 | `_parse_string`, `_parse_array`, `_parse_object`, `_unescape_string`, + return variations |
|
||||
|
||||
## JoinIR 対応状況
|
||||
|
||||
### ✅ 現状で対応可能(Pattern1-2)
|
||||
- `_match_literal` - Pattern1 + return
|
||||
- `_parse_number` - Pattern2
|
||||
- `_atoi` - Pattern2
|
||||
|
||||
### 🟡 拡張が必要(Pattern3)
|
||||
- `_skip_whitespace` - **if-else + break の組み合わせ**
|
||||
- `_trim` (leading) - **if-else + break の組み合わせ**
|
||||
- `_trim` (trailing) - **if-else + break の組み合わせ**
|
||||
|
||||
### 🔴 大きな拡張が必要(Pattern4+)
|
||||
- `_parse_string` - continue + return in loop
|
||||
- `_parse_array` - continue + multi-return
|
||||
- `_parse_object` - continue + multi-return
|
||||
- `_unescape_string` - continue + multi-continue + if-else
|
||||
|
||||
## 推奨アクション
|
||||
|
||||
### 短期(Pattern3強化)
|
||||
1. **Pattern3 + break 対応**: `_skip_whitespace`, `_trim`×2 を動かす
|
||||
2. これで JsonParserBox の一部メソッドが動作可能に
|
||||
|
||||
### 中期(Pattern4基本)
|
||||
1. **continue サポート**: `_parse_string`, `_match_literal` の return in loop 対応
|
||||
2. **return in loop → break 変換**: 内部的に return を break + 値保存に変換
|
||||
|
||||
### 長期(Pattern4+完全対応)
|
||||
1. **multi-return, multi-continue**: `_parse_array`, `_parse_object`
|
||||
2. **複雑なフラット化パターン**: `_unescape_string`
|
||||
|
||||
## 備考
|
||||
|
||||
- `_unescape_string` は既に「MIR nested-if bug workaround」としてフラット化されている
|
||||
- `_parse_value` 自体はループなし(再帰呼び出しのみ)
|
||||
- ProgramJSONBox はループなし(getter のみ)
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
# BundleResolver ループインベントリ
|
||||
|
||||
## 対象ファイル
|
||||
|
||||
`lang/src/compiler/entry/bundle_resolver.hako`
|
||||
|
||||
## ループ一覧(8個)
|
||||
|
||||
### 1. Alias table parsing - outer loop (L25-45)
|
||||
```hako
|
||||
loop(i < table.length()) {
|
||||
local j = table.indexOf("|||", i)
|
||||
local seg = ""
|
||||
if j >= 0 { seg = table.substring(i, j) } else { seg = table.substring(i, table.length()) }
|
||||
// ... process seg ...
|
||||
if j < 0 { break }
|
||||
i = j + 3
|
||||
}
|
||||
```
|
||||
| 特徴 | 値 |
|
||||
|------|-----|
|
||||
| break | ✅ あり |
|
||||
| continue | ❌ なし |
|
||||
| if-else PHI | ✅ あり(seg への代入) |
|
||||
| ループ変数 | `i`, `seg` (2変数) |
|
||||
| **パターン** | **Pattern3 (If-Else PHI) + break** |
|
||||
|
||||
---
|
||||
|
||||
### 2. Alias table parsing - inner loop for ':' search (L33)
|
||||
```hako
|
||||
loop(k < seg.length()) { if seg.substring(k,k+1) == ":" { pos = k break } k = k + 1 }
|
||||
```
|
||||
| 特徴 | 値 |
|
||||
|------|-----|
|
||||
| break | ✅ あり |
|
||||
| continue | ❌ なし |
|
||||
| if-else PHI | ❌ なし(単純if+break+代入) |
|
||||
| ループ変数 | `k`, `pos` (2変数) |
|
||||
| **パターン** | **Pattern2 (Break)** |
|
||||
|
||||
---
|
||||
|
||||
### 3. Require mods env alias check - outer loop (L52-71)
|
||||
```hako
|
||||
loop(i0 < rn0) {
|
||||
local need = "" + require_mods.get(i0)
|
||||
local present = 0
|
||||
// inner loop for bundle_names check
|
||||
// ... if present == 0 { ... }
|
||||
i0 = i0 + 1
|
||||
}
|
||||
```
|
||||
| 特徴 | 値 |
|
||||
|------|-----|
|
||||
| break | ❌ なし |
|
||||
| continue | ❌ なし |
|
||||
| if-else PHI | ❌ なし |
|
||||
| ループ変数 | `i0` (1変数) |
|
||||
| **パターン** | **Pattern1 (Simple)** |
|
||||
|
||||
---
|
||||
|
||||
### 4. Require mods env alias check - inner loop (L57)
|
||||
```hako
|
||||
loop(j0 < bn0) { if ("" + bundle_names.get(j0)) == need { present = 1 break } j0 = j0 + 1 }
|
||||
```
|
||||
| 特徴 | 値 |
|
||||
|------|-----|
|
||||
| break | ✅ あり |
|
||||
| continue | ❌ なし |
|
||||
| if-else PHI | ❌ なし |
|
||||
| ループ変数 | `j0`, `present` (2変数) |
|
||||
| **パターン** | **Pattern2 (Break)** |
|
||||
|
||||
---
|
||||
|
||||
### 5. Duplicate names check - outer loop (L76-87)
|
||||
```hako
|
||||
loop(i < n) {
|
||||
local name_i = "" + bundle_names.get(i)
|
||||
local j = i + 1
|
||||
loop(j < n) { ... }
|
||||
i = i + 1
|
||||
}
|
||||
```
|
||||
| 特徴 | 値 |
|
||||
|------|-----|
|
||||
| break | ❌ なし |
|
||||
| continue | ❌ なし |
|
||||
| if-else PHI | ❌ なし |
|
||||
| ループ変数 | `i` (1変数) |
|
||||
| **パターン** | **Pattern1 (Simple)** |
|
||||
|
||||
---
|
||||
|
||||
### 6. Duplicate names check - inner loop (L79-85)
|
||||
```hako
|
||||
loop(j < n) {
|
||||
if ("" + bundle_names.get(j)) == name_i {
|
||||
print("[bundle/duplicate] " + name_i)
|
||||
return null
|
||||
}
|
||||
j = j + 1
|
||||
}
|
||||
```
|
||||
| 特徴 | 値 |
|
||||
|------|-----|
|
||||
| break | ❌ なし(return使用) |
|
||||
| continue | ❌ なし |
|
||||
| if-else PHI | ❌ なし |
|
||||
| ループ変数 | `j` (1変数) |
|
||||
| return in loop | ✅ あり |
|
||||
| **パターン** | **Pattern1 (Simple) + return** |
|
||||
|
||||
---
|
||||
|
||||
### 7. Required modules check - outer loop (L92-101)
|
||||
```hako
|
||||
loop(idx < rn) {
|
||||
local need = "" + require_mods.get(idx)
|
||||
local found = 0
|
||||
// inner loop
|
||||
if found == 0 { print("[bundle/missing] " + need) return null }
|
||||
idx = idx + 1
|
||||
}
|
||||
```
|
||||
| 特徴 | 値 |
|
||||
|------|-----|
|
||||
| break | ❌ なし |
|
||||
| continue | ❌ なし |
|
||||
| if-else PHI | ❌ なし |
|
||||
| ループ変数 | `idx` (1変数) |
|
||||
| return in loop | ✅ あり(条件付き) |
|
||||
| **パターン** | **Pattern1 (Simple) + return** |
|
||||
|
||||
---
|
||||
|
||||
### 8. Required modules check - inner loop (L97)
|
||||
```hako
|
||||
loop(j < bn) { if ("" + bundle_names.get(j)) == need { found = 1 break } j = j + 1 }
|
||||
```
|
||||
| 特徴 | 値 |
|
||||
|------|-----|
|
||||
| break | ✅ あり |
|
||||
| continue | ❌ なし |
|
||||
| if-else PHI | ❌ なし |
|
||||
| ループ変数 | `j`, `found` (2変数) |
|
||||
| **パターン** | **Pattern2 (Break)** |
|
||||
|
||||
---
|
||||
|
||||
### 9. Merge bundle_srcs (L107)
|
||||
```hako
|
||||
loop(i < m) { merged = merged + bundle_srcs.get(i) + "\n" i = i + 1 }
|
||||
```
|
||||
| 特徴 | 値 |
|
||||
|------|-----|
|
||||
| break | ❌ なし |
|
||||
| continue | ❌ なし |
|
||||
| if-else PHI | ❌ なし |
|
||||
| ループ変数 | `i`, `merged` (2変数) |
|
||||
| **パターン** | **Pattern1 (Simple)** |
|
||||
|
||||
---
|
||||
|
||||
### 10. Merge bundle_mod_srcs (L111)
|
||||
```hako
|
||||
loop(i2 < m2) { merged = merged + bundle_mod_srcs.get(i2) + "\n" i2 = i2 + 1 }
|
||||
```
|
||||
| 特徴 | 値 |
|
||||
|------|-----|
|
||||
| break | ❌ なし |
|
||||
| continue | ❌ なし |
|
||||
| if-else PHI | ❌ なし |
|
||||
| ループ変数 | `i2`, `merged` (2変数) |
|
||||
| **パターン** | **Pattern1 (Simple)** |
|
||||
|
||||
---
|
||||
|
||||
## BundleResolver パターン別サマリ
|
||||
|
||||
| パターン | ループ数 | 対象 |
|
||||
|----------|----------|------|
|
||||
| **Pattern1 (Simple)** | 5 | L52, L76, L92, L107, L111 |
|
||||
| **Pattern1 + return** | 2 | L79, L92 (条件付きreturn) |
|
||||
| **Pattern2 (Break)** | 3 | L33, L57, L97 |
|
||||
| **Pattern3 (If-Else PHI) + break** | 1 | L25 |
|
||||
|
||||
## BundleResolver JoinIR 対応状況
|
||||
|
||||
### ✅ 現状で対応可能(Pattern1-2)
|
||||
- ほとんどのループが **Pattern1 または Pattern2** で対応可能
|
||||
- 10個中9個が単純なパターン
|
||||
|
||||
### 🟡 拡張が必要(Pattern3)
|
||||
- **L25-45 (Alias table outer loop)**: if-else で seg に代入するパターン
|
||||
- これは Pattern3 の if-else PHI + break 対応が必要
|
||||
|
||||
---
|
||||
|
||||
## 統合サマリ
|
||||
|
||||
### JsonParserBox + BundleResolver 合計
|
||||
|
||||
| パターン | JsonParserBox | BundleResolver | 合計 |
|
||||
|----------|---------------|----------------|------|
|
||||
| Pattern1 | 1 | 5 | **6** |
|
||||
| Pattern1 + return | 0 | 2 | **2** |
|
||||
| Pattern2 | 2 | 3 | **5** |
|
||||
| Pattern3 + break | 3 | 1 | **4** |
|
||||
| Pattern4 | 5 | 0 | **5** |
|
||||
| **合計** | **11** | **10** | **21** |
|
||||
|
||||
### 優先度順の対応方針
|
||||
|
||||
1. **Pattern1-2 強化** (11ループ対応可能)
|
||||
- return in loop の対応が必要(break変換)
|
||||
|
||||
2. **Pattern3 + break** (4ループ)
|
||||
- if-else PHI と break の組み合わせ
|
||||
- `_skip_whitespace`, `_trim`×2, Alias table outer loop
|
||||
|
||||
3. **Pattern4 (continue系)** (5ループ)
|
||||
- `_parse_string`, `_parse_array`, `_parse_object`, `_unescape_string`
|
||||
- JsonParserBox のコア機能
|
||||
|
||||
---
|
||||
|
||||
## 更新履歴
|
||||
|
||||
- 2025-12-06: Phase 161-impl-3 Task 161-3-1 完了 - ループインベントリ作成
|
||||
- 2025-12-06: Phase 161-impl-3 Task 161-3-3 完了 - BundleResolver 棚卸し追加
|
||||
89
docs/development/current/main/phase194_joinlooptrace.md
Normal file
89
docs/development/current/main/phase194_joinlooptrace.md
Normal file
@ -0,0 +1,89 @@
|
||||
# Phase 194: JoinLoopTrace / Debug Integration
|
||||
|
||||
**Status**: In Progress(trace.rs は実装済み、呼び出し置き換えと docs 反映が残り)
|
||||
**Date**: 2025-12-06
|
||||
|
||||
## Goal
|
||||
|
||||
JoinIR / ループ周辺のデバッグ出力を `JoinLoopTrace` に集約し、環境変数ベースの制御と `logging_policy.md` の方針に沿った形に整理する。
|
||||
|
||||
---
|
||||
|
||||
## Implemented Infrastructure
|
||||
|
||||
### JoinLoopTrace モジュール
|
||||
|
||||
- File: `src/mir/builder/control_flow/joinir/trace.rs`
|
||||
- 役割:
|
||||
- JoinIR ループまわりの `eprintln!` を 1 箱に集約する。
|
||||
- 環境変数からフラグを読み取り、どのカテゴリのトレースを出すかを制御する。
|
||||
- 対応環境変数:
|
||||
- `NYASH_TRACE_VARMAP=1` – variable_map トレース(var → ValueId)
|
||||
- `NYASH_JOINIR_DEBUG=1` – JoinIR 全般のデバッグ(パターン routing、merge 統計など)
|
||||
- `NYASH_OPTION_C_DEBUG=1` – PHI 生成(Option C)周りのトレース
|
||||
- `NYASH_JOINIR_MAINLINE_DEBUG=1` – mainline routing(代表関数の routing)トレース
|
||||
- `NYASH_LOOPFORM_DEBUG=1` – LoopForm 関連トレース(レガシー互換)
|
||||
|
||||
### 主なメソッド
|
||||
|
||||
- `pattern(tag, pattern_name, matched)` – パターン検出・選択
|
||||
- `varmap(tag, &BTreeMap<String, ValueId>)` – variable_map の状態
|
||||
- `joinir_stats(tag, func_count, block_count)` – JoinIR モジュールの統計
|
||||
- `phi(tag, msg)` – PHI 関連の操作
|
||||
- `merge(tag, msg)` – JoinIR→MIR マージ進行
|
||||
- `exit_phi(tag, var_name, old_id, new_id)` – Exit PHI 接続
|
||||
- `debug(tag, msg)` / `routing(tag, func_name, msg)` / `blocks(tag, msg)` / `instructions(tag, msg)` – 汎用デバッグ
|
||||
|
||||
グローバルアクセサ:
|
||||
|
||||
```rust
|
||||
pub fn trace() -> &'static JoinLoopTrace
|
||||
```
|
||||
|
||||
でどこからでも呼び出せる。
|
||||
|
||||
---
|
||||
|
||||
## Remaining Work (Phase 194)
|
||||
|
||||
### Task 194-3: 生 `eprintln!` の JoinLoopTrace 置き換え
|
||||
|
||||
対象(例):
|
||||
|
||||
- `src/mir/builder/control_flow/joinir/patterns/pattern4_with_continue.rs`
|
||||
- まだ 8 箇所程度 `eprintln!` ベースのログが残っている。
|
||||
- ここを順次:
|
||||
- varmap ログ → `trace().varmap(...)`
|
||||
- パターン / ルーティング系 → `trace().pattern(...)` / `trace().routing(...)`
|
||||
- それ以外の debug → `trace().debug(...)`
|
||||
に差し替える。
|
||||
|
||||
同様に、他の JoinIR / loop 関連ファイルに散在している `[joinir/...]` 系 `eprintln!` も、必要に応じて `trace.rs` 経由に寄せる。
|
||||
|
||||
### Task 194-4: logging_policy.md 反映
|
||||
|
||||
- File: `docs/development/current/main/logging_policy.md`
|
||||
- 追記内容:
|
||||
- JoinIR / ループ系のトレースカテゴリを 1 セクションにまとめる:
|
||||
- varmap(NYASH_TRACE_VARMAP)
|
||||
- joinir-debug(NYASH_JOINIR_DEBUG)
|
||||
- phi-debug(NYASH_OPTION_C_DEBUG)
|
||||
- mainline-debug(NYASH_JOINIR_MAINLINE_DEBUG)
|
||||
- 開発時のみ ON、本番パスでは OFF を前提とする運用メモ。
|
||||
- `trace.rs` による prefix(`[trace:pattern]`, `[trace:varmap]`, ...)を簡単に説明。
|
||||
|
||||
---
|
||||
|
||||
## Success Criteria
|
||||
|
||||
- JoinIR / ループ周辺の `eprintln!` が、意味あるかたちで `JoinLoopTrace` 経由に置き換わっている。
|
||||
- `NYASH_TRACE_VARMAP=1` や `NYASH_JOINIR_DEBUG=1` の挙動が `logging_policy.md` に説明されている。
|
||||
- デフォルト(env 未設定)ではトレースは出ず、既存の代表テスト(Pattern 1〜4)はログ無しで PASS する。
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
- Phase 194 は **挙動を変えない** リファクタフェーズ(観測レイヤーの整形)として扱う。
|
||||
- Loop パターンや ExitBinding まわりは Phase 193/196/197 で安定しているので、それを壊さない形でログだけを寄せることが目的。
|
||||
|
||||
Reference in New Issue
Block a user