feat(joinir): Phase 92 P0-3 - ConditionalStep → JoinIR Select generation
Complete implementation of P5b escape sequence handling pattern lowering: Core changes: - skeleton_types.rs: Add `cond` field to ConditionalStep for escape condition - escape_pattern_recognizer.rs: Extract and return escape_cond AST - pattern_recognizer.rs: Pass escape_cond to ConditionalStep - canonicalizer.rs: Store escape_cond in ConditionalStep variant JoinIR lowering: - carrier_update_emitter.rs: Add emit_conditional_step_update() function - Lower condition AST via lower_condition_to_joinir - Compute both then/else branches (carrier + delta) - Emit JoinInst::Select for conditional carrier update - loop_with_break_minimal.rs: Add skeleton parameter, detect ConditionalStep - pattern2_with_break.rs: Pass skeleton to lowering function Backward compatibility: - skeleton=None preserves existing Pattern1-4 behavior - fixtures.rs, tests.rs updated for new signature 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@ -20,6 +20,9 @@ pub struct EscapeSkipPatternInfo {
|
||||
pub quote_char: char,
|
||||
pub escape_char: char,
|
||||
pub body_stmts: Vec<ASTNode>,
|
||||
/// Phase 92 P0-3: The condition expression for conditional increment
|
||||
/// e.g., `ch == '\\'` for escape sequence handling
|
||||
pub escape_cond: Box<ASTNode>,
|
||||
}
|
||||
|
||||
/// Detect escape sequence handling pattern in loop body
|
||||
@ -57,8 +60,9 @@ pub fn detect_escape_skip_pattern(body: &[ASTNode]) -> Option<EscapeSkipPatternI
|
||||
// Find escape check after break - scan for second "if" with increment
|
||||
let escape_idx = find_escape_in_if(body, break_idx)?;
|
||||
|
||||
// Extract counter_name, escape_delta, and normal_delta from the escape if statement
|
||||
let (counter_name, escape_delta, normal_delta) = extract_delta_pair_from_if(body, escape_idx)?;
|
||||
// Extract counter_name, escape_delta, normal_delta, and condition from the escape if statement
|
||||
// Phase 92 P0-3: Now also extracts condition expression
|
||||
let (counter_name, escape_delta, normal_delta, escape_cond) = extract_delta_pair_from_if(body, escape_idx)?;
|
||||
|
||||
// Extract body statements before break check
|
||||
let body_stmts = body[..break_idx].to_vec();
|
||||
@ -70,6 +74,7 @@ pub fn detect_escape_skip_pattern(body: &[ASTNode]) -> Option<EscapeSkipPatternI
|
||||
quote_char: '"', // Default for JSON/CSV (Phase 91 MVP)
|
||||
escape_char: '\\', // Default for JSON/CSV (Phase 91 MVP)
|
||||
body_stmts,
|
||||
escape_cond, // Phase 92 P0-3: Condition for JoinIR Select
|
||||
})
|
||||
}
|
||||
|
||||
@ -139,17 +144,20 @@ fn find_escape_in_if(body: &[ASTNode], after_idx: usize) -> Option<usize> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Extract both escape_delta and normal_delta from if statement
|
||||
/// Extract escape_delta, normal_delta, and condition from if statement
|
||||
///
|
||||
/// Handles both:
|
||||
/// - if ch == escape_char { i = i + 2 } else { i = i + 1 }
|
||||
/// - if ch == escape_char { i = i + 2 } (followed by separate increment)
|
||||
fn extract_delta_pair_from_if(body: &[ASTNode], idx: usize) -> Option<(String, i64, i64)> {
|
||||
///
|
||||
/// Phase 92 P0-3: Now returns the condition expression for JoinIR Select generation
|
||||
fn extract_delta_pair_from_if(body: &[ASTNode], idx: usize) -> Option<(String, i64, i64, Box<ASTNode>)> {
|
||||
if idx >= body.len() {
|
||||
return None;
|
||||
}
|
||||
|
||||
if let ASTNode::If {
|
||||
condition,
|
||||
then_body,
|
||||
else_body,
|
||||
..
|
||||
@ -204,7 +212,8 @@ fn extract_delta_pair_from_if(body: &[ASTNode], idx: usize) -> Option<(String, i
|
||||
found_delta?
|
||||
};
|
||||
|
||||
Some((counter_name, escape_delta, normal_delta))
|
||||
// Phase 92 P0-3: Return condition along with deltas
|
||||
Some((counter_name, escape_delta, normal_delta, condition.clone()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
||||
@ -717,6 +717,7 @@ pub(crate) fn can_lower(builder: &MirBuilder, ctx: &super::router::LoopPatternCo
|
||||
///
|
||||
/// Wrapper around cf_loop_pattern2_with_break to match router signature
|
||||
/// Phase 200-C: Pass fn_body to cf_loop_pattern2_with_break
|
||||
/// Phase 92 P0-3: Pass skeleton for ConditionalStep support
|
||||
pub(crate) fn lower(
|
||||
builder: &mut MirBuilder,
|
||||
ctx: &super::router::LoopPatternContext,
|
||||
@ -727,6 +728,7 @@ pub(crate) fn lower(
|
||||
ctx.func_name,
|
||||
ctx.debug,
|
||||
ctx.fn_body,
|
||||
ctx.skeleton, // Phase 92 P0-3: Pass skeleton for ConditionalStep
|
||||
)
|
||||
}
|
||||
|
||||
@ -735,6 +737,7 @@ impl MirBuilder {
|
||||
///
|
||||
/// **Refactored**: Now uses PatternPipelineContext for unified preprocessing
|
||||
/// **Phase 200-C**: Added fn_body parameter for capture analysis
|
||||
/// **Phase 92 P0-3**: Added skeleton parameter for ConditionalStep support
|
||||
///
|
||||
/// # Pipeline (Phase 179-B)
|
||||
/// 1. Build preprocessing context → PatternPipelineContext
|
||||
@ -754,10 +757,12 @@ impl MirBuilder {
|
||||
debug: bool,
|
||||
) -> Result<Option<ValueId>, String> {
|
||||
// Phase 200-C: Delegate to impl function with fn_body=None for backward compatibility
|
||||
self.cf_loop_pattern2_with_break_impl(condition, _body, _func_name, debug, None)
|
||||
// Phase 92 P0-3: skeleton=None for backward compatibility
|
||||
self.cf_loop_pattern2_with_break_impl(condition, _body, _func_name, debug, None, None)
|
||||
}
|
||||
|
||||
/// Phase 200-C: Pattern 2 implementation with optional fn_body for capture analysis
|
||||
/// Phase 92 P0-3: Added skeleton parameter for ConditionalStep support
|
||||
fn cf_loop_pattern2_with_break_impl(
|
||||
&mut self,
|
||||
condition: &ASTNode,
|
||||
@ -765,6 +770,7 @@ impl MirBuilder {
|
||||
_func_name: &str,
|
||||
debug: bool,
|
||||
fn_body: Option<&[ASTNode]>,
|
||||
skeleton: Option<&crate::mir::loop_canonicalizer::LoopSkeleton>,
|
||||
) -> Result<Option<ValueId>, String> {
|
||||
use crate::mir::join_ir::lowering::loop_with_break_minimal::lower_loop_with_break_minimal;
|
||||
|
||||
@ -869,6 +875,7 @@ impl MirBuilder {
|
||||
analysis_body, // Phase 191/192: Pass normalized body AST for init lowering
|
||||
Some(&mut inputs.body_local_env), // Phase 191: Pass mutable body-local environment
|
||||
&mut inputs.join_value_space, // Phase 201: Unified ValueId allocation (Local region)
|
||||
skeleton, // Phase 92 P0-3: Pass skeleton for ConditionalStep support
|
||||
) {
|
||||
Ok((module, meta)) => (module, meta),
|
||||
Err(e) => {
|
||||
|
||||
Reference in New Issue
Block a user