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