refactor(mir): phase260 p0.1 strangler hardening + smoke fixtures
This commit is contained in:
@ -10,6 +10,8 @@
|
||||
//! silently fall back to an unrelated route.
|
||||
|
||||
use crate::ast::ASTNode;
|
||||
use crate::ast::UnaryOperator;
|
||||
use crate::ast::LiteralValue;
|
||||
use crate::mir::loop_pattern_detection::break_condition_analyzer::BreakConditionAnalyzer;
|
||||
|
||||
use super::policies::{loop_true_read_digits_policy, PolicyDecision};
|
||||
@ -24,6 +26,21 @@ pub(crate) struct Pattern2BreakConditionRouting {
|
||||
pub(crate) struct Pattern2BreakConditionPolicyRouterBox;
|
||||
|
||||
impl Pattern2BreakConditionPolicyRouterBox {
|
||||
fn negate_condition(condition: &ASTNode) -> ASTNode {
|
||||
match condition {
|
||||
ASTNode::UnaryOp {
|
||||
operator: UnaryOperator::Not,
|
||||
operand,
|
||||
..
|
||||
} => operand.as_ref().clone(),
|
||||
other => ASTNode::UnaryOp {
|
||||
operator: UnaryOperator::Not,
|
||||
operand: Box::new(other.clone()),
|
||||
span: other.span(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn route(condition: &ASTNode, body: &[ASTNode]) -> Result<Pattern2BreakConditionRouting, String> {
|
||||
// loop(true) read-digits family:
|
||||
// - multiple breaks exist; normalize as:
|
||||
@ -36,7 +53,24 @@ impl Pattern2BreakConditionPolicyRouterBox {
|
||||
}),
|
||||
PolicyDecision::Reject(reason) => Err(format!("[cf_loop/pattern2] {}", reason)),
|
||||
PolicyDecision::None => Ok(Pattern2BreakConditionRouting {
|
||||
// Phase 260 P0.1: If the loop has an explicit header condition and the body
|
||||
// does not contain a top-level break-guard pattern, the exit condition is
|
||||
// structurally derived as `!(loop_condition)`.
|
||||
break_condition_node: BreakConditionAnalyzer::extract_break_condition_node(body)
|
||||
.or_else(|_| {
|
||||
if matches!(
|
||||
condition,
|
||||
ASTNode::Literal {
|
||||
value: LiteralValue::Bool(true),
|
||||
..
|
||||
}
|
||||
) {
|
||||
Err("[cf_loop/pattern2] loop(true) requires a break guard pattern"
|
||||
.to_string())
|
||||
} else {
|
||||
Ok(Self::negate_condition(condition))
|
||||
}
|
||||
})
|
||||
.map_err(|_| {
|
||||
"[cf_loop/pattern2] Failed to extract break condition from loop body".to_string()
|
||||
})?,
|
||||
@ -46,4 +80,3 @@ impl Pattern2BreakConditionPolicyRouterBox {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -853,15 +853,15 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_is_const_step_pattern_negative() {
|
||||
// i - 1
|
||||
// i - j (non-const step)
|
||||
let value = ASTNode::BinaryOp {
|
||||
operator: BinaryOperator::Subtract,
|
||||
left: Box::new(ASTNode::Variable {
|
||||
name: "i".to_string(),
|
||||
span: Span::unknown(),
|
||||
}),
|
||||
right: Box::new(ASTNode::Literal {
|
||||
value: LiteralValue::Integer(1),
|
||||
right: Box::new(ASTNode::Variable {
|
||||
name: "j".to_string(),
|
||||
span: Span::unknown(),
|
||||
}),
|
||||
span: Span::unknown(),
|
||||
|
||||
Reference in New Issue
Block a user