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 | /// 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)] |
58 | macro_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)] |
72 | macro_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)] |
83 | macro_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)] |
93 | macro_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)] |
115 | macro_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)] |
126 | macro_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)] |
137 | macro_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)] |
153 | macro_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)] |
167 | macro_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)] |
223 | macro_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 | |
433 | pub 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 | |