feat(joinir): Phase 247-EX - DigitPos dual-value architecture

Extends DigitPos promotion to generate TWO carriers for Pattern A/B support:
- Boolean carrier (is_digit_pos) for break conditions
- Integer carrier (digit_value) for NumberAccumulation

## Implementation

1. **DigitPosPromoter** (loop_body_digitpos_promoter.rs)
   - Generates dual carriers: is_<var> (bool) + <base>_value (int)
   - Smart naming: "digit_pos" → "digit" (removes "_pos" suffix)

2. **UpdateEnv** (update_env.rs)
   - Context-aware promoted variable resolution
   - Priority: <base>_value (int) → is_<var> (bool) → standard
   - Pass promoted_loopbodylocals from CarrierInfo

3. **Integration** (loop_with_break_minimal.rs)
   - UpdateEnv constructor updated to pass promoted list

## Test Results

- **Before**: 925 tests PASS
- **After**: 931 tests PASS (+6 new tests, 0 failures)

## New Tests

- test_promoted_variable_resolution_digit_pos - Full dual-value
- test_promoted_variable_resolution_fallback_to_bool - Fallback
- test_promoted_variable_not_a_carrier - Error handling

## Impact

| Pattern | Before | After |
|---------|--------|-------|
| _parse_number |  Works (bool only) |  Works (bool used, int unused) |
| _atoi |  Failed (missing int) |  READY (int carrier available!) |

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
nyash-codex
2025-12-11 15:08:14 +09:00
parent d4597dacfa
commit 8900a3cc44
12 changed files with 1868 additions and 40 deletions

View File

@ -192,3 +192,43 @@ fn pattern4_continue_loop_is_detected() {
let kind = classify_body(&body);
assert_eq!(kind, LoopPatternKind::Pattern4Continue);
}
#[test]
fn test_atoi_loop_classified_as_pattern2() {
// Phase 246-EX Step 1: _atoi loop pattern classification
// loop(i < len) {
// local ch = s.substring(i, i+1)
// local digit_pos = digits.indexOf(ch)
// if digit_pos < 0 { break }
// result = result * 10 + digit_pos
// i = i + 1
// }
// Simplified: loop with break + two carrier updates
let break_cond = bin(BinaryOperator::Less, var("digit_pos"), lit_i(0));
// result = result * 10 + digit_pos (NumberAccumulation pattern)
let mul_expr = bin(BinaryOperator::Multiply, var("result"), lit_i(10));
let result_update = assignment(
var("result"),
bin(BinaryOperator::Add, mul_expr, var("digit_pos"))
);
// i = i + 1
let i_update = assignment(var("i"), bin(BinaryOperator::Add, var("i"), lit_i(1)));
let body = vec![
ASTNode::If {
condition: Box::new(break_cond),
then_body: vec![ASTNode::Break { span: span() }],
else_body: None,
span: span(),
},
result_update,
i_update,
];
let kind = classify_body(&body);
assert_eq!(kind, LoopPatternKind::Pattern2Break,
"_atoi loop should be classified as Pattern2 (Break) due to if-break structure");
}