feat(joinir): Add TrimLoopLowerer skeleton for P5 module
Phase 180-2: Create dedicated Trim/CharComparison lowering module - New module: src/mir/join_ir/lowering/trim_loop_lowering.rs - TrimLoopLowerer::try_lower_trim_like_loop() skeleton - Integrates LoopConditionScopeBox + LoopBodyCarrierPromoter - Returns TrimLoweringResult with updated condition/carrier/bindings - TODO: Phase 180-3 will implement full logic from Pattern2
This commit is contained in:
@ -60,6 +60,7 @@ pub mod skip_ws;
|
|||||||
pub mod stage1_using_resolver;
|
pub mod stage1_using_resolver;
|
||||||
pub mod stageb_body;
|
pub mod stageb_body;
|
||||||
pub mod stageb_funcscanner;
|
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_hint_policy; // Phase 65.5: 型ヒントポリシー箱化
|
||||||
pub mod type_inference; // Phase 65-2-A
|
pub mod type_inference; // Phase 65-2-A
|
||||||
pub(crate) mod value_id_ranges; // Internal ValueId range management
|
pub(crate) mod value_id_ranges; // Internal ValueId range management
|
||||||
|
|||||||
221
src/mir/join_ir/lowering/trim_loop_lowering.rs
Normal file
221
src/mir/join_ir/lowering/trim_loop_lowering.rs
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
//! 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<ConditionBinding>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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<Option<TrimLoweringResult>, 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");
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user