fix(joinir): wire balanced depth-scan policy through Pattern2

This commit is contained in:
nyash-codex
2025-12-17 22:47:36 +09:00
parent 9ec2e28b6a
commit d8ce9fdb99
4 changed files with 121 additions and 29 deletions

View File

@ -476,6 +476,7 @@ fn eq_int(left: ASTNode, n: i64) -> ASTNode {
mod tests {
use super::*;
use crate::ast::Span;
use crate::parser::NyashParser;
fn span() -> Span {
Span::unknown()
@ -520,6 +521,46 @@ mod tests {
}
}
fn find_first_loop<'a>(node: &'a ASTNode) -> Option<(&'a ASTNode, &'a [ASTNode])> {
match node {
ASTNode::Loop { condition, body, .. } => Some((condition.as_ref(), body.as_slice())),
ASTNode::Program { statements, .. } => statements.iter().find_map(find_first_loop),
ASTNode::BoxDeclaration {
methods,
constructors,
static_init,
..
} => {
for v in methods.values() {
if let Some(found) = find_first_loop(v) {
return Some(found);
}
}
for v in constructors.values() {
if let Some(found) = find_first_loop(v) {
return Some(found);
}
}
if let Some(init) = static_init {
if let Some(found) = init.iter().find_map(find_first_loop) {
return Some(found);
}
}
None
}
ASTNode::FunctionDeclaration { body, .. } => body.iter().find_map(find_first_loop),
ASTNode::If {
then_body,
else_body,
..
} => then_body
.iter()
.find_map(find_first_loop)
.or_else(|| else_body.as_ref()?.iter().find_map(find_first_loop)),
_ => None,
}
}
#[test]
fn detects_balanced_array_end_min_shape() {
// loop(i < n) {
@ -584,4 +625,29 @@ mod tests {
assert!(result.carrier_updates_override.contains_key("i"));
assert!(result.carrier_updates_override.contains_key("depth"));
}
#[test]
fn detects_balanced_array_end_min_shape_from_parser_ast() {
let src = r#"
static box Main {
f(s, idx) {
local n = s.length()
if s.substring(idx, idx+1) != "[" { return -1 }
local depth = 0
local i = idx
loop (i < n) {
local ch = s.substring(i, i+1)
if ch == "[" { depth = depth + 1 }
if ch == "]" { depth = depth - 1 if depth == 0 { return i } }
i = i + 1
}
return -1
}
}
"#;
let ast = NyashParser::parse_from_string(src).expect("parse ok");
let (condition, body) = find_first_loop(&ast).expect("find loop");
let decision = classify_balanced_depth_scan_array_end(condition, body);
assert!(matches!(decision, PolicyDecision::Use(_)), "got {:?}", decision);
}
}