]>
Commit | Line | Data |
---|---|---|
0531ce1d XL |
1 | //! This crate provides the [`quote!`] macro for turning Rust syntax tree data |
2 | //! structures into tokens of source code. | |
3 | //! | |
4 | //! [`quote!`]: macro.quote.html | |
5 | //! | |
6 | //! Procedural macros in Rust receive a stream of tokens as input, execute | |
7 | //! arbitrary Rust code to determine how to manipulate those tokens, and produce | |
8 | //! a stream of tokens to hand back to the compiler to compile into the caller's | |
9 | //! crate. Quasi-quoting is a solution to one piece of that -- producing tokens | |
10 | //! to return to the compiler. | |
11 | //! | |
12 | //! The idea of quasi-quoting is that we write *code* that we treat as *data*. | |
13 | //! Within the `quote!` macro, we can write what looks like code to our text | |
14 | //! editor or IDE. We get all the benefits of the editor's brace matching, | |
15 | //! syntax highlighting, indentation, and maybe autocompletion. But rather than | |
16 | //! compiling that as code into the current crate, we can treat it as data, pass | |
17 | //! it around, mutate it, and eventually hand it back to the compiler as tokens | |
18 | //! to compile into the macro caller's crate. | |
19 | //! | |
20 | //! This crate is motivated by the procedural macro use case, but is a | |
21 | //! general-purpose Rust quasi-quoting library and is not specific to procedural | |
22 | //! macros. | |
23 | //! | |
24 | //! *Version requirement: Quote supports any compiler version back to Rust's | |
25 | //! very first support for procedural macros in Rust 1.15.0.* | |
3b2f2976 XL |
26 | //! |
27 | //! ```toml | |
28 | //! [dependencies] | |
8faf50e0 | 29 | //! quote = "0.6" |
3b2f2976 XL |
30 | //! ``` |
31 | //! | |
0531ce1d | 32 | //! ``` |
3b2f2976 XL |
33 | //! #[macro_use] |
34 | //! extern crate quote; | |
0531ce1d XL |
35 | //! # |
36 | //! # fn main() {} | |
3b2f2976 XL |
37 | //! ``` |
38 | //! | |
0531ce1d | 39 | //! # Example |
3b2f2976 | 40 | //! |
0531ce1d XL |
41 | //! The following quasi-quoted block of code is something you might find in [a] |
42 | //! procedural macro having to do with data structure serialization. The `#var` | |
43 | //! syntax performs interpolation of runtime variables into the quoted tokens. | |
44 | //! Check out the documentation of the [`quote!`] macro for more detail about | |
45 | //! the syntax. See also the [`quote_spanned!`] macro which is important for | |
46 | //! implementing hygienic procedural macros. | |
47 | //! | |
48 | //! [a]: https://serde.rs/ | |
49 | //! [`quote_spanned!`]: macro.quote_spanned.html | |
50 | //! | |
51 | //! ``` | |
52 | //! # #[macro_use] | |
53 | //! # extern crate quote; | |
54 | //! # | |
55 | //! # fn main() { | |
56 | //! # let generics = ""; | |
57 | //! # let where_clause = ""; | |
58 | //! # let field_ty = ""; | |
59 | //! # let item_ty = ""; | |
60 | //! # let path = ""; | |
61 | //! # let value = ""; | |
62 | //! # | |
3b2f2976 XL |
63 | //! let tokens = quote! { |
64 | //! struct SerializeWith #generics #where_clause { | |
65 | //! value: &'a #field_ty, | |
66 | //! phantom: ::std::marker::PhantomData<#item_ty>, | |
67 | //! } | |
68 | //! | |
69 | //! impl #generics serde::Serialize for SerializeWith #generics #where_clause { | |
b7449926 | 70 | //! fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> |
8faf50e0 XL |
71 | //! where |
72 | //! S: serde::Serializer, | |
3b2f2976 | 73 | //! { |
b7449926 | 74 | //! #path(self.value, serializer) |
3b2f2976 XL |
75 | //! } |
76 | //! } | |
77 | //! | |
78 | //! SerializeWith { | |
79 | //! value: #value, | |
80 | //! phantom: ::std::marker::PhantomData::<#item_ty>, | |
81 | //! } | |
82 | //! }; | |
0531ce1d XL |
83 | //! # |
84 | //! # } | |
3b2f2976 XL |
85 | //! ``` |
86 | //! | |
0531ce1d | 87 | //! ## Recursion limit |
3b2f2976 | 88 | //! |
0531ce1d XL |
89 | //! The `quote!` macro relies on deep recursion so some large invocations may |
90 | //! fail with "recursion limit reached" when you compile. If it fails, bump up | |
91 | //! the recursion limit by adding `#![recursion_limit = "128"]` to your crate. | |
92 | //! An even higher limit may be necessary for especially large invocations. | |
93 | ||
94 | // Quote types in rustdoc of other crates get linked to here. | |
b7449926 | 95 | #![doc(html_root_url = "https://docs.rs/quote/0.6.8")] |
0531ce1d | 96 | |
b7449926 XL |
97 | #[cfg(all( |
98 | not(all(target_arch = "wasm32", target_os = "unknown")), | |
99 | feature = "proc-macro" | |
100 | ))] | |
0531ce1d | 101 | extern crate proc_macro; |
83c7162d | 102 | extern crate proc_macro2; |
3b2f2976 | 103 | |
8faf50e0 XL |
104 | mod ext; |
105 | pub use ext::TokenStreamExt; | |
3b2f2976 XL |
106 | |
107 | mod to_tokens; | |
0531ce1d | 108 | pub use to_tokens::ToTokens; |
3b2f2976 | 109 | |
0531ce1d XL |
110 | // Not public API. |
111 | #[doc(hidden)] | |
112 | pub mod __rt { | |
b7449926 | 113 | use ext::TokenStreamExt; |
0531ce1d XL |
114 | pub use proc_macro2::*; |
115 | ||
b7449926 XL |
116 | fn is_ident_start(c: u8) -> bool { |
117 | (b'a' <= c && c <= b'z') || (b'A' <= c && c <= b'Z') || c == b'_' | |
118 | } | |
119 | ||
120 | fn is_ident_continue(c: u8) -> bool { | |
121 | (b'a' <= c && c <= b'z') | |
122 | || (b'A' <= c && c <= b'Z') | |
123 | || c == b'_' | |
124 | || (b'0' <= c && c <= b'9') | |
125 | } | |
126 | ||
127 | fn is_ident(token: &str) -> bool { | |
128 | if token.bytes().all(|digit| digit >= b'0' && digit <= b'9') { | |
129 | return false; | |
130 | } | |
131 | ||
132 | let mut bytes = token.bytes(); | |
133 | let first = bytes.next().unwrap(); | |
134 | if !is_ident_start(first) { | |
135 | return false; | |
136 | } | |
137 | for ch in bytes { | |
138 | if !is_ident_continue(ch) { | |
139 | return false; | |
140 | } | |
141 | } | |
142 | true | |
143 | } | |
144 | ||
8faf50e0 | 145 | pub fn parse(tokens: &mut TokenStream, span: Span, s: &str) { |
b7449926 XL |
146 | if is_ident(s) { |
147 | // Fast path, since idents are the most common token. | |
148 | tokens.append(Ident::new(s, span)); | |
149 | } else { | |
150 | let s: TokenStream = s.parse().expect("invalid token stream"); | |
151 | tokens.extend(s.into_iter().map(|mut t| { | |
152 | t.set_span(span); | |
153 | t | |
154 | })); | |
155 | } | |
156 | } | |
157 | ||
158 | macro_rules! push_punct { | |
159 | ($name:ident $char1:tt) => { | |
160 | pub fn $name(tokens: &mut TokenStream, span: Span) { | |
161 | let mut punct = Punct::new($char1, Spacing::Alone); | |
162 | punct.set_span(span); | |
163 | tokens.append(punct); | |
164 | } | |
165 | }; | |
166 | ($name:ident $char1:tt $char2:tt) => { | |
167 | pub fn $name(tokens: &mut TokenStream, span: Span) { | |
168 | let mut punct = Punct::new($char1, Spacing::Joint); | |
169 | punct.set_span(span); | |
170 | tokens.append(punct); | |
171 | let mut punct = Punct::new($char2, Spacing::Alone); | |
172 | punct.set_span(span); | |
173 | tokens.append(punct); | |
174 | } | |
175 | }; | |
176 | ($name:ident $char1:tt $char2:tt $char3:tt) => { | |
177 | pub fn $name(tokens: &mut TokenStream, span: Span) { | |
178 | let mut punct = Punct::new($char1, Spacing::Joint); | |
179 | punct.set_span(span); | |
180 | tokens.append(punct); | |
181 | let mut punct = Punct::new($char2, Spacing::Joint); | |
182 | punct.set_span(span); | |
183 | tokens.append(punct); | |
184 | let mut punct = Punct::new($char3, Spacing::Alone); | |
185 | punct.set_span(span); | |
186 | tokens.append(punct); | |
187 | } | |
188 | }; | |
0531ce1d | 189 | } |
b7449926 XL |
190 | |
191 | push_punct!(push_add '+'); | |
192 | push_punct!(push_add_eq '+' '='); | |
193 | push_punct!(push_and '&'); | |
194 | push_punct!(push_and_and '&' '&'); | |
195 | push_punct!(push_and_eq '&' '='); | |
196 | push_punct!(push_at '@'); | |
197 | push_punct!(push_bang '!'); | |
198 | push_punct!(push_caret '^'); | |
199 | push_punct!(push_caret_eq '^' '='); | |
200 | push_punct!(push_colon ':'); | |
201 | push_punct!(push_colon2 ':' ':'); | |
202 | push_punct!(push_comma ','); | |
203 | push_punct!(push_div '/'); | |
204 | push_punct!(push_div_eq '/' '='); | |
205 | push_punct!(push_dot '.'); | |
206 | push_punct!(push_dot2 '.' '.'); | |
207 | push_punct!(push_dot3 '.' '.' '.'); | |
208 | push_punct!(push_dot_dot_eq '.' '.' '='); | |
209 | push_punct!(push_eq '='); | |
210 | push_punct!(push_eq_eq '=' '='); | |
211 | push_punct!(push_ge '>' '='); | |
212 | push_punct!(push_gt '>'); | |
213 | push_punct!(push_le '<' '='); | |
214 | push_punct!(push_lt '<'); | |
215 | push_punct!(push_mul_eq '*' '='); | |
216 | push_punct!(push_ne '!' '='); | |
217 | push_punct!(push_or '|'); | |
218 | push_punct!(push_or_eq '|' '='); | |
219 | push_punct!(push_or_or '|' '|'); | |
220 | push_punct!(push_pound '#'); | |
221 | push_punct!(push_question '?'); | |
222 | push_punct!(push_rarrow '-' '>'); | |
223 | push_punct!(push_larrow '<' '-'); | |
224 | push_punct!(push_rem '%'); | |
225 | push_punct!(push_rem_eq '%' '='); | |
226 | push_punct!(push_fat_arrow '=' '>'); | |
227 | push_punct!(push_semi ';'); | |
228 | push_punct!(push_shl '<' '<'); | |
229 | push_punct!(push_shl_eq '<' '<' '='); | |
230 | push_punct!(push_shr '>' '>'); | |
231 | push_punct!(push_shr_eq '>' '>' '='); | |
232 | push_punct!(push_star '*'); | |
233 | push_punct!(push_sub '-'); | |
234 | push_punct!(push_sub_eq '-' '='); | |
0531ce1d | 235 | } |
3b2f2976 XL |
236 | |
237 | /// The whole point. | |
0531ce1d XL |
238 | /// |
239 | /// Performs variable interpolation against the input and produces it as | |
8faf50e0 | 240 | /// [`TokenStream`]. For returning tokens to the compiler in a procedural macro, use |
0531ce1d XL |
241 | /// `into()` to build a `TokenStream`. |
242 | /// | |
8faf50e0 | 243 | /// [`TokenStream`]: https://docs.rs/proc-macro2/0.4/proc_macro2/struct.TokenStream.html |
0531ce1d XL |
244 | /// |
245 | /// # Interpolation | |
246 | /// | |
247 | /// Variable interpolation is done with `#var` (similar to `$var` in | |
248 | /// `macro_rules!` macros). This grabs the `var` variable that is currently in | |
b7449926 XL |
249 | /// scope and inserts it in that location in the output tokens. Any type |
250 | /// implementing the [`ToTokens`] trait can be interpolated. This includes most | |
251 | /// Rust primitive types as well as most of the syntax tree types from the [Syn] | |
252 | /// crate. | |
0531ce1d XL |
253 | /// |
254 | /// [`ToTokens`]: trait.ToTokens.html | |
b7449926 | 255 | /// [Syn]: https://github.com/dtolnay/syn |
0531ce1d XL |
256 | /// |
257 | /// Repetition is done using `#(...)*` or `#(...),*` again similar to | |
258 | /// `macro_rules!`. This iterates through the elements of any variable | |
259 | /// interpolated within the repetition and inserts a copy of the repetition body | |
260 | /// for each one. The variables in an interpolation may be anything that | |
261 | /// implements `IntoIterator`, including `Vec` or a pre-existing iterator. | |
262 | /// | |
263 | /// - `#(#var)*` — no separators | |
264 | /// - `#(#var),*` — the character before the asterisk is used as a separator | |
265 | /// - `#( struct #var; )*` — the repetition can contain other tokens | |
266 | /// - `#( #k => println!("{}", #v), )*` — even multiple interpolations | |
267 | /// | |
268 | /// # Hygiene | |
269 | /// | |
270 | /// Any interpolated tokens preserve the `Span` information provided by their | |
271 | /// `ToTokens` implementation. Tokens that originate within the `quote!` | |
83c7162d | 272 | /// invocation are spanned with [`Span::call_site()`]. |
0531ce1d | 273 | /// |
8faf50e0 | 274 | /// [`Span::call_site()`]: https://docs.rs/proc-macro2/0.4/proc_macro2/struct.Span.html#method.call_site |
0531ce1d XL |
275 | /// |
276 | /// A different span can be provided through the [`quote_spanned!`] macro. | |
277 | /// | |
278 | /// [`quote_spanned!`]: macro.quote_spanned.html | |
279 | /// | |
280 | /// # Example | |
281 | /// | |
282 | /// ``` | |
8faf50e0 | 283 | /// # #[cfg(any())] |
0531ce1d | 284 | /// extern crate proc_macro; |
83c7162d | 285 | /// # extern crate proc_macro2 as proc_macro; |
0531ce1d XL |
286 | /// |
287 | /// #[macro_use] | |
288 | /// extern crate quote; | |
289 | /// | |
290 | /// use proc_macro::TokenStream; | |
291 | /// | |
292 | /// # const IGNORE_TOKENS: &'static str = stringify! { | |
293 | /// #[proc_macro_derive(HeapSize)] | |
294 | /// # }; | |
295 | /// pub fn derive_heap_size(input: TokenStream) -> TokenStream { | |
296 | /// // Parse the input and figure out what implementation to generate... | |
297 | /// # const IGNORE_TOKENS: &'static str = stringify! { | |
298 | /// let name = /* ... */; | |
299 | /// let expr = /* ... */; | |
300 | /// # }; | |
301 | /// # | |
302 | /// # let name = 0; | |
303 | /// # let expr = 0; | |
304 | /// | |
305 | /// let expanded = quote! { | |
306 | /// // The generated impl. | |
307 | /// impl ::heapsize::HeapSize for #name { | |
308 | /// fn heap_size_of_children(&self) -> usize { | |
309 | /// #expr | |
310 | /// } | |
311 | /// } | |
312 | /// }; | |
313 | /// | |
314 | /// // Hand the output tokens back to the compiler. | |
315 | /// expanded.into() | |
316 | /// } | |
317 | /// # | |
318 | /// # fn main() {} | |
319 | /// ``` | |
b7449926 | 320 | #[macro_export(local_inner_macros)] |
3b2f2976 | 321 | macro_rules! quote { |
83c7162d | 322 | ($($tt:tt)*) => (quote_spanned!($crate::__rt::Span::call_site()=> $($tt)*)); |
0531ce1d | 323 | } |
3b2f2976 | 324 | |
0531ce1d XL |
325 | /// Same as `quote!`, but applies a given span to all tokens originating within |
326 | /// the macro invocation. | |
327 | /// | |
328 | /// # Syntax | |
329 | /// | |
330 | /// A span expression of type [`Span`], followed by `=>`, followed by the tokens | |
331 | /// to quote. The span expression should be brief -- use a variable for anything | |
332 | /// more than a few characters. There should be no space before the `=>` token. | |
333 | /// | |
8faf50e0 | 334 | /// [`Span`]: https://docs.rs/proc-macro2/0.4/proc_macro2/struct.Span.html |
0531ce1d XL |
335 | /// |
336 | /// ``` | |
337 | /// # #[macro_use] | |
338 | /// # extern crate quote; | |
339 | /// # extern crate proc_macro2; | |
340 | /// # | |
341 | /// # use proc_macro2::Span; | |
342 | /// # | |
343 | /// # fn main() { | |
344 | /// # const IGNORE_TOKENS: &'static str = stringify! { | |
345 | /// let span = /* ... */; | |
346 | /// # }; | |
347 | /// # let span = Span::call_site(); | |
348 | /// # let init = 0; | |
349 | /// | |
350 | /// // On one line, use parentheses. | |
351 | /// let tokens = quote_spanned!(span=> Box::into_raw(Box::new(#init))); | |
352 | /// | |
353 | /// // On multiple lines, place the span at the top and use braces. | |
354 | /// let tokens = quote_spanned! {span=> | |
355 | /// Box::into_raw(Box::new(#init)) | |
356 | /// }; | |
357 | /// # } | |
358 | /// ``` | |
359 | /// | |
83c7162d XL |
360 | /// The lack of space before the `=>` should look jarring to Rust programmers |
361 | /// and this is intentional. The formatting is designed to be visibly | |
362 | /// off-balance and draw the eye a particular way, due to the span expression | |
363 | /// being evaluated in the context of the procedural macro and the remaining | |
364 | /// tokens being evaluated in the generated code. | |
365 | /// | |
0531ce1d XL |
366 | /// # Hygiene |
367 | /// | |
368 | /// Any interpolated tokens preserve the `Span` information provided by their | |
369 | /// `ToTokens` implementation. Tokens that originate within the `quote_spanned!` | |
370 | /// invocation are spanned with the given span argument. | |
371 | /// | |
372 | /// # Example | |
373 | /// | |
374 | /// The following procedural macro code uses `quote_spanned!` to assert that a | |
375 | /// particular Rust type implements the [`Sync`] trait so that references can be | |
376 | /// safely shared between threads. | |
377 | /// | |
378 | /// [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html | |
379 | /// | |
380 | /// ``` | |
381 | /// # #[macro_use] | |
382 | /// # extern crate quote; | |
383 | /// # extern crate proc_macro2; | |
384 | /// # | |
8faf50e0 XL |
385 | /// # use quote::{TokenStreamExt, ToTokens}; |
386 | /// # use proc_macro2::{Span, TokenStream}; | |
0531ce1d XL |
387 | /// # |
388 | /// # struct Type; | |
389 | /// # | |
390 | /// # impl Type { | |
391 | /// # fn span(&self) -> Span { | |
392 | /// # Span::call_site() | |
393 | /// # } | |
394 | /// # } | |
395 | /// # | |
396 | /// # impl ToTokens for Type { | |
8faf50e0 | 397 | /// # fn to_tokens(&self, _tokens: &mut TokenStream) {} |
0531ce1d XL |
398 | /// # } |
399 | /// # | |
400 | /// # fn main() { | |
401 | /// # let ty = Type; | |
83c7162d | 402 | /// # let call_site = Span::call_site(); |
0531ce1d | 403 | /// # |
83c7162d | 404 | /// let ty_span = ty.span(); |
0531ce1d XL |
405 | /// let assert_sync = quote_spanned! {ty_span=> |
406 | /// struct _AssertSync where #ty: Sync; | |
407 | /// }; | |
408 | /// # } | |
409 | /// ``` | |
410 | /// | |
411 | /// If the assertion fails, the user will see an error like the following. The | |
412 | /// input span of their type is hightlighted in the error. | |
413 | /// | |
414 | /// ```text | |
415 | /// error[E0277]: the trait bound `*const (): std::marker::Sync` is not satisfied | |
416 | /// --> src/main.rs:10:21 | |
417 | /// | | |
418 | /// 10 | static ref PTR: *const () = &(); | |
419 | /// | ^^^^^^^^^ `*const ()` cannot be shared between threads safely | |
420 | /// ``` | |
421 | /// | |
422 | /// In this example it is important for the where-clause to be spanned with the | |
423 | /// line/column information of the user's input type so that error messages are | |
424 | /// placed appropriately by the compiler. But it is also incredibly important | |
425 | /// that `Sync` resolves at the macro definition site and not the macro call | |
426 | /// site. If we resolve `Sync` at the same span that the user's type is going to | |
427 | /// be resolved, then they could bypass our check by defining their own trait | |
428 | /// named `Sync` that is implemented for their type. | |
b7449926 | 429 | #[macro_export(local_inner_macros)] |
0531ce1d XL |
430 | macro_rules! quote_spanned { |
431 | ($span:expr=> $($tt:tt)*) => { | |
3b2f2976 | 432 | { |
8faf50e0 | 433 | let mut _s = $crate::__rt::TokenStream::new(); |
0531ce1d XL |
434 | let _span = $span; |
435 | quote_each_token!(_s _span $($tt)*); | |
3b2f2976 XL |
436 | _s |
437 | } | |
438 | }; | |
439 | } | |
440 | ||
441 | // Extract the names of all #metavariables and pass them to the $finish macro. | |
442 | // | |
443 | // in: pounded_var_names!(then () a #b c #( #d )* #e) | |
444 | // out: then!(() b d e) | |
b7449926 | 445 | #[macro_export(local_inner_macros)] |
3b2f2976 XL |
446 | #[doc(hidden)] |
447 | macro_rules! pounded_var_names { | |
448 | ($finish:ident ($($found:ident)*) # ( $($inner:tt)* ) $($rest:tt)*) => { | |
449 | pounded_var_names!($finish ($($found)*) $($inner)* $($rest)*) | |
450 | }; | |
451 | ||
452 | ($finish:ident ($($found:ident)*) # [ $($inner:tt)* ] $($rest:tt)*) => { | |
453 | pounded_var_names!($finish ($($found)*) $($inner)* $($rest)*) | |
454 | }; | |
455 | ||
456 | ($finish:ident ($($found:ident)*) # { $($inner:tt)* } $($rest:tt)*) => { | |
457 | pounded_var_names!($finish ($($found)*) $($inner)* $($rest)*) | |
458 | }; | |
459 | ||
460 | ($finish:ident ($($found:ident)*) # $first:ident $($rest:tt)*) => { | |
461 | pounded_var_names!($finish ($($found)* $first) $($rest)*) | |
462 | }; | |
463 | ||
464 | ($finish:ident ($($found:ident)*) ( $($inner:tt)* ) $($rest:tt)*) => { | |
465 | pounded_var_names!($finish ($($found)*) $($inner)* $($rest)*) | |
466 | }; | |
467 | ||
468 | ($finish:ident ($($found:ident)*) [ $($inner:tt)* ] $($rest:tt)*) => { | |
469 | pounded_var_names!($finish ($($found)*) $($inner)* $($rest)*) | |
470 | }; | |
471 | ||
472 | ($finish:ident ($($found:ident)*) { $($inner:tt)* } $($rest:tt)*) => { | |
473 | pounded_var_names!($finish ($($found)*) $($inner)* $($rest)*) | |
474 | }; | |
475 | ||
476 | ($finish:ident ($($found:ident)*) $ignore:tt $($rest:tt)*) => { | |
477 | pounded_var_names!($finish ($($found)*) $($rest)*) | |
478 | }; | |
479 | ||
480 | ($finish:ident ($($found:ident)*)) => { | |
481 | $finish!(() $($found)*) | |
482 | }; | |
483 | } | |
484 | ||
485 | // in: nested_tuples_pat!(() a b c d e) | |
486 | // out: ((((a b) c) d) e) | |
487 | // | |
488 | // in: nested_tuples_pat!(() a) | |
489 | // out: a | |
b7449926 | 490 | #[macro_export(local_inner_macros)] |
3b2f2976 XL |
491 | #[doc(hidden)] |
492 | macro_rules! nested_tuples_pat { | |
493 | (()) => { | |
494 | &() | |
495 | }; | |
496 | ||
497 | (() $first:ident $($rest:ident)*) => { | |
498 | nested_tuples_pat!(($first) $($rest)*) | |
499 | }; | |
500 | ||
501 | (($pat:pat) $first:ident $($rest:ident)*) => { | |
502 | nested_tuples_pat!((($pat, $first)) $($rest)*) | |
503 | }; | |
504 | ||
505 | (($done:pat)) => { | |
506 | $done | |
507 | }; | |
508 | } | |
509 | ||
510 | // in: multi_zip_expr!(() a b c d e) | |
511 | // out: a.into_iter().zip(b).zip(c).zip(d).zip(e) | |
512 | // | |
513 | // in: multi_zip_iter!(() a) | |
514 | // out: a | |
b7449926 | 515 | #[macro_export(local_inner_macros)] |
3b2f2976 XL |
516 | #[doc(hidden)] |
517 | macro_rules! multi_zip_expr { | |
518 | (()) => { | |
519 | &[] | |
520 | }; | |
521 | ||
522 | (() $single:ident) => { | |
523 | $single | |
524 | }; | |
525 | ||
526 | (() $first:ident $($rest:ident)*) => { | |
527 | multi_zip_expr!(($first.into_iter()) $($rest)*) | |
528 | }; | |
529 | ||
530 | (($zips:expr) $first:ident $($rest:ident)*) => { | |
531 | multi_zip_expr!(($zips.zip($first)) $($rest)*) | |
532 | }; | |
533 | ||
534 | (($done:expr)) => { | |
535 | $done | |
536 | }; | |
537 | } | |
538 | ||
b7449926 | 539 | #[macro_export(local_inner_macros)] |
3b2f2976 XL |
540 | #[doc(hidden)] |
541 | macro_rules! quote_each_token { | |
0531ce1d | 542 | ($tokens:ident $span:ident) => {}; |
3b2f2976 | 543 | |
0531ce1d XL |
544 | ($tokens:ident $span:ident # ! $($rest:tt)*) => { |
545 | quote_each_token!($tokens $span #); | |
546 | quote_each_token!($tokens $span !); | |
547 | quote_each_token!($tokens $span $($rest)*); | |
3b2f2976 XL |
548 | }; |
549 | ||
0531ce1d | 550 | ($tokens:ident $span:ident # ( $($inner:tt)* ) * $($rest:tt)*) => { |
3b2f2976 XL |
551 | for pounded_var_names!(nested_tuples_pat () $($inner)*) |
552 | in pounded_var_names!(multi_zip_expr () $($inner)*) { | |
0531ce1d | 553 | quote_each_token!($tokens $span $($inner)*); |
3b2f2976 | 554 | } |
0531ce1d | 555 | quote_each_token!($tokens $span $($rest)*); |
3b2f2976 XL |
556 | }; |
557 | ||
0531ce1d | 558 | ($tokens:ident $span:ident # ( $($inner:tt)* ) $sep:tt * $($rest:tt)*) => { |
3b2f2976 XL |
559 | for (_i, pounded_var_names!(nested_tuples_pat () $($inner)*)) |
560 | in pounded_var_names!(multi_zip_expr () $($inner)*).into_iter().enumerate() { | |
561 | if _i > 0 { | |
0531ce1d | 562 | quote_each_token!($tokens $span $sep); |
3b2f2976 | 563 | } |
0531ce1d | 564 | quote_each_token!($tokens $span $($inner)*); |
3b2f2976 | 565 | } |
0531ce1d | 566 | quote_each_token!($tokens $span $($rest)*); |
3b2f2976 XL |
567 | }; |
568 | ||
0531ce1d XL |
569 | ($tokens:ident $span:ident # [ $($inner:tt)* ] $($rest:tt)*) => { |
570 | quote_each_token!($tokens $span #); | |
8faf50e0 | 571 | $tokens.extend({ |
83c7162d | 572 | let mut g = $crate::__rt::Group::new( |
0531ce1d | 573 | $crate::__rt::Delimiter::Bracket, |
b7449926 | 574 | quote_spanned!($span=> $($inner)*), |
83c7162d XL |
575 | ); |
576 | g.set_span($span); | |
8faf50e0 | 577 | Some($crate::__rt::TokenTree::from(g)) |
83c7162d | 578 | }); |
0531ce1d | 579 | quote_each_token!($tokens $span $($rest)*); |
3b2f2976 XL |
580 | }; |
581 | ||
0531ce1d | 582 | ($tokens:ident $span:ident # $first:ident $($rest:tt)*) => { |
3b2f2976 | 583 | $crate::ToTokens::to_tokens(&$first, &mut $tokens); |
0531ce1d | 584 | quote_each_token!($tokens $span $($rest)*); |
3b2f2976 XL |
585 | }; |
586 | ||
0531ce1d | 587 | ($tokens:ident $span:ident ( $($first:tt)* ) $($rest:tt)*) => { |
8faf50e0 | 588 | $tokens.extend({ |
83c7162d | 589 | let mut g = $crate::__rt::Group::new( |
0531ce1d | 590 | $crate::__rt::Delimiter::Parenthesis, |
b7449926 | 591 | quote_spanned!($span=> $($first)*), |
83c7162d XL |
592 | ); |
593 | g.set_span($span); | |
8faf50e0 | 594 | Some($crate::__rt::TokenTree::from(g)) |
83c7162d | 595 | }); |
0531ce1d | 596 | quote_each_token!($tokens $span $($rest)*); |
3b2f2976 XL |
597 | }; |
598 | ||
0531ce1d | 599 | ($tokens:ident $span:ident [ $($first:tt)* ] $($rest:tt)*) => { |
8faf50e0 | 600 | $tokens.extend({ |
83c7162d | 601 | let mut g = $crate::__rt::Group::new( |
0531ce1d | 602 | $crate::__rt::Delimiter::Bracket, |
b7449926 | 603 | quote_spanned!($span=> $($first)*), |
83c7162d XL |
604 | ); |
605 | g.set_span($span); | |
8faf50e0 | 606 | Some($crate::__rt::TokenTree::from(g)) |
83c7162d | 607 | }); |
0531ce1d | 608 | quote_each_token!($tokens $span $($rest)*); |
3b2f2976 XL |
609 | }; |
610 | ||
0531ce1d | 611 | ($tokens:ident $span:ident { $($first:tt)* } $($rest:tt)*) => { |
8faf50e0 | 612 | $tokens.extend({ |
83c7162d | 613 | let mut g = $crate::__rt::Group::new( |
0531ce1d | 614 | $crate::__rt::Delimiter::Brace, |
b7449926 | 615 | quote_spanned!($span=> $($first)*), |
83c7162d XL |
616 | ); |
617 | g.set_span($span); | |
8faf50e0 | 618 | Some($crate::__rt::TokenTree::from(g)) |
83c7162d | 619 | }); |
0531ce1d | 620 | quote_each_token!($tokens $span $($rest)*); |
3b2f2976 XL |
621 | }; |
622 | ||
b7449926 XL |
623 | ($tokens:ident $span:ident + $($rest:tt)*) => { |
624 | $crate::__rt::push_add(&mut $tokens, $span); | |
625 | quote_each_token!($tokens $span $($rest)*); | |
626 | }; | |
627 | ||
628 | ($tokens:ident $span:ident += $($rest:tt)*) => { | |
629 | $crate::__rt::push_add_eq(&mut $tokens, $span); | |
630 | quote_each_token!($tokens $span $($rest)*); | |
631 | }; | |
632 | ||
633 | ($tokens:ident $span:ident & $($rest:tt)*) => { | |
634 | $crate::__rt::push_and(&mut $tokens, $span); | |
635 | quote_each_token!($tokens $span $($rest)*); | |
636 | }; | |
637 | ||
638 | ($tokens:ident $span:ident && $($rest:tt)*) => { | |
639 | $crate::__rt::push_and_and(&mut $tokens, $span); | |
640 | quote_each_token!($tokens $span $($rest)*); | |
641 | }; | |
642 | ||
643 | ($tokens:ident $span:ident &= $($rest:tt)*) => { | |
644 | $crate::__rt::push_and_eq(&mut $tokens, $span); | |
645 | quote_each_token!($tokens $span $($rest)*); | |
646 | }; | |
647 | ||
648 | ($tokens:ident $span:ident @ $($rest:tt)*) => { | |
649 | $crate::__rt::push_at(&mut $tokens, $span); | |
650 | quote_each_token!($tokens $span $($rest)*); | |
651 | }; | |
652 | ||
653 | ($tokens:ident $span:ident ! $($rest:tt)*) => { | |
654 | $crate::__rt::push_bang(&mut $tokens, $span); | |
655 | quote_each_token!($tokens $span $($rest)*); | |
656 | }; | |
657 | ||
658 | ($tokens:ident $span:ident ^ $($rest:tt)*) => { | |
659 | $crate::__rt::push_caret(&mut $tokens, $span); | |
660 | quote_each_token!($tokens $span $($rest)*); | |
661 | }; | |
662 | ||
663 | ($tokens:ident $span:ident ^= $($rest:tt)*) => { | |
664 | $crate::__rt::push_caret_eq(&mut $tokens, $span); | |
665 | quote_each_token!($tokens $span $($rest)*); | |
666 | }; | |
667 | ||
668 | ($tokens:ident $span:ident : $($rest:tt)*) => { | |
669 | $crate::__rt::push_colon(&mut $tokens, $span); | |
670 | quote_each_token!($tokens $span $($rest)*); | |
671 | }; | |
672 | ||
673 | ($tokens:ident $span:ident :: $($rest:tt)*) => { | |
674 | $crate::__rt::push_colon2(&mut $tokens, $span); | |
675 | quote_each_token!($tokens $span $($rest)*); | |
676 | }; | |
677 | ||
678 | ($tokens:ident $span:ident , $($rest:tt)*) => { | |
679 | $crate::__rt::push_comma(&mut $tokens, $span); | |
680 | quote_each_token!($tokens $span $($rest)*); | |
681 | }; | |
682 | ||
683 | ($tokens:ident $span:ident / $($rest:tt)*) => { | |
684 | $crate::__rt::push_div(&mut $tokens, $span); | |
685 | quote_each_token!($tokens $span $($rest)*); | |
686 | }; | |
687 | ||
688 | ($tokens:ident $span:ident /= $($rest:tt)*) => { | |
689 | $crate::__rt::push_div_eq(&mut $tokens, $span); | |
690 | quote_each_token!($tokens $span $($rest)*); | |
691 | }; | |
692 | ||
693 | ($tokens:ident $span:ident . $($rest:tt)*) => { | |
694 | $crate::__rt::push_dot(&mut $tokens, $span); | |
695 | quote_each_token!($tokens $span $($rest)*); | |
696 | }; | |
697 | ||
698 | ($tokens:ident $span:ident .. $($rest:tt)*) => { | |
699 | $crate::__rt::push_dot2(&mut $tokens, $span); | |
700 | quote_each_token!($tokens $span $($rest)*); | |
701 | }; | |
702 | ||
703 | ($tokens:ident $span:ident ... $($rest:tt)*) => { | |
704 | $crate::__rt::push_dot3(&mut $tokens, $span); | |
705 | quote_each_token!($tokens $span $($rest)*); | |
706 | }; | |
707 | ||
708 | ($tokens:ident $span:ident ..= $($rest:tt)*) => { | |
709 | $crate::__rt::push_dot_dot_eq(&mut $tokens, $span); | |
710 | quote_each_token!($tokens $span $($rest)*); | |
711 | }; | |
712 | ||
713 | ($tokens:ident $span:ident = $($rest:tt)*) => { | |
714 | $crate::__rt::push_eq(&mut $tokens, $span); | |
715 | quote_each_token!($tokens $span $($rest)*); | |
716 | }; | |
717 | ||
718 | ($tokens:ident $span:ident == $($rest:tt)*) => { | |
719 | $crate::__rt::push_eq_eq(&mut $tokens, $span); | |
720 | quote_each_token!($tokens $span $($rest)*); | |
721 | }; | |
722 | ||
723 | ($tokens:ident $span:ident >= $($rest:tt)*) => { | |
724 | $crate::__rt::push_ge(&mut $tokens, $span); | |
725 | quote_each_token!($tokens $span $($rest)*); | |
726 | }; | |
727 | ||
728 | ($tokens:ident $span:ident > $($rest:tt)*) => { | |
729 | $crate::__rt::push_gt(&mut $tokens, $span); | |
730 | quote_each_token!($tokens $span $($rest)*); | |
731 | }; | |
732 | ||
733 | ($tokens:ident $span:ident <= $($rest:tt)*) => { | |
734 | $crate::__rt::push_le(&mut $tokens, $span); | |
735 | quote_each_token!($tokens $span $($rest)*); | |
736 | }; | |
737 | ||
738 | ($tokens:ident $span:ident < $($rest:tt)*) => { | |
739 | $crate::__rt::push_lt(&mut $tokens, $span); | |
740 | quote_each_token!($tokens $span $($rest)*); | |
741 | }; | |
742 | ||
743 | ($tokens:ident $span:ident *= $($rest:tt)*) => { | |
744 | $crate::__rt::push_mul_eq(&mut $tokens, $span); | |
745 | quote_each_token!($tokens $span $($rest)*); | |
746 | }; | |
747 | ||
748 | ($tokens:ident $span:ident != $($rest:tt)*) => { | |
749 | $crate::__rt::push_ne(&mut $tokens, $span); | |
750 | quote_each_token!($tokens $span $($rest)*); | |
751 | }; | |
752 | ||
753 | ($tokens:ident $span:ident | $($rest:tt)*) => { | |
754 | $crate::__rt::push_or(&mut $tokens, $span); | |
755 | quote_each_token!($tokens $span $($rest)*); | |
756 | }; | |
757 | ||
758 | ($tokens:ident $span:ident |= $($rest:tt)*) => { | |
759 | $crate::__rt::push_or_eq(&mut $tokens, $span); | |
760 | quote_each_token!($tokens $span $($rest)*); | |
761 | }; | |
762 | ||
763 | ($tokens:ident $span:ident || $($rest:tt)*) => { | |
764 | $crate::__rt::push_or_or(&mut $tokens, $span); | |
765 | quote_each_token!($tokens $span $($rest)*); | |
766 | }; | |
767 | ||
768 | ($tokens:ident $span:ident # $($rest:tt)*) => { | |
769 | $crate::__rt::push_pound(&mut $tokens, $span); | |
770 | quote_each_token!($tokens $span $($rest)*); | |
771 | }; | |
772 | ||
773 | ($tokens:ident $span:ident ? $($rest:tt)*) => { | |
774 | $crate::__rt::push_question(&mut $tokens, $span); | |
775 | quote_each_token!($tokens $span $($rest)*); | |
776 | }; | |
777 | ||
778 | ($tokens:ident $span:ident -> $($rest:tt)*) => { | |
779 | $crate::__rt::push_rarrow(&mut $tokens, $span); | |
780 | quote_each_token!($tokens $span $($rest)*); | |
781 | }; | |
782 | ||
783 | ($tokens:ident $span:ident <- $($rest:tt)*) => { | |
784 | $crate::__rt::push_larrow(&mut $tokens, $span); | |
785 | quote_each_token!($tokens $span $($rest)*); | |
786 | }; | |
787 | ||
788 | ($tokens:ident $span:ident % $($rest:tt)*) => { | |
789 | $crate::__rt::push_rem(&mut $tokens, $span); | |
790 | quote_each_token!($tokens $span $($rest)*); | |
791 | }; | |
792 | ||
793 | ($tokens:ident $span:ident %= $($rest:tt)*) => { | |
794 | $crate::__rt::push_rem_eq(&mut $tokens, $span); | |
795 | quote_each_token!($tokens $span $($rest)*); | |
796 | }; | |
797 | ||
798 | ($tokens:ident $span:ident => $($rest:tt)*) => { | |
799 | $crate::__rt::push_fat_arrow(&mut $tokens, $span); | |
800 | quote_each_token!($tokens $span $($rest)*); | |
801 | }; | |
802 | ||
803 | ($tokens:ident $span:ident ; $($rest:tt)*) => { | |
804 | $crate::__rt::push_semi(&mut $tokens, $span); | |
805 | quote_each_token!($tokens $span $($rest)*); | |
806 | }; | |
807 | ||
808 | ($tokens:ident $span:ident << $($rest:tt)*) => { | |
809 | $crate::__rt::push_shl(&mut $tokens, $span); | |
810 | quote_each_token!($tokens $span $($rest)*); | |
811 | }; | |
812 | ||
813 | ($tokens:ident $span:ident <<= $($rest:tt)*) => { | |
814 | $crate::__rt::push_shl_eq(&mut $tokens, $span); | |
815 | quote_each_token!($tokens $span $($rest)*); | |
816 | }; | |
817 | ||
818 | ($tokens:ident $span:ident >> $($rest:tt)*) => { | |
819 | $crate::__rt::push_shr(&mut $tokens, $span); | |
820 | quote_each_token!($tokens $span $($rest)*); | |
821 | }; | |
822 | ||
823 | ($tokens:ident $span:ident >>= $($rest:tt)*) => { | |
824 | $crate::__rt::push_shr_eq(&mut $tokens, $span); | |
825 | quote_each_token!($tokens $span $($rest)*); | |
826 | }; | |
827 | ||
828 | ($tokens:ident $span:ident * $($rest:tt)*) => { | |
829 | $crate::__rt::push_star(&mut $tokens, $span); | |
830 | quote_each_token!($tokens $span $($rest)*); | |
831 | }; | |
832 | ||
833 | ($tokens:ident $span:ident - $($rest:tt)*) => { | |
834 | $crate::__rt::push_sub(&mut $tokens, $span); | |
835 | quote_each_token!($tokens $span $($rest)*); | |
836 | }; | |
837 | ||
838 | ($tokens:ident $span:ident -= $($rest:tt)*) => { | |
839 | $crate::__rt::push_sub_eq(&mut $tokens, $span); | |
840 | quote_each_token!($tokens $span $($rest)*); | |
841 | }; | |
842 | ||
0531ce1d | 843 | ($tokens:ident $span:ident $first:tt $($rest:tt)*) => { |
b7449926 | 844 | $crate::__rt::parse(&mut $tokens, $span, quote_stringify!($first)); |
0531ce1d | 845 | quote_each_token!($tokens $span $($rest)*); |
3b2f2976 XL |
846 | }; |
847 | } | |
b7449926 XL |
848 | |
849 | // Unhygienically invoke whatever `stringify` the caller has in scope i.e. not a | |
850 | // local macro. The macros marked `local_inner_macros` above cannot invoke | |
851 | // `stringify` directly. | |
852 | #[macro_export] | |
853 | #[doc(hidden)] | |
854 | macro_rules! quote_stringify { | |
855 | ($tt:tt) => { | |
856 | stringify!($tt) | |
857 | }; | |
858 | } |