Files
hakorune/src/mir/loop_canonicalizer/mod.rs

152 lines
4.8 KiB
Rust
Raw Normal View History

feat(mir): Phase 1 - Loop Canonicalizer type definitions Implements the foundation for loop canonicalization - a preprocessing layer that decomposes AST loops into normalized skeleton representation to prevent combinatorial explosion in pattern detection. ## Implementation (Phase 1) Created `src/mir/loop_canonicalizer/mod.rs` with: 1. **Core Types**: - `LoopSkeleton`: Canonical loop representation - `SkeletonStep`: Step kinds (HeaderCond, BreakCheck, ContinueCheck, Update, Body) - `UpdateKind`: Carrier update classification (ConstStep, Conditional, Arbitrary) - `ExitContract`: Exit presence tracking (break/continue/return) - `CarrierSlot`: Loop variables with roles and update rules - `CarrierRole`: Semantic roles (Counter, Accumulator, ConditionVar, Derived) - `CapturedSlot`: Outer scope variable capture 2. **Capability Guard**: - `RoutingDecision`: Pattern selection with diagnostics - `capability_tags` module: Standardized Fail-Fast vocabulary (CAP_MISSING_CONST_STEP, CAP_MISSING_SINGLE_BREAK, etc.) 3. **Helper Methods**: - Skeleton counting (break_checks, continue_checks) - Carrier name extraction - Exit contract queries - Display implementations for debugging 4. **Unit Tests**: 6 tests covering all basic functionality ## Design Principles - **Input**: AST only (no JoinIR dependencies) - **Output**: LoopSkeleton only (no BlockId/ValueId) - **Boundary**: Clear separation from lowering concerns - **Fail-Fast**: Capability-based rejection with clear reasons ## Next Steps (Not in this commit) - Phase 2: `LoopCanonicalizer::canonicalize(ast) -> Result<LoopSkeleton>` - Phase 3: Test with skip_whitespace fixture - Phase 4: Integration with existing JoinIR lowering ## Acceptance Criteria ✅ `cargo build --release` succeeds ✅ `cargo test --release --lib` passes (1039 tests) ✅ 6 new unit tests for loop_canonicalizer pass ✅ No regressions in existing tests Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-16 04:59:26 +09:00
//! Loop Canonicalizer - AST Level Loop Preprocessing
//!
//! ## Purpose
//!
//! Decomposes AST-level loops into a normalized "skeleton" representation
//! to prevent combinatorial explosion in pattern detection and lowering.
//!
//! ## Design Principle
//!
//! - **Input**: AST (LoopExpr)
//! - **Output**: LoopSkeleton only (no JoinIR generation)
//! - **Boundary**: No JoinIR-specific information (BlockId, ValueId, etc.)
//!
//! ## Architecture
//!
//! ```
//! AST → LoopSkeleton → Capability Guard → RoutingDecision → Pattern Lowerer
//! ```
//!
//! ## Module Structure (Phase 138 Refactoring)
//!
//! - `skeleton_types` - Core data structures (LoopSkeleton, SkeletonStep, etc.)
//! - `capability_guard` - Routing decisions and capability tags
//! - `pattern_recognizer` - Pattern detection logic (skip_whitespace, etc.)
//! - `canonicalizer` - Main canonicalization entry point
//!
feat(mir): Phase 1 - Loop Canonicalizer type definitions Implements the foundation for loop canonicalization - a preprocessing layer that decomposes AST loops into normalized skeleton representation to prevent combinatorial explosion in pattern detection. ## Implementation (Phase 1) Created `src/mir/loop_canonicalizer/mod.rs` with: 1. **Core Types**: - `LoopSkeleton`: Canonical loop representation - `SkeletonStep`: Step kinds (HeaderCond, BreakCheck, ContinueCheck, Update, Body) - `UpdateKind`: Carrier update classification (ConstStep, Conditional, Arbitrary) - `ExitContract`: Exit presence tracking (break/continue/return) - `CarrierSlot`: Loop variables with roles and update rules - `CarrierRole`: Semantic roles (Counter, Accumulator, ConditionVar, Derived) - `CapturedSlot`: Outer scope variable capture 2. **Capability Guard**: - `RoutingDecision`: Pattern selection with diagnostics - `capability_tags` module: Standardized Fail-Fast vocabulary (CAP_MISSING_CONST_STEP, CAP_MISSING_SINGLE_BREAK, etc.) 3. **Helper Methods**: - Skeleton counting (break_checks, continue_checks) - Carrier name extraction - Exit contract queries - Display implementations for debugging 4. **Unit Tests**: 6 tests covering all basic functionality ## Design Principles - **Input**: AST only (no JoinIR dependencies) - **Output**: LoopSkeleton only (no BlockId/ValueId) - **Boundary**: Clear separation from lowering concerns - **Fail-Fast**: Capability-based rejection with clear reasons ## Next Steps (Not in this commit) - Phase 2: `LoopCanonicalizer::canonicalize(ast) -> Result<LoopSkeleton>` - Phase 3: Test with skip_whitespace fixture - Phase 4: Integration with existing JoinIR lowering ## Acceptance Criteria ✅ `cargo build --release` succeeds ✅ `cargo test --release --lib` passes (1039 tests) ✅ 6 new unit tests for loop_canonicalizer pass ✅ No regressions in existing tests Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-16 04:59:26 +09:00
//! ## References
//!
//! - Design SSOT: `docs/development/current/main/design/loop-canonicalizer.md`
//! - JoinIR Architecture: `docs/development/current/main/joinir-architecture-overview.md`
//! - Pattern Space: `docs/development/current/main/loop_pattern_space.md`
// ============================================================================
// Module Declarations
feat(mir): Phase 1 - Loop Canonicalizer type definitions Implements the foundation for loop canonicalization - a preprocessing layer that decomposes AST loops into normalized skeleton representation to prevent combinatorial explosion in pattern detection. ## Implementation (Phase 1) Created `src/mir/loop_canonicalizer/mod.rs` with: 1. **Core Types**: - `LoopSkeleton`: Canonical loop representation - `SkeletonStep`: Step kinds (HeaderCond, BreakCheck, ContinueCheck, Update, Body) - `UpdateKind`: Carrier update classification (ConstStep, Conditional, Arbitrary) - `ExitContract`: Exit presence tracking (break/continue/return) - `CarrierSlot`: Loop variables with roles and update rules - `CarrierRole`: Semantic roles (Counter, Accumulator, ConditionVar, Derived) - `CapturedSlot`: Outer scope variable capture 2. **Capability Guard**: - `RoutingDecision`: Pattern selection with diagnostics - `capability_tags` module: Standardized Fail-Fast vocabulary (CAP_MISSING_CONST_STEP, CAP_MISSING_SINGLE_BREAK, etc.) 3. **Helper Methods**: - Skeleton counting (break_checks, continue_checks) - Carrier name extraction - Exit contract queries - Display implementations for debugging 4. **Unit Tests**: 6 tests covering all basic functionality ## Design Principles - **Input**: AST only (no JoinIR dependencies) - **Output**: LoopSkeleton only (no BlockId/ValueId) - **Boundary**: Clear separation from lowering concerns - **Fail-Fast**: Capability-based rejection with clear reasons ## Next Steps (Not in this commit) - Phase 2: `LoopCanonicalizer::canonicalize(ast) -> Result<LoopSkeleton>` - Phase 3: Test with skip_whitespace fixture - Phase 4: Integration with existing JoinIR lowering ## Acceptance Criteria ✅ `cargo build --release` succeeds ✅ `cargo test --release --lib` passes (1039 tests) ✅ 6 new unit tests for loop_canonicalizer pass ✅ No regressions in existing tests Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-16 04:59:26 +09:00
// ============================================================================
mod canonicalizer;
mod capability_guard;
mod pattern_recognizer;
mod skeleton_types;
feat(mir): Phase 1 - Loop Canonicalizer type definitions Implements the foundation for loop canonicalization - a preprocessing layer that decomposes AST loops into normalized skeleton representation to prevent combinatorial explosion in pattern detection. ## Implementation (Phase 1) Created `src/mir/loop_canonicalizer/mod.rs` with: 1. **Core Types**: - `LoopSkeleton`: Canonical loop representation - `SkeletonStep`: Step kinds (HeaderCond, BreakCheck, ContinueCheck, Update, Body) - `UpdateKind`: Carrier update classification (ConstStep, Conditional, Arbitrary) - `ExitContract`: Exit presence tracking (break/continue/return) - `CarrierSlot`: Loop variables with roles and update rules - `CarrierRole`: Semantic roles (Counter, Accumulator, ConditionVar, Derived) - `CapturedSlot`: Outer scope variable capture 2. **Capability Guard**: - `RoutingDecision`: Pattern selection with diagnostics - `capability_tags` module: Standardized Fail-Fast vocabulary (CAP_MISSING_CONST_STEP, CAP_MISSING_SINGLE_BREAK, etc.) 3. **Helper Methods**: - Skeleton counting (break_checks, continue_checks) - Carrier name extraction - Exit contract queries - Display implementations for debugging 4. **Unit Tests**: 6 tests covering all basic functionality ## Design Principles - **Input**: AST only (no JoinIR dependencies) - **Output**: LoopSkeleton only (no BlockId/ValueId) - **Boundary**: Clear separation from lowering concerns - **Fail-Fast**: Capability-based rejection with clear reasons ## Next Steps (Not in this commit) - Phase 2: `LoopCanonicalizer::canonicalize(ast) -> Result<LoopSkeleton>` - Phase 3: Test with skip_whitespace fixture - Phase 4: Integration with existing JoinIR lowering ## Acceptance Criteria ✅ `cargo build --release` succeeds ✅ `cargo test --release --lib` passes (1039 tests) ✅ 6 new unit tests for loop_canonicalizer pass ✅ No regressions in existing tests Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-16 04:59:26 +09:00
// ============================================================================
// Public Re-exports
feat(mir): Phase 1 - Loop Canonicalizer type definitions Implements the foundation for loop canonicalization - a preprocessing layer that decomposes AST loops into normalized skeleton representation to prevent combinatorial explosion in pattern detection. ## Implementation (Phase 1) Created `src/mir/loop_canonicalizer/mod.rs` with: 1. **Core Types**: - `LoopSkeleton`: Canonical loop representation - `SkeletonStep`: Step kinds (HeaderCond, BreakCheck, ContinueCheck, Update, Body) - `UpdateKind`: Carrier update classification (ConstStep, Conditional, Arbitrary) - `ExitContract`: Exit presence tracking (break/continue/return) - `CarrierSlot`: Loop variables with roles and update rules - `CarrierRole`: Semantic roles (Counter, Accumulator, ConditionVar, Derived) - `CapturedSlot`: Outer scope variable capture 2. **Capability Guard**: - `RoutingDecision`: Pattern selection with diagnostics - `capability_tags` module: Standardized Fail-Fast vocabulary (CAP_MISSING_CONST_STEP, CAP_MISSING_SINGLE_BREAK, etc.) 3. **Helper Methods**: - Skeleton counting (break_checks, continue_checks) - Carrier name extraction - Exit contract queries - Display implementations for debugging 4. **Unit Tests**: 6 tests covering all basic functionality ## Design Principles - **Input**: AST only (no JoinIR dependencies) - **Output**: LoopSkeleton only (no BlockId/ValueId) - **Boundary**: Clear separation from lowering concerns - **Fail-Fast**: Capability-based rejection with clear reasons ## Next Steps (Not in this commit) - Phase 2: `LoopCanonicalizer::canonicalize(ast) -> Result<LoopSkeleton>` - Phase 3: Test with skip_whitespace fixture - Phase 4: Integration with existing JoinIR lowering ## Acceptance Criteria ✅ `cargo build --release` succeeds ✅ `cargo test --release --lib` passes (1039 tests) ✅ 6 new unit tests for loop_canonicalizer pass ✅ No regressions in existing tests Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-16 04:59:26 +09:00
// ============================================================================
// Skeleton Types
pub use skeleton_types::{
CapturedSlot, CarrierRole, CarrierSlot, ExitContract, LoopSkeleton, SkeletonStep, UpdateKind,
};
// Capability Guard
pub use capability_guard::{CapabilityTag, RoutingDecision};
// Canonicalization Entry Point
pub use canonicalizer::canonicalize_loop_expr;
feat(mir): Phase 1 - Loop Canonicalizer type definitions Implements the foundation for loop canonicalization - a preprocessing layer that decomposes AST loops into normalized skeleton representation to prevent combinatorial explosion in pattern detection. ## Implementation (Phase 1) Created `src/mir/loop_canonicalizer/mod.rs` with: 1. **Core Types**: - `LoopSkeleton`: Canonical loop representation - `SkeletonStep`: Step kinds (HeaderCond, BreakCheck, ContinueCheck, Update, Body) - `UpdateKind`: Carrier update classification (ConstStep, Conditional, Arbitrary) - `ExitContract`: Exit presence tracking (break/continue/return) - `CarrierSlot`: Loop variables with roles and update rules - `CarrierRole`: Semantic roles (Counter, Accumulator, ConditionVar, Derived) - `CapturedSlot`: Outer scope variable capture 2. **Capability Guard**: - `RoutingDecision`: Pattern selection with diagnostics - `capability_tags` module: Standardized Fail-Fast vocabulary (CAP_MISSING_CONST_STEP, CAP_MISSING_SINGLE_BREAK, etc.) 3. **Helper Methods**: - Skeleton counting (break_checks, continue_checks) - Carrier name extraction - Exit contract queries - Display implementations for debugging 4. **Unit Tests**: 6 tests covering all basic functionality ## Design Principles - **Input**: AST only (no JoinIR dependencies) - **Output**: LoopSkeleton only (no BlockId/ValueId) - **Boundary**: Clear separation from lowering concerns - **Fail-Fast**: Capability-based rejection with clear reasons ## Next Steps (Not in this commit) - Phase 2: `LoopCanonicalizer::canonicalize(ast) -> Result<LoopSkeleton>` - Phase 3: Test with skip_whitespace fixture - Phase 4: Integration with existing JoinIR lowering ## Acceptance Criteria ✅ `cargo build --release` succeeds ✅ `cargo test --release --lib` passes (1039 tests) ✅ 6 new unit tests for loop_canonicalizer pass ✅ No regressions in existing tests Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-16 04:59:26 +09:00
// ============================================================================
// Tests
feat(mir): Phase 1 - Loop Canonicalizer type definitions Implements the foundation for loop canonicalization - a preprocessing layer that decomposes AST loops into normalized skeleton representation to prevent combinatorial explosion in pattern detection. ## Implementation (Phase 1) Created `src/mir/loop_canonicalizer/mod.rs` with: 1. **Core Types**: - `LoopSkeleton`: Canonical loop representation - `SkeletonStep`: Step kinds (HeaderCond, BreakCheck, ContinueCheck, Update, Body) - `UpdateKind`: Carrier update classification (ConstStep, Conditional, Arbitrary) - `ExitContract`: Exit presence tracking (break/continue/return) - `CarrierSlot`: Loop variables with roles and update rules - `CarrierRole`: Semantic roles (Counter, Accumulator, ConditionVar, Derived) - `CapturedSlot`: Outer scope variable capture 2. **Capability Guard**: - `RoutingDecision`: Pattern selection with diagnostics - `capability_tags` module: Standardized Fail-Fast vocabulary (CAP_MISSING_CONST_STEP, CAP_MISSING_SINGLE_BREAK, etc.) 3. **Helper Methods**: - Skeleton counting (break_checks, continue_checks) - Carrier name extraction - Exit contract queries - Display implementations for debugging 4. **Unit Tests**: 6 tests covering all basic functionality ## Design Principles - **Input**: AST only (no JoinIR dependencies) - **Output**: LoopSkeleton only (no BlockId/ValueId) - **Boundary**: Clear separation from lowering concerns - **Fail-Fast**: Capability-based rejection with clear reasons ## Next Steps (Not in this commit) - Phase 2: `LoopCanonicalizer::canonicalize(ast) -> Result<LoopSkeleton>` - Phase 3: Test with skip_whitespace fixture - Phase 4: Integration with existing JoinIR lowering ## Acceptance Criteria ✅ `cargo build --release` succeeds ✅ `cargo test --release --lib` passes (1039 tests) ✅ 6 new unit tests for loop_canonicalizer pass ✅ No regressions in existing tests Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-16 04:59:26 +09:00
// ============================================================================
#[cfg(test)]
mod tests {
use super::*;
use crate::ast::Span;
feat(mir): Phase 1 - Loop Canonicalizer type definitions Implements the foundation for loop canonicalization - a preprocessing layer that decomposes AST loops into normalized skeleton representation to prevent combinatorial explosion in pattern detection. ## Implementation (Phase 1) Created `src/mir/loop_canonicalizer/mod.rs` with: 1. **Core Types**: - `LoopSkeleton`: Canonical loop representation - `SkeletonStep`: Step kinds (HeaderCond, BreakCheck, ContinueCheck, Update, Body) - `UpdateKind`: Carrier update classification (ConstStep, Conditional, Arbitrary) - `ExitContract`: Exit presence tracking (break/continue/return) - `CarrierSlot`: Loop variables with roles and update rules - `CarrierRole`: Semantic roles (Counter, Accumulator, ConditionVar, Derived) - `CapturedSlot`: Outer scope variable capture 2. **Capability Guard**: - `RoutingDecision`: Pattern selection with diagnostics - `capability_tags` module: Standardized Fail-Fast vocabulary (CAP_MISSING_CONST_STEP, CAP_MISSING_SINGLE_BREAK, etc.) 3. **Helper Methods**: - Skeleton counting (break_checks, continue_checks) - Carrier name extraction - Exit contract queries - Display implementations for debugging 4. **Unit Tests**: 6 tests covering all basic functionality ## Design Principles - **Input**: AST only (no JoinIR dependencies) - **Output**: LoopSkeleton only (no BlockId/ValueId) - **Boundary**: Clear separation from lowering concerns - **Fail-Fast**: Capability-based rejection with clear reasons ## Next Steps (Not in this commit) - Phase 2: `LoopCanonicalizer::canonicalize(ast) -> Result<LoopSkeleton>` - Phase 3: Test with skip_whitespace fixture - Phase 4: Integration with existing JoinIR lowering ## Acceptance Criteria ✅ `cargo build --release` succeeds ✅ `cargo test --release --lib` passes (1039 tests) ✅ 6 new unit tests for loop_canonicalizer pass ✅ No regressions in existing tests Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-16 04:59:26 +09:00
#[test]
fn test_skeleton_creation() {
let skeleton = LoopSkeleton::new(Span::unknown());
assert_eq!(skeleton.steps.len(), 0);
assert_eq!(skeleton.carriers.len(), 0);
assert!(!skeleton.exits.has_any_exit());
}
#[test]
fn test_exit_contract() {
let mut contract = ExitContract::none();
assert!(!contract.has_any_exit());
contract.has_break = true;
assert!(contract.has_any_exit());
}
#[test]
fn test_routing_decision() {
use crate::mir::loop_pattern_detection::LoopPatternKind;
feat(mir): Phase 1 - Loop Canonicalizer type definitions Implements the foundation for loop canonicalization - a preprocessing layer that decomposes AST loops into normalized skeleton representation to prevent combinatorial explosion in pattern detection. ## Implementation (Phase 1) Created `src/mir/loop_canonicalizer/mod.rs` with: 1. **Core Types**: - `LoopSkeleton`: Canonical loop representation - `SkeletonStep`: Step kinds (HeaderCond, BreakCheck, ContinueCheck, Update, Body) - `UpdateKind`: Carrier update classification (ConstStep, Conditional, Arbitrary) - `ExitContract`: Exit presence tracking (break/continue/return) - `CarrierSlot`: Loop variables with roles and update rules - `CarrierRole`: Semantic roles (Counter, Accumulator, ConditionVar, Derived) - `CapturedSlot`: Outer scope variable capture 2. **Capability Guard**: - `RoutingDecision`: Pattern selection with diagnostics - `capability_tags` module: Standardized Fail-Fast vocabulary (CAP_MISSING_CONST_STEP, CAP_MISSING_SINGLE_BREAK, etc.) 3. **Helper Methods**: - Skeleton counting (break_checks, continue_checks) - Carrier name extraction - Exit contract queries - Display implementations for debugging 4. **Unit Tests**: 6 tests covering all basic functionality ## Design Principles - **Input**: AST only (no JoinIR dependencies) - **Output**: LoopSkeleton only (no BlockId/ValueId) - **Boundary**: Clear separation from lowering concerns - **Fail-Fast**: Capability-based rejection with clear reasons ## Next Steps (Not in this commit) - Phase 2: `LoopCanonicalizer::canonicalize(ast) -> Result<LoopSkeleton>` - Phase 3: Test with skip_whitespace fixture - Phase 4: Integration with existing JoinIR lowering ## Acceptance Criteria ✅ `cargo build --release` succeeds ✅ `cargo test --release --lib` passes (1039 tests) ✅ 6 new unit tests for loop_canonicalizer pass ✅ No regressions in existing tests Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-16 04:59:26 +09:00
let success = RoutingDecision::success(LoopPatternKind::Pattern1SimpleWhile);
assert!(success.is_success());
assert!(!success.is_fail_fast());
let fail =
RoutingDecision::fail_fast(vec![CapabilityTag::ConstStep], "Test failure".to_string());
feat(mir): Phase 1 - Loop Canonicalizer type definitions Implements the foundation for loop canonicalization - a preprocessing layer that decomposes AST loops into normalized skeleton representation to prevent combinatorial explosion in pattern detection. ## Implementation (Phase 1) Created `src/mir/loop_canonicalizer/mod.rs` with: 1. **Core Types**: - `LoopSkeleton`: Canonical loop representation - `SkeletonStep`: Step kinds (HeaderCond, BreakCheck, ContinueCheck, Update, Body) - `UpdateKind`: Carrier update classification (ConstStep, Conditional, Arbitrary) - `ExitContract`: Exit presence tracking (break/continue/return) - `CarrierSlot`: Loop variables with roles and update rules - `CarrierRole`: Semantic roles (Counter, Accumulator, ConditionVar, Derived) - `CapturedSlot`: Outer scope variable capture 2. **Capability Guard**: - `RoutingDecision`: Pattern selection with diagnostics - `capability_tags` module: Standardized Fail-Fast vocabulary (CAP_MISSING_CONST_STEP, CAP_MISSING_SINGLE_BREAK, etc.) 3. **Helper Methods**: - Skeleton counting (break_checks, continue_checks) - Carrier name extraction - Exit contract queries - Display implementations for debugging 4. **Unit Tests**: 6 tests covering all basic functionality ## Design Principles - **Input**: AST only (no JoinIR dependencies) - **Output**: LoopSkeleton only (no BlockId/ValueId) - **Boundary**: Clear separation from lowering concerns - **Fail-Fast**: Capability-based rejection with clear reasons ## Next Steps (Not in this commit) - Phase 2: `LoopCanonicalizer::canonicalize(ast) -> Result<LoopSkeleton>` - Phase 3: Test with skip_whitespace fixture - Phase 4: Integration with existing JoinIR lowering ## Acceptance Criteria ✅ `cargo build --release` succeeds ✅ `cargo test --release --lib` passes (1039 tests) ✅ 6 new unit tests for loop_canonicalizer pass ✅ No regressions in existing tests Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-16 04:59:26 +09:00
assert!(!fail.is_success());
assert!(fail.is_fail_fast());
assert_eq!(fail.missing_caps.len(), 1);
assert_eq!(fail.missing_caps[0], CapabilityTag::ConstStep);
feat(mir): Phase 1 - Loop Canonicalizer type definitions Implements the foundation for loop canonicalization - a preprocessing layer that decomposes AST loops into normalized skeleton representation to prevent combinatorial explosion in pattern detection. ## Implementation (Phase 1) Created `src/mir/loop_canonicalizer/mod.rs` with: 1. **Core Types**: - `LoopSkeleton`: Canonical loop representation - `SkeletonStep`: Step kinds (HeaderCond, BreakCheck, ContinueCheck, Update, Body) - `UpdateKind`: Carrier update classification (ConstStep, Conditional, Arbitrary) - `ExitContract`: Exit presence tracking (break/continue/return) - `CarrierSlot`: Loop variables with roles and update rules - `CarrierRole`: Semantic roles (Counter, Accumulator, ConditionVar, Derived) - `CapturedSlot`: Outer scope variable capture 2. **Capability Guard**: - `RoutingDecision`: Pattern selection with diagnostics - `capability_tags` module: Standardized Fail-Fast vocabulary (CAP_MISSING_CONST_STEP, CAP_MISSING_SINGLE_BREAK, etc.) 3. **Helper Methods**: - Skeleton counting (break_checks, continue_checks) - Carrier name extraction - Exit contract queries - Display implementations for debugging 4. **Unit Tests**: 6 tests covering all basic functionality ## Design Principles - **Input**: AST only (no JoinIR dependencies) - **Output**: LoopSkeleton only (no BlockId/ValueId) - **Boundary**: Clear separation from lowering concerns - **Fail-Fast**: Capability-based rejection with clear reasons ## Next Steps (Not in this commit) - Phase 2: `LoopCanonicalizer::canonicalize(ast) -> Result<LoopSkeleton>` - Phase 3: Test with skip_whitespace fixture - Phase 4: Integration with existing JoinIR lowering ## Acceptance Criteria ✅ `cargo build --release` succeeds ✅ `cargo test --release --lib` passes (1039 tests) ✅ 6 new unit tests for loop_canonicalizer pass ✅ No regressions in existing tests Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-16 04:59:26 +09:00
}
#[test]
fn test_carrier_role_display() {
assert_eq!(CarrierRole::Counter.to_string(), "Counter");
assert_eq!(CarrierRole::Accumulator.to_string(), "Accumulator");
assert_eq!(CarrierRole::ConditionVar.to_string(), "ConditionVar");
assert_eq!(CarrierRole::Derived.to_string(), "Derived");
}
#[test]
fn test_skeleton_count_helpers() {
use crate::ast::{ASTNode, LiteralValue};
feat(mir): Phase 1 - Loop Canonicalizer type definitions Implements the foundation for loop canonicalization - a preprocessing layer that decomposes AST loops into normalized skeleton representation to prevent combinatorial explosion in pattern detection. ## Implementation (Phase 1) Created `src/mir/loop_canonicalizer/mod.rs` with: 1. **Core Types**: - `LoopSkeleton`: Canonical loop representation - `SkeletonStep`: Step kinds (HeaderCond, BreakCheck, ContinueCheck, Update, Body) - `UpdateKind`: Carrier update classification (ConstStep, Conditional, Arbitrary) - `ExitContract`: Exit presence tracking (break/continue/return) - `CarrierSlot`: Loop variables with roles and update rules - `CarrierRole`: Semantic roles (Counter, Accumulator, ConditionVar, Derived) - `CapturedSlot`: Outer scope variable capture 2. **Capability Guard**: - `RoutingDecision`: Pattern selection with diagnostics - `capability_tags` module: Standardized Fail-Fast vocabulary (CAP_MISSING_CONST_STEP, CAP_MISSING_SINGLE_BREAK, etc.) 3. **Helper Methods**: - Skeleton counting (break_checks, continue_checks) - Carrier name extraction - Exit contract queries - Display implementations for debugging 4. **Unit Tests**: 6 tests covering all basic functionality ## Design Principles - **Input**: AST only (no JoinIR dependencies) - **Output**: LoopSkeleton only (no BlockId/ValueId) - **Boundary**: Clear separation from lowering concerns - **Fail-Fast**: Capability-based rejection with clear reasons ## Next Steps (Not in this commit) - Phase 2: `LoopCanonicalizer::canonicalize(ast) -> Result<LoopSkeleton>` - Phase 3: Test with skip_whitespace fixture - Phase 4: Integration with existing JoinIR lowering ## Acceptance Criteria ✅ `cargo build --release` succeeds ✅ `cargo test --release --lib` passes (1039 tests) ✅ 6 new unit tests for loop_canonicalizer pass ✅ No regressions in existing tests Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-16 04:59:26 +09:00
let mut skeleton = LoopSkeleton::new(Span::unknown());
skeleton.steps.push(SkeletonStep::BreakCheck {
cond: Box::new(ASTNode::Literal {
value: LiteralValue::Bool(true),
span: Span::unknown(),
}),
has_value: false,
});
skeleton.steps.push(SkeletonStep::ContinueCheck {
cond: Box::new(ASTNode::Literal {
value: LiteralValue::Bool(true),
span: Span::unknown(),
}),
});
assert_eq!(skeleton.count_break_checks(), 1);
assert_eq!(skeleton.count_continue_checks(), 1);
}
#[test]
fn test_skeleton_carrier_names() {
let mut skeleton = LoopSkeleton::new(Span::unknown());
skeleton.carriers.push(CarrierSlot {
name: "i".to_string(),
role: CarrierRole::Counter,
update_kind: UpdateKind::ConstStep { delta: 1 },
});
skeleton.carriers.push(CarrierSlot {
name: "sum".to_string(),
role: CarrierRole::Accumulator,
update_kind: UpdateKind::Arbitrary,
});
let names = skeleton.carrier_names();
assert_eq!(names, vec!["i", "sum"]);
}
}