• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::{Error, Result};
2 use proc_macro2::{Delimiter, Ident, Span, TokenStream, TokenTree};
3 use quote::ToTokens;
4 use std::iter::Peekable;
5 
parse_input( input: TokenStream, ) -> Result<(Vec<Attribute>, Vec<TokenTree>, TokenTree)>6 pub(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 
parse_next_attr( input: &mut Peekable<impl Iterator<Item = TokenTree>>, ) -> Result<Option<Attribute>>27 fn 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 
parse_signature(input: &mut Peekable<impl Iterator<Item = TokenTree>>) -> Vec<TokenTree>59 fn 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 
72 pub(crate) struct Attribute {
73     pub(crate) shebang: TokenTree,
74     pub(crate) group: TokenTree,
75     pub(crate) path: Option<Ident>,
76 }
77 
78 impl Attribute {
path_is_ident(&self, ident: &str) -> bool79     pub(crate) fn path_is_ident(&self, ident: &str) -> bool {
80         self.path.as_ref().map_or(false, |p| *p == ident)
81     }
82 }
83 
84 impl ToTokens for Attribute {
to_tokens(&self, ts: &mut TokenStream)85     fn to_tokens(&self, ts: &mut TokenStream) {
86         self.shebang.to_tokens(ts);
87         self.group.to_tokens(ts);
88     }
89 }
90