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