feat(normalization): Phase 143 P0 Step 1-2 - Pattern detection skeleton + routing
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:
2025-12-19 05:52:19 +09:00
parent af2a5e27d6
commit 3f81640764
3 changed files with 177 additions and 0 deletions

View File

@ -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::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_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::post_if_post_k::PostIfPostKBuilderBox; // Phase 129-C
use crate::mir::control_tree::normalized_shadow::legacy::LegacyLowerer; use crate::mir::control_tree::normalized_shadow::legacy::LegacyLowerer;
use crate::mir::control_tree::step_tree::StepTree; use crate::mir::control_tree::step_tree::StepTree;
@ -98,6 +99,11 @@ impl StepTreeNormalizedShadowLowererBox {
return Ok(Some((module, meta))); 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)) // Not supported: fall back to legacy (returns Ok(None))
Ok(None) Ok(None)
} }

View File

@ -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));
}
}

View File

@ -35,6 +35,7 @@ pub mod normalized_verifier;
pub mod env_layout; pub mod env_layout;
pub mod if_as_last_join_k; pub mod if_as_last_join_k;
pub mod loop_true_break_once; // Phase 131: loop(true) break-once 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 post_if_post_k; // Phase 129-C: post-if with post_k continuation
pub mod legacy; pub mod legacy;
pub mod dev_pipeline; pub mod dev_pipeline;