diff --git a/src/mir/builder/control_flow/joinir/patterns/ast_feature_extractor.rs b/src/mir/builder/control_flow/joinir/patterns/ast_feature_extractor.rs index 7c48df9a..db5f1378 100644 --- a/src/mir/builder/control_flow/joinir/patterns/ast_feature_extractor.rs +++ b/src/mir/builder/control_flow/joinir/patterns/ast_feature_extractor.rs @@ -201,6 +201,45 @@ fn has_break_node(node: &ASTNode) -> bool { } } +/// Phase 170-B: Extract break condition from loop body +/// +/// Searches for the first `if { break }` pattern in the loop body. +/// This is used to delegate break condition lowering to `condition_to_joinir`. +/// +/// # Arguments +/// +/// * `body` - Loop body statements to search +/// +/// # Returns +/// +/// `Some(&ASTNode)` - The condition AST node from `if { break }` +/// `None` - No break statement found or break is not in a simple if statement +/// +/// # Example +/// +/// ```nyash +/// loop(i < 3) { +/// if i >= 2 { break } // <- Returns the "i >= 2" condition +/// i = i + 1 +/// } +/// ``` +pub fn extract_break_condition(body: &[ASTNode]) -> Option<&ASTNode> { + for stmt in body { + if let ASTNode::If { + condition, + then_body, + .. + } = stmt + { + // Check if the then_body contains a break statement + if then_body.iter().any(|node| matches!(node, ASTNode::Break { .. })) { + return Some(condition.as_ref()); + } + } + } + None +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/mir/builder/control_flow/joinir/patterns/pattern2_with_break.rs b/src/mir/builder/control_flow/joinir/patterns/pattern2_with_break.rs index 5ed0cd02..40f9b931 100644 --- a/src/mir/builder/control_flow/joinir/patterns/pattern2_with_break.rs +++ b/src/mir/builder/control_flow/joinir/patterns/pattern2_with_break.rs @@ -141,9 +141,14 @@ impl MirBuilder { variable_definitions: BTreeMap::new(), }; - // Phase 169 / Phase 171-fix / Phase 172-3: Call Pattern 2 lowerer with ConditionEnv + // Phase 170-B: Extract break condition from loop body + use super::ast_feature_extractor; + let break_condition = ast_feature_extractor::extract_break_condition(_body) + .ok_or_else(|| "[cf_loop/pattern2] Failed to extract break condition from loop body".to_string())?; + + // Phase 169 / Phase 171-fix / Phase 172-3 / Phase 170-B: Call Pattern 2 lowerer with break_condition // Phase 33-14: Now returns (JoinModule, JoinFragmentMeta) for expr_result + carrier separation - let (join_module, fragment_meta) = match lower_loop_with_break_minimal(scope, condition, &env, &loop_var_name) { + let (join_module, fragment_meta) = match lower_loop_with_break_minimal(scope, condition, break_condition, &env, &loop_var_name) { Ok((module, meta)) => (module, meta), Err(e) => { // Phase 195: Use unified trace diff --git a/src/mir/builder/control_flow/joinir/routing.rs b/src/mir/builder/control_flow/joinir/routing.rs index 11b2f976..e9ca6b5d 100644 --- a/src/mir/builder/control_flow/joinir/routing.rs +++ b/src/mir/builder/control_flow/joinir/routing.rs @@ -76,6 +76,7 @@ impl MirBuilder { "TrimTest.trim/1" => true, "Main.trim/1" => true, // Phase 171-fix: Main box variant "Main.trim_string_simple/1" => true, // Phase 33-13: Simple trim variant + "TrimTest.main/0" => true, // Phase 170: TrimTest.main for loop pattern test _ => false, }; diff --git a/src/mir/join_ir/lowering/loop_with_break_minimal.rs b/src/mir/join_ir/lowering/loop_with_break_minimal.rs index b2073255..bc214c15 100644 --- a/src/mir/join_ir/lowering/loop_with_break_minimal.rs +++ b/src/mir/join_ir/lowering/loop_with_break_minimal.rs @@ -117,10 +117,12 @@ use crate::mir::ValueId; /// /// # Arguments /// +/// * `break_condition` - AST node for the break condition (e.g., `i >= 2`) - Phase 170-B /// * `loop_var_name` - Name of the loop variable (for ExitMeta construction) pub fn lower_loop_with_break_minimal( _scope: LoopScopeShape, condition: &ASTNode, + break_condition: &ASTNode, env: &ConditionEnv, loop_var_name: &str, ) -> Result<(JoinModule, JoinFragmentMeta), String> { @@ -162,8 +164,14 @@ pub fn lower_loop_with_break_minimal( // After condition lowering, allocate remaining ValueIds let exit_cond = alloc_value(); // Exit condition (negated loop condition) - let const_2 = alloc_value(); // Break limit (hardcoded for now) - let break_cond = alloc_value(); // Break condition (i >= 2) + + // Phase 170-B: Lower break condition using condition_to_joinir (no hardcoding!) + let (break_cond_value, mut break_cond_instructions) = lower_condition_to_joinir( + break_condition, + &mut alloc_value, + env, + )?; + let const_1 = alloc_value(); // Increment constant let i_next = alloc_value(); // i + 1 @@ -224,31 +232,16 @@ pub fn lower_loop_with_break_minimal( }); // ------------------------------------------------------------------ - // Break Condition Check: i >= 2 + // Phase 170-B: Break Condition Check (delegated to condition_to_joinir) // ------------------------------------------------------------------ - // Step 1: const 2 - loop_step_func - .body - .push(JoinInst::Compute(MirLikeInst::Const { - dst: const_2, - value: ConstValue::Integer(2), - })); - - // Step 2: break_cond = (i >= 2) - loop_step_func - .body - .push(JoinInst::Compute(MirLikeInst::Compare { - dst: break_cond, - op: CompareOp::Ge, - lhs: i_param, - rhs: const_2, - })); + // Insert all break condition evaluation instructions + loop_step_func.body.append(&mut break_cond_instructions); // Jump(k_exit, [i], cond=break_cond) // Break exit path loop_step_func.body.push(JoinInst::Jump { cont: k_exit_id.as_cont(), args: vec![i_param], // Pass current i as exit value - cond: Some(break_cond), + cond: Some(break_cond_value), // Phase 170-B: Use lowered condition }); // ------------------------------------------------------------------ @@ -302,9 +295,10 @@ pub fn lower_loop_with_break_minimal( // Set entry point join_module.entry = Some(main_id); - eprintln!("[joinir/pattern2] Generated JoinIR for Loop with Break Pattern (Phase 169)"); + eprintln!("[joinir/pattern2] Generated JoinIR for Loop with Break Pattern (Phase 170-B)"); eprintln!("[joinir/pattern2] Functions: main, loop_step, k_exit"); - eprintln!("[joinir/pattern2] Condition from AST (not hardcoded)"); + eprintln!("[joinir/pattern2] Loop condition from AST (delegated to condition_to_joinir)"); + eprintln!("[joinir/pattern2] Break condition from AST (delegated to condition_to_joinir)"); eprintln!("[joinir/pattern2] Exit PHI: k_exit receives i from both natural exit and break"); // Phase 172-3 → Phase 33-14: Build JoinFragmentMeta with expr_result