mirror of
https://github.com/github/codeql.git
synced 2026-05-14 19:29:28 +02:00
Yeast: Unify tree! and trees! into a single tree! macro
tree! now returns Id for a single element or Vec<Id> for multiple,
determined by how many top-level elements appear in the template.
trees! is kept as an alias for backward compatibility.
- tree!(ctx, (single_node ...)) → Id
- tree!(ctx, (node1 ...) (node2 ...)) → Vec<Id>
- tree!(ctx, (node) {..splice}) → Vec<Id>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -404,29 +404,30 @@ fn parse_builder_child_list(tokens: &mut Tokens) -> Result<Vec<TokenStream>> {
|
||||
// tree! / trees! parsing — direct code generation against BuildCtx
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// Parse `tree!(ctx, (template))` — first arg is context ident, then a comma,
|
||||
/// then a single node template.
|
||||
/// Parse `tree!(ctx, template)` — unified macro that returns `Id` for a single
|
||||
/// top-level element or `Vec<Id>` for multiple elements.
|
||||
pub fn parse_tree_top(input: TokenStream) -> Result<TokenStream> {
|
||||
let mut tokens = input.into_iter().peekable();
|
||||
let ctx = expect_ident(&mut tokens, "expected build context identifier")?;
|
||||
expect_punct(&mut tokens, ',', "expected `,` after context")?;
|
||||
let body = parse_direct_node(&mut tokens, &ctx)?;
|
||||
|
||||
// Parse the first element
|
||||
let first = parse_direct_node(&mut tokens, &ctx)?;
|
||||
|
||||
// If nothing follows, return a single Id
|
||||
if tokens.peek().is_none() {
|
||||
return Ok(quote! { { #first } });
|
||||
}
|
||||
|
||||
// Multiple elements — collect into Vec<Id>
|
||||
let mut items = vec![quote! { __nodes.push(#first); }];
|
||||
let rest = parse_direct_list(&mut tokens, &ctx)?;
|
||||
items.extend(rest);
|
||||
|
||||
if let Some(tok) = tokens.next() {
|
||||
return Err(syn::Error::new_spanned(tok, "unexpected token after tree! template"));
|
||||
}
|
||||
Ok(quote! { { #body } })
|
||||
}
|
||||
|
||||
/// Parse `trees!(ctx, (node1) (node2) {expr} ...)` — context ident, comma,
|
||||
/// then a list of node templates / embedded expressions.
|
||||
pub fn parse_trees_top(input: TokenStream) -> Result<TokenStream> {
|
||||
let mut tokens = input.into_iter().peekable();
|
||||
let ctx = expect_ident(&mut tokens, "expected build context identifier")?;
|
||||
expect_punct(&mut tokens, ',', "expected `,` after context")?;
|
||||
let items = parse_direct_list(&mut tokens, &ctx)?;
|
||||
if let Some(tok) = tokens.next() {
|
||||
return Err(syn::Error::new_spanned(tok, "unexpected token after trees! template"));
|
||||
}
|
||||
Ok(quote! {
|
||||
{
|
||||
let mut __nodes: Vec<usize> = Vec::new();
|
||||
@@ -436,6 +437,11 @@ pub fn parse_trees_top(input: TokenStream) -> Result<TokenStream> {
|
||||
})
|
||||
}
|
||||
|
||||
/// Kept for backward compatibility — identical to `parse_tree_top`.
|
||||
pub fn parse_trees_top(input: TokenStream) -> Result<TokenStream> {
|
||||
parse_tree_top(input)
|
||||
}
|
||||
|
||||
/// Parse a single node template and generate code that returns an `Id`.
|
||||
/// Handles: `(kind fields... children...)`, `@capture`, `{expr}`.
|
||||
fn parse_direct_node(tokens: &mut Tokens, ctx: &Ident) -> Result<TokenStream> {
|
||||
|
||||
@@ -13,7 +13,7 @@ pub fn rules() -> Vec<Rule> {
|
||||
let left_ids = match_.get_all("left");
|
||||
let mut ctx = BuildCtx::new(ast, &match_);
|
||||
|
||||
yeast::trees!(ctx,
|
||||
yeast::tree!(ctx,
|
||||
(assignment
|
||||
left: (identifier $tmp)
|
||||
right: @right
|
||||
@@ -43,7 +43,7 @@ pub fn rules() -> Vec<Rule> {
|
||||
);
|
||||
let for_transform = |ast: &mut Ast, match_: Captures| {
|
||||
let mut ctx = BuildCtx::new(ast, &match_);
|
||||
yeast::trees!(ctx,
|
||||
vec![yeast::tree!(ctx,
|
||||
(call
|
||||
receiver: @val
|
||||
method: (identifier "each")
|
||||
@@ -60,7 +60,7 @@ pub fn rules() -> Vec<Rule> {
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)]
|
||||
};
|
||||
|
||||
let for_rule = Rule::new(for_query, Box::new(for_transform));
|
||||
|
||||
Reference in New Issue
Block a user