]>
Commit | Line | Data |
---|---|---|
3b2f2976 XL |
1 | Rust 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 | ||
0531ce1d XL |
8 | This crate provides the [`quote!`] macro for turning Rust syntax tree data |
9 | structures into tokens of source code. | |
10 | ||
8faf50e0 | 11 | [`quote!`]: https://docs.rs/quote/0.6/quote/macro.quote.html |
0531ce1d XL |
12 | |
13 | Procedural macros in Rust receive a stream of tokens as input, execute arbitrary | |
14 | Rust code to determine how to manipulate those tokens, and produce a stream of | |
15 | tokens to hand back to the compiler to compile into the caller's crate. | |
16 | Quasi-quoting is a solution to one piece of that -- producing tokens to return | |
17 | to the compiler. | |
18 | ||
19 | The idea of quasi-quoting is that we write *code* that we treat as *data*. | |
20 | Within the `quote!` macro, we can write what looks like code to our text editor | |
21 | or IDE. We get all the benefits of the editor's brace matching, syntax | |
22 | highlighting, indentation, and maybe autocompletion. But rather than compiling | |
23 | that as code into the current crate, we can treat it as data, pass it around, | |
24 | mutate it, and eventually hand it back to the compiler as tokens to compile into | |
25 | the macro caller's crate. | |
26 | ||
27 | This crate is motivated by the procedural macro use case, but is a | |
28 | general-purpose Rust quasi-quoting library and is not specific to procedural | |
29 | macros. | |
30 | ||
31 | *Version requirement: Quote supports any compiler version back to Rust's very | |
32 | first support for procedural macros in Rust 1.15.0.* | |
3b2f2976 | 33 | |
8faf50e0 XL |
34 | [*Release notes*](https://github.com/dtolnay/quote/releases) |
35 | ||
3b2f2976 XL |
36 | ```toml |
37 | [dependencies] | |
8faf50e0 | 38 | quote = "0.6" |
3b2f2976 XL |
39 | ``` |
40 | ||
41 | ```rust | |
42 | #[macro_use] | |
43 | extern crate quote; | |
44 | ``` | |
45 | ||
3b2f2976 XL |
46 | ## Syntax |
47 | ||
0531ce1d | 48 | The quote crate provides a [`quote!`] macro within which you can write Rust code |
8faf50e0 XL |
49 | that gets packaged into a [`TokenStream`] and can be treated as data. You should |
50 | think of `TokenStream` as representing a fragment of Rust source code. This type | |
51 | can be returned directly back to the compiler by a procedural macro to get | |
52 | compiled into the caller's crate. | |
0531ce1d | 53 | |
8faf50e0 | 54 | [`TokenStream`]: https://docs.rs/proc-macro2/0.4/proc_macro2/struct.TokenStream.html |
3b2f2976 XL |
55 | |
56 | Within the `quote!` macro, interpolation is done with `#var`. Any type | |
0531ce1d XL |
57 | implementing the [`quote::ToTokens`] trait can be interpolated. This includes |
58 | most Rust primitive types as well as most of the syntax tree types from [`syn`]. | |
59 | ||
8faf50e0 | 60 | [`quote::ToTokens`]: https://docs.rs/quote/0.6/quote/trait.ToTokens.html |
0531ce1d | 61 | [`syn`]: https://github.com/dtolnay/syn |
3b2f2976 XL |
62 | |
63 | ```rust | |
64 | let tokens = quote! { | |
65 | struct SerializeWith #generics #where_clause { | |
66 | value: &'a #field_ty, | |
67 | phantom: ::std::marker::PhantomData<#item_ty>, | |
68 | } | |
69 | ||
70 | impl #generics serde::Serialize for SerializeWith #generics #where_clause { | |
b7449926 | 71 | fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> |
8faf50e0 XL |
72 | where |
73 | S: serde::Serializer, | |
3b2f2976 | 74 | { |
b7449926 | 75 | #path(self.value, serializer) |
3b2f2976 XL |
76 | } |
77 | } | |
78 | ||
79 | SerializeWith { | |
80 | value: #value, | |
81 | phantom: ::std::marker::PhantomData::<#item_ty>, | |
82 | } | |
83 | }; | |
84 | ``` | |
85 | ||
0531ce1d | 86 | ## Repetition |
3b2f2976 | 87 | |
0531ce1d XL |
88 | Repetition is done using `#(...)*` or `#(...),*` similar to `macro_rules!`. This |
89 | iterates through the elements of any variable interpolated within the repetition | |
90 | and inserts a copy of the repetition body for each one. The variables in an | |
91 | interpolation may be anything that implements `IntoIterator`, including `Vec` or | |
92 | a pre-existing iterator. | |
3b2f2976 | 93 | |
0531ce1d XL |
94 | - `#(#var)*` — no separators |
95 | - `#(#var),*` — the character before the asterisk is used as a separator | |
96 | - `#( struct #var; )*` — the repetition can contain other things | |
97 | - `#( #k => println!("{}", #v), )*` — even multiple interpolations | |
3b2f2976 | 98 | |
0531ce1d XL |
99 | Note that there is a difference between `#(#var ,)*` and `#(#var),*`—the latter |
100 | does not produce a trailing comma. This matches the behavior of delimiters in | |
101 | `macro_rules!`. | |
102 | ||
103 | ## Hygiene | |
104 | ||
105 | Any interpolated tokens preserve the `Span` information provided by their | |
106 | `ToTokens` implementation. Tokens that originate within a `quote!` invocation | |
8faf50e0 | 107 | are spanned with [`Span::call_site()`]. |
0531ce1d | 108 | |
8faf50e0 | 109 | [`Span::call_site()`]: https://docs.rs/proc-macro2/0.4/proc_macro2/struct.Span.html#method.call_site |
0531ce1d XL |
110 | |
111 | A different span can be provided explicitly through the [`quote_spanned!`] | |
112 | macro. | |
113 | ||
8faf50e0 XL |
114 | [`quote_spanned!`]: https://docs.rs/quote/0.6/quote/macro.quote_spanned.html |
115 | ||
116 | ### Limitations | |
117 | ||
118 | - A non-repeating variable may not be interpolated inside of a repeating block | |
119 | ([#7]). | |
120 | - The same variable may not be interpolated more than once inside of a repeating | |
121 | block ([#8]). | |
122 | ||
123 | [#7]: https://github.com/dtolnay/quote/issues/7 | |
124 | [#8]: https://github.com/dtolnay/quote/issues/8 | |
0531ce1d XL |
125 | |
126 | ### Recursion limit | |
3b2f2976 XL |
127 | |
128 | The `quote!` macro relies on deep recursion so some large invocations may fail | |
129 | with "recursion limit reached" when you compile. If it fails, bump up the | |
130 | recursion limit by adding `#![recursion_limit = "128"]` to your crate. An even | |
131 | higher limit may be necessary for especially large invocations. You don't need | |
132 | this unless the compiler tells you that you need it. | |
133 | ||
134 | ## License | |
135 | ||
136 | Licensed under either of | |
137 | ||
138 | * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) | |
139 | * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) | |
140 | ||
141 | at your option. | |
142 | ||
143 | ### Contribution | |
144 | ||
145 | Unless you explicitly state otherwise, any contribution intentionally submitted | |
146 | for inclusion in this crate by you, as defined in the Apache-2.0 license, shall | |
147 | be dual licensed as above, without any additional terms or conditions. |