feat(normalization): Phase 143 P0 Step 1-2 - Pattern detection skeleton + routing
Some checks are pending
fast-smoke / fast (push) Waiting to run
Some checks are pending
fast-smoke / fast (push) Waiting to run
Phase 143-loopvocab P0: Steps 1-2 complete
Step 1: Pattern detection skeleton
- New file: src/mir/control_tree/normalized_shadow/loop_true_if_break_continue.rs
- Implements extract_loop_true_if_break() for pattern recognition
- Returns Ok(None) for minimal P0 scope (loop(true){ if(cond_pure) break } only)
- Unit tests for pattern detection and literal checks
Step 2: Routing integration
- Added module declaration in mod.rs
- Added import and routing in builder.rs
- Priority: Phase 131 (loop_true_break_once) → Phase 143 P0 (loop_true_if_break_continue) → Legacy
Status: Skeleton compiles ✅ (cargo check passes)
- Full JoinIR generation deferred to Steps 3-6
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
@ -12,6 +12,7 @@ use crate::mir::control_tree::normalized_shadow::env_layout::{
|
||||
};
|
||||
use crate::mir::control_tree::normalized_shadow::if_as_last_join_k::IfAsLastJoinKLowererBox;
|
||||
use crate::mir::control_tree::normalized_shadow::loop_true_break_once::LoopTrueBreakOnceBuilderBox; // Phase 131
|
||||
use crate::mir::control_tree::normalized_shadow::loop_true_if_break_continue::LoopTrueIfBreakContinueBuilderBox; // Phase 143 P0
|
||||
use crate::mir::control_tree::normalized_shadow::post_if_post_k::PostIfPostKBuilderBox; // Phase 129-C
|
||||
use crate::mir::control_tree::normalized_shadow::legacy::LegacyLowerer;
|
||||
use crate::mir::control_tree::step_tree::StepTree;
|
||||
@ -98,6 +99,11 @@ impl StepTreeNormalizedShadowLowererBox {
|
||||
return Ok(Some((module, meta)));
|
||||
}
|
||||
|
||||
// Phase 143 P0: loop(true) + if + break pattern
|
||||
if let Some((module, meta)) = LoopTrueIfBreakContinueBuilderBox::lower(step_tree, &env_layout)? {
|
||||
return Ok(Some((module, meta)));
|
||||
}
|
||||
|
||||
// Not supported: fall back to legacy (returns Ok(None))
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
@ -0,0 +1,170 @@
|
||||
//! Phase 143 P0: loop(true) + if + break Normalized lowering
|
||||
//!
|
||||
//! ## Responsibility
|
||||
//!
|
||||
//! - Lower `loop(true) { if(cond_pure) break }` to Normalized JoinModule
|
||||
//! - Conditional exit control flow (Branch instructions)
|
||||
//! - PHI-free: all state passing via env arguments + continuations
|
||||
//! - Pure condition expressions only (Phase 143 P0 scope)
|
||||
//!
|
||||
//! ## Scope (P0)
|
||||
//!
|
||||
//! - Loop condition: `true` literal only
|
||||
//! - Loop body: Single `if` statement only
|
||||
//! - If branch: `break` only (no continue, no else)
|
||||
//! - Condition expression: Pure only (variables, literals, arith, compare)
|
||||
//!
|
||||
//! ## Return Behavior
|
||||
//!
|
||||
//! - Ok(Some((module, meta))): Successfully lowered
|
||||
//! - Ok(None): Out of scope (fallback to legacy)
|
||||
//! - Err(msg): In scope but failed (internal error, strict mode freeze)
|
||||
|
||||
use super::env_layout::EnvLayout;
|
||||
use crate::mir::control_tree::step_tree::{StepNode, StepStmtKind, StepTree};
|
||||
use crate::mir::join_ir::lowering::carrier_info::JoinFragmentMeta;
|
||||
use crate::mir::join_ir::JoinModule;
|
||||
|
||||
/// Box-First: loop(true) + if + break lowering to Normalized
|
||||
pub struct LoopTrueIfBreakContinueBuilderBox;
|
||||
|
||||
impl LoopTrueIfBreakContinueBuilderBox {
|
||||
/// Try to lower loop(true) + if + break pattern to Normalized JoinModule.
|
||||
///
|
||||
/// Phase 143 P0: Minimal scope - loop(true){ if(cond) break } only
|
||||
pub fn lower(
|
||||
step_tree: &StepTree,
|
||||
env_layout: &EnvLayout,
|
||||
) -> Result<Option<(JoinModule, JoinFragmentMeta)>, String> {
|
||||
// DEBUG: Log attempt
|
||||
if crate::config::env::joinir_dev_enabled() {
|
||||
eprintln!("[phase143/debug] Attempting loop_true_if_break pattern (P0 minimal scope)");
|
||||
}
|
||||
|
||||
// Pattern: loop(true) { if(cond) break }
|
||||
// Extract must succeed for this phase to proceed
|
||||
let _extracted = match Self::extract_loop_true_if_break(&step_tree.root) {
|
||||
Some(_) => {
|
||||
if crate::config::env::joinir_dev_enabled() {
|
||||
eprintln!("[phase143/debug] Pattern matched: loop(true) if break");
|
||||
}
|
||||
}
|
||||
None => {
|
||||
if crate::config::env::joinir_dev_enabled() {
|
||||
eprintln!("[phase143/debug] Pattern not matched, out of scope");
|
||||
}
|
||||
return Ok(None); // Out of scope
|
||||
}
|
||||
};
|
||||
|
||||
// Phase 143 P0: Skeleton returns Ok(None) for now
|
||||
// Full implementation in Steps 2-6
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
/// Extract loop(true) + single if + break pattern
|
||||
///
|
||||
/// Returns Some(()) if pattern matches, None otherwise.
|
||||
/// Pattern: StepNode::Loop with body containing single If with break
|
||||
fn extract_loop_true_if_break(root: &StepNode) -> Option<()> {
|
||||
match root {
|
||||
StepNode::Loop { cond_ast, body, .. } => {
|
||||
// Condition must be Bool(true) literal
|
||||
if !Self::is_bool_true_literal(&cond_ast.0) {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Body must be single if statement (possibly wrapped in Block)
|
||||
let if_node = match body.as_ref() {
|
||||
StepNode::If { .. } => Some(body.as_ref()),
|
||||
StepNode::Block(stmts) if stmts.len() == 1 => {
|
||||
match &stmts[0] {
|
||||
StepNode::If { .. } => Some(&stmts[0]),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
}?;
|
||||
|
||||
// If statement structure: if(cond_pure) { break }
|
||||
if let StepNode::If {
|
||||
then_branch,
|
||||
else_branch,
|
||||
..
|
||||
} = if_node
|
||||
{
|
||||
// Phase 143 P0: no else branch allowed
|
||||
if else_branch.is_some() {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Then branch must be Break statement
|
||||
let has_break = match then_branch.as_ref() {
|
||||
StepNode::Stmt {
|
||||
kind: StepStmtKind::Break,
|
||||
..
|
||||
} => true,
|
||||
StepNode::Block(stmts) if stmts.len() == 1 => {
|
||||
matches!(
|
||||
&stmts[0],
|
||||
StepNode::Stmt {
|
||||
kind: StepStmtKind::Break,
|
||||
..
|
||||
}
|
||||
)
|
||||
}
|
||||
_ => false,
|
||||
};
|
||||
|
||||
if has_break {
|
||||
Some(()) // Pattern matched
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if AST node is Bool(true) literal
|
||||
fn is_bool_true_literal(ast: &crate::ast::ASTNode) -> bool {
|
||||
matches!(
|
||||
ast,
|
||||
crate::ast::ASTNode::Literal {
|
||||
value: crate::ast::LiteralValue::Bool(true),
|
||||
..
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_pattern_detection_out_of_scope_no_loop() {
|
||||
// If pattern is not loop, should return None
|
||||
assert_eq!(LoopTrueIfBreakContinueBuilderBox::extract_loop_true_if_break(
|
||||
&StepNode::Block(vec![])
|
||||
), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_bool_true_literal() {
|
||||
let true_lit = crate::ast::ASTNode::Literal {
|
||||
value: crate::ast::LiteralValue::Bool(true),
|
||||
span: (0, 0),
|
||||
};
|
||||
assert!(LoopTrueIfBreakContinueBuilderBox::is_bool_true_literal(&true_lit));
|
||||
|
||||
let false_lit = crate::ast::ASTNode::Literal {
|
||||
value: crate::ast::LiteralValue::Bool(false),
|
||||
span: (0, 0),
|
||||
};
|
||||
assert!(!LoopTrueIfBreakContinueBuilderBox::is_bool_true_literal(&false_lit));
|
||||
}
|
||||
}
|
||||
@ -35,6 +35,7 @@ pub mod normalized_verifier;
|
||||
pub mod env_layout;
|
||||
pub mod if_as_last_join_k;
|
||||
pub mod loop_true_break_once; // Phase 131: loop(true) break-once
|
||||
pub mod loop_true_if_break_continue; // Phase 143 P0: loop(true) + if + break
|
||||
pub mod post_if_post_k; // Phase 129-C: post-if with post_k continuation
|
||||
pub mod legacy;
|
||||
pub mod dev_pipeline;
|
||||
|
||||
Reference in New Issue
Block a user