1use crate::{Error, Result};
2use proc_macro2::{Delimiter, Ident, Span, TokenStream, TokenTree};
3use quote::ToTokens;
4use std::iter::Peekable;
5
6pub(crate) fn parse_input(
7 input: TokenStream,
8) -> Result<(Vec<Attribute>, Vec<TokenTree>, TokenTree)> {
9 let mut input: impl Iterator = input.into_iter().peekable();
10 let mut attrs: Vec = Vec::new();
11
12 while let Some(attr: Attribute) = parse_next_attr(&mut input)? {
13 attrs.push(attr);
14 }
15
16 let sig: Vec = parse_signature(&mut input);
17 let body: TokenTree = input.next().ok_or_else(|| {
18 Error::new(
19 Span::call_site(),
20 message:"`#[proc_macro_error]` can be applied only to functions".to_string(),
21 )
22 })?;
23
24 Ok((attrs, sig, body))
25}
26
27fn parse_next_attr(
28 input: &mut Peekable<impl Iterator<Item = TokenTree>>,
29) -> Result<Option<Attribute>> {
30 let shebang = match input.peek() {
31 Some(TokenTree::Punct(ref punct)) if punct.as_char() == '#' => input.next().unwrap(),
32 _ => return Ok(None),
33 };
34
35 let group = match input.peek() {
36 Some(TokenTree::Group(ref group)) if group.delimiter() == Delimiter::Bracket => {
37 let res = group.clone();
38 input.next();
39 res
40 }
41 other => {
42 let span = other.map_or(Span::call_site(), |tt| tt.span());
43 return Err(Error::new(span, "expected `[`".to_string()));
44 }
45 };
46
47 let path = match group.stream().into_iter().next() {
48 Some(TokenTree::Ident(ident)) => Some(ident),
49 _ => None,
50 };
51
52 Ok(Some(Attribute {
53 shebang,
54 group: TokenTree::Group(group),
55 path,
56 }))
57}
58
59fn parse_signature(input: &mut Peekable<impl Iterator<Item = TokenTree>>) -> Vec<TokenTree> {
60 let mut sig: Vec = Vec::new();
61 loop {
62 match input.peek() {
63 Some(TokenTree::Group(ref group: &Group)) if group.delimiter() == Delimiter::Brace => {
64 return sig;
65 }
66 None => return sig,
67 _ => sig.push(input.next().unwrap()),
68 }
69 }
70}
71
72pub(crate) struct Attribute {
73 pub(crate) shebang: TokenTree,
74 pub(crate) group: TokenTree,
75 pub(crate) path: Option<Ident>,
76}
77
78impl Attribute {
79 pub(crate) fn path_is_ident(&self, ident: &str) -> bool {
80 self.path.as_ref().map_or(default:false, |p: &Ident| *p == ident)
81 }
82}
83
84impl ToTokens for Attribute {
85 fn to_tokens(&self, ts: &mut TokenStream) {
86 self.shebang.to_tokens(ts);
87 self.group.to_tokens(ts);
88 }
89}
90