• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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             match tokens.next().unwrap() {
143                 TokenTree::Ident(vis) => return Ok(Some(vis)),
144                 _ => unreachable!(),
145             }
146         }
147     }
148     Ok(None)
149 }
150 
parse_attributes(tokens: Iter) -> Result<TokenStream, Error>151 fn parse_attributes(tokens: Iter) -> Result<TokenStream, Error> {
152     let mut attrs = TokenStream::new();
153     while let Some(TokenTree::Punct(punct)) = tokens.peek() {
154         if punct.as_char() != '#' {
155             break;
156         }
157         let span = punct.span();
158         attrs.extend(tokens.next());
159         match tokens.peek() {
160             Some(TokenTree::Group(group)) if group.delimiter() == Bracket => {
161                 attrs.extend(tokens.next());
162             }
163             _ => return Err(Error::new(span, "unexpected input")),
164         }
165     }
166     Ok(attrs)
167 }
168 
parse_export_args(tokens: Iter) -> Result<ExportArgs, Error>169 pub(crate) fn parse_export_args(tokens: Iter) -> Result<ExportArgs, Error> {
170     let mut args = ExportArgs {
171         support_nested: false,
172         internal_macro_calls: 0,
173         fake_call_site: false,
174         only_hack_old_rustc: false,
175     };
176 
177     while let Some(tt) = tokens.next() {
178         match &tt {
179             TokenTree::Ident(ident) if ident.to_string() == "support_nested" => {
180                 args.support_nested = true;
181             }
182             TokenTree::Ident(ident) if ident.to_string() == "internal_macro_calls" => {
183                 parse_punct(tokens, '=')?;
184                 let calls = parse_int(tokens).map_err(|span| {
185                     Error::new(span, "expected integer value for internal_macro_calls")
186                 })?;
187                 args.internal_macro_calls = calls;
188             }
189             TokenTree::Ident(ident) if ident.to_string() == "fake_call_site" => {
190                 args.fake_call_site = true;
191             }
192             TokenTree::Ident(ident) if ident.to_string() == "only_hack_old_rustc" => {
193                 args.only_hack_old_rustc = true;
194             }
195             _ => {
196                 return Err(Error::new(
197                     tt.span(),
198                     "expected one of: `support_nested`, `internal_macro_calls`, `fake_call_site`, `only_hack_old_rustc`",
199                 ));
200             }
201         }
202         if tokens.peek().is_none() {
203             break;
204         }
205         parse_punct(tokens, ',')?;
206     }
207 
208     Ok(args)
209 }
210 
parse_define_args(tokens: Iter) -> Result<(), Error>211 pub(crate) fn parse_define_args(tokens: Iter) -> Result<(), Error> {
212     match tokens.peek() {
213         None => Ok(()),
214         Some(token) => Err(Error::new(
215             token.span(),
216             "unexpected argument to proc_macro_hack macro implementation; args are only accepted on the macro declaration (the `pub use`)",
217         )),
218     }
219 }
220 
parse_enum_hack(tokens: Iter) -> Result<TokenStream, Error>221 pub(crate) fn parse_enum_hack(tokens: Iter) -> Result<TokenStream, Error> {
222     parse_keyword(tokens, "enum")?;
223     parse_ident(tokens)?;
224 
225     let ref mut braces = parse_group(tokens, Brace)?;
226     parse_ident(braces)?;
227     parse_punct(braces, '=')?;
228 
229     let ref mut parens = parse_group(braces, Parenthesis)?;
230     parse_ident(parens)?;
231     parse_punct(parens, '!')?;
232 
233     let ref mut inner = parse_group(parens, Brace)?;
234     let token_stream = inner.collect();
235 
236     parse_punct(parens, ',')?;
237     let _ = parens.next();
238     parse_punct(braces, '.')?;
239     let _ = braces.next();
240     parse_punct(braces, ',')?;
241 
242     Ok(token_stream)
243 }
244 
parse_fake_call_site(tokens: Iter) -> Result<FakeCallSite, Error>245 pub(crate) fn parse_fake_call_site(tokens: Iter) -> Result<FakeCallSite, Error> {
246     parse_punct(tokens, '#')?;
247     let ref mut attr = parse_group(tokens, Bracket)?;
248     parse_keyword(attr, "derive")?;
249     let ref mut path = parse_group(attr, Parenthesis)?;
250     Ok(FakeCallSite {
251         derive: parse_ident(path)?,
252         rest: tokens.collect(),
253     })
254 }
255