macro_rules! delimiter {
({}) => {
::proc_macro2::Delimiter::Brace
};
([]) => {
::proc_macro2::Delimiter::Bracket
};
(()) => {
::proc_macro2::Delimiter::Parenthesis
};
(<>) => {
::proc_macro2::Delimiter::None
};
(none) => {
::proc_macro2::Delimiter::None
};
}
pub(crate) mod angle;
pub(crate) mod preprocess_helpers;
pub(crate) mod where_process;
pub(crate) use angle::*;
pub(crate) use preprocess_helpers::*;
pub(crate) use where_process::*;
use proc_macro2::{Group, Ident, TokenStream, TokenTree};
use quote::quote;
use syn::ItemTrait;
use crate::ast::fresh_param;
use crate::diagnostic::compile_error_str;
use crate::scan::Cursor;
pub(crate) fn expand_tokens(
cursor: &mut Cursor, trait_def: &ItemTrait, trait_full_path: &TokenStream,
) -> 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)
{
result.extend(expand_directive(
name,
cursor,
trait_def,
trait_full_path,
)?);
continue;
}
let Some(tt) = cursor.peek() else {
break;
};
if let TokenTree::Group(g) = tt
&& g.delimiter() == delimiter![[]]
&& !cursor.prev_bracket_passthrough()
{
let inner = expand_tokens(
&mut Cursor::new(&g.stream().into_iter().collect::<Vec<_>>()),
trait_def,
trait_full_path,
)?;
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,
trait_full_path: &TokenStream,
) -> Result<Vec<TokenTree>, TokenStream> {
if let Some(TokenTree::Group(args)) = cursor.peek_at(2) {
match args.delimiter() {
delimiter![{}] => {
cursor.bump(); cursor.bump(); cursor.bump(); expand_single(name, args, trait_def).map(|tt| vec![tt])
}
_ => {
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![{}] {
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).map(|tt| vec![tt]),
"delegate" => {
expand_delegate(args, body, trait_def).map(|tt| vec![tt])
}
"blanket" => {
expand_blanket(args, body, trait_def, trait_full_path)
}
_ => {
let inner = quote! {
#name ! { #args #body #trait_def }
};
Ok(vec![Group::new(delimiter![{}], inner).into()])
}
}
}
}
} else {
Err(compile_error_str(&format!(
"`#{}` 后期望括号参数 `(args)` 或代码块 `{{body}}`",
name
)))
}
}
fn expand_single(
method_name: &Ident, body: &Group, trait_def: &ItemTrait,
) -> Result<TokenTree, TokenStream> {
let item = get_trait_item(trait_def, method_name)?;
Ok(Group::new(delimiter![{}], build_from_item(item, &body.stream())).into())
}
fn expand_many(
args_group: &Group, trait_def: &ItemTrait,
build: impl Fn(&Ident, &syn::TraitItem) -> Result<TokenStream, TokenStream>,
) -> Result<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(name, item)?);
}
Ok(Group::new(delimiter![{}], methods).into())
}
fn expand_fill(
args_group: &Group, body: &Group, trait_def: &ItemTrait,
) -> Result<TokenTree, TokenStream> {
let body_stream = body.stream();
expand_many(args_group, trait_def, |_name, item| {
Ok(build_from_item(item, &body_stream))
})
}
fn expand_delegate(
args_group: &Group, target: &Group, trait_def: &ItemTrait,
) -> Result<TokenTree, TokenStream> {
let target_stream = target.stream();
expand_many(args_group, trait_def, |name, item| {
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).map_err(|pat| {
compile_error_str(&format!(
"batch-impl: #delegate 方法 `{}::{}` 的参数 `{}` 无法委托转发:\
仅支持 `self` 与纯标识符模式",
trait_def.ident, name, pat
))
})?;
let body = quote! { (#target_stream) . #name ( #(#call_args),* ) };
Ok(build_from_item(item, &body))
})
}
fn expand_blanket(
args_group: &Group, body: &Group, trait_def: &ItemTrait,
trait_full_path: &TokenStream,
) -> Result<Vec<TokenTree>, TokenStream> {
let body_tokens = angle_collect(&body.stream().into_iter().collect::<Vec<_>>())?;
let wrappers = parse_blanket_wrappers(&body_tokens)?;
let method_names = parse_names_from_tokens(
&args_group.stream().into_iter().collect::<Vec<_>>(),
trait_def,
)?;
let t = fresh_param();
let generics = &trait_def.generics;
let param_names: Vec<TokenStream> = generics
.params
.iter()
.map(|p| match p {
syn::GenericParam::Lifetime(ld) => quote!(#ld),
syn::GenericParam::Type(tp) => {
let id = &tp.ident;
quote!(#id)
}
syn::GenericParam::Const(cp) => {
let id = &cp.ident;
quote!(#id)
}
})
.collect();
let t_bound = if param_names.is_empty() {
quote!(#trait_full_path)
} else {
let args_group = Group::new(delimiter![<>], quote!(#(#param_names),*));
quote!(#trait_full_path #args_group)
};
let impl_generics_inner = if generics.params.is_empty() {
quote!(#t : #t_bound)
} else {
let ps = &generics.params;
quote!(#ps , #t : #t_bound)
};
let impl_generics = Group::new(delimiter![<>], impl_generics_inner);
let trait_part = if param_names.is_empty() {
quote!()
} else {
let args_group = Group::new(delimiter![<>], quote!(#(#param_names),*));
quote!(#trait_full_path #args_group)
};
let where_part = match &generics.where_clause {
Some(wc) => {
let preds = &wc.predicates;
quote!(where { #preds })
}
None => quote!(),
};
let as_trait = if param_names.is_empty() {
quote!(#t as #trait_full_path)
} else {
quote!(#t as #trait_full_path < #(#param_names),*>)
};
let mut spec_streams = vec![];
for wrapper in &wrappers {
let star = "*".repeat(wrapper.depth + 1);
let self_ty: TokenStream = format!("{}self", star).parse().unwrap();
let mut methods = TokenStream::new();
for name in &method_names {
let item = get_trait_item(trait_def, name)?;
match item {
syn::TraitItem::Fn(f) => {
let sig = f.sig.clone();
let call_args = collect_call_args(&sig).map_err(|pat| {
compile_error_str(&format!(
"batch-impl: #blanket 方法 `{}::{}` 的参数 `{}` 无法委托转发:\
仅支持 `self` 与纯标识符模式",
trait_def.ident, name, pat
))
})?;
let body = quote! { (#self_ty) . #name ( #(#call_args),* ) };
methods.extend(build_from_item(item, &body));
}
syn::TraitItem::Type(_) | syn::TraitItem::Const(_) => {
let body = quote! { < #as_trait >::#name };
methods.extend(build_from_item(item, &body));
}
_ => {
return Err(compile_error_str(&format!(
"batch-impl: #blanket 不支持 trait `{}` 中的 `{}`(未知 item 形态)",
trait_def.ident, name
)));
}
}
}
let wrapper_ty = &wrapper.ty;
spec_streams.push(quote! {
#impl_generics #trait_part #wrapper_ty ^ #t #where_part { #methods }
});
}
Ok(quote!(#(#spec_streams),*).into_iter().collect())
}
struct BlanketWrapper {
ty: TokenStream,
depth: usize,
}
fn parse_blanket_wrappers(
tokens: &[TokenTree],
) -> Result<Vec<BlanketWrapper>, TokenStream> {
let mut wrappers = vec![];
let mut current: Vec<TokenTree> = vec![];
let flush = |current: Vec<TokenTree>,
wrappers: &mut Vec<BlanketWrapper>|
-> Result<(), TokenStream> {
if current.is_empty() {
return Err(compile_error_str(
"batch-impl: #blanket 包装列表含空元素(如 `&,Box`);元素间用 `,` 分隔",
));
}
let mut depth = 1usize;
let mut ty_end = current.len();
for i in (0..current.len()).rev() {
if crate::scan::is_single_colon(¤t, i) {
match ¤t.get(i + 1) {
Some(TokenTree::Literal(lit)) => {
depth = lit.to_string().parse().map_err(|_| {
compile_error_str(&format!(
"batch-impl: #blanket 的 `:{}` 深度非法(应为正整数,如 `Box^Arc:2`)",
lit
))
})?;
if depth == 0 {
return Err(compile_error_str(
"batch-impl: #blanket 的 `:0` 无意义(解引用层数须 ≥ 1)",
));
}
ty_end = i;
}
Some(other) => {
return Err(compile_error_str(&format!(
"batch-impl: #blanket 的 `:{}` 后必须是数字(如 `Box^Arc:2`)",
other
)));
}
None => {}
}
break;
}
}
let ty_tokens = ¤t[..ty_end];
match ty_tokens {
[] => Err(compile_error_str(
"batch-impl: #blanket 的 `:N` 前缺少包装类型(如 `Box^Arc:2`)",
)),
[TokenTree::Punct(a), TokenTree::Ident(n)]
if a.as_char() == '*' && (n == "const" || n == "mut") =>
{
Err(compile_error_str(
"batch-impl: #blanket 不支持 `*const`/`*mut` 包装(解引用 unsafe,\
无法委托);请手写 #delegate",
))
}
[TokenTree::Ident(id)] if id == "self" => Err(compile_error_str(
"batch-impl: #blanket 不支持 `self` 包装(委托无意义);请手写 #delegate",
)),
_ => {
let ty = ty_tokens.iter().cloned().collect();
wrappers.push(BlanketWrapper { ty, depth });
Ok(())
}
}
};
for tt in tokens {
if let TokenTree::Punct(p) = tt
&& p.as_char() == ','
{
flush(current, &mut wrappers)?;
current = vec![];
} else {
current.push(tt.clone());
}
}
flush(current, &mut wrappers)?;
Ok(wrappers)
}