1#![allow(dead_code)]
2
3mod to_tokens;
4mod token_stream;
5
6pub mod runtime;
7pub use to_tokens::*;
8pub use token_stream::*;
9
10/// The whole point.
11///
12/// Performs variable interpolation against the input and produces it as
13/// [`TokenStream`].
14///
15/// # Interpolation
16///
17/// Variable interpolation is done with `#var` (similar to `$var` in
18/// `macro_rules!` macros). This grabs the `var` variable that is currently in
19/// scope and inserts it in that location in the output tokens. Any type
20/// implementing the [`ToTokens`] trait can be interpolated. This includes most
21/// Rust primitive types.
22///
23/// [`ToTokens`]: trait.ToTokens.html
24///
25/// Repetition is done using `#(...)*` or `#(...),*` again similar to
26/// `macro_rules!`. This iterates through the elements of any variable
27/// interpolated within the repetition and inserts a copy of the repetition body
28/// for each one. The variables in an interpolation may be a `Vec`, slice,
29/// `BTreeSet`, or any `Iterator`.
30///
31/// - `#(#var)*` — no separators
32/// - `#(#var),*` — the character before the asterisk is used as a separator
33/// - `#( struct #var; )*` — the repetition can contain other tokens
34/// - `#( #k => println!("{}", #v), )*` — even multiple interpolations
35#[macro_export]
36#[doc(hidden)]
37macro_rules! quote {
38 () => {
39 $crate::tokens::TokenStream::new()
40 };
41 ($($tt:tt)*) => {{
42 let mut _s = $crate::tokens::TokenStream::new();
43 $crate::quote_each_token!(_s $($tt)*);
44 _s
45 }};
46}
47
48/// Formatting macro for constructing a `TokenStream`.
49///
50/// <br>
51///
52/// # Syntax
53///
54/// Syntax is copied from the [`format!`] macro, supporting both positional and
55/// named arguments.
56#[macro_export]
57#[doc(hidden)]
58macro_rules! format_token {
59 ($($fmt:tt)*) => {
60 $crate::TokenStream::from(format!($($fmt)*))
61 };
62}
63
64// Extract the names of all #metavariables and pass them to the $call macro.
65//
66// in: pounded_var_names!(then!(...) a #b c #( #d )* #e)
67// out: then!(... b);
68// then!(... d);
69// then!(... e);
70#[macro_export]
71#[doc(hidden)]
72macro_rules! pounded_var_names {
73 ($call:ident! $extra:tt $($tts:tt)*) => {
74 $crate::pounded_var_names_with_context!($call! $extra
75 (@ $($tts)*)
76 ($($tts)* @)
77 )
78 };
79}
80
81#[macro_export]
82#[doc(hidden)]
83macro_rules! pounded_var_names_with_context {
84 ($call:ident! $extra:tt ($($b1:tt)*) ($($curr:tt)*)) => {
85 $(
86 $crate::pounded_var_with_context!($call! $extra $b1 $curr);
87 )*
88 };
89}
90
91#[macro_export]
92#[doc(hidden)]
93macro_rules! pounded_var_with_context {
94 ($call:ident! $extra:tt $b1:tt ( $($inner:tt)* )) => {
95 $crate::pounded_var_names!($call! $extra $($inner)*);
96 };
97
98 ($call:ident! $extra:tt $b1:tt [ $($inner:tt)* ]) => {
99 $crate::pounded_var_names!($call! $extra $($inner)*);
100 };
101
102 ($call:ident! $extra:tt $b1:tt { $($inner:tt)* }) => {
103 $crate::pounded_var_names!($call! $extra $($inner)*);
104 };
105
106 ($call:ident!($($extra:tt)*) # $var:ident) => {
107 $crate::$call!($($extra)* $var);
108 };
109
110 ($call:ident! $extra:tt $b1:tt $curr:tt) => {};
111}
112
113#[macro_export]
114#[doc(hidden)]
115macro_rules! quote_bind_into_iter {
116 ($has_iter:ident $var:ident) => {
117 // `mut` may be unused if $var occurs multiple times in the list.
118 #[allow(unused_mut)]
119 let (mut $var, i) = $var.quote_into_iter();
120 let $has_iter = $has_iter | i;
121 };
122}
123
124#[macro_export]
125#[doc(hidden)]
126macro_rules! quote_bind_next_or_break {
127 ($var:ident) => {
128 let $var = match $var.next() {
129 Some(_x) => $crate::tokens::runtime::RepInterp(_x),
130 None => break,
131 };
132 };
133}
134
135#[macro_export]
136#[doc(hidden)]
137macro_rules! quote_each_token {
138 ($tokens:ident $($tts:tt)*) => {
139 $crate::quote_tokens_with_context!($tokens
140 (@ @ @ @ @ @ $($tts)*)
141 (@ @ @ @ @ $($tts)* @)
142 (@ @ @ @ $($tts)* @ @)
143 (@ @ @ $(($tts))* @ @ @)
144 (@ @ $($tts)* @ @ @ @)
145 (@ $($tts)* @ @ @ @ @)
146 ($($tts)* @ @ @ @ @ @)
147 );
148 };
149}
150
151#[macro_export]
152#[doc(hidden)]
153macro_rules! quote_tokens_with_context {
154 ($tokens:ident
155 ($($b3:tt)*) ($($b2:tt)*) ($($b1:tt)*)
156 ($($curr:tt)*)
157 ($($a1:tt)*) ($($a2:tt)*) ($($a3:tt)*)
158 ) => {
159 $(
160 $crate::quote_token_with_context!($tokens $b3 $b2 $b1 $curr $a1 $a2 $a3);
161 )*
162 };
163}
164
165#[macro_export]
166#[doc(hidden)]
167macro_rules! quote_token_with_context {
168 ($tokens:ident $b3:tt $b2:tt $b1:tt @ $a1:tt $a2:tt $a3:tt) => {};
169
170 ($tokens:ident $b3:tt $b2:tt $b1:tt (#) ( $($inner:tt)* ) * $a3:tt) => {{
171 use $crate::tokens::runtime::ext::*;
172 let has_iter = $crate::tokens::runtime::ThereIsNoIteratorInRepetition;
173 $crate::pounded_var_names!(quote_bind_into_iter!(has_iter) () $($inner)*);
174 let _: $crate::tokens::runtime::HasIterator = has_iter;
175 // This is `while true` instead of `loop` because if there are no
176 // iterators used inside of this repetition then the body would not
177 // contain any `break`, so the compiler would emit unreachable code
178 // warnings on anything below the loop. We use has_iter to detect and
179 // fail to compile when there are no iterators, so here we just work
180 // around the unneeded extra warning.
181 while true {
182 $crate::pounded_var_names!(quote_bind_next_or_break!() () $($inner)*);
183 $crate::quote_each_token!($tokens $($inner)*);
184 }
185 }};
186 ($tokens:ident $b3:tt $b2:tt # (( $($inner:tt)* )) * $a2:tt $a3:tt) => {};
187 ($tokens:ident $b3:tt # ( $($inner:tt)* ) (*) $a1:tt $a2:tt $a3:tt) => {};
188
189 ($tokens:ident $b3:tt $b2:tt $b1:tt (#) ( $($inner:tt)* ) $sep:tt *) => {{
190 use $crate::tokens::runtime::ext::*;
191 let mut _i = 0usize;
192 let has_iter = $crate::tokens::runtime::ThereIsNoIteratorInRepetition;
193 $crate::pounded_var_names!(quote_bind_into_iter!(has_iter) () $($inner)*);
194 let _: $crate::tokens::runtime::HasIterator = has_iter;
195 while true {
196 $crate::pounded_var_names!(quote_bind_next_or_break!() () $($inner)*);
197 if _i > 0 {
198 $crate::quote_token!($tokens $sep);
199 }
200 _i += 1;
201 $crate::quote_each_token!($tokens $($inner)*);
202 }
203 }};
204 ($tokens:ident $b3:tt $b2:tt # (( $($inner:tt)* )) $sep:tt * $a3:tt) => {};
205 ($tokens:ident $b3:tt # ( $($inner:tt)* ) ($sep:tt) * $a2:tt $a3:tt) => {};
206 ($tokens:ident # ( $($inner:tt)* ) * (*) $a1:tt $a2:tt $a3:tt) => {
207 // https://github.com/dtolnay/quote/issues/130
208 $crate::quote_token!($tokens *);
209 };
210 ($tokens:ident # ( $($inner:tt)* ) $sep:tt (*) $a1:tt $a2:tt $a3:tt) => {};
211
212 ($tokens:ident $b3:tt $b2:tt $b1:tt (#) $var:ident $a2:tt $a3:tt) => {
213 $crate::tokens::ToTokens::to_tokens(&$var, &mut $tokens);
214 };
215 ($tokens:ident $b3:tt $b2:tt # ($var:ident) $a1:tt $a2:tt $a3:tt) => {};
216 ($tokens:ident $b3:tt $b2:tt $b1:tt ($curr:tt) $a1:tt $a2:tt $a3:tt) => {
217 $crate::quote_token!($tokens $curr);
218 };
219}
220
221#[macro_export]
222#[doc(hidden)]
223macro_rules! quote_token {
224 ($tokens:ident ( $($inner:tt)* )) => {
225 $crate::tokens::runtime::push_group(
226 &mut $tokens,
227 $crate::tokens::Delimiter::Parenthesis,
228 $crate::quote!($($inner)*),
229 );
230 };
231
232 ($tokens:ident [ $($inner:tt)* ]) => {
233 $crate::tokens::runtime::push_group(
234 &mut $tokens,
235 $crate::tokens::Delimiter::Bracket,
236 $crate::quote!($($inner)*),
237 );
238 };
239
240 ($tokens:ident { $($inner:tt)* }) => {
241 $crate::tokens::runtime::push_group(
242 &mut $tokens,
243 $crate::tokens::Delimiter::Brace,
244 $crate::quote!($($inner)*),
245 );
246 };
247
248 ($tokens:ident +) => {
249 $crate::tokens::runtime::push_add(&mut $tokens);
250 };
251
252 ($tokens:ident +=) => {
253 $crate::tokens::runtime::push_add_eq(&mut $tokens);
254 };
255
256 ($tokens:ident &) => {
257 $crate::tokens::runtime::push_and(&mut $tokens);
258 };
259
260 ($tokens:ident &&) => {
261 $crate::tokens::runtime::push_and_and(&mut $tokens);
262 };
263
264 ($tokens:ident &=) => {
265 $crate::tokens::runtime::push_and_eq(&mut $tokens);
266 };
267
268 ($tokens:ident @) => {
269 $crate::tokens::runtime::push_at(&mut $tokens);
270 };
271
272 ($tokens:ident !) => {
273 $crate::tokens::runtime::push_bang(&mut $tokens);
274 };
275
276 ($tokens:ident ^) => {
277 $crate::tokens::runtime::push_caret(&mut $tokens);
278 };
279
280 ($tokens:ident ^=) => {
281 $crate::tokens::runtime::push_caret_eq(&mut $tokens);
282 };
283
284 ($tokens:ident :) => {
285 $crate::tokens::runtime::push_colon(&mut $tokens);
286 };
287
288 ($tokens:ident ::) => {
289 $crate::tokens::runtime::push_colon2(&mut $tokens);
290 };
291
292 ($tokens:ident ,) => {
293 $crate::tokens::runtime::push_comma(&mut $tokens);
294 };
295
296 ($tokens:ident /) => {
297 $crate::tokens::runtime::push_div(&mut $tokens);
298 };
299
300 ($tokens:ident /=) => {
301 $crate::tokens::runtime::push_div_eq(&mut $tokens);
302 };
303
304 ($tokens:ident .) => {
305 $crate::tokens::runtime::push_dot(&mut $tokens);
306 };
307
308 ($tokens:ident ..) => {
309 $crate::tokens::runtime::push_dot2(&mut $tokens);
310 };
311
312 ($tokens:ident ...) => {
313 $crate::tokens::runtime::push_dot3(&mut $tokens);
314 };
315
316 ($tokens:ident ..=) => {
317 $crate::tokens::runtime::push_dot_dot_eq(&mut $tokens);
318 };
319
320 ($tokens:ident =) => {
321 $crate::tokens::runtime::push_eq(&mut $tokens);
322 };
323
324 ($tokens:ident ==) => {
325 $crate::tokens::runtime::push_eq_eq(&mut $tokens);
326 };
327
328 ($tokens:ident >=) => {
329 $crate::tokens::runtime::push_ge(&mut $tokens);
330 };
331
332 ($tokens:ident >) => {
333 $crate::tokens::runtime::push_gt(&mut $tokens);
334 };
335
336 ($tokens:ident <=) => {
337 $crate::tokens::runtime::push_le(&mut $tokens);
338 };
339
340 ($tokens:ident <) => {
341 $crate::tokens::runtime::push_lt(&mut $tokens);
342 };
343
344 ($tokens:ident *=) => {
345 $crate::tokens::runtime::push_mul_eq(&mut $tokens);
346 };
347
348 ($tokens:ident !=) => {
349 $crate::tokens::runtime::push_ne(&mut $tokens);
350 };
351
352 ($tokens:ident |) => {
353 $crate::tokens::runtime::push_or(&mut $tokens);
354 };
355
356 ($tokens:ident |=) => {
357 $crate::tokens::runtime::push_or_eq(&mut $tokens);
358 };
359
360 ($tokens:ident ||) => {
361 $crate::tokens::runtime::push_or_or(&mut $tokens);
362 };
363
364 ($tokens:ident #) => {
365 $crate::tokens::runtime::push_pound(&mut $tokens);
366 };
367
368 ($tokens:ident ?) => {
369 $crate::tokens::runtime::push_question(&mut $tokens);
370 };
371
372 ($tokens:ident ->) => {
373 $crate::tokens::runtime::push_rarrow(&mut $tokens);
374 };
375
376 ($tokens:ident <-) => {
377 $crate::tokens::runtime::push_larrow(&mut $tokens);
378 };
379
380 ($tokens:ident %) => {
381 $crate::tokens::runtime::push_rem(&mut $tokens);
382 };
383
384 ($tokens:ident %=) => {
385 $crate::tokens::runtime::push_rem_eq(&mut $tokens);
386 };
387
388 ($tokens:ident =>) => {
389 $crate::tokens::runtime::push_fat_arrow(&mut $tokens);
390 };
391
392 ($tokens:ident ;) => {
393 $crate::tokens::runtime::push_semi(&mut $tokens);
394 };
395
396 ($tokens:ident <<) => {
397 $crate::tokens::runtime::push_shl(&mut $tokens);
398 };
399
400 ($tokens:ident <<=) => {
401 $crate::tokens::runtime::push_shl_eq(&mut $tokens);
402 };
403
404 ($tokens:ident >>) => {
405 $crate::tokens::runtime::push_shr(&mut $tokens);
406 };
407
408 ($tokens:ident >>=) => {
409 $crate::tokens::runtime::push_shr_eq(&mut $tokens);
410 };
411
412 ($tokens:ident *) => {
413 $crate::tokens::runtime::push_star(&mut $tokens);
414 };
415
416 ($tokens:ident -) => {
417 $crate::tokens::runtime::push_sub(&mut $tokens);
418 };
419
420 ($tokens:ident -=) => {
421 $crate::tokens::runtime::push_sub_eq(&mut $tokens);
422 };
423
424 ($tokens:ident $ident:ident) => {
425 $crate::tokens::runtime::push_ident(&mut $tokens, stringify!($ident));
426 };
427
428 ($tokens:ident $other:tt) => {
429 $crate::tokens::runtime::parse(&mut $tokens, stringify!($other));
430 };
431}
432
433pub fn to_ident(name: &str) -> TokenStream {
434 // keywords list based on https://doc.rust-lang.org/reference/keywords.html
435 match name {
436 "abstract" | "as" | "become" | "box" | "break" | "const" | "continue" | "crate" | "do"
437 | "else" | "enum" | "extern" | "false" | "final" | "fn" | "for" | "if" | "impl" | "in"
438 | "let" | "loop" | "macro" | "match" | "mod" | "move" | "mut" | "override" | "priv"
439 | "pub" | "ref" | "return" | "static" | "struct" | "super" | "trait" | "true" | "type"
440 | "typeof" | "unsafe" | "unsized" | "use" | "virtual" | "where" | "while" | "yield"
441 | "try" | "async" | "await" | "dyn" => format!("r#{name}").into(),
442 "Self" | "self" => format!("{name}_").into(),
443 "_" => "unused".into(),
444 _ => name.into(),
445 }
446}
447