yeast: Fix bug in matching (_)

Turns out, `(_)` would match both named and unnamed nodes, as we never
checked the value of the `match_unnamed` field. This is the real reason
why the final catch-all rule we removed in the last commit was
superfluous -- unnamed nodes were being caught by the penultimate rule
instead (and mapped to `unsupported_node`).

Having fixed the bug, we now (correctly) get errors due to unmatched
unnamed nodes in the input. To fix this, we change the catch-all rule to
match unnamed nodes as well. This restores the previous behaviour
exactly.

At some point, we should find a better way to handle unnamed nodes, as
it seems wasteful to map these to `unsupported_node` (since we in
practice only use them for their string content). Perhaps we should not
attempt to translate unnamed nodes at all?
This commit is contained in:
Taus
2026-07-02 12:57:43 +00:00
parent ee04938ded
commit 11afcce8b3
2 changed files with 19 additions and 2 deletions

View File

@@ -66,7 +66,17 @@ impl QueryNode {
pub fn do_match(&self, ast: &Ast, node: Id, matches: &mut Captures) -> Result<bool, String> {
match self {
QueryNode::Any { .. } => Ok(true),
QueryNode::Any { match_unnamed } => {
if *match_unnamed {
Ok(true)
} else {
// `(_)` only matches named nodes, matching tree-sitter
// semantics. Bare `_` (with `match_unnamed = true`)
// matches any node.
let n = ast.get_node(node).unwrap();
Ok(n.is_named())
}
}
QueryNode::Node { kind, children } => {
let node = ast.get_node(node).unwrap();
let target_kind = ast

View File

@@ -1215,8 +1215,15 @@ fn translation_rules() -> Vec<Rule<SwiftContext>> {
// Preprocessor conditionals — unsupported
rule!((diagnostic) => (unsupported_node)),
// ---- Fallbacks ----
// Bare `_` (rather than `(_)`) so this matches both named nodes
// and unnamed tokens. Any unnamed token that escapes the
// input-schema-specific rules (e.g. captured operators in
// `additive_expression op: @op`) has its auto-translated value
// replaced with an `unsupported_node` whose source range is
// inherited from the original token, so `#{op}` still reads the
// original text.
rule!(
(_)
_
=>
(unsupported_node)
),