]>
Commit | Line | Data |
---|---|---|
8faf50e0 XL |
1 | /// Quasi-quotation macro that accepts input like the [`quote!`] macro but uses |
2 | /// type inference to figure out a return type for those tokens. | |
3 | /// | |
0731742a | 4 | /// [`quote!`]: https://docs.rs/quote/0.6/quote/index.html |
8faf50e0 | 5 | /// |
0731742a | 6 | /// The return type can be any syntax tree node that implements the [`Parse`] |
8faf50e0 XL |
7 | /// trait. |
8 | /// | |
0731742a | 9 | /// [`Parse`]: parse/trait.Parse.html |
8faf50e0 | 10 | /// |
dc9dc135 XL |
11 | /// ```edition2018 |
12 | /// use quote::quote; | |
13 | /// use syn::{parse_quote, Stmt}; | |
8faf50e0 XL |
14 | /// |
15 | /// fn main() { | |
16 | /// let name = quote!(v); | |
17 | /// let ty = quote!(u8); | |
18 | /// | |
19 | /// let stmt: Stmt = parse_quote! { | |
20 | /// let #name: #ty = Default::default(); | |
21 | /// }; | |
22 | /// | |
23 | /// println!("{:#?}", stmt); | |
24 | /// } | |
25 | /// ``` | |
26 | /// | |
27 | /// *This macro is available if Syn is built with the `"parsing"` feature, | |
28 | /// although interpolation of syntax tree nodes into the quoted tokens is only | |
29 | /// supported if Syn is built with the `"printing"` feature as well.* | |
30 | /// | |
31 | /// # Example | |
32 | /// | |
33 | /// The following helper function adds a bound `T: HeapSize` to every type | |
34 | /// parameter `T` in the input generics. | |
35 | /// | |
dc9dc135 XL |
36 | /// ```edition2018 |
37 | /// use syn::{parse_quote, Generics, GenericParam}; | |
0731742a | 38 | /// |
8faf50e0 XL |
39 | /// // Add a bound `T: HeapSize` to every type parameter T. |
40 | /// fn add_trait_bounds(mut generics: Generics) -> Generics { | |
41 | /// for param in &mut generics.params { | |
dc9dc135 | 42 | /// if let GenericParam::Type(type_param) = param { |
8faf50e0 XL |
43 | /// type_param.bounds.push(parse_quote!(HeapSize)); |
44 | /// } | |
45 | /// } | |
46 | /// generics | |
47 | /// } | |
8faf50e0 XL |
48 | /// ``` |
49 | /// | |
50 | /// # Special cases | |
51 | /// | |
52 | /// This macro can parse the following additional types as a special case even | |
0731742a | 53 | /// though they do not implement the `Parse` trait. |
8faf50e0 XL |
54 | /// |
55 | /// - [`Attribute`] — parses one attribute, allowing either outer like `#[...]` | |
56 | /// or inner like `#![...]` | |
57 | /// - [`Punctuated<T, P>`] — parses zero or more `T` separated by punctuation | |
58 | /// `P` with optional trailing punctuation | |
59 | /// | |
60 | /// [`Attribute`]: struct.Attribute.html | |
61 | /// [`Punctuated<T, P>`]: punctuated/struct.Punctuated.html | |
62 | /// | |
63 | /// # Panics | |
64 | /// | |
65 | /// Panics if the tokens fail to parse as the expected syntax tree type. The | |
66 | /// caller is responsible for ensuring that the input tokens are syntactically | |
67 | /// valid. | |
0731742a | 68 | #[macro_export(local_inner_macros)] |
8faf50e0 XL |
69 | macro_rules! parse_quote { |
70 | ($($tt:tt)*) => { | |
0731742a XL |
71 | $crate::parse_quote::parse($crate::export::From::from(quote_impl!($($tt)*))) |
72 | }; | |
73 | } | |
74 | ||
75 | #[cfg(not(syn_can_call_macro_by_path))] | |
76 | #[doc(hidden)] | |
77 | #[macro_export] | |
78 | macro_rules! quote_impl { | |
79 | ($($tt:tt)*) => { | |
80 | // Require caller to have their own `#[macro_use] extern crate quote`. | |
81 | quote!($($tt)*) | |
82 | }; | |
83 | } | |
84 | ||
85 | #[cfg(syn_can_call_macro_by_path)] | |
86 | #[doc(hidden)] | |
87 | #[macro_export] | |
88 | macro_rules! quote_impl { | |
89 | ($($tt:tt)*) => { | |
90 | $crate::export::quote::quote!($($tt)*) | |
8faf50e0 XL |
91 | }; |
92 | } | |
93 | ||
94 | //////////////////////////////////////////////////////////////////////////////// | |
0731742a | 95 | // Can parse any type that implements Parse. |
8faf50e0 | 96 | |
0731742a | 97 | use parse::{Parse, ParseStream, Parser, Result}; |
8faf50e0 | 98 | use proc_macro2::TokenStream; |
8faf50e0 XL |
99 | |
100 | // Not public API. | |
101 | #[doc(hidden)] | |
102 | pub fn parse<T: ParseQuote>(token_stream: TokenStream) -> T { | |
103 | let parser = T::parse; | |
104 | match parser.parse2(token_stream) { | |
105 | Ok(t) => t, | |
0731742a | 106 | Err(err) => panic!("{}", err), |
8faf50e0 XL |
107 | } |
108 | } | |
109 | ||
110 | // Not public API. | |
111 | #[doc(hidden)] | |
112 | pub trait ParseQuote: Sized { | |
0731742a | 113 | fn parse(input: ParseStream) -> Result<Self>; |
8faf50e0 XL |
114 | } |
115 | ||
0731742a XL |
116 | impl<T: Parse> ParseQuote for T { |
117 | fn parse(input: ParseStream) -> Result<Self> { | |
118 | <T as Parse>::parse(input) | |
8faf50e0 XL |
119 | } |
120 | } | |
121 | ||
122 | //////////////////////////////////////////////////////////////////////////////// | |
123 | // Any other types that we want `parse_quote!` to be able to parse. | |
124 | ||
125 | use punctuated::Punctuated; | |
8faf50e0 | 126 | #[cfg(any(feature = "full", feature = "derive"))] |
0731742a | 127 | use {attr, Attribute}; |
8faf50e0 XL |
128 | |
129 | #[cfg(any(feature = "full", feature = "derive"))] | |
130 | impl ParseQuote for Attribute { | |
0731742a XL |
131 | fn parse(input: ParseStream) -> Result<Self> { |
132 | if input.peek(Token![#]) && input.peek2(Token![!]) { | |
133 | attr::parsing::single_parse_inner(input) | |
134 | } else { | |
135 | attr::parsing::single_parse_outer(input) | |
136 | } | |
137 | } | |
138 | } | |
8faf50e0 | 139 | |
0731742a XL |
140 | impl<T: Parse, P: Parse> ParseQuote for Punctuated<T, P> { |
141 | fn parse(input: ParseStream) -> Result<Self> { | |
142 | Self::parse_terminated(input) | |
8faf50e0 XL |
143 | } |
144 | } |