template_quote/lib.rs
1//! This create provide [`quote!`] macro.
2
3/// The entrypoint with fully backward-compatibility with traditional `quote!`
4/// macro.
5///
6/// This macro is intended to use in your proc-macro, to generate `TokenStream`
7/// expanding variable interporation and expanding templates.
8///
9/// This macro is constructed based on `proc_macro` crate.
10///
11/// # Interporation
12///
13/// For backward compatibility, interporation rule is same as traditional
14/// `quote!` macro. The interporation is done with `#var` (similar to the
15/// variable `$var` in `macro_rules!`). Most variables in `Syn` crate are
16/// interporated using [`::proc_quote::ToTokens`] trait.
17///
18/// ## Rules
19///
20/// Repetition is done using syntax like `#(...)*` or `#(...),*`. It repeats the
21/// variables (`#var`) inside this syntax, which implements
22/// [`::proc_quote::Repeat`].
23///
24/// - `#(...)*` - repeat ... with no separators. at least one variable should be
25/// included in ...
26/// - `#(...),*` - same as before, but interporates with separator ','.
27///
28/// ## Problem
29///
30/// The interporation rule is **rough**, so I implemented new 'template' syntax.
31/// For example, the following code will not allowed, because `#var1` cannot be
32/// iterated double.
33///
34/// ```
35/// # use template_quote::quote;
36/// let var1 = vec!['a', 'b'];
37/// let var2 = vec![vec![1, 2], vec![3, 4]];
38/// let tokens = quote!{
39/// #(#(#var1 #var2)*)*
40/// };
41/// assert_eq!("'a' 1i32 'a' 2i32 'b' 3i32 'b' 4i32", tokens.to_string());
42/// ```
43///
44/// # Template syntax
45///
46/// Template syntax is proceedual-like syntax, which allows you to use structual
47/// statementsinside the macro.
48///
49/// ## If syntax
50///
51/// This code iterates around `#i` (with interporation), and emits `i32` into
52/// `TokenStream` while the number meets the condition.
53///
54/// ```
55/// # use template_quote::quote;
56/// let i = vec![1, 2, 3];
57/// let tokens = quote!{
58/// #(
59/// #(if i > &2) {
60/// #i
61/// }
62/// )*
63/// };
64/// assert_eq!("3i32", tokens.to_string());
65/// ```
66///
67/// The if-else and if-else-if is also allowed.
68///
69/// ```
70/// # use template_quote::quote;
71/// let i = vec![1, 2, 3];
72/// let tokens = quote!{
73/// #(
74/// #(if i > &2) {
75/// + #i
76/// }
77/// #(else) {
78/// - #i
79/// }
80/// )*
81/// };
82/// assert_eq!("- 1i32 - 2i32 + 3i32", tokens.to_string());
83/// ```
84///
85/// ```
86/// # use template_quote::quote;
87/// let i = vec![1, 2, 3, 4, 5];
88/// let tokens = quote!{
89/// #(
90/// #(if i % &2 == 0) {
91/// + #i
92/// }
93/// #(else if i % &3 == 0) {
94/// - #i
95/// }
96/// #(else) {
97/// #i
98/// }
99/// )*
100/// };
101/// assert_eq!("1i32 + 2i32 - 3i32 + 4i32 5i32", tokens.to_string());
102/// ```
103///
104/// ## For syntax
105///
106/// For syntax iterates around the variable (like interporation), but it
107/// specifies which variable to iterate.
108///
109/// ```
110/// # use template_quote::quote;
111/// let v1 = vec![1, 2];
112/// let v2 = vec!['a', 'b'];
113/// let tokens = quote!{
114/// #(for i1 in &v1) {
115/// #(for i2 in &v2) {
116/// #i1 -> #i2
117/// }
118/// }
119/// };
120/// assert_eq!("1i32 -> 'a' 1i32 -> 'b' 2i32 -> 'a' 2i32 -> 'b'", tokens.to_string());
121/// ```
122///
123/// Internal loop can be replaced with interporation:
124///
125/// ```
126/// # use template_quote::quote;
127/// let v1 = vec![1, 2];
128/// let v2 = vec!['a', 'b'];
129/// let tokens = quote!{
130/// #(for i1 in &v1) {
131/// #(
132/// #i1 -> #v2
133/// )*
134/// }
135/// };
136/// assert_eq!("1i32 -> 'a' 1i32 -> 'b' 2i32 -> 'a' 2i32 -> 'b'", tokens.to_string());
137/// ```
138///
139/// You can also specify separator with for statement.
140///
141/// ```
142/// # use template_quote::quote;
143/// let v = vec![1, 2];
144/// let tokens = quote!{
145/// #(for i in v) | { #i }
146/// };
147/// assert_eq!("1i32 | 2i32", tokens.to_string());
148/// ```
149///
150/// Interporation is not usable with variables binded in for syntax. For
151/// example,
152///
153/// ```compile_fail
154/// # use template_quote::quote;
155/// let v = vec![vec![1, 2], vec![3]];
156/// let tokens = quote!{
157/// #(
158/// #(for i in v) { #i }
159/// ),*
160/// };
161/// assert_eq!("1i32 2i32 , 3i32", tokens.to_string());
162/// ```
163///
164/// will fail into error because no variables is available in the interporation
165/// syntax.
166///
167/// ```text
168/// error: proc macro panicked
169/// --> ***
170/// |
171/// 6 | let tokens = quote!{
172/// | ______________^
173/// 7 | | #(
174/// 8 | | #(for i in v) { #i }
175/// 9 | | )*
176/// 10 | | };
177/// | |_^
178/// |
179/// = help: message: Iterative vals not found
180/// ```
181///
182/// In this case, you can use `#(for i in #v)` syntax to specify which variable
183/// to iterate with interporation:
184///
185/// ```
186/// # use template_quote::quote;
187/// let v = vec![vec![1, 2], vec![3]];
188/// let tokens = quote!{
189/// #(
190/// #(for i in #v) { #i }
191/// ),*
192/// };
193/// assert_eq!("1i32 2i32 , 3i32", tokens.to_string());
194/// ```
195///
196/// ## While syntax
197///
198/// ```
199/// # use template_quote::quote;
200/// let mut v = vec![1, 2].into_iter();
201/// let tokens = quote!{
202/// #(while v.next().is_some()) { hello }
203/// };
204/// assert_eq!("hello hello", tokens.to_string());
205/// ```
206///
207/// ## While-Let syntax
208///
209/// ```
210/// # use template_quote::quote;
211/// let mut v = vec![1, 2].into_iter();
212/// let tokens = quote!{
213/// #(while let Some(i) = v.next()) { #i }
214/// };
215/// assert_eq!("1i32 2i32", tokens.to_string());
216/// ```
217///
218/// Same as 'for' syntax, the binded valiables in 'while' is not iteratable with
219/// interporation syntax. For example,
220///
221/// ```compile_fail
222/// # use template_quote::quote;
223/// let mut v = vec![1, 2].into_iter();
224/// quote!{
225/// #(
226/// #(while let Some(i) = v.next()) { #i }
227/// )*
228/// };
229/// ```
230///
231/// will fail.
232///
233/// ## Let syntax
234///
235/// Let syntax bind new variables usable inside the block.
236///
237/// ```
238/// # use template_quote::quote;
239/// let v = vec![(1, 'a'), (2, 'b')];
240/// let tokens = quote!{
241/// #(for i in v), {
242/// #(let (n, c) = i) {
243/// #n -> #c
244/// }
245/// }
246/// };
247/// assert_eq!("1i32 -> 'a' , 2i32 -> 'b'", tokens.to_string());
248/// ```
249///
250/// Here, `#n` and `#c` is not iteratable with interporation syntax.
251///
252/// ## Inline expression
253///
254/// You can place inline expression in `quote!` macro.
255///
256/// ```
257/// # use template_quote::quote;
258/// let v = vec![1, 2];
259/// let tokens = quote!{
260/// #(for i in v){
261/// #i -> #{ i.to_string() }
262/// }
263/// };
264/// assert_eq!("1i32 -> \"1\" 2i32 -> \"2\"", tokens.to_string());
265/// ```
266///
267/// The following example will fail to compile because it does not understand
268/// which variable to be interpolated:
269///
270/// ```compile_fail
271/// # use template_quote::quote;
272/// let v = vec![1, 2];
273/// let tokens = quote!{
274/// #(
275/// #{ v.to_string() }
276/// )*
277/// };
278/// assert_eq!("\"1\" \"2\"", tokens.to_string());
279/// ```
280///
281/// In this case, you can use `#i` syntax in inline expression to specify which
282/// variable to iterate with interporation syntax.
283///
284/// ```
285/// # use template_quote::quote;
286/// let v = vec![1, 2];
287/// let tokens = quote!{
288/// #(
289/// #{ #v.to_string() }
290/// )*
291/// };
292/// assert_eq!("\"1\" \"2\"", tokens.to_string());
293/// ```
294///
295/// ## Inline statement
296///
297/// You can place arbitrary statement inside this macro. For example,
298///
299/// ```
300/// # use template_quote::quote;
301/// let v = vec![1, 2, 3];
302/// let tokens = quote!{
303/// #(
304/// #v
305/// #{ eprintln!("debug: {}", &v); }
306/// )*
307/// };
308/// assert_eq!("1i32 2i32 3i32", tokens.to_string());
309/// ```
310///
311/// will print:
312///
313/// ```text
314/// debug: 1
315/// debug: 2
316/// debug: 3
317/// ```
318///
319/// To be distinguishable, all statements have to end with ';'. For example,
320/// 'if' statement in inline statement syntax should placed with extra ';'.
321///
322/// ```
323/// # use template_quote::quote;
324/// let v = vec![1, 2, 3];
325/// quote!{
326/// #(
327/// #v
328/// #{ if v >= &2 { eprintln!("debug: {}", &v); } ; }
329/// )*
330/// };
331/// ```
332///
333/// ## Break, Continue
334///
335/// You can put control statement like `break` or `continue` in inline
336/// statement, but it is a bit danger.
337///
338/// If you use `break;` inside block (like `{ ... }` or `( ... )`), `break` will
339/// suddenly give up emitting whole group, and nothing will be emitted. For
340/// example, the following code does not emit any group:
341///
342/// ```
343/// # use template_quote::quote;
344/// let v = vec![1, 2, 3];
345/// let tokens = quote!{
346/// #(for i in v) {
347/// #i // this is emitted once
348/// // The block is not emitted
349/// {
350/// #i
351/// #{ break; }
352/// }
353/// }
354/// };
355/// assert_eq!("1i32", tokens.to_string());
356/// ```
357///
358/// `break` also affects on interporation syntax like:
359///
360/// ```
361/// # use template_quote::quote;
362/// let v = vec![1, 2, 3];
363/// let tokens = quote!{
364/// #(
365/// #v
366/// #{ break; }
367/// ),*
368/// };
369/// assert_eq!("1i32", tokens.to_string());
370/// ```
371///
372/// Unfortunately, `break` will leak outside of `quote!` macro. This is example
373/// which the internal `break` affects on 'for' loop, which is placed outer of
374/// the `quote!` macro.
375///
376/// ```
377/// # use template_quote::quote;
378/// let mut v = Vec::new();
379/// for _ in 0..3 {
380/// let tokens = quote!{
381/// #{ break; }
382/// };
383/// v.push(tokens);
384/// }
385/// assert_eq!(v.len(), 0);
386/// ```
387pub use template_quote_impl::quote;
388
389/// [`quote_configured!`] macro is configurable version of [`quote!`].
390///
391/// ```ignore
392/// # use template_quote::quote_configured;
393/// quote_configured! {
394/// {
395/// proc_macro2: ::proc_macro2,
396/// quote: ::quote,
397/// core: ::core, // core crate in std
398/// quote: ::quote,
399/// span: ::some_span,
400/// } =>
401/// ...
402/// };
403/// ```
404pub use template_quote_impl::quote_configured;
405
406/// [`quote_spanned!`] macro emit `TokenTree` with specified
407/// `Span`.
408///
409/// ```ignore
410/// use syn::Span;
411/// let span = Span::call_site();
412/// let tokens = quote_spanned! {span => ... };
413/// ```
414pub use template_quote_impl::quote_spanned;
415
416pub use imp::Repeat;
417pub use quote::ToTokens;
418
419mod imp {
420 use quote::ToTokens;
421 use std::borrow::Borrow;
422 use std::slice;
423
424 // This trait is from `proc-quote` crate.
425 pub unsafe trait Repeat<T: Iterator> {
426 #[allow(non_snake_case)]
427 #[doc(hidden)]
428 fn __template_quote__as_repeat(self) -> T;
429
430 #[allow(non_snake_case)]
431 #[doc(hidden)]
432 fn __template_quote_is_iterable(&self) -> bool;
433 }
434
435 unsafe impl<T, I: Iterator<Item = T>> Repeat<I> for I {
436 fn __template_quote__as_repeat(self) -> I {
437 self
438 }
439
440 fn __template_quote_is_iterable(&self) -> bool {
441 true
442 }
443 }
444
445 unsafe impl<'a, T: 'a, S: Borrow<[T]>> Repeat<slice::Iter<'a, T>> for &'a S {
446 fn __template_quote__as_repeat(self) -> slice::Iter<'a, T> {
447 (*self).borrow().iter()
448 }
449
450 fn __template_quote_is_iterable(&self) -> bool {
451 true
452 }
453 }
454
455 unsafe impl<'a, T: ToTokens + 'a> Repeat<ToTokensRepeat<'a, T>> for &'a T {
456 fn __template_quote__as_repeat(self) -> ToTokensRepeat<'a, T> {
457 ToTokensRepeat(self)
458 }
459
460 fn __template_quote_is_iterable(&self) -> bool {
461 false
462 }
463 }
464
465 pub struct ToTokensRepeat<'a, T: ToTokens + 'a>(&'a T);
466 impl<'a, T: ToTokens + 'a> Iterator for ToTokensRepeat<'a, T> {
467 type Item = &'a T;
468 fn next(&mut self) -> Option<Self::Item> {
469 Some(self.0)
470 }
471 }
472}