use crate::core::recursion::{span_suffix, RecursionGuard};
use crate::core::tuple::*;
use crate::core::types::{display_tokens, err, ImplSpec, ParseResult, PrefixItem, TargetItem};
use crate::core::utils::*;
use crate::core::dash::{split_by_dash, dash_parse_slots_public, dash_append_public};
use proc_macro2::{Delimiter, Span, TokenStream as TokenStream2, TokenTree};
use quote::quote;
pub fn split_by_caret(tokens: &[TokenTree]) -> Option<(Vec<TokenTree>, Vec<TokenTree>)> {
split_at_punct(tokens, '^')
}
pub fn parse_prefix_items(tokens: &[TokenTree]) -> Result<Vec<PrefixItem>, String> {
if tokens.is_empty() {
return Err("^ 左侧缺少前缀,期望 &, self, Box 等".into());
}
if tokens.len() == 1 {
if let TokenTree::Group(ref g) = tokens[0] {
if g.delimiter() == Delimiter::Bracket {
let inner: Vec<TokenTree> = g.stream().into_iter().collect();
if inner.is_empty() {
return Err("^ 左侧 [] 为空,期望前缀列表,如 [&,Box]".into());
}
let (segs, d) = split_raw(inner.into_iter().collect(), ',');
if d > 0 {
return Err("^ 左侧 [] 内尖括号不匹配,检查 <> 是否配对".into());
}
return segs
.iter()
.map(|s| parse_single_prefix(&s.clone().into_iter().collect::<Vec<_>>()))
.collect();
}
}
}
Ok(vec![parse_single_prefix(tokens)?])
}
pub fn parse_single_prefix(tokens: &[TokenTree]) -> Result<PrefixItem, String> {
if let [TokenTree::Group(ref g)] = tokens {
if g.delimiter() == Delimiter::Parenthesis {
let inner: Vec<TokenTree> = g.stream().into_iter().collect();
if inner.is_empty() {
return Ok(PrefixItem::Tuple {
elem: None,
bound: None,
});
}
if inner.len() >= 2 && matches!(&inner[0], TokenTree::Punct(p) if p.as_char() == '<') {
let (result, _) = parse_balanced(&inner, 1);
let bound_tokens = match result {
Ok(args) if args.len() == 1 => args.into_iter().next().unwrap(),
_ => return Err("元组 bound 格式错误,期望 (<Trait>) 如 (<Clone>)".to_string()),
};
return Ok(PrefixItem::Tuple {
elem: None,
bound: Some(bound_tokens),
});
}
let inner_ts: TokenStream2 = inner.into_iter().collect();
if has_top_level_char(&inner_ts, ',') {
let trimmed = strip_trailing_comma(inner_ts);
return Ok(PrefixItem::Tuple {
elem: Some(trimmed),
bound: None,
});
}
}
}
match tokens {
[TokenTree::Ident(id)] if id == "self" => Ok(PrefixItem::Self_),
[TokenTree::Punct(p)] if p.as_char() == '&' => Ok(PrefixItem::Ref),
[TokenTree::Punct(p), TokenTree::Ident(id)] if p.as_char() == '&' && id == "mut" => {
Ok(PrefixItem::RefMut)
}
[TokenTree::Punct(p), TokenTree::Ident(id)] if p.as_char() == '*' && id == "const" => {
Ok(PrefixItem::ConstPtr)
}
[TokenTree::Punct(p), TokenTree::Ident(id)] if p.as_char() == '*' && id == "mut" => {
Ok(PrefixItem::MutPtr)
}
[TokenTree::Punct(p), TokenTree::Group(g)] if p.as_char() == '#' && g.delimiter() == Delimiter::Bracket => {
let mut attr_ts = TokenStream2::new();
attr_ts.extend(std::iter::once(TokenTree::Punct(proc_macro2::Punct::new('#', proc_macro2::Spacing::Alone))));
attr_ts.extend(std::iter::once(TokenTree::Group(g.clone())));
Ok(PrefixItem::Attribute(attr_ts))
}
[TokenTree::Ident(id)] if id == "unsafe" => Ok(PrefixItem::Unsafe),
[TokenTree::Ident(id)] if id == "fn" => Ok(PrefixItem::Fn),
[TokenTree::Ident(id)] => Ok(PrefixItem::Container {
name: id.clone(),
prefill: None,
}),
[TokenTree::Ident(id), TokenTree::Punct(p), ..] if p.as_char() == '<' => {
let (result, _) = parse_balanced(tokens, 2);
let prefill = match result {
Ok(args) if !args.is_empty() => Some(args),
_ => return Err(format!("容器 `{}` 的泛型参数解析失败", id)),
};
Ok(PrefixItem::Container {
name: id.clone(),
prefill,
})
}
[TokenTree::Group(g)] if g.delimiter() == Delimiter::Parenthesis => {
let inner: Vec<TokenTree> = g.stream().into_iter().collect();
if inner.len() == 1 && matches!(&inner[0], TokenTree::Ident(_)) {
Err(format!(
"`({})` 是分组而非元组,若需单元素元组请写 `({},)`",
display_tokens(&inner),
display_tokens(&inner)
))
} else {
Err(format!(
"无法识别的 ^ 前缀: `{}`。支持: self, &, &mut, unsafe, 标识符(如Box), (), (<bound>)",
display_tokens(tokens)
))
}
}
_ => Err(format!(
"无法识别的 ^ 前缀: `{}`。支持: self, &, &mut, unsafe, 标识符(如Box), (), (<bound>)",
display_tokens(tokens)
)),
}
}
pub fn parse_target_items(tokens: &[TokenTree]) -> Result<Vec<TargetItem>, String> {
if tokens.is_empty() {
return Err("^ 右侧缺少目标".into());
}
if tokens.len() == 1 {
if let TokenTree::Group(ref g) = tokens[0] {
if g.delimiter() == Delimiter::Bracket {
let inner: Vec<TokenTree> = g.stream().into_iter().collect();
if inner.is_empty() {
return Err("^ 右侧 [] 为空,期望类型列表,如 ^[A,B]".into());
}
let (segs, d) = split_raw(inner.into_iter().collect(), ',');
if d > 0 {
return Err("^ 右侧 [] 内尖括号不匹配".into());
}
if segs.len() == 1 {
return Ok(vec![TargetItem::Single(tokens.iter().cloned().collect())]);
}
return Ok(segs.into_iter().map(TargetItem::Single).collect());
}
}
}
if tokens.len() >= 2 && is_punct(&tokens[0], '<') {
let (r, pos) = parse_balanced(tokens, 1);
if pos < tokens.len() {
return Ok(vec![TargetItem::Single(tokens.iter().cloned().collect())]);
}
return r.map(|a| vec![TargetItem::Multi(a)]);
}
Ok(vec![TargetItem::Single(tokens.iter().cloned().collect())])
}
pub fn apply_caret(prefix: &PrefixItem, target: &TargetItem) -> Result<TokenStream2, String> {
match (prefix, target) {
(PrefixItem::Self_, TargetItem::Single(ts)) => Ok(ts.clone()),
(PrefixItem::Self_, _) => Err("self^ 不能用于多参目标,如 <X,Y>".into()),
(PrefixItem::Ref, TargetItem::Single(ts)) => Ok(quote! { & #ts }),
(PrefixItem::Ref, _) => Err("&^ 不能用于多参目标,如 <X,Y>".into()),
(PrefixItem::RefMut, TargetItem::Single(ts)) => Ok(quote! { &mut #ts }),
(PrefixItem::RefMut, _) => Err("&mut^ 不能用于多参目标,如 <X,Y>".into()),
(PrefixItem::ConstPtr, TargetItem::Single(ts)) => Ok(quote! { *const #ts }),
(PrefixItem::ConstPtr, _) => Err("*const^ 不能用于多参目标,如 <X,Y>".into()),
(PrefixItem::MutPtr, TargetItem::Single(ts)) => Ok(quote! { *mut #ts }),
(PrefixItem::MutPtr, _) => Err("*mut^ 不能用于多参目标,如 <X,Y>".into()),
(PrefixItem::Unsafe, TargetItem::Single(ts)) => Ok(ts.clone()),
(PrefixItem::Unsafe, _) => Err("unsafe^ 不能用于多参目标".into()),
(PrefixItem::Fn, TargetItem::Single(ts)) => Ok(quote! { fn #ts }),
(PrefixItem::Fn, _) => Err("fn^ 不能用于多参目标".into()),
(PrefixItem::Container { name, prefill }, TargetItem::Single(ts)) => {
match prefill {
Some(args) => {
Ok(quote! { #name < #(#args),* , #ts > })
}
None => {
Ok(quote! { #name < #ts > })
}
}
}
(PrefixItem::Container { name, prefill }, TargetItem::Multi(args)) => {
match prefill {
Some(prefill_args) => {
Ok(quote! { #name < #(#prefill_args),* , #(#args),* > })
}
None => {
Ok(quote! { #name < #(#args),* > })
}
}
}
(PrefixItem::Tuple { .. }, _) => Err("元组 ^ 的内部错误,这不应该发生,请报告 bug".into()),
(PrefixItem::Attribute(_), _) => Err("属性 ^ 的内部错误,这不应该发生,请报告 bug".into()),
}
}
fn expand_bracket_with_comma(
inner_ts: TokenStream2,
types: &[TokenStream2],
tr: &Option<Vec<TokenStream2>>,
assoc: &[(TokenStream2, TokenStream2)],
body: &Option<TokenStream2>,
span: Span,
specs: &mut Vec<ImplSpec>,
simple_targets: &mut Vec<TargetItem>,
) -> ParseResult {
let (segs, _) = split_raw(inner_ts, ',');
for seg in segs {
let stv: Vec<TokenTree> = seg.into_iter().collect();
if split_by_caret(&stv).is_some() {
match expand_caret(stv.into_iter().collect(), types, tr, assoc, body.clone(), span) {
ParseResult::Ok(sub) => specs.extend(sub),
ParseResult::Err(e) => return ParseResult::Err(e),
}
} else {
simple_targets.push(TargetItem::Single(stv.into_iter().collect()));
}
}
ParseResult::Ok(vec![])
}
fn expand_nested_bracket(
inner_ts: TokenStream2,
types: &[TokenStream2],
tr: &Option<Vec<TokenStream2>>,
assoc: &[(TokenStream2, TokenStream2)],
body: &Option<TokenStream2>,
span: Span,
simple_targets: &mut Vec<TargetItem>,
) -> Result<bool, TokenStream2> {
let mut unwrap_count = 0usize;
let mut probe_ts = inner_ts.clone();
loop {
let pvec: Vec<TokenTree> = probe_ts.clone().into_iter().collect();
if pvec.len() == 1 {
if let TokenTree::Group(ref pg) = pvec[0] {
if pg.delimiter() == Delimiter::Bracket {
let pinner: TokenStream2 = pg.stream();
if !has_top_level_char(&pinner, ',') {
unwrap_count += 1;
probe_ts = pinner;
continue;
}
}
}
}
break;
}
let (inner_segs, _) = split_raw(probe_ts, ',');
let mut any_expanded = false;
for seg in inner_segs {
let stv: Vec<TokenTree> = seg.into_iter().collect();
if split_by_caret(&stv).is_some() {
any_expanded = true;
match expand_caret(stv.into_iter().collect(), types, tr, assoc, body.clone(), span) {
ParseResult::Ok(sub) => {
for spec in sub {
let mut target = spec.target;
for _ in 0..unwrap_count {
let mut wrapped = TokenStream2::new();
wrapped.extend(std::iter::once(TokenTree::Group(
proc_macro2::Group::new(Delimiter::Bracket, target),
)));
target = wrapped;
}
simple_targets.push(TargetItem::Single(target));
}
}
ParseResult::Err(e) => return Err(e),
}
} else if unwrap_count > 0 {
any_expanded = true;
let mut target: TokenStream2 = stv.into_iter().collect();
for _ in 0..unwrap_count - 1 {
let mut wrapped = TokenStream2::new();
wrapped.extend(std::iter::once(TokenTree::Group(
proc_macro2::Group::new(Delimiter::Bracket, target),
)));
target = wrapped;
}
simple_targets.push(TargetItem::Single(target));
}
}
Ok(any_expanded)
}
pub fn expand_caret(
tokens: TokenStream2,
types: &[TokenStream2],
tr: &Option<Vec<TokenStream2>>,
assoc: &[(TokenStream2, TokenStream2)],
body: Option<TokenStream2>,
span: Span,
) -> ParseResult {
let _guard = match RecursionGuard::new() {
Ok(g) => g,
Err(e) => return e,
};
let tv: Vec<TokenTree> = tokens.clone().into_iter().collect();
let (left, right) = split_by_caret(&tv).unwrap_or_else(|| (vec![], vec![]));
let suffix = left.first().map(|t| span_suffix(t.span())).unwrap_or(0);
let prefixes = match parse_prefix_items(&left) {
Ok(p) => p,
Err(e) => return ParseResult::Err(err(span, &e)),
};
let has_unsafe = prefixes.iter().any(|p| matches!(p, PrefixItem::Unsafe));
let prefixes: Vec<_> = prefixes
.into_iter()
.filter(|p| !matches!(p, PrefixItem::Unsafe))
.collect();
let mut attrs: Vec<TokenStream2> = Vec::new();
let prefixes: Vec<_> = prefixes
.into_iter()
.filter_map(|p| {
if let PrefixItem::Attribute(attr_ts) = &p {
attrs.push(attr_ts.clone());
None
} else {
Some(p)
}
})
.collect();
let (caret_target_right, caret_dash_suffix): (Vec<TokenTree>, Option<Vec<TokenTree>>) = {
if let Some((args, suffix)) = split_by_dash(&right) {
(args, Some(suffix))
} else {
(right.clone(), None)
}
};
let targets = match parse_target_items(&caret_target_right) {
Ok(t) => t,
Err(e) => return ParseResult::Err(err(span, &e)),
};
let targets = match expand_targets_recursive(targets, span) {
Ok(t) => t,
Err(e) => return e,
};
let mut specs = Vec::new();
let mut simple_targets: Vec<TargetItem> = Vec::new();
for t in &targets {
if let TargetItem::Single(ts) = t {
let tv: Vec<TokenTree> = ts.clone().into_iter().collect();
if tv.len() == 1 {
if let TokenTree::Group(ref g) = tv[0] {
if g.delimiter() == Delimiter::Bracket {
let inner_ts: TokenStream2 = g.stream();
if has_top_level_char(&inner_ts, ',') {
match expand_bracket_with_comma(
inner_ts, types, tr, assoc, &body, span,
&mut specs, &mut simple_targets,
) {
ParseResult::Ok(_) => {},
ParseResult::Err(e) => return ParseResult::Err(e),
}
continue;
}
match expand_nested_bracket(
inner_ts.clone(), types, tr, assoc, &body, span,
&mut simple_targets,
) {
Ok(true) => {}, Ok(false) => {
let mut ts = TokenStream2::new();
ts.extend(std::iter::once(TokenTree::Group(
proc_macro2::Group::new(Delimiter::Bracket, inner_ts),
)));
simple_targets.push(TargetItem::Single(ts));
}
Err(e) => return ParseResult::Err(e),
}
continue;
}
}
}
if split_by_caret(&tv).is_some() {
let has_fn = prefixes.iter().any(|p| matches!(p, PrefixItem::Fn));
match expand_caret(tv.into_iter().collect(), types, tr, assoc, body.clone(), span) {
ParseResult::Ok(sub) => {
for spec in sub {
let target_ts = if has_fn {
match apply_caret(&PrefixItem::Fn, &TargetItem::Single(spec.target)) {
Ok(ts) => ts,
Err(e) => return ParseResult::Err(err(span, &e)),
}
} else {
spec.target
};
if let Some(ref suffix) = caret_dash_suffix {
match dash_parse_slots_public(&suffix.clone().into_iter().collect(), span) {
Ok(slots) => {
for slot in slots {
let (new_target, extra_types) = dash_append_public(&target_ts, &slot, 0);
let mut all_types = spec.type_params.clone();
all_types.extend(extra_types);
specs.push(ImplSpec::new(
all_types,
spec.trait_params.clone(),
spec.assoc_bindings.clone(),
new_target,
spec.custom_body.clone(),
));
}
}
Err(e) => return e,
}
} else {
specs.push(ImplSpec::new(
spec.type_params,
spec.trait_params,
spec.assoc_bindings,
target_ts,
spec.custom_body,
));
}
}
}
ParseResult::Err(e) => return ParseResult::Err(e),
}
continue;
}
}
simple_targets.push(t.clone());
}
if prefixes.is_empty() {
for t in &simple_targets {
let ts: TokenStream2 = match t {
TargetItem::Single(ts) => ts.clone(),
TargetItem::Multi(_) => {
return ParseResult::Err(err(span, "unsafe^ 后不能直接跟多参目标如 <X,Y>"));
}
};
if let Some(ref suffix) = caret_dash_suffix {
match dash_parse_slots_public(&suffix.clone().into_iter().collect(), span) {
Ok(slots) => {
for slot in slots {
let (new_target, extra_types) = dash_append_public(&ts, &slot, 0);
let mut all_types = types.to_vec();
all_types.extend(extra_types);
specs.push(ImplSpec::new(
all_types,
tr.clone(),
assoc.to_vec(),
new_target,
body.clone(),
));
}
}
Err(e) => return e,
}
} else {
specs.push(ImplSpec::new(
types.to_vec(),
tr.clone(),
assoc.to_vec(),
ts,
body.clone(),
));
}
}
} else {
for p in &prefixes {
if let PrefixItem::Tuple { elem, bound } = p {
for t in &simple_targets {
if let Ok((start, count)) = parse_tuple_count(t) {
specs.extend(generate_tuples(
elem,
bound,
start,
count,
types,
tr,
body.clone(),
suffix,
));
} else {
let target_ts = match t {
TargetItem::Single(ts) => ts.clone(),
TargetItem::Multi(args) => {
let mut ts = TokenStream2::new();
ts.extend(std::iter::once(TokenTree::Group(
proc_macro2::Group::new(Delimiter::Parenthesis, {
let mut inner = TokenStream2::new();
for (i, arg) in args.iter().enumerate() {
if i > 0 {
inner.extend(std::iter::once(TokenTree::Punct(
proc_macro2::Punct::new(
',',
proc_macro2::Spacing::Alone,
),
)));
}
inner.extend(arg.clone());
}
inner
}),
)));
ts
}
};
let new_target = match elem {
None => {
let mut ts = TokenStream2::new();
ts.extend(std::iter::once(TokenTree::Group(
proc_macro2::Group::new(Delimiter::Parenthesis, {
let mut inner = target_ts;
inner.extend(std::iter::once(TokenTree::Punct(
proc_macro2::Punct::new(
',',
proc_macro2::Spacing::Alone,
),
)));
inner
}),
)));
ts
}
Some(e) => {
let mut ts = TokenStream2::new();
ts.extend(std::iter::once(TokenTree::Group(
proc_macro2::Group::new(Delimiter::Parenthesis, {
let mut inner = e.clone();
inner.extend(std::iter::once(TokenTree::Punct(
proc_macro2::Punct::new(
',',
proc_macro2::Spacing::Alone,
),
)));
inner.extend(target_ts);
inner
}),
)));
ts
}
};
let mut all_types = types.to_vec();
if let Some(b) = bound {
all_types.extend(b.clone().into_iter().map(|tt| {
let mut ts = TokenStream2::new();
ts.extend(std::iter::once(tt));
ts
}));
}
specs.push(ImplSpec::new(
all_types,
tr.clone(),
assoc.to_vec(),
new_target,
body.clone(),
));
}
}
} else if caret_dash_suffix.is_some() {
let suffix_tokens = caret_dash_suffix.as_ref().unwrap();
for t in &simple_targets {
let ts = match apply_caret(p, t) {
Ok(ts) => ts,
Err(e) => return ParseResult::Err(err(span, &e)),
};
match dash_parse_slots_public(&suffix_tokens.clone().into_iter().collect(), span) {
Ok(slots) => {
for slot in slots {
let (new_target, extra_types) = dash_append_public(&ts, &slot, 0);
let mut all_types = types.to_vec();
all_types.extend(extra_types);
specs.push(ImplSpec::new(
all_types,
tr.clone(),
assoc.to_vec(),
new_target,
body.clone(),
));
}
}
Err(e) => return e,
}
}
} else {
for t in &simple_targets {
let ts = match apply_caret(p, t) {
Ok(ts) => ts,
Err(e) => return ParseResult::Err(err(span, &e)),
};
specs.push(ImplSpec::new(
types.to_vec(),
tr.clone(),
assoc.to_vec(),
ts,
body.clone(),
));
}
}
}
}
if has_unsafe {
for spec in &mut specs {
spec.is_unsafe = true;
}
}
if !attrs.is_empty() {
for spec in &mut specs {
spec.attributes.extend(attrs.clone());
}
}
ParseResult::Ok(specs)
}
pub fn expand_targets_recursive(
items: Vec<TargetItem>,
span: Span,
) -> crate::core::types::PResult<Vec<TargetItem>> {
let mut result = Vec::new();
for item in items {
match item {
TargetItem::Single(ts) => {
result.extend(expand_single(ts, span)?);
}
other => result.push(other),
}
}
Ok(result)
}
pub fn expand_single(ts: TokenStream2, span: Span) -> crate::core::types::PResult<Vec<TargetItem>> {
let _guard = RecursionGuard::new()?;
let tokens: Vec<TokenTree> = ts.clone().into_iter().collect();
if let Some((left, right)) = split_by_caret(&tokens) {
let prefixes = parse_prefix_items(&left).map_err(|e| ParseResult::Err(err(span, &e)))?;
if prefixes
.iter()
.any(|p| matches!(p, PrefixItem::Tuple { .. }))
{
return Ok(vec![TargetItem::Single(ts)]);
}
let filtered_prefixes: Vec<_> = prefixes
.into_iter()
.filter(|p| !matches!(p, PrefixItem::Attribute(_) | PrefixItem::Unsafe))
.collect();
let targets = parse_target_items(&right).map_err(|e| ParseResult::Err(err(span, &e)))?;
let targets = expand_targets_recursive(targets, span)?;
if filtered_prefixes.is_empty() {
return Ok(targets);
}
let mut r = Vec::new();
for p in &filtered_prefixes {
for t in &targets {
let ts = apply_caret(p, t).map_err(|e| ParseResult::Err(err(span, &e)))?;
r.push(TargetItem::Single(ts));
}
}
return Ok(r);
}
if crate::core::dash::split_by_dash(&tokens).is_some() {
match crate::core::dash::expand_dash(ts, &[], &None, &[], None, span) {
ParseResult::Ok(specs) => {
return Ok(specs
.into_iter()
.map(|s| TargetItem::Single(s.target))
.collect());
}
ParseResult::Err(e) => return Err(ParseResult::Err(e)),
}
}
if let [TokenTree::Group(ref g)] = tokens.as_slice() {
if g.delimiter() == Delimiter::Bracket || g.delimiter() == Delimiter::Brace {
let inner: TokenStream2 = g.stream();
if g.delimiter() == Delimiter::Bracket && has_top_level_char(&inner, ',') {
let has_caret = has_top_level_char(&inner, '^');
let (segs, _) = split_raw(inner, ',');
if has_caret {
let mut results = Vec::new();
for seg in segs {
let mut wrapped = TokenStream2::new();
wrapped.extend(std::iter::once(TokenTree::Group(proc_macro2::Group::new(
Delimiter::Bracket,
seg,
))));
results.push(TargetItem::Single(wrapped));
}
return Ok(results);
}
let mut results = Vec::new();
for seg in segs {
results.extend(expand_single(seg, span)?);
}
return Ok(results);
}
let expanded = expand_single(inner, span)?;
let mut r = Vec::new();
for item in expanded {
if let TargetItem::Single(inner_ts) = item {
let mut wrapped = TokenStream2::new();
wrapped.extend(std::iter::once(TokenTree::Group(proc_macro2::Group::new(
g.delimiter(),
inner_ts,
))));
r.push(TargetItem::Single(wrapped));
} else {
r.push(item);
}
}
return Ok(r);
}
}
Ok(vec![TargetItem::Single(ts)])
}