1use crate::iter::{self, Iter, IterImpl};
2use crate::{Define, Error, Export, ExportArgs, FakeCallSite, Input, Macro, Visibility};
3use proc_macro::Delimiter::{Brace, Bracket, Parenthesis};
4use proc_macro::{Delimiter, Ident, Span, TokenStream, TokenTree};
5
6pub(crate) fn parse_input(tokens: Iter) -> Result<Input, Error> {
7 let attrs: TokenStream = parse_attributes(tokens)?;
8 let vis: Option = parse_visibility(tokens);
9 let kw: Ident = parse_ident(tokens)?;
10 if kw.to_string() == "use" {
11 parse_export(attrs, vis, tokens).map(op:Input::Export)
12 } else if kw.to_string() == "fn" {
13 parse_define(attrs, vis, kw.span(), tokens).map(op:Input::Define)
14 } else {
15 Err(Error::new(
16 kw.span(),
17 msg:"unexpected input to #[proc_macro_hack]",
18 ))
19 }
20}
21
22fn 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
57fn parse_punct(tokens: Iter, ch: char) -> Result<(), Error> {
58 match tokens.peek() {
59 Some(TokenTree::Punct(punct: &Punct)) if punct.as_char() == ch => {
60 tokens.next().unwrap();
61 Ok(())
62 }
63 tt: Option<&TokenTree> => Err(Error::new(
64 span:tt.map_or_else(Span::call_site, TokenTree::span),
65 msg:format!("expected `{}`", ch),
66 )),
67 }
68}
69
70fn 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 span:fn_token,
79 msg:"functions tagged with `#[proc_macro_hack]` must be `pub`",
80 ));
81 }
82 let name: Ident = parse_ident(tokens)?;
83 let body: TokenStream = tokens.collect();
84 Ok(Define { attrs, name, body })
85}
86
87fn parse_macro(tokens: Iter) -> Result<Macro, Error> {
88 let name: Ident = parse_ident(tokens)?;
89 let export_as: Ident = match tokens.peek() {
90 Some(TokenTree::Ident(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
99fn parse_ident(tokens: Iter) -> Result<Ident, Error> {
100 match tokens.next() {
101 Some(TokenTree::Ident(ident: Ident)) => Ok(ident),
102 tt: Option => Err(Error::new(
103 span:tt.as_ref().map_or_else(Span::call_site, TokenTree::span),
104 msg:"expected identifier",
105 )),
106 }
107}
108
109fn parse_keyword(tokens: Iter, kw: &'static str) -> Result<(), Error> {
110 match &tokens.next() {
111 Some(TokenTree::Ident(ident: &Ident)) if ident.to_string() == kw => Ok(()),
112 tt: &Option => Err(Error::new(
113 span:tt.as_ref().map_or_else(Span::call_site, TokenTree::span),
114 msg:format!("expected `{}`", kw),
115 )),
116 }
117}
118
119fn parse_int(tokens: Iter) -> Result<u16, Span> {
120 match tokens.next() {
121 Some(TokenTree::Literal(lit: Literal)) => lit.to_string().parse().map_err(|_| lit.span()),
122 Some(tt: TokenTree) => Err(tt.span()),
123 None => Err(Span::call_site()),
124 }
125}
126
127fn parse_group(tokens: Iter, delimiter: Delimiter) -> Result<IterImpl, Error> {
128 match &tokens.next() {
129 Some(TokenTree::Group(group: &Group)) if group.delimiter() == delimiter => {
130 Ok(iter::new(tokens:group.stream()))
131 }
132 tt: &Option => Err(Error::new(
133 span:tt.as_ref().map_or_else(Span::call_site, TokenTree::span),
134 msg:"expected delimiter",
135 )),
136 }
137}
138
139fn parse_visibility(tokens: Iter) -> Visibility {
140 if let Some(TokenTree::Ident(ident: &Ident)) = tokens.peek() {
141 if ident.to_string() == "pub" {
142 match tokens.next().unwrap() {
143 TokenTree::Ident(vis: Ident) => return Some(vis),
144 _ => unreachable!(),
145 }
146 }
147 }
148 None
149}
150
151fn parse_attributes(tokens: Iter) -> Result<TokenStream, Error> {
152 let mut attrs: TokenStream = TokenStream::new();
153 while let Some(TokenTree::Punct(punct: &Punct)) = tokens.peek() {
154 if punct.as_char() != '#' {
155 break;
156 }
157 let span: Span = punct.span();
158 attrs.extend(iter:tokens.next());
159 match tokens.peek() {
160 Some(TokenTree::Group(group: &Group)) if group.delimiter() == Bracket => {
161 attrs.extend(iter:tokens.next());
162 }
163 _ => return Err(Error::new(span, msg:"unexpected input")),
164 }
165 }
166 Ok(attrs)
167}
168
169pub(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
211pub(crate) fn parse_define_args(tokens: Iter) -> Result<(), Error> {
212 match tokens.peek() {
213 None => Ok(()),
214 Some(token: &TokenTree) => Err(Error::new(
215 token.span(),
216 msg:"unexpected argument to proc_macro_hack macro implementation; args are only accepted on the macro declaration (the `pub use`)",
217 )),
218 }
219}
220
221pub(crate) fn parse_enum_hack(tokens: Iter) -> Result<TokenStream, Error> {
222 parse_keyword(tokens, kw:"enum")?;
223 parse_ident(tokens)?;
224
225 let ref mut braces: &mut IterImpl = parse_group(tokens, delimiter:Brace)?;
226 parse_ident(tokens:braces)?;
227 parse_punct(tokens:braces, ch:'=')?;
228
229 let ref mut parens: &mut IterImpl = parse_group(tokens:braces, delimiter:Parenthesis)?;
230 parse_ident(tokens:parens)?;
231 parse_punct(tokens:parens, ch:'!')?;
232
233 let ref mut inner: &mut IterImpl = parse_group(tokens:parens, delimiter:Brace)?;
234 let token_stream: TokenStream = inner.collect();
235
236 parse_punct(tokens:parens, ch:',')?;
237 let _ = parens.next();
238 parse_punct(tokens:braces, ch:'.')?;
239 let _ = braces.next();
240 parse_punct(tokens:braces, ch:',')?;
241
242 Ok(token_stream)
243}
244
245pub(crate) fn parse_fake_call_site(tokens: Iter) -> Result<FakeCallSite, Error> {
246 parse_punct(tokens, ch:'#')?;
247 let ref mut attr: &mut IterImpl = parse_group(tokens, delimiter:Bracket)?;
248 parse_keyword(tokens:attr, kw:"derive")?;
249 let ref mut path: &mut IterImpl = parse_group(tokens:attr, delimiter:Parenthesis)?;
250 Ok(FakeCallSite {
251 derive: parse_ident(tokens:path)?,
252 rest: tokens.collect(),
253 })
254}
255