use proc_macro2::{Delimiter, Group, Ident, TokenStream, TokenTree};
use quote::quote;
use syn::ItemTrait;
use crate::diagnostic::compile_error_str;
use crate::preprocess_helpers::{build_from_item, collect_call_args, get_trait_item, parse_names_from_tokens};
use crate::scan::Cursor;
pub(crate) fn expand_tokens(
cursor: &mut Cursor,
trait_def: &ItemTrait,
) -> Result<Vec<TokenTree>, TokenStream> {
let mut result = vec![];
while !cursor.at_end() {
if cursor.is_punct('#')
&& let Some(TokenTree::Ident(name)) = cursor.peek_at(1)
{
let expanded = expand_directive(name, cursor, trait_def)?;
result.extend(expanded);
continue;
}
let Some(tt) = cursor.peek() else {
break;
};
if let TokenTree::Group(g) = tt
&& g.delimiter() == Delimiter::Bracket
{
let inner = expand_tokens(
&mut Cursor::new(
&g.stream().into_iter().collect::<Vec<_>>(),
),
trait_def,
)?;
let new_group =
Group::new(g.delimiter(), inner.into_iter().collect());
result.push(new_group.into());
cursor.bump();
} else {
result.push(tt.clone());
cursor.bump();
}
}
Ok(result)
}
fn expand_directive(
name: &Ident,
cursor: &mut Cursor,
trait_def: &ItemTrait,
) -> Result<Vec<TokenTree>, TokenStream> {
if let Some(TokenTree::Group(args)) = cursor.peek_at(2) {
match args.delimiter() {
Delimiter::Brace => {
cursor.bump(); cursor.bump(); cursor.bump(); expand_single(name, args, trait_def)
},
Delimiter::Bracket if name == "where" => {
let body = cursor.peek_at(3);
let Some(TokenTree::Group(body_group)) = body else {
return Err(compile_error_str(
"`#where[...]` 后期望 `{ predicates }` 代码块",
));
};
if body_group.delimiter() != Delimiter::Brace {
return Err(compile_error_str(
"`#where[...]` 后期望 `{ predicates }` 代码块",
));
}
cursor.bump(); cursor.bump(); cursor.bump(); cursor.bump(); let predicates = body_group.stream();
Ok(quote! { < where { #predicates } > }
.into_iter()
.collect())
},
_ => {
let body_tt = cursor.peek_at(3);
let Some(TokenTree::Group(body)) = body_tt else {
return Err(compile_error_str(&format!(
"`#{}` 后期望 `(args)` + `{{body}}` 或直接 `{{body}}`",
name
)));
};
if body.delimiter() != Delimiter::Brace {
return Err(compile_error_str(&format!(
"`#{}` 后期望 `(args)` + `{{body}}` 或直接 `{{body}}`",
name
)));
}
cursor.bump(); cursor.bump(); cursor.bump(); cursor.bump(); match name.to_string().as_str() {
"fill" => expand_fill(args, body, trait_def),
"delegate" => expand_delegate(args, body, trait_def),
_ => Ok(quote! {
#[#name[#args #body]]#trait_def
}
.into_iter()
.collect()),
}
},
}
} else {
Err(compile_error_str(&format!(
"`#{}` 后期望括号参数 `(args)`、`[占位]` 或代码块 `{{body}}`",
name
)))
}
}
fn expand_single(
method_name: &Ident,
body: &Group,
trait_def: &ItemTrait,
) -> Result<Vec<TokenTree>, TokenStream> {
let item = get_trait_item(trait_def, method_name)?;
Ok(vec![TokenTree::Group(Group::new(
Delimiter::Brace,
build_from_item(item, &body.stream()),
))])
}
fn expand_fill(
args_group: &Group,
body: &Group,
trait_def: &ItemTrait,
) -> Result<Vec<TokenTree>, TokenStream> {
let method_names = parse_names_from_tokens(
&args_group.stream().into_iter().collect::<Vec<_>>(),
trait_def,
)?;
let mut methods = TokenStream::new();
for name in &method_names {
let item = get_trait_item(trait_def, name)?;
methods.extend(build_from_item(&item, &body.stream()));
}
Ok(vec![TokenTree::Group(Group::new(
Delimiter::Brace,
methods,
))])
}
fn expand_delegate(
args_group: &Group,
target: &Group,
trait_def: &ItemTrait,
) -> Result<Vec<TokenTree>, TokenStream> {
let method_names = parse_names_from_tokens(
&args_group.stream().into_iter().collect::<Vec<_>>(),
trait_def,
)?;
let mut methods = TokenStream::new();
for name in &method_names {
let item = get_trait_item(trait_def, name)?;
let syn::TraitItem::Fn(f) = item else {
return Err(compile_error_str(&format!(
"batch-impl: #delegate 只能用于方法,trait `{}` 中的 `{}` 不是方法",
trait_def.ident, name
)));
};
let sig = f.sig.clone();
let call_args = collect_call_args(&sig);
let target = target.stream();
let body = quote! { (#target) . #name ( #(#call_args),* ) };
methods.extend(build_from_item(&item, &body));
}
Ok(vec![TokenTree::Group(Group::new(
Delimiter::Brace,
methods,
))])
}