Files
hakorune/docs/development/current/main/phase224-digitpos-condition-normalizer.md
nyash-codex ed8e2d3142 feat(joinir): Phase 248 - Normalized JoinIR infrastructure
Major refactoring of JoinIR normalization pipeline:

Key changes:
- Structured→Normalized→MIR(direct) pipeline established
- ShapeGuard enhanced with Pattern2 loop validation
- dev_env.rs: New development fixtures and env control
- fixtures.rs: jsonparser_parse_number_real fixture
- normalized_bridge/direct.rs: Direct MIR generation from Normalized
- pattern2_step_schedule.rs: Extracted step scheduling logic

Files changed:
- normalized.rs: Enhanced NormalizedJoinModule with DevEnv support
- shape_guard.rs: Pattern2-specific validation (+300 lines)
- normalized_bridge.rs: Unified bridge with direct path
- loop_with_break_minimal.rs: Integrated step scheduling
- Deleted: step_schedule.rs (moved to pattern2_step_schedule.rs)

New files:
- param_guess.rs: Loop parameter inference
- pattern2_step_schedule.rs: Step scheduling for Pattern2
- phase43-norm-canon-p2-mid.md: Design doc

Tests: 937/937 PASS (+6 from baseline 931)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-12 03:15:45 +09:00

