diff --git a/apps/tests/loop_continue_pattern4.hako b/apps/tests/loop_continue_pattern4.hako new file mode 100644 index 00000000..fabeb5c4 --- /dev/null +++ b/apps/tests/loop_continue_pattern4.hako @@ -0,0 +1,17 @@ +// Pattern 4: Loop with Continue +// Expected output: sum = 25 (1+3+5+7+9, skip even numbers) +static box Main { + main() { + local i = 0 + local sum = 0 + loop(i < 10) { + i = i + 1 + if (i % 2 == 0) { + continue + } + sum = sum + i + } + print(sum) + return 0 + } +} diff --git a/src/mir/builder/control_flow/joinir/patterns/mod.rs b/src/mir/builder/control_flow/joinir/patterns/mod.rs index 9229f63b..4e7c6f8e 100644 --- a/src/mir/builder/control_flow/joinir/patterns/mod.rs +++ b/src/mir/builder/control_flow/joinir/patterns/mod.rs @@ -4,6 +4,7 @@ //! - Pattern 1: Simple While Loop (pattern1_minimal.rs) //! - Pattern 2: Loop with Conditional Break (pattern2_with_break.rs) //! - Pattern 3: Loop with If-Else PHI (pattern3_with_if_phi.rs) +//! - Pattern 4: Loop with Continue (pattern4_with_continue.rs) [Phase 194+] //! //! Phase 194: Table-driven router for pattern dispatch //! - Router module provides table-driven pattern matching @@ -13,6 +14,7 @@ pub(in crate::mir::builder) mod pattern1_minimal; pub(in crate::mir::builder) mod pattern2_with_break; pub(in crate::mir::builder) mod pattern3_with_if_phi; +pub(in crate::mir::builder) mod pattern4_with_continue; pub(in crate::mir::builder) mod router; // Re-export router for convenience diff --git a/src/mir/builder/control_flow/joinir/patterns/pattern4_with_continue.rs b/src/mir/builder/control_flow/joinir/patterns/pattern4_with_continue.rs new file mode 100644 index 00000000..5246b39c --- /dev/null +++ b/src/mir/builder/control_flow/joinir/patterns/pattern4_with_continue.rs @@ -0,0 +1,120 @@ +//! Pattern 4: Loop with Continue minimal lowerer +//! +//! Phase 194+: Structure-based detection for loops with continue statements. + +use crate::ast::ASTNode; +use crate::mir::builder::MirBuilder; +use crate::mir::ValueId; +use super::super::trace; + +/// Phase 194+: Detection function for Pattern 4 +/// +/// Pattern 4 matches loops with continue statements. +/// +/// # Structure-based Detection (Phase 194+) +/// +/// Uses AST-based detection from LoopPatternContext: +/// - ctx.has_continue == true +/// - ctx.has_break == false (for simplicity) +/// +/// This is structure-based detection that does NOT depend on function names +/// or variable names like "sum". +/// +/// # Detection Rules +/// +/// 1. **Must have continue**: `ctx.has_continue == true` +/// 2. **No break statements**: `ctx.has_break == false` (for simplicity in Pattern 4) +/// +/// If both conditions are met, Pattern 4 is detected. +pub fn can_lower(_builder: &MirBuilder, ctx: &super::router::LoopPatternContext) -> bool { + // Phase 194+: Structure-based detection using AST analysis + // Pattern 4 is characterized by: + // - Has continue statement(s) + // - No break statements (for simplicity) + + ctx.has_continue && !ctx.has_break +} + +/// Phase 194+: Lowering function for Pattern 4 +/// +/// Wrapper around cf_loop_pattern4_with_continue to match router signature. +/// +/// # TODO +/// +/// Implement Pattern 4 lowering logic: +/// 1. Extract loop variables from condition +/// 2. Generate JoinIR with continue support +/// 3. Convert JoinModule → MirModule +/// 4. Create JoinInlineBoundary for input/output mapping +/// 5. Merge MIR blocks into current_function +/// 6. Return Void (loop doesn't produce values) +pub fn lower( + builder: &mut MirBuilder, + ctx: &super::router::LoopPatternContext, +) -> Result, String> { + builder.cf_loop_pattern4_with_continue(ctx.condition, ctx.body, ctx.func_name, ctx.debug) +} + +impl MirBuilder { + /// Phase 194+: Pattern 4 (Loop with Continue) minimal lowerer + /// + /// Handles loops with continue statements that skip to next iteration. + /// + /// # Example + /// + /// ```nyash + /// local i = 0 + /// local sum = 0 + /// loop(i < 10) { + /// i = i + 1 + /// if (i % 2 == 0) { + /// continue // Skip even numbers + /// } + /// sum = sum + i + /// } + /// // sum = 25 (1+3+5+7+9) + /// ``` + /// + /// # Implementation Status + /// + /// **TODO**: This is a stub implementation. Pattern 4 lowering logic needs to be implemented. + /// + /// The lowerer should: + /// 1. Detect continue statements in the loop body + /// 2. Generate appropriate PHI nodes for continue targets + /// 3. Handle carrier variables (i, sum) across continue boundaries + /// 4. Generate exit PHI nodes for final values + /// + /// # Steps (TODO) + /// + /// 1. Extract loop variables (i, sum) + /// 2. Generate JoinIR using loop_with_continue_minimal (not yet implemented) + /// 3. Convert JoinModule → MirModule + /// 4. Create JoinInlineBoundary for input/output mapping + /// 5. Merge MIR blocks into current_function + /// 6. Return Void (loop doesn't produce values) + pub(in crate::mir::builder) fn cf_loop_pattern4_with_continue( + &mut self, + condition: &ASTNode, + _body: &[ASTNode], + func_name: &str, + debug: bool, + ) -> Result, String> { + // Phase 195: Use unified trace + trace::trace().debug("pattern4", "Pattern 4 lowerer called (stub implementation)"); + + // TODO: Implement Pattern 4 lowering logic + // + // For now, return an error to fall back to legacy loop builder + // This allows the test to run (even if it produces wrong results) + + if debug { + eprintln!("[pattern4] Pattern 4 lowerer not yet implemented for '{}'", func_name); + eprintln!("[pattern4] Falling back to legacy loop builder"); + } + + // Return None to indicate pattern not supported + // This will cause the router to try other patterns or fall back to legacy + Ok(None) + } +} diff --git a/src/mir/builder/control_flow/joinir/patterns/router.rs b/src/mir/builder/control_flow/joinir/patterns/router.rs index 11f44726..89a57bc7 100644 --- a/src/mir/builder/control_flow/joinir/patterns/router.rs +++ b/src/mir/builder/control_flow/joinir/patterns/router.rs @@ -34,25 +34,91 @@ pub struct LoopPatternContext<'a> { /// Debug logging enabled pub debug: bool, + + /// Has continue statement(s) in body? (Phase 194+) + pub has_continue: bool, + + /// Has break statement(s) in body? (Phase 194+) + pub has_break: bool, } impl<'a> LoopPatternContext<'a> { /// Create new context from routing parameters + /// + /// Phase 194+: Automatically detects continue/break statements in body pub fn new( condition: &'a ASTNode, body: &'a [ASTNode], func_name: &'a str, debug: bool, ) -> Self { + // Phase 194+: Detect continue/break statements in AST + let has_continue = detect_continue_in_ast(body); + let has_break = detect_break_in_ast(body); + Self { condition, body, func_name, debug, + has_continue, + has_break, } } } +/// Phase 194+: Detect continue statements in AST +/// +/// This is a simple recursive scan of the AST looking for Continue nodes. +/// It's not perfect (doesn't handle nested loops correctly) but sufficient +/// for initial implementation. +fn detect_continue_in_ast(body: &[ASTNode]) -> bool { + for stmt in body { + if has_continue_node(stmt) { + return true; + } + } + false +} + +/// Phase 194+: Detect break statements in AST +/// +/// Similar to detect_continue_in_ast, scans for Break nodes. +fn detect_break_in_ast(body: &[ASTNode]) -> bool { + for stmt in body { + if has_break_node(stmt) { + return true; + } + } + false +} + +/// Recursive helper to check if AST node contains Continue +fn has_continue_node(node: &ASTNode) -> bool { + match node { + ASTNode::Continue { .. } => true, + ASTNode::If { then_body, else_body, .. } => { + then_body.iter().any(has_continue_node) + || else_body.as_ref().map_or(false, |e| e.iter().any(has_continue_node)) + } + ASTNode::Loop { body, .. } => body.iter().any(has_continue_node), + _ => false, + } +} + +/// Recursive helper to check if AST node contains Break +fn has_break_node(node: &ASTNode) -> bool { + match node { + ASTNode::Break { .. } => true, + ASTNode::If { then_body, else_body, .. } => { + then_body.iter().any(has_break_node) + || else_body.as_ref().map_or(false, |e| e.iter().any(has_break_node)) + } + ASTNode::Loop { body, .. } => body.iter().any(has_break_node), + _ => false, + } +} + /// Entry in the loop pattern router table. /// Each pattern registers a detect function and a lower function. pub struct LoopPatternEntry { @@ -74,6 +140,10 @@ pub struct LoopPatternEntry { /// /// # Current Patterns /// +/// - Pattern 4 (priority 5): Loop with Continue (loop_continue_pattern4.hako) [Phase 194+] +/// - Structure-based detection: has_continue == true +/// - TODO: Implement lowering logic +/// /// - Pattern 1 (priority 10): Simple While Loop (loop_min_while.hako) /// - Function: "main" without 'sum' variable /// - Detection: func_name == "main" && !has_sum_var @@ -86,6 +156,12 @@ pub struct LoopPatternEntry { /// - Function: "main" with 'sum' variable /// - Detection: func_name == "main" && has_sum_var pub static LOOP_PATTERNS: &[LoopPatternEntry] = &[ + LoopPatternEntry { + name: "Pattern4_WithContinue", + priority: 5, // Highest priority - continue is most specific + detect: super::pattern4_with_continue::can_lower, + lower: super::pattern4_with_continue::lower, + }, LoopPatternEntry { name: "Pattern3_WithIfPhi", priority: 30, // NOTE: Pattern 3 must be checked BEFORE Pattern 1 (both use "main") diff --git a/src/mir/join_ir/lowering/loop_patterns.rs b/src/mir/join_ir/lowering/loop_patterns.rs index c2b8fc30..cacb3fb9 100644 --- a/src/mir/join_ir/lowering/loop_patterns.rs +++ b/src/mir/join_ir/lowering/loop_patterns.rs @@ -466,6 +466,118 @@ pub fn lower_loop_with_conditional_phi_to_joinir( None } +// ============================================================================ +// Pattern 4: Loop with Continue +// ============================================================================ + +/// Lowering for Pattern 4: Loop with Continue +/// +/// # Transformation (Pseudocode) +/// +/// ```text +/// fn loop_step(i, sum): +/// exit_cond = !(i < 10) +/// Jump(k_exit, [sum], cond=exit_cond) // Natural exit +/// i_next = i + 1 +/// continue_cond = (i_next % 2 == 0) +/// Jump(loop_step, [i_next, sum], cond=continue_cond) // Continue jumps to loop start +/// sum_next = sum + i_next +/// Call(loop_step, [i_next, sum_next]) // Normal iteration +/// ``` +/// +/// # Steps (Pattern 4 Transformation) +/// +/// 1. **Extract Loop Variables** (multiple carriers: i + sum) +/// 2. **Create loop_step Function** (params: i, sum, k_exit) +/// 3. **Create k_exit with Exit PHI** (receives sum exit value) +/// 4. **Generate Exit Condition Check** (same as Pattern 1) +/// 5. **Generate Continue Check** +/// - Extract continue condition (if exists) +/// - Add conditional Jump back to loop_step: `Jump(loop_step, [i_next, sum], cond=continue_cond)` +/// 6. **Translate Loop Body** (remaining instructions after continue) +/// 7. **Generate Tail Recursion** (with multiple carriers: i_next, sum_next) +/// +/// # Key Difference from Pattern 1/2/3 +/// +/// - **Continue Jump**: Continue jumps back to loop_step with current carrier values +/// - **Dual Path**: Continue path + normal path (both recursive) +/// - **PHI at Loop Start**: Loop header receives values from both continue and normal paths +/// +/// # Arguments +/// +/// * `loop_form` - The loop structure to lower (must have continue_targets) +/// * `lowerer` - The LoopToJoinLowerer builder +/// +/// # Returns +/// +/// * `Some(JoinInst)` - Lowering succeeded, returns generated JoinIR instruction +/// * `None` - Lowering failed (pattern not matched or unsupported) +/// +/// # Errors +/// +/// Returns `None` if: +/// - Loop has no continues (use Pattern 1 instead) +/// - Loop has break statements (not yet supported) +/// - Continue is not in an if statement +/// +/// # Reference +/// +/// See design.md § Pattern 4 for complete transformation details and pseudocode. +/// +/// # Example Usage +/// +/// ```rust,ignore +/// use crate::mir::loop_pattern_detection::is_loop_with_continue_pattern; +/// +/// if is_loop_with_continue_pattern(&loop_form) { +/// lower_loop_with_continue_to_joinir(&loop_form, &mut lowerer)?; +/// } +/// ``` +pub fn lower_loop_with_continue_to_joinir( + _loop_form: &LoopForm, + _lowerer: &mut LoopToJoinLowerer, +) -> Option { + // Phase 188-Impl-4: Pattern 4 implementation placeholder + // TODO: Implement Pattern 4 lowering + // + // Step 1: Extract Loop Variables (Carriers) + // ========================================== + // From header PHI: %i = phi [%0, preheader], [%i_next, body] + // %sum = phi [%0, preheader], [%sum_next, body] + // Extract: (var_name: "i", init_value: 0, next_value: i_next) + // (var_name: "sum", init_value: 0, next_value: sum_next) + // + // Step 2: Create loop_step Function Signature + // ============================================ + // Signature: fn loop_step(i: ValueId, sum: ValueId, k_exit: JoinContId) -> ... + // + // Step 3: Create k_exit Continuation + // =================================== + // fn k_exit(sum_exit) -> ValueId // Returns final sum value + // + // Step 4: Generate Exit Condition Check + // ====================================== + // exit_cond = !(i < 10) + // Jump(k_exit, [sum], cond=exit_cond) + // + // Step 5: Generate Continue Check + // ================================ + // i_next = i + 1 + // continue_cond = (i_next % 2 == 0) + // Jump(loop_step, [i_next, sum], cond=continue_cond) // Continue to loop start + // + // Step 6: Translate Loop Body (after continue) + // ============================================= + // sum_next = sum + i_next + // + // Step 7: Generate Tail Recursion + // ================================ + // Call(loop_step, [i_next, sum_next], k_next: None) + + eprintln!("[loop_patterns] Pattern 4: Continue lowering not yet implemented"); + None +} + // ============================================================================ // Helper Functions (Future Use) // ============================================================================ @@ -583,4 +695,39 @@ mod tests { // Step 3: Verify Select instruction is generated // Step 4: Verify Select has correct cond/then_val/else_val } + + // ======================================================================== + // Pattern 4: Loop with Continue Tests + // ======================================================================== + + #[test] + #[ignore] // TODO: Implement test after lowering logic is complete + fn test_pattern4_lowering_success() { + // TODO: Add integration test for continue pattern lowering + // Step 1: Create mock LoopForm for continue pattern + // Step 2: Create mock LoopToJoinLowerer + // Step 3: Call lower_loop_with_continue_to_joinir() + // Step 4: Assert returns Ok(()) + // Step 5: Verify generated JoinIR structure (Jump to loop_step on continue) + } + + #[test] + #[ignore] // TODO: Implement test after lowering logic is complete + fn test_pattern4_continue_jump_correct() { + // TODO: Add test that verifies continue jumps to loop_step + // Step 1: Create mock LoopForm for continue pattern + // Step 2: Call lower_loop_with_continue_to_joinir() + // Step 3: Verify conditional Jump targets loop_step + // Step 4: Verify Jump passes current carrier values as arguments + } + + #[test] + #[ignore] // TODO: Implement test after lowering logic is complete + fn test_pattern4_multiple_carriers() { + // TODO: Add test that verifies multiple carrier variables + // Step 1: Create mock LoopForm with i + sum carriers + // Step 2: Call lower_loop_with_continue_to_joinir() + // Step 3: Verify loop_step params = [i, sum] + // Step 4: Verify both tail Call and continue Jump use [i_next, sum_next] + } } diff --git a/src/mir/join_ir/lowering/mod.rs b/src/mir/join_ir/lowering/mod.rs index ba70a48b..6fb622cb 100644 --- a/src/mir/join_ir/lowering/mod.rs +++ b/src/mir/join_ir/lowering/mod.rs @@ -419,44 +419,51 @@ pub fn try_lower_loop_pattern_to_joinir( loop_form: &LoopForm, lowerer: &mut LoopToJoinLowerer, ) -> Option { - // Phase 188: Pattern-based loop lowering router - // Tries patterns in order: Pattern 1 → Pattern 2 → Pattern 3 + // Phase 194: Structure-based pattern classification + // Tries patterns based on CFG structure, not function names - use crate::mir::loop_pattern_detection::{ - is_loop_with_break_pattern, is_loop_with_conditional_phi_pattern, is_simple_while_pattern, - }; + use crate::mir::loop_pattern_detection::{classify, extract_features, LoopPatternKind}; - // Pattern 1: Simple While Loop (easiest, most common) - // ==================================================== - if is_simple_while_pattern(loop_form) { - if let Some(inst) = loop_patterns::lower_simple_while_to_joinir(loop_form, lowerer) { - eprintln!("[try_lower_loop_pattern] ✅ Pattern 1 (Simple While) matched"); - return Some(inst); + // Step 1: Extract features from LoopForm (no LoopScope needed for now) + let features = extract_features(loop_form, None); + + // Step 2: Classify pattern based on structure + let pattern = classify(&features); + + // Step 3: Route to appropriate lowerer based on pattern + match pattern { + LoopPatternKind::Pattern4Continue => { + if let Some(inst) = loop_patterns::lower_loop_with_continue_to_joinir(loop_form, lowerer) { + eprintln!("[try_lower_loop_pattern] ✅ Pattern 4 (Continue) matched"); + return Some(inst); + } } - } - - // Pattern 2: Loop with Conditional Break (medium complexity) - // =========================================================== - if is_loop_with_break_pattern(loop_form) { - if let Some(inst) = loop_patterns::lower_loop_with_break_to_joinir(loop_form, lowerer) { - eprintln!("[try_lower_loop_pattern] ✅ Pattern 2 (Loop with Break) matched"); - return Some(inst); + LoopPatternKind::Pattern3IfPhi => { + if let Some(inst) = loop_patterns::lower_loop_with_conditional_phi_to_joinir(loop_form, lowerer) { + eprintln!("[try_lower_loop_pattern] ✅ Pattern 3 (If-Else PHI) matched"); + return Some(inst); + } } - } - - // Pattern 3: Loop with If-Else PHI (leverages existing If lowering) - // ================================================================== - // Phase 188-Impl-3: Pattern 3 implementation - if is_loop_with_conditional_phi_pattern(loop_form) { - if let Some(inst) = loop_patterns::lower_loop_with_conditional_phi_to_joinir(loop_form, lowerer) { - eprintln!("[try_lower_loop_pattern] ✅ Pattern 3 (Loop with If-Else PHI) matched"); - return Some(inst); + LoopPatternKind::Pattern2Break => { + if let Some(inst) = loop_patterns::lower_loop_with_break_to_joinir(loop_form, lowerer) { + eprintln!("[try_lower_loop_pattern] ✅ Pattern 2 (Break) matched"); + return Some(inst); + } + } + LoopPatternKind::Pattern1SimpleWhile => { + if let Some(inst) = loop_patterns::lower_simple_while_to_joinir(loop_form, lowerer) { + eprintln!("[try_lower_loop_pattern] ✅ Pattern 1 (Simple While) matched"); + return Some(inst); + } + } + LoopPatternKind::Unknown => { + eprintln!("[try_lower_loop_pattern] ❌ Unknown pattern, fallback to existing lowering"); } } // No Pattern Matched (fallback to existing lowering) // =================================================== - eprintln!("[try_lower_loop_pattern] ❌ No pattern matched, fallback to existing lowering"); + eprintln!("[try_lower_loop_pattern] ❌ Pattern lowering failed, fallback to existing lowering"); None } diff --git a/src/mir/loop_pattern_detection.rs b/src/mir/loop_pattern_detection.rs index b25ed5fd..c791b2c8 100644 --- a/src/mir/loop_pattern_detection.rs +++ b/src/mir/loop_pattern_detection.rs @@ -2,17 +2,183 @@ //! //! Phase 188 Task 188-4: Pattern detection helpers for JoinIR loop lowering. //! -//! This module provides detection functions for 3 loop patterns: +//! This module provides detection functions for 4 loop patterns: //! - Pattern 1: Simple While Loop (foundational) //! - Pattern 2: Loop with Conditional Break (early exit) //! - Pattern 3: Loop with If-Else PHI (variable mutation) +//! - Pattern 4: Loop with Continue (skip iteration) //! -//! These functions are "thin boxes" that take LoopForm and return bool. -//! No side effects, pure detection logic. +//! Phase 194+: Structure-based detection using LoopFeatures. +//! Patterns are classified based on CFG structure, not function names. +//! +//! # Architecture +//! +//! ``` +//! LoopForm → extract_features() → LoopFeatures → classify() → LoopPatternKind +//! ``` //! //! Reference: docs/private/roadmap2/phases/phase-188-joinir-loop-pattern-expansion/design.md use crate::mir::loop_form::LoopForm; +use crate::mir::join_ir::lowering::loop_scope_shape::LoopScopeShape; + +// ============================================================================ +// Pattern Classification System (Phase 194+) +// ============================================================================ + +/// Loop pattern classification based on structure. +/// +/// This enum represents the 4 main loop patterns we support. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum LoopPatternKind { + /// Pattern 1: Simple While Loop + /// - No break, no continue + /// - Single backedge + Pattern1SimpleWhile, + + /// Pattern 2: Loop with Conditional Break + /// - Has break statement(s) + /// - No continue statements + Pattern2Break, + + /// Pattern 3: Loop with If-Else PHI + /// - Has if-else statement with PHI + /// - No break, no continue + /// - Multiple carrier variables + Pattern3IfPhi, + + /// Pattern 4: Loop with Continue + /// - Has continue statement(s) + /// - No break statements (for simplicity) + Pattern4Continue, + + /// Pattern not recognized + Unknown, +} + +/// Feature vector extracted from loop structure. +/// +/// This structure captures all relevant properties needed for pattern classification. +/// It is name-agnostic and purely structure-based. +#[derive(Debug, Clone)] +pub struct LoopFeatures { + /// Has break statement(s)? + pub has_break: bool, + + /// Has continue statement(s)? + pub has_continue: bool, + + /// Has if statement(s) in body? + pub has_if: bool, + + /// Has if-else statement with PHI nodes? + /// (detected via multiple carriers or specific CFG patterns) + pub has_if_else_phi: bool, + + /// Number of carrier variables (loop variables that are updated) + pub carrier_count: usize, + + /// Number of break targets + pub break_count: usize, + + /// Number of continue targets + pub continue_count: usize, +} + +/// Extract features from LoopForm for pattern classification. +/// +/// This function is the entry point for structure-based pattern detection. +/// It analyzes the CFG structure without relying on variable names. +/// +/// # Arguments +/// * `loop_form` - The loop structure to analyze +/// * `scope` - Optional LoopScopeShape for carrier analysis +/// +/// # Returns +/// * `LoopFeatures` - Feature vector for pattern classification +pub fn extract_features(loop_form: &LoopForm, scope: Option<&LoopScopeShape>) -> LoopFeatures { + // Phase 194: Basic feature extraction from LoopForm + let has_break = !loop_form.break_targets.is_empty(); + let has_continue = !loop_form.continue_targets.is_empty(); + let break_count = loop_form.break_targets.len(); + let continue_count = loop_form.continue_targets.len(); + + // Phase 194+: Extract carrier_count from LoopScopeShape if available + let carrier_count = scope.map(|s| s.carriers.len()).unwrap_or(0); + + // Pattern 3 heuristic: has_if_else_phi if carrier_count > 1 + // This is a conservative heuristic - multiple carriers typically + // indicate if-else statements with PHI nodes. + let has_if_else_phi = carrier_count > 1; + + // TODO: Implement has_if detection via CFG analysis + // For now, we infer it from carrier_count > 1 (Pattern 3 heuristic) + let has_if = has_if_else_phi; + + LoopFeatures { + has_break, + has_continue, + has_if, + has_if_else_phi, + carrier_count, + break_count, + continue_count, + } +} + +/// Classify loop pattern based on feature vector. +/// +/// This function implements the pattern classification logic using +/// structure-based rules. It does NOT depend on function names or +/// variable names like "sum". +/// +/// # Pattern Classification Rules +/// +/// 1. **Pattern 4 (Continue)**: `has_continue == true` +/// - Priority: Check first (most specific) +/// +/// 2. **Pattern 3 (If-Else PHI)**: `has_if_else_phi && !has_break && !has_continue` +/// - Multiple carriers indicate if-else with PHI +/// +/// 3. **Pattern 2 (Break)**: `has_break && !has_continue` +/// - Has break but no continue +/// +/// 4. **Pattern 1 (Simple While)**: `!has_break && !has_continue && !has_if_else_phi` +/// - No control flow alterations +/// +/// # Arguments +/// * `features` - Feature vector from extract_features() +/// +/// # Returns +/// * `LoopPatternKind` - Classified pattern +pub fn classify(features: &LoopFeatures) -> LoopPatternKind { + // Pattern 4: Continue (highest priority) + if features.has_continue { + return LoopPatternKind::Pattern4Continue; + } + + // Pattern 3: If-Else PHI (check before Pattern 1) + if features.has_if_else_phi && !features.has_break && !features.has_continue { + return LoopPatternKind::Pattern3IfPhi; + } + + // Pattern 2: Break + if features.has_break && !features.has_continue { + return LoopPatternKind::Pattern2Break; + } + + // Pattern 1: Simple While + if !features.has_break && !features.has_continue && !features.has_if_else_phi { + return LoopPatternKind::Pattern1SimpleWhile; + } + + // Unknown pattern + LoopPatternKind::Unknown +} + +// ============================================================================ +// Legacy Detection Functions (Phase 188) +// ============================================================================ // ============================================================================ // Pattern 1: Simple While Loop @@ -200,6 +366,71 @@ pub fn is_loop_with_conditional_phi_pattern(loop_form: &LoopForm) -> bool { true } +// ============================================================================ +// Pattern 4: Loop with Continue +// ============================================================================ + +/// Detect Pattern 4: Loop with Continue +/// +/// Returns true ONLY if: +/// - Loop has continue statement(s) +/// - Continue is typically in an if statement +/// - NO break statements (for simplicity) +/// - Loop has multiple carrier variables +/// +/// # Arguments +/// * `loop_form` - The loop structure to analyze +/// +/// # Returns +/// * `true` if the loop matches Pattern 4 (Continue), `false` otherwise +/// +/// # Reference +/// See design.md § Pattern 4 → LoopScopeShape Recognition +/// +/// # Example +/// ```rust,ignore +/// let loop_form = /* ... */; +/// if is_loop_with_continue_pattern(&loop_form) { +/// // Lower to loop with continue pattern +/// } +/// ``` +pub fn is_loop_with_continue_pattern(loop_form: &LoopForm) -> bool { + // Pattern 4 Recognition Criteria: + // 1. continue_targets: NON-EMPTY (at least 1 continue) + // 2. break_targets: EMPTY (for simplicity in Pattern 4) + // 3. At least ONE continue target + // + // Phase 188-Impl-4: Minimal implementation + // Advanced checks (nested loops, if-statement structure) are deferred to + // lowering phase where we can fail gracefully if needed. + + // Check 1: continue_targets is NON-EMPTY (has at least 1 continue) + if loop_form.continue_targets.is_empty() { + return false; + } + + // Check 2: At least ONE continue target (pattern assumes single continue for now) + if loop_form.continue_targets.len() < 1 { + return false; + } + + // Check 3: No break statements (for simplicity in Pattern 4) + if !loop_form.break_targets.is_empty() { + return false; + } + + // Pattern 4 matched + // The LoopForm structure guarantees: + // - Valid loop structure + // - At least one continue target + // - No breaks + // + // Advanced checks (continue is in if-statement, etc.) are deferred to + // lowering phase for graceful failure. + + true +} + // ============================================================================ // Helper Functions (Future Use) // ============================================================================ @@ -344,4 +575,29 @@ mod tests { // Step 2: Call is_loop_with_conditional_phi_pattern() // Step 3: Assert returns false } + + // ======================================================================== + // Pattern 4: Loop with Continue Tests + // ======================================================================== + + #[test] + #[ignore] // TODO: Implement test after detection logic is complete + fn test_pattern4_continue_detection() { + // TODO: Add unit test for continue pattern detection + // Step 1: Create mock LoopForm with: + // - Non-empty continue_targets (at least 1) + // - Empty break_targets + // - If statement with continue + // Step 2: Call is_loop_with_continue_pattern() + // Step 3: Assert returns true + } + + #[test] + #[ignore] // TODO: Implement test after detection logic is complete + fn test_pattern4_rejects_no_continue() { + // TODO: Add test that rejects loop without continue + // Step 1: Create mock LoopForm with empty continue_targets + // Step 2: Call is_loop_with_continue_pattern() + // Step 3: Assert returns false + } }