diff --git a/shared/yeast-macros/src/parse.rs b/shared/yeast-macros/src/parse.rs index eb864c55d5c..6987ee79e82 100644 --- a/shared/yeast-macros/src/parse.rs +++ b/shared/yeast-macros/src/parse.rs @@ -630,11 +630,12 @@ pub fn parse_rule_top(input: TokenStream) -> Result { .unwrap_or_else(|| panic!("node kind '{}' not found", #output_kind_str)); let mut __fields = std::collections::BTreeMap::new(); #(#field_stmts)* - let __id = #ctx_ident.ast.create_node( + let __id = #ctx_ident.ast.create_node_with_range( __kind, yeast::NodeContent::DynamicString(String::new()), __fields, true, + __source_range, ); vec![__id] } diff --git a/shared/yeast/src/lib.rs b/shared/yeast/src/lib.rs index 539757dfa67..5d909a9f078 100644 --- a/shared/yeast/src/lib.rs +++ b/shared/yeast/src/lib.rs @@ -556,16 +556,16 @@ impl Rule { } } -const MAX_RULE_DEPTH: usize = 100; +const MAX_REWRITE_DEPTH: usize = 100; fn apply_rules(rules: &Vec, ast: &mut Ast, id: Id, fresh: &tree_builder::FreshScope) -> Result, String> { apply_rules_inner(rules, ast, id, fresh, 0) } -fn apply_rules_inner(rules: &Vec, ast: &mut Ast, id: Id, fresh: &tree_builder::FreshScope, depth: usize) -> Result, String> { - if depth > MAX_RULE_DEPTH { +fn apply_rules_inner(rules: &Vec, ast: &mut Ast, id: Id, fresh: &tree_builder::FreshScope, rewrite_depth: usize) -> Result, String> { + if rewrite_depth > MAX_REWRITE_DEPTH { return Err(format!( - "Desugaring exceeded maximum depth ({MAX_RULE_DEPTH}). \ + "Desugaring exceeded maximum rewrite depth ({MAX_REWRITE_DEPTH}). \ This likely indicates a non-terminating rule cycle." )); } @@ -574,7 +574,8 @@ fn apply_rules_inner(rules: &Vec, ast: &mut Ast, id: Id, fresh: &tree_buil if let Some(result_node) = rule.try_rule(ast, id, fresh)? { let mut results = Vec::new(); for node in result_node { - results.extend(apply_rules_inner(rules, ast, node, fresh, depth + 1)?); + // Increment depth only when re-processing rule output + results.extend(apply_rules_inner(rules, ast, node, fresh, rewrite_depth + 1)?); } return Ok(results); } @@ -583,6 +584,7 @@ fn apply_rules_inner(rules: &Vec, ast: &mut Ast, id: Id, fresh: &tree_buil let mut node = ast.nodes[id].clone(); // recursively descend into all the fields + // Child traversal does not increment rewrite depth for vec in node.fields.values_mut() { let old = std::mem::take(vec); let mut new = Vec::new(); diff --git a/shared/yeast/src/query.rs b/shared/yeast/src/query.rs index 04f7aed89b1..87535940809 100644 --- a/shared/yeast/src/query.rs +++ b/shared/yeast/src/query.rs @@ -125,11 +125,18 @@ impl QueryListElem { loop { let matches_initial = matches.clone(); let start = remaining_children.clone(); + let start_next = start.clone().next(); if !match_children(children.iter(), ast, remaining_children, matches)? { *remaining_children = start; *matches = matches_initial; break; } + // Guard against zero-width matches: if the iterator + // didn't advance, break to avoid infinite looping. + let current_next = remaining_children.clone().next(); + if start_next == current_next { + break; + } iters += 1; if *rep == Rep::ZeroOrOne { break;