refactor(joinir): split Pattern2 orchestrator into smaller steps

This commit is contained in:
nyash-codex
2025-12-18 00:44:31 +09:00
parent e4735f4054
commit 9bcda215f8
7 changed files with 268 additions and 181 deletions

View File

@ -29,12 +29,26 @@ pub fn classify_p5b_escape_derived(
body: &[ASTNode],
loop_var_name: &str,
) -> P5bEscapeDerivedDecision {
let strict = joinir_dev::strict_enabled();
let has_ch_init = find_local_init_expr(body, "ch").is_some();
let has_ch_reassign = has_assignment_to_var(body, "ch");
let Some(info) = super::super::ast_feature_extractor::detect_escape_skip_pattern(body) else {
if strict && has_ch_init && has_ch_reassign {
return P5bEscapeDerivedDecision::Reject(error_tags::freeze(
"[phase94/body_local_derived/contract/unhandled_reassign] Body-local reassignment to 'ch' detected but escape shape is not recognized",
));
}
return P5bEscapeDerivedDecision::None;
};
if info.counter_name != loop_var_name {
// Not the loop counter we lower as the JoinIR loop var; ignore to avoid misrouting.
if strict && has_ch_init && has_ch_reassign {
return P5bEscapeDerivedDecision::Reject(error_tags::freeze(
"[phase94/body_local_derived/contract/loop_counter_mismatch] Body-local reassignment to 'ch' detected but loop counter does not match Pattern2 loop var",
));
}
return P5bEscapeDerivedDecision::None;
}
@ -55,6 +69,29 @@ pub fn classify_p5b_escape_derived(
}
}
fn has_assignment_to_var(body: &[ASTNode], name: &str) -> bool {
fn node_has_assignment(node: &ASTNode, name: &str) -> bool {
match node {
ASTNode::Assignment { target, .. } => is_var_named(target.as_ref(), name),
ASTNode::If {
then_body,
else_body,
..
} => {
then_body.iter().any(|n| node_has_assignment(n, name))
|| else_body
.as_ref()
.map_or(false, |e| e.iter().any(|n| node_has_assignment(n, name)))
}
ASTNode::Loop { body, .. } => body.iter().any(|n| node_has_assignment(n, name)),
ASTNode::ScopeBox { body, .. } => body.iter().any(|n| node_has_assignment(n, name)),
_ => false,
}
}
body.iter().any(|n| node_has_assignment(n, name))
}
fn build_recipe_from_info(
body: &[ASTNode],
info: &EscapeSkipPatternInfo,