1Rust Quasi-Quoting 2================== 3 4[](https://travis-ci.org/dtolnay/quote) 5[](https://crates.io/crates/quote) 6[](https://docs.rs/quote/) 7 8This crate provides the [`quote!`] macro for turning Rust syntax tree data 9structures into tokens of source code. 10 11[`quote!`]: https://docs.rs/quote/1.0/quote/macro.quote.html 12 13Procedural macros in Rust receive a stream of tokens as input, execute arbitrary 14Rust code to determine how to manipulate those tokens, and produce a stream of 15tokens to hand back to the compiler to compile into the caller's crate. 16Quasi-quoting is a solution to one piece of that — producing tokens to 17return to the compiler. 18 19The idea of quasi-quoting is that we write *code* that we treat as *data*. 20Within the `quote!` macro, we can write what looks like code to our text editor 21or IDE. We get all the benefits of the editor's brace matching, syntax 22highlighting, indentation, and maybe autocompletion. But rather than compiling 23that as code into the current crate, we can treat it as data, pass it around, 24mutate it, and eventually hand it back to the compiler as tokens to compile into 25the macro caller's crate. 26 27This crate is motivated by the procedural macro use case, but is a 28general-purpose Rust quasi-quoting library and is not specific to procedural 29macros. 30 31*Version requirement: Quote supports any compiler version back to Rust's very 32first support for procedural macros in Rust 1.15.0.* 33 34[*Release notes*](https://github.com/dtolnay/quote/releases) 35 36```toml 37[dependencies] 38quote = "1.0" 39``` 40 41## Syntax 42 43The quote crate provides a [`quote!`] macro within which you can write Rust code 44that gets packaged into a [`TokenStream`] and can be treated as data. You should 45think of `TokenStream` as representing a fragment of Rust source code. 46 47[`TokenStream`]: https://docs.rs/proc-macro2/1.0/proc_macro2/struct.TokenStream.html 48 49Within the `quote!` macro, interpolation is done with `#var`. Any type 50implementing the [`quote::ToTokens`] trait can be interpolated. This includes 51most Rust primitive types as well as most of the syntax tree types from [`syn`]. 52 53[`quote::ToTokens`]: https://docs.rs/quote/1.0/quote/trait.ToTokens.html 54[`syn`]: https://github.com/dtolnay/syn 55 56```rust 57let tokens = quote! { 58 struct SerializeWith #generics #where_clause { 59 value: &'a #field_ty, 60 phantom: core::marker::PhantomData<#item_ty>, 61 } 62 63 impl #generics serde::Serialize for SerializeWith #generics #where_clause { 64 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 65 where 66 S: serde::Serializer, 67 { 68 #path(self.value, serializer) 69 } 70 } 71 72 SerializeWith { 73 value: #value, 74 phantom: core::marker::PhantomData::<#item_ty>, 75 } 76}; 77``` 78 79## Repetition 80 81Repetition is done using `#(...)*` or `#(...),*` similar to `macro_rules!`. This 82iterates through the elements of any variable interpolated within the repetition 83and inserts a copy of the repetition body for each one. The variables in an 84interpolation may be anything that implements `IntoIterator`, including `Vec` or 85a pre-existing iterator. 86 87- `#(#var)*` — no separators 88- `#(#var),*` — the character before the asterisk is used as a separator 89- `#( struct #var; )*` — the repetition can contain other things 90- `#( #k => println!("{}", #v), )*` — even multiple interpolations 91 92Note that there is a difference between `#(#var ,)*` and `#(#var),*`—the latter 93does not produce a trailing comma. This matches the behavior of delimiters in 94`macro_rules!`. 95 96## Returning tokens to the compiler 97 98The `quote!` macro evaluates to an expression of type 99`proc_macro2::TokenStream`. Meanwhile Rust procedural macros are expected to 100return the type `proc_macro::TokenStream`. 101 102The difference between the two types is that `proc_macro` types are entirely 103specific to procedural macros and cannot ever exist in code outside of a 104procedural macro, while `proc_macro2` types may exist anywhere including tests 105and non-macro code like main.rs and build.rs. This is why even the procedural 106macro ecosystem is largely built around `proc_macro2`, because that ensures the 107libraries are unit testable and accessible in non-macro contexts. 108 109There is a [`From`]-conversion in both directions so returning the output of 110`quote!` from a procedural macro usually looks like `tokens.into()` or 111`proc_macro::TokenStream::from(tokens)`. 112 113[`From`]: https://doc.rust-lang.org/std/convert/trait.From.html 114 115## Examples 116 117### Combining quoted fragments 118 119Usually you don't end up constructing an entire final `TokenStream` in one 120piece. Different parts may come from different helper functions. The tokens 121produced by `quote!` themselves implement `ToTokens` and so can be interpolated 122into later `quote!` invocations to build up a final result. 123 124```rust 125let type_definition = quote! {...}; 126let methods = quote! {...}; 127 128let tokens = quote! { 129 #type_definition 130 #methods 131}; 132``` 133 134### Constructing identifiers 135 136Suppose we have an identifier `ident` which came from somewhere in a macro 137input and we need to modify it in some way for the macro output. Let's consider 138prepending the identifier with an underscore. 139 140Simply interpolating the identifier next to an underscore will not have the 141behavior of concatenating them. The underscore and the identifier will continue 142to be two separate tokens as if you had written `_ x`. 143 144```rust 145// incorrect 146quote! { 147 let mut _#ident = 0; 148} 149``` 150 151The solution is to build a new identifier token with the correct value. As this 152is such a common case, the `format_ident!` macro provides a convenient utility 153for doing so correctly. 154 155```rust 156let varname = format_ident!("_{}", ident); 157quote! { 158 let mut #varname = 0; 159} 160``` 161 162Alternatively, the APIs provided by Syn and proc-macro2 can be used to directly 163build the identifier. This is roughly equivalent to the above, but will not 164handle `ident` being a raw identifier. 165 166```rust 167let concatenated = format!("_{}", ident); 168let varname = syn::Ident::new(&concatenated, ident.span()); 169quote! { 170 let mut #varname = 0; 171} 172``` 173 174### Making method calls 175 176Let's say our macro requires some type specified in the macro input to have a 177constructor called `new`. We have the type in a variable called `field_type` of 178type `syn::Type` and want to invoke the constructor. 179 180```rust 181// incorrect 182quote! { 183 let value = #field_type::new(); 184} 185``` 186 187This works only sometimes. If `field_type` is `String`, the expanded code 188contains `String::new()` which is fine. But if `field_type` is something like 189`Vec<i32>` then the expanded code is `Vec<i32>::new()` which is invalid syntax. 190Ordinarily in handwritten Rust we would write `Vec::<i32>::new()` but for macros 191often the following is more convenient. 192 193```rust 194quote! { 195 let value = <#field_type>::new(); 196} 197``` 198 199This expands to `<Vec<i32>>::new()` which behaves correctly. 200 201A similar pattern is appropriate for trait methods. 202 203```rust 204quote! { 205 let value = <#field_type as core::default::Default>::default(); 206} 207``` 208 209## Hygiene 210 211Any interpolated tokens preserve the `Span` information provided by their 212`ToTokens` implementation. Tokens that originate within a `quote!` invocation 213are spanned with [`Span::call_site()`]. 214 215[`Span::call_site()`]: https://docs.rs/proc-macro2/1.0/proc_macro2/struct.Span.html#method.call_site 216 217A different span can be provided explicitly through the [`quote_spanned!`] 218macro. 219 220[`quote_spanned!`]: https://docs.rs/quote/1.0/quote/macro.quote_spanned.html 221 222<br> 223 224#### License 225 226<sup> 227Licensed under either of <a href="LICENSE-APACHE">Apache License, Version 2282.0</a> or <a href="LICENSE-MIT">MIT license</a> at your option. 229</sup> 230 231<br> 232 233<sub> 234Unless you explicitly state otherwise, any contribution intentionally submitted 235for inclusion in this crate by you, as defined in the Apache-2.0 license, shall 236be dual licensed as above, without any additional terms or conditions. 237</sub> 238