2025-12-07 23:09:25 +09:00
# Phase 171-A: Blocked Loop Inventory
**Date**: 2025-12-07
**Status**: Initial inventory complete
**Purpose**: Identify loops blocked by LoopBodyLocal variables in break conditions
---
## Overview
This document catalogs loops that cannot be lowered by Pattern 2/4 because they use **LoopBodyLocal** variables in their break conditions. These are candidates for Pattern 5 carrier promotion.
---
## Blocked Loops Found
### 1. TrimTest.trim/1 - Leading Whitespace Trim
**File**: `local_tests/test_trim_main_pattern.hako`
**Lines**: 20-27
```hako
loop(start < end ) {
local ch = s.substring(start, start+1)
if ch == " " || ch == "\t" || ch == "\n" || ch == "\r" {
start = start + 1
} else {
break
}
}
```
**Blocking Variable**: `ch` (LoopBodyLocal)
**Analysis**:
- Loop parameter: `start` (LoopParam)
- Outer variable: `end` (OuterLocal)
- Break condition uses: `ch` (LoopBodyLocal)
- `ch` is defined inside loop body as `s.substring(start, start+1)`
**Error Message**:
```
[trace:debug] pattern2: Pattern 2 lowerer failed: Variable 'ch' not bound in ConditionEnv
```
**Why Blocked**:
Pattern 2 expects break conditions to only use:
- LoopParam (`start` )
- OuterLocal (`end` , `s` )
But the break condition `ch == " " || ...` uses `ch` , which is defined inside the loop body.
---
### 2. TrimTest.trim/1 - Trailing Whitespace Trim
**File**: `local_tests/test_trim_main_pattern.hako`
**Lines**: 30-37
```hako
loop(end > start) {
local ch = s.substring(end-1, end)
if ch == " " || ch == "\t" || ch == "\n" || ch == "\r" {
end = end - 1
} else {
break
}
}
```
**Blocking Variable**: `ch` (LoopBodyLocal)
**Analysis**:
- Loop parameter: `end` (LoopParam)
- Outer variable: `start` (OuterLocal)
- Break condition uses: `ch` (LoopBodyLocal)
- `ch` is defined inside loop body as `s.substring(end-1, end)`
**Same blocking reason as Loop 1.**
---
### 3. JsonParserBox - MethodCall in Condition
**File**: `tools/hako_shared/json_parser.hako`
```hako
loop(i < s.length ( ) ) {
// ...
}
```
**Blocking Issue**: `s.length()` is a MethodCall in the condition expression.
**Error Message**:
```
[ERROR] ❌ MIR compilation error: [cf_loop/pattern4] Lowering failed:
Unsupported expression in value context: MethodCall {
object: Variable { name: "s", ... },
method: "length",
arguments: [],
...
}
```
**Why Blocked**:
Pattern 4's value context lowering doesn't support MethodCall expressions yet.
**Note**: This is not a LoopBodyLocal issue, but a MethodCall limitation. May be addressed in Phase 171-D (Optional).
---
## Pattern5-A Target Decision
### Selected Target: TrimTest Loop 1 (Leading Whitespace)
We select the **first loop** from TrimTest as Pattern5-A target for the following reasons:
1. **Clear structure** : Simple substring + equality checks
2. **Representative** : Same pattern as many real-world parsers
3. **Self-contained** : Doesn't depend on complex outer state
4. **Testable** : Easy to write unit tests
### Pattern5-A Specification
**Loop Structure**:
```hako
loop(start < end ) {
local ch = s.substring(start, start+1)
if ch == " " || ch == "\t" || ch == "\n" || ch == "\r" {
start = start + 1
} else {
break
}
}
```
**Variables**:
- `start` : LoopParam (carrier, mutated)
- `end` : OuterLocal (condition-only)
- `s` : OuterLocal (used in body)
- `ch` : LoopBodyLocal (blocking variable)
**Break Condition**:
```
!(ch == " " || ch == "\t" || ch == "\n" || ch == "\r")
```
---
## Promotion Strategy: Design D (Evaluated Bool Carrier)
### Rationale
We choose **Design D** (Evaluated Bool Carrier) over other options:
**Why not carry `ch` directly?**
- `ch` is a StringBox, not a primitive value
- Would require complex carrier type system
- Would break existing Pattern 2/4 assumptions
**Design D approach**:
- Introduce a new carrier: `is_whitespace` (bool)
- Evaluate `ch == " " || ...` in loop body
- Store result in `is_whitespace` carrier
- Use `is_whitespace` in break condition
### Transformed Structure
**Before (Pattern5-A)**:
```hako
loop(start < end ) {
local ch = s.substring(start, start+1)
if ch == " " || ch == "\t" || ch == "\n" || ch == "\r" {
start = start + 1
} else {
break
}
}
```
**After (Pattern2 compatible)**:
```hako
// Initialization (before loop)
local is_whitespace = true // Initial assumption
loop(start < end & & is_whitespace ) {
local ch = s.substring(start, start+1)
is_whitespace = (ch == " " || ch == "\t" || ch == "\n" || ch == "\r")
if is_whitespace {
start = start + 1
} else {
break // Now redundant, but kept for clarity
}
}
```
**Key transformations**:
1. Add `is_whitespace` carrier initialization
2. Update loop condition to include `is_whitespace`
3. Compute `is_whitespace` in loop body
4. Original if-else becomes simpler (could be optimized away)
---
## Next Steps (Phase 171-C)
### Phase 171-C-1: Skeleton Implementation ✅
- Create `LoopBodyCarrierPromoter` box
- Define `PromotionRequest` / `PromotionResult` types
- Implement skeleton `try_promote()` method
- Add `find_definition_in_body()` helper
### Phase 171-C-2: Trim Pattern Promotion Logic
- Detect substring + equality pattern
- Generate `is_whitespace` carrier
- Generate initialization statement
- Generate update statement
### Phase 171-C-3: Integration with Pattern 2/4
- Call `LoopBodyCarrierPromoter::try_promote()` in routing
- If promotion succeeds, route to Pattern 2
- If promotion fails, return UnsupportedPattern
### Phase 171-D: MethodCall Support (Optional)
- Handle `s.length()` in loop conditions
- May require carrier promotion for method results
- Lower priority than Trim pattern
---
## Summary
**Blocked Loops**:
- 2 loops in TrimTest (LoopBodyLocal `ch` )
- 1+ loops in JsonParser (MethodCall in condition)
**Pattern5-A Target**:
- TrimTest leading whitespace trim loop
- Clear, representative, testable
**Promotion Strategy**:
- Design D: Evaluated Bool Carrier
- Transform `ch` checks → `is_whitespace` carrier
- Make compatible with Pattern 2
**Implementation Status**:
- Phase 171-A: ✅ Inventory complete
- Phase 171-B: ✅ Target selected
- Phase 171-C-1: ✅ Skeleton implementation complete
- Phase 171-C-2: ✅ Trim pattern detection implemented
- `find_definition_in_body()` : AST traversal for variable definitions
- `is_substring_method_call()` : Detects `substring()` method calls
- `extract_equality_literals()` : Extracts string literals from OR chains
- `TrimPatternInfo` : Captures pattern details for carrier promotion
2025-12-08 02:41:53 +09:00
- Phase 171-C-3: ✅ Integration with Pattern 2/4 routing complete
- Phase 171-C-4: ✅ CarrierInfo integration complete (2025-12-07)
- `CarrierInfo::merge_from()` : Deduplicated carrier merging with deterministic sorting
- `TrimPatternInfo::to_carrier_info()` : Conversion to CarrierInfo with TrimLoopHelper
- Pattern 2/4 lowerers: Promoted carrier merging in `Promoted` branch
- 7 unit tests: Merge success/failure/duplication/determinism validation
- Phase 171-C-5: ✅ TrimLoopHelper design complete (2025-12-07)
- `TrimLoopHelper` struct: Encapsulates Trim pattern lowering logic
- `CarrierInfo::trim_helper()` : Accessor for pattern-specific helper
- Module export: `mod.rs` updated with `pub use TrimLoopHelper`
- 4 unit tests: Helper creation and accessor validation
---
## Phase 171-C-3/4/5: Responsibility Positions and Data Flow
### Responsibility Separation Principle
The promotion system follows Box Theory's single responsibility principle:
1. **router.rs** : Pattern table + `can_lower()` /`lower()` call abstraction (no Scope/condition logic)
2. **Pattern 2/4 lowerer** : Holds LoopScope / ConditionScope / CarrierInfo / Promoter
3. **LoopBodyCarrierPromoter** : LoopBodyLocal handling specialist box
4. **TrimLoopHelper** : Trim pattern-specific helper (future extensibility)
### Data Flow Diagram
```
LoopConditionScopeBox::analyze()
↓
has_loop_body_local()?
↓ true
LoopBodyCarrierPromoter::try_promote()
↓ Promoted { trim_info }
TrimPatternInfo::to_carrier_info()
↓
CarrierInfo::merge_from()
↓
TrimLoopHelper (attached to CarrierInfo)
↓
Pattern 2/4 lowerer (JoinIR generation)
```
### Implementation Locations
**Phase 171-C-4 Changes**:
- `src/mir/join_ir/lowering/carrier_info.rs` : Added `merge_from()` , `trim_helper()` , `trim_helper` field
- `src/mir/loop_pattern_detection/loop_body_carrier_promoter.rs` : Updated `to_carrier_info()` to attach TrimLoopHelper
- `src/mir/builder/control_flow/joinir/patterns/pattern2_with_break.rs` : Promoted branch now merges carriers
- `src/mir/builder/control_flow/joinir/patterns/pattern4_with_continue.rs` : Promoted branch now merges carriers
**Phase 171-C-5 Changes**:
- `src/mir/loop_pattern_detection/trim_loop_helper.rs` : NEW - TrimLoopHelper struct with 4 unit tests
- `src/mir/loop_pattern_detection/mod.rs` : Export TrimLoopHelper module
---
## Phase 171-impl-Trim: Trim 特例の実戦投入
**Date**: 2025-12-08
**Status**: ✅ Validation complete
**Purpose**: Safely integrate Trim pattern detection into JoinIR pipeline with validation-only implementation
### 設計原則
> **「LoopBodyLocal を全面解禁」ではなく、Trim パターンだけを箱経由でホワイトリストに載せる**
### 安全機構
1. `TrimLoopHelper::is_safe_trim()` - 構造的に安全か判定
2. `TrimLoopHelper::is_trim_like()` - Trim パターンに合致するか判定
3. `TrimLoopHelper::has_valid_structure()` - 構造チェック
### データフロー( Trim 特例)
```
LoopConditionScopeBox::analyze()
↓
has_loop_body_local() == true
↓
LoopBodyCarrierPromoter::try_promote()
↓ Promoted { trim_info }
TrimPatternInfo::to_carrier_info()
↓
CarrierInfo::merge_from()
↓
carrier_info.trim_helper()?.is_safe_trim()
↓ true
✅ Validation Success (TODO: JoinIR lowering in Phase 172)
```
### 実装状況
- [x] Phase 171-impl-Trim-1: 受け入れ条件を 1 箇所に ✅
- `TrimLoopHelper::is_safe_trim()` implemented
- `Pattern2/4` で Trim 特例ルート実装
- Fail-Fast on unsafe patterns
- [x] Phase 171-impl-Trim-2: TrimLoopHelper 判定メソッド ✅
- `is_trim_like()` , `has_valid_structure()` implemented
- 4+ ユニットテスト追加 (9 tests total, all passing)
- [x] Phase 171-impl-Trim-3: E2E テスト ✅
- `local_tests/test_trim_main_pattern.hako` validated
- 出力: `[pattern2/trim] Safe Trim pattern detected`
- 出力: `✅ Trim pattern validation successful!`
- Status: Validation-only (JoinIR lowering deferred to Phase 172)
- [x] Phase 171-impl-Trim-4: ドキュメント更新 ✅
- `phase171-pattern5-loop-inventory.md` updated
- `CURRENT_TASK.md` status tracking
### 実装詳細
**ファイル変更**:
1. `src/mir/loop_pattern_detection/trim_loop_helper.rs`
- `is_safe_trim()` , `is_trim_like()` , `has_valid_structure()` methods
- 4 new unit tests for safety validation
2. `src/mir/builder/control_flow/joinir/patterns/pattern2_with_break.rs`
- Trim exception route with safety check
- `body_locals` extraction from loop body AST
- Validation message for successful detection
3. `src/mir/builder/control_flow/joinir/patterns/pattern4_with_continue.rs`
- Same Trim exception logic as Pattern2
- `body_locals` extraction from normalized loop body
4. `src/mir/loop_pattern_detection/loop_body_carrier_promoter.rs`
- `ASTNode::Local { variables, initial_values, .. }` handler
- Support for `local ch = expr` pattern recognition
### テスト結果
**ユニットテスト**: ✅ 9/9 passing
- `test_is_safe_trim`
- `test_is_safe_trim_empty_carrier`
- `test_is_safe_trim_no_whitespace`
- `test_has_valid_structure`
- (+ 5 existing tests)
**E2E テスト**: ✅ Validation successful
```
[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, bypassing LoopBodyLocal restriction
[pattern2/trim] Carrier: 'is_ch_match', original var: 'ch', whitespace chars: ["\r", "\n", "\t", " "]
✅ Trim pattern validation successful! Carrier 'is_ch_match' ready for Phase 172 implementation.
(Pattern detection: PASS, Safety check: PASS, JoinIR lowering: TODO)
```
**ビルド結果**: ✅ Success
- `cargo build --release` : Success
- `cargo test --lib trim_loop_helper` : 9/9 passing
### 重要な発見
1. **AST構造の理解** : `local ch = expr` は `ASTNode::Local { variables, initial_values, .. }` として表現される
2. **body_locals 抽出** : Pattern2/4 で `LoopScopeShape.body_locals` を AST から抽出する必要があった
3. **段階的実装** : Validation-only approach で安全性を先に確立し、JoinIR lowering は Phase 172 に分離
### 次のステップ (Phase 172)
- [ ] Phase 172-1: Trim pattern JoinIR generation
- Carrier initialization code
- Carrier update logic (substring + OR chain → bool)
- Exit PHI mapping
- [ ] Phase 172-2: JsonParser loops への展開
- Similar pattern recognition
- Generalized carrier promotion