proc_macro_error_attr2/
parse.rs

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 = input.into_iter().peekable();
10    let mut attrs = Vec::new();
11
12    while let Some(attr) = parse_next_attr(&mut input)? {
13        attrs.push(attr);
14    }
15
16    let sig = parse_signature(&mut input);
17    let body = input.next().ok_or_else(|| {
18        Error::new(
19            Span::call_site(),
20            "`#[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(), TokenTree::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::new();
61    loop {
62        match input.peek() {
63            Some(TokenTree::Group(ref 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(false, |p| *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}