1 use crate::iter::{self, Iter, IterImpl};
2 use crate::{Define, Error, Export, ExportArgs, FakeCallSite, Input, Macro, Visibility};
3 use proc_macro::Delimiter::{Brace, Bracket, Parenthesis};
4 use proc_macro::{Delimiter, Ident, Span, TokenStream, TokenTree};
5 
parse_input(tokens: Iter) -> Result<Input, Error>6 pub(crate) fn parse_input(tokens: Iter) -> Result<Input, Error> {
7     let attrs = parse_attributes(tokens)?;
8     let vis = parse_visibility(tokens)?;
9     let kw = parse_ident(tokens)?;
10     if kw.to_string() == "use" {
11         parse_export(attrs, vis, tokens).map(Input::Export)
12     } else if kw.to_string() == "fn" {
13         parse_define(attrs, vis, kw.span(), tokens).map(Input::Define)
14     } else {
15         Err(Error::new(
16             kw.span(),
17             "unexpected input to #[proc_macro_hack]",
18         ))
19     }
20 }
21 
parse_export(attrs: TokenStream, vis: Visibility, tokens: Iter) -> Result<Export, Error>22 fn parse_export(attrs: TokenStream, vis: Visibility, tokens: Iter) -> Result<Export, Error> {
23     let _ = parse_punct(tokens, ':');
24     let _ = parse_punct(tokens, ':');
25     let from = parse_ident(tokens)?;
26     parse_punct(tokens, ':')?;
27     parse_punct(tokens, ':')?;
28 
29     let mut macros = Vec::new();
30     match tokens.peek() {
31         Some(TokenTree::Group(group)) if group.delimiter() == Brace => {
32             let ref mut content = iter::new(group.stream());
33             loop {
34                 macros.push(parse_macro(content)?);
35                 if content.peek().is_none() {
36                     break;
37                 }
38                 parse_punct(content, ',')?;
39                 if content.peek().is_none() {
40                     break;
41                 }
42             }
43             tokens.next().unwrap();
44         }
45         _ => macros.push(parse_macro(tokens)?),
46     }
47 
48     parse_punct(tokens, ';')?;
49     Ok(Export {
50         attrs,
51         vis,
52         from,
53         macros,
54     })
55 }
56 
parse_punct(tokens: Iter, ch: char) -> Result<(), Error>57 fn parse_punct(tokens: Iter, ch: char) -> Result<(), Error> {
58     match tokens.peek() {
59         Some(TokenTree::Punct(punct)) if punct.as_char() == ch => {
60             tokens.next().unwrap();
61             Ok(())
62         }
63         tt => Err(Error::new(
64             tt.map_or_else(Span::call_site, TokenTree::span),
65             format!("expected `{}`", ch),
66         )),
67     }
68 }
69 
parse_define( attrs: TokenStream, vis: Visibility, fn_token: Span, tokens: Iter, ) -> Result<Define, Error>70 fn parse_define(
71     attrs: TokenStream,
72     vis: Visibility,
73     fn_token: Span,
74     tokens: Iter,
75 ) -> Result<Define, Error> {
76     if vis.is_none() {
77         return Err(Error::new(
78             fn_token,
79             "functions tagged with `#[proc_macro_hack]` must be `pub`",
80         ));
81     }
82     let name = parse_ident(tokens)?;
83     let body = tokens.collect();
84     Ok(Define { attrs, name, body })
85 }
86 
parse_macro(tokens: Iter) -> Result<Macro, Error>87 fn parse_macro(tokens: Iter) -> Result<Macro, Error> {
88     let name = parse_ident(tokens)?;
89     let export_as = match tokens.peek() {
90         Some(TokenTree::Ident(ident)) if ident.to_string() == "as" => {
91             tokens.next().unwrap();
92             parse_ident(tokens)?
93         }
94         _ => name.clone(),
95     };
96     Ok(Macro { name, export_as })
97 }
98 
parse_ident(tokens: Iter) -> Result<Ident, Error>99 fn parse_ident(tokens: Iter) -> Result<Ident, Error> {
100     match tokens.next() {
101         Some(TokenTree::Ident(ident)) => Ok(ident),
102         tt => Err(Error::new(
103             tt.as_ref().map_or_else(Span::call_site, TokenTree::span),
104             "expected identifier",
105         )),
106     }
107 }
108 
parse_keyword(tokens: Iter, kw: &'static str) -> Result<(), Error>109 fn parse_keyword(tokens: Iter, kw: &'static str) -> Result<(), Error> {
110     match &tokens.next() {
111         Some(TokenTree::Ident(ident)) if ident.to_string() == kw => Ok(()),
112         tt => Err(Error::new(
113             tt.as_ref().map_or_else(Span::call_site, TokenTree::span),
114             format!("expected `{}`", kw),
115         )),
116     }
117 }
118 
parse_int(tokens: Iter) -> Result<u16, Span>119 fn parse_int(tokens: Iter) -> Result<u16, Span> {
120     match tokens.next() {
121         Some(TokenTree::Literal(lit)) => lit.to_string().parse().map_err(|_| lit.span()),
122         Some(tt) => Err(tt.span()),
123         None => Err(Span::call_site()),
124     }
125 }
126 
parse_group(tokens: Iter, delimiter: Delimiter) -> Result<IterImpl, Error>127 fn parse_group(tokens: Iter, delimiter: Delimiter) -> Result<IterImpl, Error> {
128     match &tokens.next() {
129         Some(TokenTree::Group(group)) if group.delimiter() == delimiter => {
130             Ok(iter::new(group.stream()))
131         }
132         tt => Err(Error::new(
133             tt.as_ref().map_or_else(Span::call_site, TokenTree::span),
134             "expected delimiter",
135         )),
136     }
137 }
138 
parse_visibility(tokens: Iter) -> Result<Visibility, Error>139 fn parse_visibility(tokens: Iter) -> Result<Visibility, Error> {
140     if let Some(TokenTree::Ident(ident)) = tokens.peek() {
141         if ident.to_string() == "pub" {
142             return Ok(Some(tokens.next().unwrap().span()));
143         }
144     }
145     Ok(None)
146 }
147 
parse_attributes(tokens: Iter) -> Result<TokenStream, Error>148 fn parse_attributes(tokens: Iter) -> Result<TokenStream, Error> {
149     let mut attrs = TokenStream::new();
150     while let Some(TokenTree::Punct(punct)) = tokens.peek() {
151         if punct.as_char() != '#' {
152             break;
153         }
154         let span = punct.span();
155         attrs.extend(tokens.next());
156         match tokens.peek() {
157             Some(TokenTree::Group(group)) if group.delimiter() == Bracket => {
158                 attrs.extend(tokens.next());
159             }
160             _ => return Err(Error::new(span, "unexpected input")),
161         }
162     }
163     Ok(attrs)
164 }
165 
parse_export_args(tokens: Iter) -> Result<ExportArgs, Error>166 pub(crate) fn parse_export_args(tokens: Iter) -> Result<ExportArgs, Error> {
167     let mut args = ExportArgs {
168         support_nested: false,
169         internal_macro_calls: 0,
170         fake_call_site: false,
171     };
172 
173     while let Some(tt) = tokens.next() {
174         match &tt {
175             TokenTree::Ident(ident) if ident.to_string() == "support_nested" => {
176                 args.support_nested = true;
177             }
178             TokenTree::Ident(ident) if ident.to_string() == "internal_macro_calls" => {
179                 parse_punct(tokens, '=')?;
180                 let calls = parse_int(tokens).map_err(|span| {
181                     Error::new(span, "expected integer value for internal_macro_calls")
182                 })?;
183                 args.internal_macro_calls = calls;
184             }
185             TokenTree::Ident(ident) if ident.to_string() == "fake_call_site" => {
186                 args.fake_call_site = true;
187             }
188             _ => {
189                 return Err(Error::new(
190                     tt.span(),
191                     "expected one of: `support_nested`, `internal_macro_calls`, `fake_call_site`",
192                 ))
193             }
194         }
195         if tokens.peek().is_none() {
196             break;
197         }
198         parse_punct(tokens, ',')?;
199     }
200 
201     Ok(args)
202 }
203 
parse_define_args(tokens: Iter) -> Result<(), Error>204 pub(crate) fn parse_define_args(tokens: Iter) -> Result<(), Error> {
205     if tokens.peek().is_none() {
206         Ok(())
207     } else {
208         Err(Error::new(Span::call_site(), "unexpected input"))
209     }
210 }
211 
parse_enum_hack(tokens: Iter) -> Result<TokenStream, Error>212 pub(crate) fn parse_enum_hack(tokens: Iter) -> Result<TokenStream, Error> {
213     parse_keyword(tokens, "enum")?;
214     parse_ident(tokens)?;
215 
216     let ref mut braces = parse_group(tokens, Brace)?;
217     parse_ident(braces)?;
218     parse_punct(braces, '=')?;
219 
220     let ref mut parens = parse_group(braces, Parenthesis)?;
221     parse_ident(parens)?;
222     parse_punct(parens, '!')?;
223 
224     let ref mut inner = parse_group(parens, Brace)?;
225     let token_stream = inner.collect();
226 
227     parse_punct(parens, ',')?;
228     let _ = parens.next();
229     parse_punct(braces, '.')?;
230     let _ = braces.next();
231     parse_punct(braces, ',')?;
232 
233     Ok(token_stream)
234 }
235 
parse_fake_call_site(tokens: Iter) -> Result<FakeCallSite, Error>236 pub(crate) fn parse_fake_call_site(tokens: Iter) -> Result<FakeCallSite, Error> {
237     parse_punct(tokens, '#')?;
238     let ref mut attr = parse_group(tokens, Bracket)?;
239     parse_keyword(attr, "derive")?;
240     let ref mut path = parse_group(attr, Parenthesis)?;
241     Ok(FakeCallSite {
242         derive: parse_ident(path)?,
243         rest: tokens.collect(),
244     })
245 }
246