Skip to content

Commit ddc9516

Browse files
committed
Yeast: better support for rewriting unnamed nodes
- Ensure the full wildcard _ supports quantifiers - Also rewrite unnamed nodes in one-shot phases
1 parent 0006894 commit ddc9516

3 files changed

Lines changed: 30 additions & 10 deletions

File tree

shared/yeast-macros/src/parse.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ fn parse_query_list(tokens: &mut Tokens) -> Result<Vec<TokenStream>> {
259259
yeast::query::QueryListElem::SingleNode(#node)
260260
},
261261
)?;
262+
let elem = maybe_wrap_list_capture(tokens, elem)?;
262263
elems.push(elem);
263264
continue;
264265
}
@@ -276,6 +277,7 @@ fn parse_query_list(tokens: &mut Tokens) -> Result<Vec<TokenStream>> {
276277
yeast::query::QueryListElem::SingleNode(#node)
277278
},
278279
)?;
280+
let elem = maybe_wrap_list_capture(tokens, elem)?;
279281
elems.push(elem);
280282
continue;
281283
}
@@ -717,8 +719,11 @@ fn extract_captures_inner(
717719
}
718720
last_mult = CaptureMultiplicity::Single;
719721
}
720-
TokenTree::Punct(p) if matches!(p.as_char(), '*' | '+' | '?') => {
721-
// Keep last_mult — the @capture follows
722+
TokenTree::Punct(p) if p.as_char() == '*' || p.as_char() == '+' => {
723+
last_mult = CaptureMultiplicity::Repeated;
724+
}
725+
TokenTree::Punct(p) if p.as_char() == '?' => {
726+
last_mult = CaptureMultiplicity::Optional;
722727
}
723728
_ => {
724729
last_mult = CaptureMultiplicity::Single;

shared/yeast/src/lib.rs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -825,14 +825,6 @@ fn apply_one_shot_rules_inner(
825825

826826
let node_kind = ast.get_node(id).map(|n| n.kind()).unwrap_or("");
827827

828-
// Don't rewrite unnamed nodes (punctuation, keywords, etc.); leave them
829-
// as-is. Rules target named nodes only.
830-
if let Some(node) = ast.get_node(id) {
831-
if !node.is_named() {
832-
return Ok(vec![id]);
833-
}
834-
}
835-
836828
for rule in index.rules_for_kind(node_kind) {
837829
if let Some(mut captures) = rule.try_match(ast, id)? {
838830
// Recursively translate every captured node before invoking the

shared/yeast/tests/test.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,29 @@ fn test_capture_unnamed_node_parenthesized() {
389389
assert!(!op_node.is_named());
390390
}
391391

392+
#[test]
393+
fn test_capture_bare_underscore_repeated() {
394+
// `_` matches named and unnamed nodes in bare-child position. On this
395+
// assignment shape, bare children correspond to unnamed tokens (the `=`).
396+
let runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), &[]);
397+
let ast = runner.run("x = 1").unwrap();
398+
399+
let query = yeast::query!((assignment _* @all));
400+
401+
let mut cursor = AstCursor::new(&ast);
402+
cursor.goto_first_child();
403+
let assignment_id = cursor.node_id();
404+
405+
let mut captures = yeast::captures::Captures::new();
406+
let matched = query.do_match(&ast, assignment_id, &mut captures).unwrap();
407+
assert!(matched);
408+
409+
let all = captures.get_all("all");
410+
assert_eq!(all.len(), 1);
411+
assert_eq!(ast.get_node(all[0]).unwrap().kind(), "=");
412+
assert!(!ast.get_node(all[0]).unwrap().is_named());
413+
}
414+
392415
#[test]
393416
fn test_capture_unnamed_node_bare_literal() {
394417
// `"=" @op` (without surrounding parens) is the same as `("=") @op`.

0 commit comments

Comments
 (0)