diff --git a/src/mir/builder/control_flow/joinir/patterns/mod.rs b/src/mir/builder/control_flow/joinir/patterns/mod.rs index 6b391748..3833c19f 100644 --- a/src/mir/builder/control_flow/joinir/patterns/mod.rs +++ b/src/mir/builder/control_flow/joinir/patterns/mod.rs @@ -51,6 +51,7 @@ pub(in crate::mir::builder) mod pattern3_with_if_phi; pub(in crate::mir::builder) mod pattern4_carrier_analyzer; pub(in crate::mir::builder) mod pattern4_with_continue; pub(in crate::mir::builder) mod router; +pub(in crate::mir::builder) mod trim_loop_lowering; // Phase 180: Dedicated Trim/P5 lowering module pub(in crate::mir::builder) mod trim_pattern_validator; pub(in crate::mir::builder) mod trim_pattern_lowerer; 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 be188251..e8594abf 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 @@ -4,8 +4,6 @@ use crate::ast::ASTNode; use crate::mir::builder::MirBuilder; use crate::mir::ValueId; use super::super::trace; -use super::trim_pattern_validator::TrimPatternValidator; -use super::trim_pattern_lowerer::TrimPatternLowerer; /// Phase 194: Detection function for Pattern 2 /// @@ -177,202 +175,37 @@ impl MirBuilder { break_condition_raw.clone() }; - // Phase 171-C-3: LoopBodyCarrierPromoter integration - // Check if LoopConditionScopeBox detects LoopBodyLocal variables, and attempt promotion - { - use crate::mir::loop_pattern_detection::loop_condition_scope::LoopConditionScopeBox; - use crate::mir::loop_pattern_detection::loop_body_carrier_promoter::{ - LoopBodyCarrierPromoter, PromotionRequest, PromotionResult, - }; + // Phase 180-3: Delegate Trim/P5 processing to TrimLoopLowerer + let effective_break_condition = if let Some(trim_result) = super::trim_loop_lowering::TrimLoopLowerer::try_lower_trim_like_loop( + self, + &scope, + condition, + &break_condition_node, + _body, + &loop_var_name, + &mut carrier_info, + &mut alloc_join_value, + )? { + // Trim pattern detected and lowered + eprintln!("[pattern2/trim] TrimLoopLowerer processed Trim pattern successfully"); - // First check: Does the condition reference LoopBodyLocal variables? - let cond_scope = LoopConditionScopeBox::analyze( - &loop_var_name, - &[condition, &break_condition_node], - Some(&scope), - ); + // Update carrier_info from result + carrier_info = trim_result.carrier_info; - eprintln!("[pattern2/check] Analyzing condition scope: {} variables", cond_scope.vars.len()); - for var in &cond_scope.vars { - eprintln!("[pattern2/check] '{}': {:?}", var.name, var.scope); + // Extend condition_bindings with Trim bindings + condition_bindings.extend(trim_result.condition_bindings.iter().cloned()); + + // Add bindings to env for JoinIR + for binding in &trim_result.condition_bindings { + env.insert(binding.name.clone(), binding.join_value); } - eprintln!("[pattern2/check] has_loop_body_local() = {}", cond_scope.has_loop_body_local()); - if cond_scope.has_loop_body_local() { - eprintln!("[pattern2/promotion] LoopBodyLocal detected in condition scope"); + eprintln!("[pattern2/trim] Extended condition_bindings with {} Trim bindings", trim_result.condition_bindings.len()); - // Phase 171-C-3: Try promotion - let request = PromotionRequest { - scope: &scope, - cond_scope: &cond_scope, - break_cond: Some(&break_condition_node), - loop_body: _body, - }; - - match LoopBodyCarrierPromoter::try_promote(&request) { - PromotionResult::Promoted { trim_info } => { - eprintln!( - "[pattern2/promoter] LoopBodyLocal '{}' promoted to carrier '{}'", - trim_info.var_name, trim_info.carrier_name - ); - - // Phase 171-C-4: Convert to CarrierInfo and merge - let promoted_carrier = trim_info.to_carrier_info(); - - eprintln!( - "[pattern2/promoter] Phase 171-C-4 DEBUG: BEFORE merge - carrier_info.loop_var_name='{}'", - carrier_info.loop_var_name - ); - eprintln!( - "[pattern2/promoter] Phase 171-C-4 DEBUG: promoted_carrier.loop_var_name='{}'", - promoted_carrier.loop_var_name - ); - - carrier_info.merge_from(&promoted_carrier); - - eprintln!( - "[pattern2/promoter] Phase 171-C-4 DEBUG: AFTER merge - carrier_info.loop_var_name='{}'", - carrier_info.loop_var_name - ); - eprintln!( - "[pattern2/promoter] Phase 171-C-4: Merged carrier '{}' into CarrierInfo (total carriers: {})", - trim_info.carrier_name, - carrier_info.carrier_count() - ); - - // Phase 172: Implement Trim pattern lowering - // Clone helper data to avoid borrow conflicts - let trim_helper_data = carrier_info.trim_helper().map(|h| { - (h.carrier_name.clone(), h.original_var.clone(), h.whitespace_chars.clone(), h.is_safe_trim()) - }); - - if let Some((carrier_name, original_var, whitespace_chars, is_safe)) = trim_helper_data { - if is_safe { - eprintln!("[pattern2/trim] Safe Trim pattern detected, implementing lowering"); - eprintln!("[pattern2/trim] Carrier: '{}', original var: '{}', whitespace chars: {:?}", - carrier_name, original_var, whitespace_chars); - - // Phase 172-2: Extract substring pattern and generate initial check - let (s_name, start_expr) = TrimPatternValidator::extract_substring_args(_body, &original_var) - .ok_or_else(|| { - format!( - "[cf_loop/pattern2] Failed to extract substring pattern for Trim carrier '{}'", - carrier_name - ) - })?; - - eprintln!("[pattern2/trim] Extracted substring pattern: s='{}', start={:?}", s_name, start_expr); - - // Get ValueIds for string and start - let s_id = self.variable_map.get(&s_name) - .copied() - .ok_or_else(|| format!("[pattern2/trim] String variable '{}' not found", s_name))?; - - // Compile start expression to get ValueId - let start_id = self.build_expression_impl(*start_expr)?; - - // Generate: start + 1 - use crate::mir::builder::emission::constant::emit_integer; - use crate::mir::types::BinaryOp; - use crate::mir::instruction::MirInstruction; - let one = emit_integer(self, 1); - let start_plus_1 = self.value_gen.next(); - self.emit_instruction(MirInstruction::BinOp { - dst: start_plus_1, - op: BinaryOp::Add, - lhs: start_id, - rhs: one, - })?; - - // Generate: ch0 = s.substring(start, start+1) - let ch0 = self.value_gen.next(); - self.emit_method_call( - Some(ch0), - s_id, - "substring".to_string(), - vec![start_id, start_plus_1], - )?; - - eprintln!("[pattern2/trim] Generated initial substring call: ch0 = {:?}", ch0); - - // Generate: is_ch_match0 = (ch0 == " " || ch0 == "\t" || ...) - let is_ch_match0 = TrimPatternValidator::emit_whitespace_check(self, ch0, &whitespace_chars)?; - - eprintln!("[pattern2/trim] Generated initial whitespace check: is_ch_match0 = {:?}", is_ch_match0); - - // Register carrier in variable_map - self.variable_map.insert(carrier_name.clone(), is_ch_match0); - - eprintln!("[pattern2/trim] Registered carrier '{}' in variable_map", carrier_name); - - // Note: DO NOT overwrite carrier_info.loop_var_id/loop_var_name here! - // The loop variable is 'pos' (counter), not 'is_ch_match' (carrier). - // carrier_info.loop_var_name should remain as the original loop variable. - - eprintln!("[pattern2/trim] Carrier registered. Loop var='{}' remains unchanged", - carrier_info.loop_var_name); - - // Phase 172-4: Break condition will be replaced below after JoinIR generation - eprintln!("[pattern2/trim] Trim pattern lowering enabled, proceeding to JoinIR generation"); - } else { - return Err(format!( - "[cf_loop/pattern2] Trim pattern detected but not safe: carrier='{}', whitespace_count={}", - carrier_name, - whitespace_chars.len() - )); - } - } else if carrier_info.trim_helper().is_some() { - return Err(format!( - "[cf_loop/pattern2] Promoted but TrimLoopHelper check failed (carrier: '{}')", - trim_info.carrier_name - )); - } - } - PromotionResult::CannotPromote { reason, vars } => { - // Phase 171-C-3: Fail-Fast on promotion failure - return Err(format!( - "[cf_loop/pattern2] Cannot promote LoopBodyLocal variables {:?}: {}", - vars, reason - )); - } - } - } - } - - // Phase 172-4: Replace break condition for Trim pattern and add carrier to ConditionEnv - let effective_break_condition = if let Some(helper) = carrier_info.trim_helper() { - if helper.is_safe_trim() { - // Add carrier to ConditionEnv using TrimPatternLowerer - let get_value = |name: &str| self.variable_map.get(name).copied(); - let binding = TrimPatternLowerer::add_to_condition_env( - helper, - get_value, - |name, value| { env.insert(name, value); }, - &mut alloc_join_value, - )?; - condition_bindings.push(binding); - - eprintln!("[pattern2/trim] Added carrier '{}' to ConditionEnv: HOST {:?} → JoinIR {:?}", - helper.carrier_name, condition_bindings.last().unwrap().host_value, condition_bindings.last().unwrap().join_value); - - // Phase 176-6: Also map the original variable name to the same JoinIR ValueId - // This allows the loop body to reference the original variable (e.g., 'ch') - // even though it was promoted to a carrier (e.g., 'is_ch_match') - let join_value = condition_bindings.last().unwrap().join_value; - env.insert(helper.original_var.clone(), join_value); - - eprintln!("[pattern2/trim] Phase 176-6: Also mapped original var '{}' → JoinIR {:?}", - helper.original_var, join_value); - - // Generate negated carrier check: !is_ch_match - let negated_carrier = TrimPatternLowerer::generate_trim_break_condition(helper); - - eprintln!("[pattern2/trim] Replaced break condition with !{}", helper.carrier_name); - negated_carrier - } else { - break_condition_node.clone() - } + // Use Trim break condition + trim_result.condition } else { + // Not a Trim pattern - use original break condition break_condition_node.clone() }; diff --git a/src/mir/builder/control_flow/joinir/patterns/trim_loop_lowering.rs b/src/mir/builder/control_flow/joinir/patterns/trim_loop_lowering.rs new file mode 100644 index 00000000..e8d890fe --- /dev/null +++ b/src/mir/builder/control_flow/joinir/patterns/trim_loop_lowering.rs @@ -0,0 +1,416 @@ +//! Phase 180: Trim/P5 Dedicated Lowering Module +//! +//! Consolidates all Trim pattern lowering logic from Pattern2/Pattern4. +//! Pattern2/Pattern4 handle generic loop structures, while this module +//! handles Trim/CharComparison (Pattern 5) specific knowledge. +//! +//! ## Responsibilities +//! +//! - Detect Trim-like loops (whitespace skipping patterns) +//! - Promote LoopBodyLocal variables to carriers +//! - Generate carrier initialization code (substring + whitespace check) +//! - Replace break conditions with carrier checks +//! - Setup ConditionEnv bindings for JoinIR +//! +//! ## Design Philosophy +//! +//! Follows Box Theory principles: +//! - **Single Responsibility**: Only handles Trim/P5 lowering logic +//! - **Reusability**: Used by Pattern2, Pattern4, and future patterns +//! - **Testability**: Pure data transformations, easy to unit test +//! - **Fail-Fast**: Returns errors early, no silent fallbacks +//! +//! ## Example Use Case +//! +//! **Original pattern** (Pattern 2 with Trim): +//! ```nyash +//! loop(start < end) { +//! local ch = s.substring(start, start+1) +//! if ch == " " || ch == "\t" { start = start + 1 } else { break } +//! } +//! ``` +//! +//! **After TrimLoopLowerer processing**: +//! - LoopBodyLocal `ch` promoted to bool carrier `is_ch_match` +//! - Carrier initialized: `is_ch_match = (s.substring(start, start+1) == " " || ...)` +//! - Break condition replaced: `break on !is_ch_match` +//! - ConditionEnv binding: `ch` → JoinIR ValueId + +use crate::ast::ASTNode; +use crate::mir::builder::MirBuilder; +use crate::mir::join_ir::lowering::carrier_info::CarrierInfo; +use crate::mir::join_ir::lowering::condition_env::ConditionBinding; +use crate::mir::join_ir::lowering::loop_scope_shape::LoopScopeShape; +use crate::mir::loop_pattern_detection::loop_body_carrier_promoter::{ + LoopBodyCarrierPromoter, PromotionRequest, PromotionResult, +}; +use crate::mir::loop_pattern_detection::loop_condition_scope::LoopConditionScopeBox; +use crate::mir::ValueId; + +/// Trim pattern lowering orchestrator +/// +/// Phase 180: Single entry point for all Trim/P5 lowering operations. +pub struct TrimLoopLowerer; + +/// Result of successful Trim lowering preprocessing +/// +/// Contains all data needed by Pattern2/4 to complete lowering: +/// - Replaced break condition +/// - Updated carrier info with promoted carrier +/// - Condition environment bindings +/// - Trim helper for pattern-specific operations +pub struct TrimLoweringResult { + /// Replaced break condition (e.g., `!is_carrier`) + /// + /// Pattern2/4 will use this instead of the original break condition + pub condition: ASTNode, + + /// Updated carrier info with promoted Trim carrier + /// + /// Pattern2/4 will use this for JoinIR lowering + pub carrier_info: CarrierInfo, + + /// Condition environment bindings for the carrier + /// + /// Pattern2/4 will extend their condition_bindings with these + pub condition_bindings: Vec, +} + +impl TrimLoopLowerer { + /// Try to lower a Trim-like loop pattern + /// + /// Phase 180: Main entry point for Trim pattern detection and lowering. + /// + /// # Algorithm + /// + /// 1. Check if condition references LoopBodyLocal variables + /// 2. Try to promote LoopBodyLocal to carrier (via LoopBodyCarrierPromoter) + /// 3. If promoted as Trim pattern: + /// - Generate carrier initialization code + /// - Replace break condition with carrier check + /// - Setup ConditionEnv bindings + /// 4. Return TrimLoweringResult with all updates + /// + /// # Arguments + /// + /// * `builder` - MirBuilder for code generation + /// * `scope` - Loop structure metadata + /// * `loop_cond` - Main loop condition (e.g., `start < end`) + /// * `break_cond` - Break condition from loop body + /// * `body` - Loop body AST nodes + /// * `loop_var_name` - Loop variable name (e.g., "start") + /// * `carrier_info` - Current carrier info (will be updated if Trim pattern) + /// * `alloc_join_value` - JoinIR ValueId allocator closure + /// + /// # Returns + /// + /// - `Ok(Some(TrimLoweringResult))` - Trim pattern detected and lowered + /// - `Ok(None)` - Not a Trim pattern (normal loop, no action taken) + /// - `Err(String)` - Trim pattern detected but lowering failed + /// + /// # Example + /// + /// ```ignore + /// if let Some(trim_result) = TrimLoopLowerer::try_lower_trim_like_loop( + /// self, + /// &scope, + /// condition, + /// &break_condition_node, + /// _body, + /// &loop_var_name, + /// &mut carrier_info, + /// &mut alloc_join_value, + /// )? { + /// // Use trim_result.condition, carrier_info, condition_bindings + /// } + /// ``` + pub fn try_lower_trim_like_loop( + builder: &mut MirBuilder, + scope: &LoopScopeShape, + loop_cond: &ASTNode, + break_cond: &ASTNode, + body: &[ASTNode], + loop_var_name: &str, + carrier_info: &mut CarrierInfo, + alloc_join_value: &mut dyn FnMut() -> ValueId, + ) -> Result, String> { + // Phase 180-2: Skeleton implementation + // TODO: Phase 180-3 will implement full logic from Pattern2 + + // Step 1: Check if condition references LoopBodyLocal variables + let cond_scope = LoopConditionScopeBox::analyze( + loop_var_name, + &[loop_cond, break_cond], + Some(scope), + ); + + eprintln!( + "[TrimLoopLowerer] Analyzing condition scope: {} variables", + cond_scope.vars.len() + ); + + if !cond_scope.has_loop_body_local() { + // Not a Trim pattern - normal loop + eprintln!("[TrimLoopLowerer] No LoopBodyLocal detected, skipping Trim lowering"); + return Ok(None); + } + + eprintln!("[TrimLoopLowerer] LoopBodyLocal detected in condition scope"); + + // Step 2: Try promotion via LoopBodyCarrierPromoter + let request = PromotionRequest { + scope, + cond_scope: &cond_scope, + break_cond: Some(break_cond), + loop_body: body, + }; + + match LoopBodyCarrierPromoter::try_promote(&request) { + PromotionResult::Promoted { trim_info } => { + eprintln!( + "[TrimLoopLowerer] LoopBodyLocal '{}' promoted to carrier '{}'", + trim_info.var_name, trim_info.carrier_name + ); + + // Step 3: Convert to CarrierInfo and merge + let promoted_carrier = trim_info.to_carrier_info(); + carrier_info.merge_from(&promoted_carrier); + + eprintln!( + "[TrimLoopLowerer] Merged carrier '{}' into CarrierInfo (total carriers: {})", + trim_info.carrier_name, + carrier_info.carrier_count() + ); + + // Step 4: Safety check via TrimLoopHelper + let trim_helper = carrier_info + .trim_helper() + .ok_or_else(|| { + format!( + "[TrimLoopLowerer] Promoted but no TrimLoopHelper attached (carrier: '{}')", + trim_info.carrier_name + ) + })?; + + if !trim_helper.is_safe_trim() { + return Err(format!( + "[TrimLoopLowerer] Trim pattern detected but not safe: carrier='{}', whitespace_count={}", + trim_helper.carrier_name, + trim_helper.whitespace_chars.len() + )); + } + + eprintln!("[TrimLoopLowerer] Safe Trim pattern detected, implementing lowering"); + eprintln!( + "[TrimLoopLowerer] Carrier: '{}', original var: '{}', whitespace chars: {:?}", + trim_helper.carrier_name, trim_helper.original_var, trim_helper.whitespace_chars + ); + + // Step 5: Generate carrier initialization code + Self::generate_carrier_initialization( + builder, + body, + trim_helper, + )?; + + eprintln!( + "[TrimLoopLowerer] Registered carrier '{}' in variable_map", + trim_helper.carrier_name + ); + + // Step 6: Generate Trim break condition + let trim_break_condition = Self::generate_trim_break_condition(trim_helper); + + eprintln!( + "[TrimLoopLowerer] Replaced break condition with !{}", + trim_helper.carrier_name + ); + + // Step 7: Setup ConditionEnv bindings + let condition_bindings = Self::setup_condition_env_bindings( + builder, + trim_helper, + alloc_join_value, + )?; + + eprintln!( + "[TrimLoopLowerer] Added {} condition bindings", + condition_bindings.len() + ); + + // Step 8: Return result with all updates + Ok(Some(TrimLoweringResult { + condition: trim_break_condition, + carrier_info: carrier_info.clone(), + condition_bindings, + })) + } + PromotionResult::CannotPromote { reason, vars } => { + // Phase 180: Fail-Fast on promotion failure + Err(format!( + "[TrimLoopLowerer] Cannot promote LoopBodyLocal variables {:?}: {}", + vars, reason + )) + } + } + } + + /// Generate carrier initialization code + /// + /// Phase 180-3: Extracted from Pattern2 (lines 256-313) + /// + /// Generates: + /// 1. ch0 = s.substring(start, start+1) + /// 2. is_ch_match0 = (ch0 == " " || ch0 == "\t" || ...) + /// 3. Registers carrier in variable_map + fn generate_carrier_initialization( + builder: &mut MirBuilder, + body: &[ASTNode], + trim_helper: &crate::mir::loop_pattern_detection::trim_loop_helper::TrimLoopHelper, + ) -> Result<(), String> { + use crate::mir::builder::control_flow::joinir::patterns::trim_pattern_validator::TrimPatternValidator; + + // Extract substring pattern from body + let (s_name, start_expr) = TrimPatternValidator::extract_substring_args(body, &trim_helper.original_var) + .ok_or_else(|| { + format!( + "[TrimLoopLowerer] Failed to extract substring pattern for Trim carrier '{}'", + trim_helper.carrier_name + ) + })?; + + eprintln!( + "[TrimLoopLowerer] Extracted substring pattern: s='{}', start={:?}", + s_name, start_expr + ); + + // Get ValueIds for string and start + let s_id = builder + .variable_map + .get(&s_name) + .copied() + .ok_or_else(|| format!("[TrimLoopLowerer] String variable '{}' not found", s_name))?; + + // Compile start expression to get ValueId + let start_id = builder.build_expression_impl(*start_expr)?; + + // Generate: start + 1 + use crate::mir::builder::emission::constant::emit_integer; + use crate::mir::instruction::MirInstruction; + use crate::mir::types::BinaryOp; + let one = emit_integer(builder, 1); + let start_plus_1 = builder.value_gen.next(); + builder.emit_instruction(MirInstruction::BinOp { + dst: start_plus_1, + op: BinaryOp::Add, + lhs: start_id, + rhs: one, + })?; + + // Generate: ch0 = s.substring(start, start+1) + let ch0 = builder.value_gen.next(); + builder.emit_method_call( + Some(ch0), + s_id, + "substring".to_string(), + vec![start_id, start_plus_1], + )?; + + eprintln!("[TrimLoopLowerer] Generated initial substring call: ch0 = {:?}", ch0); + + // Generate: is_ch_match0 = (ch0 == " " || ch0 == "\t" || ...) + let is_ch_match0 = + TrimPatternValidator::emit_whitespace_check(builder, ch0, &trim_helper.whitespace_chars)?; + + eprintln!( + "[TrimLoopLowerer] Generated initial whitespace check: is_ch_match0 = {:?}", + is_ch_match0 + ); + + // Register carrier in variable_map + builder + .variable_map + .insert(trim_helper.carrier_name.clone(), is_ch_match0); + + Ok(()) + } + + /// Generate Trim break condition + /// + /// Phase 180-3: Extracted from Pattern2 (lines 343-377) + /// + /// Returns: !is_carrier (negated carrier check) + fn generate_trim_break_condition( + trim_helper: &crate::mir::loop_pattern_detection::trim_loop_helper::TrimLoopHelper, + ) -> ASTNode { + use crate::mir::builder::control_flow::joinir::patterns::trim_pattern_lowerer::TrimPatternLowerer; + TrimPatternLowerer::generate_trim_break_condition(trim_helper) + } + + /// Setup ConditionEnv bindings for Trim carrier + /// + /// Phase 180-3: Extracted from Pattern2 (lines 345-377) + /// + /// Creates bindings for: + /// 1. Carrier variable (e.g., "is_ch_match") + /// 2. Original variable (e.g., "ch") - mapped to same JoinIR ValueId + fn setup_condition_env_bindings( + builder: &mut MirBuilder, + trim_helper: &crate::mir::loop_pattern_detection::trim_loop_helper::TrimLoopHelper, + alloc_join_value: &mut dyn FnMut() -> ValueId, + ) -> Result, String> { + use crate::mir::builder::control_flow::joinir::patterns::trim_pattern_lowerer::TrimPatternLowerer; + + let mut bindings = Vec::new(); + + // Add carrier to ConditionEnv + let get_value = |name: &str| builder.variable_map.get(name).copied(); + let mut env_temp = std::collections::HashMap::new(); // Temporary env for closure + + let binding = TrimPatternLowerer::add_to_condition_env( + trim_helper, + get_value, + |name, value| { + env_temp.insert(name, value); + }, + alloc_join_value, + )?; + + eprintln!( + "[TrimLoopLowerer] Added carrier '{}' to ConditionEnv: HOST {:?} → JoinIR {:?}", + trim_helper.carrier_name, binding.host_value, binding.join_value + ); + + bindings.push(binding.clone()); + + // Phase 176-6: Also map the original variable name to the same JoinIR ValueId + // This allows the loop body to reference the original variable (e.g., 'ch') + // even though it was promoted to a carrier (e.g., 'is_ch_match') + let original_binding = ConditionBinding { + name: trim_helper.original_var.clone(), + host_value: binding.host_value, + join_value: binding.join_value, + }; + + eprintln!( + "[TrimLoopLowerer] Phase 176-6: Also mapped original var '{}' → JoinIR {:?}", + trim_helper.original_var, binding.join_value + ); + + bindings.push(original_binding); + + Ok(bindings) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_trim_loop_lowerer_skeleton() { + // Phase 180-2: Basic existence test + // Full tests will be added in Phase 180-3 + assert!(true, "TrimLoopLowerer skeleton compiles"); + } +} diff --git a/src/mir/join_ir/lowering/mod.rs b/src/mir/join_ir/lowering/mod.rs index 2c78f230..1f2c9067 100644 --- a/src/mir/join_ir/lowering/mod.rs +++ b/src/mir/join_ir/lowering/mod.rs @@ -60,7 +60,6 @@ pub mod skip_ws; pub mod stage1_using_resolver; pub mod stageb_body; pub mod stageb_funcscanner; -pub mod trim_loop_lowering; // Phase 180: Trim/P5 dedicated lowering module pub mod type_hint_policy; // Phase 65.5: 型ヒントポリシー箱化 pub mod type_inference; // Phase 65-2-A pub(crate) mod value_id_ranges; // Internal ValueId range management diff --git a/src/mir/join_ir/lowering/trim_loop_lowering.rs b/src/mir/join_ir/lowering/trim_loop_lowering.rs deleted file mode 100644 index e0cc0a90..00000000 --- a/src/mir/join_ir/lowering/trim_loop_lowering.rs +++ /dev/null @@ -1,221 +0,0 @@ -//! Phase 180: Trim/P5 Dedicated Lowering Module -//! -//! Consolidates all Trim pattern lowering logic from Pattern2/Pattern4. -//! Pattern2/Pattern4 handle generic loop structures, while this module -//! handles Trim/CharComparison (Pattern 5) specific knowledge. -//! -//! ## Responsibilities -//! -//! - Detect Trim-like loops (whitespace skipping patterns) -//! - Promote LoopBodyLocal variables to carriers -//! - Generate carrier initialization code (substring + whitespace check) -//! - Replace break conditions with carrier checks -//! - Setup ConditionEnv bindings for JoinIR -//! -//! ## Design Philosophy -//! -//! Follows Box Theory principles: -//! - **Single Responsibility**: Only handles Trim/P5 lowering logic -//! - **Reusability**: Used by Pattern2, Pattern4, and future patterns -//! - **Testability**: Pure data transformations, easy to unit test -//! - **Fail-Fast**: Returns errors early, no silent fallbacks -//! -//! ## Example Use Case -//! -//! **Original pattern** (Pattern 2 with Trim): -//! ```nyash -//! loop(start < end) { -//! local ch = s.substring(start, start+1) -//! if ch == " " || ch == "\t" { start = start + 1 } else { break } -//! } -//! ``` -//! -//! **After TrimLoopLowerer processing**: -//! - LoopBodyLocal `ch` promoted to bool carrier `is_ch_match` -//! - Carrier initialized: `is_ch_match = (s.substring(start, start+1) == " " || ...)` -//! - Break condition replaced: `break on !is_ch_match` -//! - ConditionEnv binding: `ch` → JoinIR ValueId - -use crate::ast::ASTNode; -use crate::mir::builder::MirBuilder; -use crate::mir::join_ir::lowering::carrier_info::CarrierInfo; -use crate::mir::join_ir::lowering::condition_env::ConditionBinding; -use crate::mir::join_ir::lowering::loop_scope_shape::LoopScopeShape; -use crate::mir::loop_pattern_detection::loop_body_carrier_promoter::{ - LoopBodyCarrierPromoter, PromotionRequest, PromotionResult, -}; -use crate::mir::loop_pattern_detection::loop_condition_scope::LoopConditionScopeBox; -use crate::mir::ValueId; - -/// Trim pattern lowering orchestrator -/// -/// Phase 180: Single entry point for all Trim/P5 lowering operations. -pub struct TrimLoopLowerer; - -/// Result of successful Trim lowering preprocessing -/// -/// Contains all data needed by Pattern2/4 to complete lowering: -/// - Replaced break condition -/// - Updated carrier info with promoted carrier -/// - Condition environment bindings -/// - Trim helper for pattern-specific operations -pub struct TrimLoweringResult { - /// Replaced break condition (e.g., `!is_carrier`) - /// - /// Pattern2/4 will use this instead of the original break condition - pub condition: ASTNode, - - /// Updated carrier info with promoted Trim carrier - /// - /// Pattern2/4 will use this for JoinIR lowering - pub carrier_info: CarrierInfo, - - /// Condition environment bindings for the carrier - /// - /// Pattern2/4 will extend their condition_bindings with these - pub condition_bindings: Vec, -} - -impl TrimLoopLowerer { - /// Try to lower a Trim-like loop pattern - /// - /// Phase 180: Main entry point for Trim pattern detection and lowering. - /// - /// # Algorithm - /// - /// 1. Check if condition references LoopBodyLocal variables - /// 2. Try to promote LoopBodyLocal to carrier (via LoopBodyCarrierPromoter) - /// 3. If promoted as Trim pattern: - /// - Generate carrier initialization code - /// - Replace break condition with carrier check - /// - Setup ConditionEnv bindings - /// 4. Return TrimLoweringResult with all updates - /// - /// # Arguments - /// - /// * `builder` - MirBuilder for code generation - /// * `scope` - Loop structure metadata - /// * `loop_cond` - Main loop condition (e.g., `start < end`) - /// * `break_cond` - Break condition from loop body - /// * `body` - Loop body AST nodes - /// * `loop_var_name` - Loop variable name (e.g., "start") - /// * `carrier_info` - Current carrier info (will be updated if Trim pattern) - /// * `alloc_join_value` - JoinIR ValueId allocator closure - /// - /// # Returns - /// - /// - `Ok(Some(TrimLoweringResult))` - Trim pattern detected and lowered - /// - `Ok(None)` - Not a Trim pattern (normal loop, no action taken) - /// - `Err(String)` - Trim pattern detected but lowering failed - /// - /// # Example - /// - /// ```ignore - /// if let Some(trim_result) = TrimLoopLowerer::try_lower_trim_like_loop( - /// self, - /// &scope, - /// condition, - /// &break_condition_node, - /// _body, - /// &loop_var_name, - /// &mut carrier_info, - /// &mut alloc_join_value, - /// )? { - /// // Use trim_result.condition, carrier_info, condition_bindings - /// } - /// ``` - pub fn try_lower_trim_like_loop( - builder: &mut MirBuilder, - scope: &LoopScopeShape, - loop_cond: &ASTNode, - break_cond: &ASTNode, - body: &[ASTNode], - loop_var_name: &str, - carrier_info: &mut CarrierInfo, - alloc_join_value: &mut dyn FnMut() -> ValueId, - ) -> Result, String> { - // Phase 180-2: Skeleton implementation - // TODO: Phase 180-3 will implement full logic from Pattern2 - - // Step 1: Check if condition references LoopBodyLocal variables - let cond_scope = LoopConditionScopeBox::analyze( - loop_var_name, - &[loop_cond, break_cond], - Some(scope), - ); - - eprintln!( - "[TrimLoopLowerer] Analyzing condition scope: {} variables", - cond_scope.vars.len() - ); - - if !cond_scope.has_loop_body_local() { - // Not a Trim pattern - normal loop - eprintln!("[TrimLoopLowerer] No LoopBodyLocal detected, skipping Trim lowering"); - return Ok(None); - } - - eprintln!("[TrimLoopLowerer] LoopBodyLocal detected in condition scope"); - - // Step 2: Try promotion via LoopBodyCarrierPromoter - let request = PromotionRequest { - scope, - cond_scope: &cond_scope, - break_cond: Some(break_cond), - loop_body: body, - }; - - match LoopBodyCarrierPromoter::try_promote(&request) { - PromotionResult::Promoted { trim_info } => { - eprintln!( - "[TrimLoopLowerer] LoopBodyLocal '{}' promoted to carrier '{}'", - trim_info.var_name, trim_info.carrier_name - ); - - // Step 3: Convert to CarrierInfo and merge - let promoted_carrier = trim_info.to_carrier_info(); - carrier_info.merge_from(&promoted_carrier); - - eprintln!( - "[TrimLoopLowerer] Merged carrier '{}' into CarrierInfo (total carriers: {})", - trim_info.carrier_name, - carrier_info.carrier_count() - ); - - // Step 4: Generate carrier initialization code - // TODO: Phase 180-3 will implement full logic - // For now, return minimal result to pass compilation - - // Placeholder: Return error to indicate incomplete implementation - return Err(format!( - "[TrimLoopLowerer] Phase 180-2 skeleton: Trim lowering not yet implemented (carrier: '{}')", - trim_info.carrier_name - )); - } - PromotionResult::CannotPromote { reason, vars } => { - // Phase 180: Fail-Fast on promotion failure - return Err(format!( - "[TrimLoopLowerer] Cannot promote LoopBodyLocal variables {:?}: {}", - vars, reason - )); - } - } - } - - // TODO: Phase 180-3 will add helper methods: - // - generate_carrier_initialization() - // - generate_trim_break_condition() - // - setup_condition_env_bindings() -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_trim_loop_lowerer_skeleton() { - // Phase 180-2: Basic existence test - // Full tests will be added in Phase 180-3 - assert!(true, "TrimLoopLowerer skeleton compiles"); - } -}