Skip to content

Commit 5d0cb9e

Browse files
asgerfCopilot
andcommitted
YEAST: fix one-shot rules for unnamed nodes and self-captures
One-shot desugaring rules now skip unnamed nodes (punctuation, keywords, etc.) since rules are intended to target named nodes only. Also prevent infinite recursion when a capture refers to the root node of the matched tree (e.g. an @_ capture on the pattern root). Additionally fix the swift.rs add_phase call to match the updated 3-arg signature introduced by the one-shot phase kind commit. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent bb9e996 commit 5d0cb9e

2 files changed

Lines changed: 19 additions & 2 deletions

File tree

shared/yeast/src/lib.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -703,6 +703,7 @@ fn apply_one_shot_rules_inner(
703703
fresh: &tree_builder::FreshScope,
704704
rewrite_depth: usize,
705705
) -> Result<Vec<Id>, String> {
706+
706707
if rewrite_depth > MAX_REWRITE_DEPTH {
707708
return Err(format!(
708709
"Desugaring exceeded maximum rewrite depth ({MAX_REWRITE_DEPTH}). \
@@ -711,13 +712,29 @@ fn apply_one_shot_rules_inner(
711712
}
712713

713714
let node_kind = ast.get_node(id).map(|n| n.kind()).unwrap_or("");
715+
716+
// Don't rewrite unnamed nodes (punctuation, keywords, etc.); leave them
717+
// as-is. Rules target named nodes only.
718+
if let Some(node) = ast.get_node(id) {
719+
if !node.is_named() {
720+
return Ok(vec![id]);
721+
}
722+
}
723+
714724
for rule in index.rules_for_kind(node_kind) {
715725
if let Some(mut captures) = rule.try_match(ast, id)? {
716726
// Recursively translate every captured node before invoking the
717727
// transform. The transform's output uses output-schema kinds, so
718728
// we must translate captured input-schema nodes to their
719729
// output-schema equivalents first.
720730
captures.try_map_all_captures(|captured_id| {
731+
// Avoid infinite recursion when a capture refers to the root
732+
// node of the matched tree (e.g. an `@_` capture on the
733+
// pattern root): re-analyzing it would match the same rule
734+
// again indefinitely.
735+
if captured_id == id {
736+
return Ok(captured_id);
737+
}
721738
let result =
722739
apply_one_shot_rules_inner(index, ast, captured_id, fresh, rewrite_depth + 1)?;
723740
if result.len() != 1 {

unified/extractor/src/languages/swift/swift.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use codeql_extractor::extractor::simple;
2-
use yeast::{rule, DesugaringConfig};
2+
use yeast::{rule, DesugaringConfig, PhaseKind};
33

44
fn desugaring_rules() -> Vec<yeast::Rule> {
55
vec![
@@ -12,7 +12,7 @@ fn desugaring_rules() -> Vec<yeast::Rule> {
1212
}
1313

1414
pub fn language_spec() -> simple::LanguageSpec {
15-
let desugar = DesugaringConfig::new().add_phase("desugar", desugaring_rules());
15+
let desugar = DesugaringConfig::new().add_phase("desugar", PhaseKind::Repeating, desugaring_rules());
1616
simple::LanguageSpec {
1717
prefix: "swift",
1818
ts_language: tree_sitter_swift::LANGUAGE.into(),

0 commit comments

Comments
 (0)