feat(phase143): Step 3 - Condition lowering integration with validation

Phase 143 P0 Step 3: Integrate NormalizedExprLowererBox for condition validation

- Extract If condition AST from loop(true) { if(cond) break } pattern
- Validate condition with PureOnly scope (variables, literals, arith, compare only)
- Return Ok(None) gracefully if condition is impure or out-of-scope
- Maintain skeleton structure: returns Ok(None) overall (full JoinModule in Steps 4-6)
- cargo check passes with no errors

Key changes:
- Updated extract_loop_true_if_break() to return condition AST
- Implemented validation using NormalizedExprLowererBox::lower_expr_with_scope()
- Proper error handling with fallback to Ok(None) for out-of-scope
- Debug logging for dev-only tracing

🤖 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:58:36 +09:00
parent 3f81640764
commit f55f6cc653

View File

@ -21,9 +21,13 @@
//! - Err(msg): In scope but failed (internal error, strict mode freeze)
use super::env_layout::EnvLayout;
use super::common::expr_lowerer_box::NormalizedExprLowererBox;
use super::common::expr_lowering_contract::ExprLoweringScope;
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;
use crate::mir::join_ir::{JoinFunction, JoinFuncId, JoinInst, JoinModule};
use crate::mir::ValueId;
use std::collections::BTreeMap;
/// Box-First: loop(true) + if + break lowering to Normalized
pub struct LoopTrueIfBreakContinueBuilderBox;
@ -42,12 +46,13 @@ impl LoopTrueIfBreakContinueBuilderBox {
}
// 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(_) => {
// Step 1: Extract pattern match
let cond_ast = match Self::extract_loop_true_if_break(&step_tree.root) {
Some(cond) => {
if crate::config::env::joinir_dev_enabled() {
eprintln!("[phase143/debug] Pattern matched: loop(true) if break");
}
cond
}
None => {
if crate::config::env::joinir_dev_enabled() {
@ -57,16 +62,62 @@ impl LoopTrueIfBreakContinueBuilderBox {
}
};
// Phase 143 P0: Skeleton returns Ok(None) for now
// Full implementation in Steps 2-6
// Step 3 (P0): Validate condition lowering with PureOnly scope
// This step checks if the condition can be lowered as a pure expression.
// We don't emit the actual JoinModule yet (that's Steps 4-6),
// but we verify early that the condition is in scope.
let env_fields = env_layout.env_fields();
let mut env_check: BTreeMap<String, ValueId> = BTreeMap::new();
// Build a dummy env for validation (temp ValueIds)
let mut temp_vid = 1u32;
for field in &env_fields {
env_check.insert(field.clone(), ValueId(temp_vid));
temp_vid += 1;
}
// Try to lower the condition with PureOnly scope
let mut dummy_body: Vec<JoinInst> = Vec::new();
let mut temp_next_vid = temp_vid;
match NormalizedExprLowererBox::lower_expr_with_scope(
ExprLoweringScope::PureOnly,
&cond_ast,
&env_check,
&mut dummy_body,
&mut temp_next_vid,
) {
Ok(Some(_vid)) => {
if crate::config::env::joinir_dev_enabled() {
eprintln!("[phase143/debug] Condition is pure and lowerable");
}
}
Ok(None) => {
if crate::config::env::joinir_dev_enabled() {
eprintln!("[phase143/debug] Condition is not pure (impure/out-of-scope), falling back to legacy");
}
return Ok(None); // Condition not pure, fallback to legacy
}
Err(e) => {
return Err(format!("phase143/condition_lowering: {}", e));
}
}
// Phase 143 P0: Skeleton continues to return Ok(None)
// Steps 4-6 will build the actual JoinModule with Jump instructions
if crate::config::env::joinir_dev_enabled() {
eprintln!("[phase143/debug] Step 3 validation passed, skeleton still returns Ok(None)");
}
Ok(None)
}
/// Extract loop(true) + single if + break pattern
///
/// Returns Some(()) if pattern matches, None otherwise.
/// Returns Some(cond_ast) if pattern matches, None otherwise.
/// Pattern: StepNode::Loop with body containing single If with break
fn extract_loop_true_if_break(root: &StepNode) -> Option<()> {
/// Also returns the If condition AST for lowering.
fn extract_loop_true_if_break(root: &StepNode) -> Option<crate::ast::ASTNode> {
match root {
StepNode::Loop { cond_ast, body, .. } => {
// Condition must be Bool(true) literal
@ -88,6 +139,7 @@ impl LoopTrueIfBreakContinueBuilderBox {
// If statement structure: if(cond_pure) { break }
if let StepNode::If {
cond_ast: if_cond,
then_branch,
else_branch,
..
@ -117,7 +169,7 @@ impl LoopTrueIfBreakContinueBuilderBox {
};
if has_break {
Some(()) // Pattern matched
Some((*if_cond.0).clone()) // Return If condition AST
} else {
None
}
@ -148,9 +200,9 @@ mod tests {
#[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(
assert!(LoopTrueIfBreakContinueBuilderBox::extract_loop_true_if_break(
&StepNode::Block(vec![])
), None);
).is_none());
}
#[test]