195 lines
6.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Phase 224-E: DigitPos Condition Normalizer
Status: ActiveDigitPos 条件正規化ラインの設計メモ / 実装ガイド)
Scope: digit_pos → is_digit_pos Carrier / ConditionEnv / ExprLowerer の正規化経路の SSOT ドキュメントだよ。Phase 26H / 34 系の JsonParser `_parse_number` / `_atoi` でもこの設計を前提にしている。
## Problem Statement
### Background
Phase 228-8 successfully implemented the DigitPos pattern promotion:
- `digit_pos: i32``is_digit_pos: bool` carrier
- CarrierRole::ConditionOnly + CarrierInit::BoolConst(false)
- ConditionEnv alias: `digit_pos → is_digit_pos`
### Current Error
```
Type error: unsupported compare Lt on Bool(false) and Integer(0)
```
**Root Cause**: The break condition AST still contains `digit_pos < 0`, which after alias resolution becomes `Bool(is_digit_pos) < Integer(0)`, causing a type mismatch.
**Why alias isn't enough**:
- Alias only renames the variable reference
- The comparison operator and integer literal remain unchanged
- Need to transform the entire expression structure
## Solution
### Transformation
Transform the break condition AST from integer comparison to boolean negation:
**Before**: `digit_pos < 0`
```
BinaryOp {
operator: Lt,
left: Var("digit_pos"),
right: Const(0)
}
```
**After**: `!is_digit_pos`
```
UnaryOp {
operator: Not,
expr: Var("is_digit_pos")
}
```
### Semantic Equivalence
- `digit_pos < 0` means "indexOf() didn't find the character" (returns -1)
- `!is_digit_pos` means "character is not a digit" (bool carrier is false)
- Both express the same condition: "break when character not found/matched"
## Design
### Box: DigitPosConditionNormalizer
**Responsibility**: Transform digit_pos comparison patterns to boolean carrier expressions
**API**:
```rust
pub struct DigitPosConditionNormalizer;
impl DigitPosConditionNormalizer {
/// Normalize digit_pos condition AST
///
/// Transforms: `digit_pos < 0` → `!is_digit_pos`
///
/// # Arguments
/// * `cond` - Break/continue condition AST
/// * `promoted_var` - Original variable name (e.g., "digit_pos")
/// * `carrier_name` - Promoted carrier name (e.g., "is_digit_pos")
///
/// # Returns
/// Normalized AST (or original if pattern doesn't match)
pub fn normalize(
cond: &ASTNode,
promoted_var: &str,
carrier_name: &str,
) -> ASTNode;
}
```
### Pattern Matching Logic
**Match Pattern**: `<var> < 0` where:
1. Operator is `Lt` (Less than)
2. Left operand is `Var(promoted_var)`
3. Right operand is `Const(0)`
**Transformation**: → `UnaryOp { op: Not, expr: Var(carrier_name) }`
**Non-Match Behavior**: Return original AST unchanged (Fail-Safe)
### Integration Point
**Location**: `src/mir/builder/control_flow/joinir/patterns/pattern2_with_break.rs`
**Integration Steps**:
1. After `LoopBodyCondPromoter::try_promote_for_condition()` succeeds
2. Extract `promoted_var` and `carrier_name` from promotion result
3. Apply `DigitPosConditionNormalizer::normalize()` to break condition AST
4. Use normalized AST in subsequent condition lowering
**Code Position** (around line 331):
```rust
ConditionPromotionResult::Promoted {
carrier_info: promoted_carrier,
promoted_var,
carrier_name,
} => {
// ... existing merge logic ...
// Phase 224-E: Normalize digit_pos condition before lowering
let normalized_break_condition = DigitPosConditionNormalizer::normalize(
&break_condition_node,
&promoted_var,
&carrier_name,
);
// Use normalized_break_condition in subsequent processing
}
```
## Testing Strategy
### Unit Tests (3-4 tests)
1. **Happy path**: `digit_pos < 0``!is_digit_pos`
2. **Wrong operator**: `digit_pos >= 0` → No change
3. **Wrong variable**: `other_var < 0` → No change
4. **Wrong constant**: `digit_pos < 10` → No change
### E2E Test
**Test File**: `apps/tests/phase2235_p2_digit_pos_min.hako`
このテストは digit_pos 昇格と型整合性・SSA 安定性を確認するインフラ用途で、数値としての戻り値の意味論は今後の JsonParser 本体フェーズで定義する予定だよ。
**Success Criteria**:
- No type error ("unsupported compare Lt on Bool and Integer")
- Break condition correctly evaluates
- Loop exits when digit not found
**Debug Command**:
```bash
NYASH_JOINIR_DEBUG=1 ./target/release/hakorune apps/tests/phase2235_p2_digit_pos_min.hako
```
### Regression Tests
- Verify existing Trim tests still pass
- Verify skip_whitespace tests still pass
- Check that 877/884 test count is maintained
## Success Criteria
1.`cargo build --release` succeeds
2. ✅ Unit tests (3-4) pass
3. ✅ Type error eliminated from phase2235_p2_digit_pos_min.hako
4. ✅ Existing 877/884 tests remain passing
5. ✅ No regressions in Trim/skip_whitespace patterns
## Box-First Principles
### Single Responsibility
- DigitPosConditionNormalizer only handles AST transformation
- No side effects, no state mutation
- Pure pattern matching function
### Fail-Safe Design
- Non-matching patterns returned unchanged
- No panics, no errors
- Conservative transformation strategy
### Boundary Clarity
- Input: AST + promoted_var + carrier_name
- Output: Transformed or original AST
- Clear interface contract
## Future Extensions
**Pattern 4 Support**: When Pattern 4 (continue) needs similar normalization, the same box can be reused with continue condition AST.
**Other Comparison Operators**: Currently handles `< 0`. Could extend to:
- `>= 0``is_digit_pos` (no NOT)
- `!= -1``is_digit_pos`
- `== -1``!is_digit_pos`
**Multiple Conditions**: For complex boolean expressions with multiple promoted variables, apply normalization recursively.
## References
- **Phase 228-8**: DigitPos promotion implementation
- **Phase 229**: Dynamic condition variable resolution
- **CarrierInfo**: `src/mir/join_ir/lowering/carrier_info.rs`
- **ConditionEnv**: `src/mir/join_ir/lowering/condition_env.rs`
Status: Active
Scope: digitpos condition 正規化ExprLowerer ライン)