futures_await_quote/
lib.rs

1//! Quasi-quoting without a Syntex dependency, intended for use with [Macros
2//! 1.1](https://github.com/rust-lang/rfcs/blob/master/text/1681-macros-1.1.md).
3//!
4//! ```toml
5//! [dependencies]
6//! quote = "0.3"
7//! ```
8//!
9//! ```rust,ignore
10//! #[macro_use]
11//! extern crate quote;
12//! ```
13//!
14//! Interpolation is done with `#var`:
15//!
16//! ```text
17//! let tokens = quote! {
18//!     struct SerializeWith #generics #where_clause {
19//!         value: &'a #field_ty,
20//!         phantom: ::std::marker::PhantomData<#item_ty>,
21//!     }
22//!
23//!     impl #generics serde::Serialize for SerializeWith #generics #where_clause {
24//!         fn serialize<S>(&self, s: &mut S) -> Result<(), S::Error>
25//!             where S: serde::Serializer
26//!         {
27//!             #path(self.value, s)
28//!         }
29//!     }
30//!
31//!     SerializeWith {
32//!         value: #value,
33//!         phantom: ::std::marker::PhantomData::<#item_ty>,
34//!     }
35//! };
36//! ```
37//!
38//! Repetition is done using `#(...)*` or `#(...),*` very similar to `macro_rules!`:
39//!
40//! - `#(#var)*` - no separators
41//! - `#(#var),*` - the character before the asterisk is used as a separator
42//! - `#( struct #var; )*` - the repetition can contain other things
43//! - `#( #k => println!("{}", #v), )*` - even multiple interpolations
44//!
45//! The return type of `quote!` is `quote::Tokens`. Tokens can be interpolated into
46//! other quotes:
47//!
48//! ```text
49//! let t = quote! { /* ... */ };
50//! return quote! { /* ... */ #t /* ... */ };
51//! ```
52//!
53//! Call `to_string()` or `as_str()` on a Tokens to get a `String` or `&str` of Rust
54//! code.
55//!
56//! The `quote!` macro relies on deep recursion so some large invocations may fail
57//! with "recursion limit reached" when you compile. If it fails, bump up the
58//! recursion limit by adding `#![recursion_limit = "128"]` to your crate. An even
59//! higher limit may be necessary for especially large invocations.
60
61extern crate proc_macro;
62extern crate proc_macro2;
63
64mod tokens;
65pub use tokens::Tokens;
66
67mod to_tokens;
68pub use to_tokens::{ToTokens, ByteStr};
69
70pub mod __rt {
71    pub use proc_macro2::*;
72
73    pub fn parse(tokens: &mut ::Tokens, s: &str) {
74        let s: TokenStream = s.parse().expect("invalid token stream");
75        tokens.append_all(s.into_iter());
76    }
77
78    pub fn append_kind(tokens: &mut ::Tokens, kind: TokenNode) {
79        tokens.append(TokenTree {
80            span: Default::default(),
81            kind: kind,
82        })
83    }
84}
85
86/// The whole point.
87#[macro_export]
88macro_rules! quote {
89    () => {
90        $crate::Tokens::new()
91    };
92
93    ($($tt:tt)+) => {
94        {
95            let mut _s = $crate::Tokens::new();
96            quote_each_token!(_s $($tt)*);
97            _s
98        }
99    };
100}
101
102// Extract the names of all #metavariables and pass them to the $finish macro.
103//
104// in:   pounded_var_names!(then () a #b c #( #d )* #e)
105// out:  then!(() b d e)
106#[macro_export]
107#[doc(hidden)]
108macro_rules! pounded_var_names {
109    ($finish:ident ($($found:ident)*) # ( $($inner:tt)* ) $($rest:tt)*) => {
110        pounded_var_names!($finish ($($found)*) $($inner)* $($rest)*)
111    };
112
113    ($finish:ident ($($found:ident)*) # [ $($inner:tt)* ] $($rest:tt)*) => {
114        pounded_var_names!($finish ($($found)*) $($inner)* $($rest)*)
115    };
116
117    ($finish:ident ($($found:ident)*) # { $($inner:tt)* } $($rest:tt)*) => {
118        pounded_var_names!($finish ($($found)*) $($inner)* $($rest)*)
119    };
120
121    ($finish:ident ($($found:ident)*) # $first:ident $($rest:tt)*) => {
122        pounded_var_names!($finish ($($found)* $first) $($rest)*)
123    };
124
125    ($finish:ident ($($found:ident)*) ( $($inner:tt)* ) $($rest:tt)*) => {
126        pounded_var_names!($finish ($($found)*) $($inner)* $($rest)*)
127    };
128
129    ($finish:ident ($($found:ident)*) [ $($inner:tt)* ] $($rest:tt)*) => {
130        pounded_var_names!($finish ($($found)*) $($inner)* $($rest)*)
131    };
132
133    ($finish:ident ($($found:ident)*) { $($inner:tt)* } $($rest:tt)*) => {
134        pounded_var_names!($finish ($($found)*) $($inner)* $($rest)*)
135    };
136
137    ($finish:ident ($($found:ident)*) $ignore:tt $($rest:tt)*) => {
138        pounded_var_names!($finish ($($found)*) $($rest)*)
139    };
140
141    ($finish:ident ($($found:ident)*)) => {
142        $finish!(() $($found)*)
143    };
144}
145
146// in:   nested_tuples_pat!(() a b c d e)
147// out:  ((((a b) c) d) e)
148//
149// in:   nested_tuples_pat!(() a)
150// out:  a
151#[macro_export]
152#[doc(hidden)]
153macro_rules! nested_tuples_pat {
154    (()) => {
155        &()
156    };
157
158    (() $first:ident $($rest:ident)*) => {
159        nested_tuples_pat!(($first) $($rest)*)
160    };
161
162    (($pat:pat) $first:ident $($rest:ident)*) => {
163        nested_tuples_pat!((($pat, $first)) $($rest)*)
164    };
165
166    (($done:pat)) => {
167        $done
168    };
169}
170
171// in:   multi_zip_expr!(() a b c d e)
172// out:  a.into_iter().zip(b).zip(c).zip(d).zip(e)
173//
174// in:   multi_zip_iter!(() a)
175// out:  a
176#[macro_export]
177#[doc(hidden)]
178macro_rules! multi_zip_expr {
179    (()) => {
180        &[]
181    };
182
183    (() $single:ident) => {
184        $single
185    };
186
187    (() $first:ident $($rest:ident)*) => {
188        multi_zip_expr!(($first.into_iter()) $($rest)*)
189    };
190
191    (($zips:expr) $first:ident $($rest:ident)*) => {
192        multi_zip_expr!(($zips.zip($first)) $($rest)*)
193    };
194
195    (($done:expr)) => {
196        $done
197    };
198}
199
200#[macro_export]
201#[doc(hidden)]
202macro_rules! quote_each_token {
203    ($tokens:ident) => {};
204
205    ($tokens:ident # ! $($rest:tt)*) => {
206        quote_each_token!($tokens #);
207        quote_each_token!($tokens !);
208        quote_each_token!($tokens $($rest)*);
209    };
210
211    ($tokens:ident # ( $($inner:tt)* ) * $($rest:tt)*) => {
212        for pounded_var_names!(nested_tuples_pat () $($inner)*)
213        in pounded_var_names!(multi_zip_expr () $($inner)*) {
214            quote_each_token!($tokens $($inner)*);
215        }
216        quote_each_token!($tokens $($rest)*);
217    };
218
219    ($tokens:ident # ( $($inner:tt)* ) $sep:tt * $($rest:tt)*) => {
220        for (_i, pounded_var_names!(nested_tuples_pat () $($inner)*))
221        in pounded_var_names!(multi_zip_expr () $($inner)*).into_iter().enumerate() {
222            if _i > 0 {
223                quote_each_token!($tokens $sep);
224            }
225            quote_each_token!($tokens $($inner)*);
226        }
227        quote_each_token!($tokens $($rest)*);
228    };
229
230    ($tokens:ident # [ $($inner:tt)* ] $($rest:tt)*) => {
231        quote_each_token!($tokens #);
232        $crate::__rt::append_kind(&mut $tokens,
233            $crate::__rt::TokenNode::Group(
234                $crate::__rt::Delimiter::Bracket,
235                quote! { $($inner)* }.into()
236            ));
237        quote_each_token!($tokens $($rest)*);
238    };
239
240    ($tokens:ident # $first:ident $($rest:tt)*) => {
241        $crate::ToTokens::to_tokens(&$first, &mut $tokens);
242        quote_each_token!($tokens $($rest)*);
243    };
244
245    ($tokens:ident ( $($first:tt)* ) $($rest:tt)*) => {
246        $crate::__rt::append_kind(&mut $tokens,
247            $crate::__rt::TokenNode::Group(
248                $crate::__rt::Delimiter::Parenthesis,
249                quote! { $($first)* }.into()
250            ));
251        quote_each_token!($tokens $($rest)*);
252    };
253
254    ($tokens:ident [ $($first:tt)* ] $($rest:tt)*) => {
255        $crate::__rt::append_kind(&mut $tokens,
256            $crate::__rt::TokenNode::Group(
257                $crate::__rt::Delimiter::Bracket,
258                quote! { $($first)* }.into()
259            ));
260        quote_each_token!($tokens $($rest)*);
261    };
262
263    ($tokens:ident { $($first:tt)* } $($rest:tt)*) => {
264        $crate::__rt::append_kind(&mut $tokens,
265            $crate::__rt::TokenNode::Group(
266                $crate::__rt::Delimiter::Brace,
267                quote! { $($first)* }.into()
268            ));
269        quote_each_token!($tokens $($rest)*);
270    };
271
272    ($tokens:ident $first:tt $($rest:tt)*) => {
273        // TODO: this seems slow... special case some `:tt` arguments?
274        $crate::__rt::parse(&mut $tokens, stringify!($first));
275        quote_each_token!($tokens $($rest)*);
276    };
277}