• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1Rust Quasi-Quoting
2==================
3
4[![Build Status](https://api.travis-ci.org/dtolnay/quote.svg?branch=master)](https://travis-ci.org/dtolnay/quote)
5[![Latest Version](https://img.shields.io/crates/v/quote.svg)](https://crates.io/crates/quote)
6[![Rust Documentation](https://img.shields.io/badge/api-rustdoc-blue.svg)](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