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:
nyash-codex
2025-12-06 16:22:38 +09:00
parent ae61226691
commit 701f1fd650
17 changed files with 1570 additions and 11 deletions

View File

@ -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 について知りたい場合

View File

@ -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 棚卸し追加

View File

@ -0,0 +1,89 @@
# Phase 194: JoinLoopTrace / Debug Integration
**Status**: In Progresstrace.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 セクションにまとめる:
- varmapNYASH_TRACE_VARMAP
- joinir-debugNYASH_JOINIR_DEBUG
- phi-debugNYASH_OPTION_C_DEBUG
- mainline-debugNYASH_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 で安定しているので、それを壊さない形でログだけを寄せることが目的。