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 ///
4 /// [`quote!`]: https://docs.rs/quote/1.0/quote/index.html
5 ///
6 /// The return type can be any syntax tree node that implements the [`Parse`]
7 /// trait.
8 ///
9 /// [`Parse`]: crate::parse::Parse
10 ///
11 /// ```
12 /// use quote::quote;
13 /// use syn::{parse_quote, Stmt};
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 only if Syn is built with both the `"parsing"` and
28 /// `"printing"` features.*
29 ///
30 /// # Example
31 ///
32 /// The following helper function adds a bound `T: HeapSize` to every type
33 /// parameter `T` in the input generics.
34 ///
35 /// ```
36 /// use syn::{parse_quote, Generics, GenericParam};
37 ///
38 /// // Add a bound `T: HeapSize` to every type parameter T.
39 /// fn add_trait_bounds(mut generics: Generics) -> Generics {
40 /// for param in &mut generics.params {
41 /// if let GenericParam::Type(type_param) = param {
42 /// type_param.bounds.push(parse_quote!(HeapSize));
43 /// }
44 /// }
45 /// generics
46 /// }
47 /// ```
48 ///
49 /// # Special cases
50 ///
51 /// This macro can parse the following additional types as a special case even
52 /// though they do not implement the `Parse` trait.
53 ///
54 /// - [`Attribute`] — parses one attribute, allowing either outer like `#[...]`
55 /// or inner like `#![...]`
56 /// - [`Punctuated<T, P>`] — parses zero or more `T` separated by punctuation
57 /// `P` with optional trailing punctuation
58 /// - [`Vec<Stmt>`] — parses the same as `Block::parse_within`
59 ///
60 /// [`Vec<Stmt>`]: Block::parse_within
61 ///
62 /// # Panics
63 ///
64 /// Panics if the tokens fail to parse as the expected syntax tree type. The
65 /// caller is responsible for ensuring that the input tokens are syntactically
66 /// valid.
67 #[cfg_attr(doc_cfg, doc(cfg(all(feature = "parsing", feature = "printing"))))]
68 #[macro_export]
69 macro_rules! parse_quote {
70 ($($tt:tt)*) => {
71 $crate::__private::parse_quote($crate::__private::quote::quote!($($tt)*))
72 };
73 }
74
75 /// This macro is [`parse_quote!`] + [`quote_spanned!`][quote::quote_spanned].
76 ///
77 /// Please refer to each of their documentation.
78 ///
79 /// # Example
80 ///
81 /// ```
82 /// use quote::{quote, quote_spanned};
83 /// use syn::spanned::Spanned;
84 /// use syn::{parse_quote_spanned, ReturnType, Signature};
85 ///
86 /// // Changes `fn()` to `fn() -> Pin<Box<dyn Future<Output = ()>>>`,
87 /// // and `fn() -> T` to `fn() -> Pin<Box<dyn Future<Output = T>>>`,
88 /// // without introducing any call_site() spans.
89 /// fn make_ret_pinned_future(sig: &mut Signature) {
90 /// let ret = match &sig.output {
91 /// ReturnType::Default => quote_spanned!(sig.paren_token.span=> ()),
92 /// ReturnType::Type(_, ret) => quote!(#ret),
93 /// };
94 /// sig.output = parse_quote_spanned! {ret.span()=>
95 /// -> ::std::pin::Pin<::std::boxed::Box<dyn ::std::future::Future<Output = #ret>>>
96 /// };
97 /// }
98 /// ```
99 #[cfg_attr(doc_cfg, doc(cfg(all(feature = "parsing", feature = "printing"))))]
100 #[macro_export]
101 macro_rules! parse_quote_spanned {
102 ($span:expr=> $($tt:tt)*) => {
103 $crate::__private::parse_quote($crate::__private::quote::quote_spanned!($span=> $($tt)*))
104 };
105 }
106
107 ////////////////////////////////////////////////////////////////////////////////
108 // Can parse any type that implements Parse.
109
110 use crate::parse::{Parse, ParseStream, Parser, Result};
111 use proc_macro2::TokenStream;
112
113 // Not public API.
114 #[doc(hidden)]
parse<T: ParseQuote>(token_stream: TokenStream) -> T115 pub fn parse<T: ParseQuote>(token_stream: TokenStream) -> T {
116 let parser = T::parse;
117 match parser.parse2(token_stream) {
118 Ok(t) => t,
119 Err(err) => panic!("{}", err),
120 }
121 }
122
123 #[doc(hidden)]
124 pub trait ParseQuote: Sized {
parse(input: ParseStream) -> Result<Self>125 fn parse(input: ParseStream) -> Result<Self>;
126 }
127
128 impl<T: Parse> ParseQuote for T {
parse(input: ParseStream) -> Result<Self>129 fn parse(input: ParseStream) -> Result<Self> {
130 <T as Parse>::parse(input)
131 }
132 }
133
134 ////////////////////////////////////////////////////////////////////////////////
135 // Any other types that we want `parse_quote!` to be able to parse.
136
137 use crate::punctuated::Punctuated;
138 #[cfg(any(feature = "full", feature = "derive"))]
139 use crate::{attr, Attribute, Field, FieldMutability, Ident, Type, Visibility};
140 #[cfg(feature = "full")]
141 use crate::{Block, Pat, Stmt};
142
143 #[cfg(any(feature = "full", feature = "derive"))]
144 impl ParseQuote for Attribute {
parse(input: ParseStream) -> Result<Self>145 fn parse(input: ParseStream) -> Result<Self> {
146 if input.peek(Token![#]) && input.peek2(Token![!]) {
147 attr::parsing::single_parse_inner(input)
148 } else {
149 attr::parsing::single_parse_outer(input)
150 }
151 }
152 }
153
154 #[cfg(any(feature = "full", feature = "derive"))]
155 impl ParseQuote for Field {
parse(input: ParseStream) -> Result<Self>156 fn parse(input: ParseStream) -> Result<Self> {
157 let attrs = input.call(Attribute::parse_outer)?;
158 let vis: Visibility = input.parse()?;
159
160 let ident: Option<Ident>;
161 let colon_token: Option<Token![:]>;
162 let is_named = input.peek(Ident) && input.peek2(Token![:]) && !input.peek2(Token![::]);
163 if is_named {
164 ident = Some(input.parse()?);
165 colon_token = Some(input.parse()?);
166 } else {
167 ident = None;
168 colon_token = None;
169 }
170
171 let ty: Type = input.parse()?;
172
173 Ok(Field {
174 attrs,
175 vis,
176 mutability: FieldMutability::None,
177 ident,
178 colon_token,
179 ty,
180 })
181 }
182 }
183
184 #[cfg(feature = "full")]
185 impl ParseQuote for Pat {
parse(input: ParseStream) -> Result<Self>186 fn parse(input: ParseStream) -> Result<Self> {
187 Pat::parse_multi_with_leading_vert(input)
188 }
189 }
190
191 #[cfg(feature = "full")]
192 impl ParseQuote for Box<Pat> {
parse(input: ParseStream) -> Result<Self>193 fn parse(input: ParseStream) -> Result<Self> {
194 <Pat as ParseQuote>::parse(input).map(Box::new)
195 }
196 }
197
198 impl<T: Parse, P: Parse> ParseQuote for Punctuated<T, P> {
parse(input: ParseStream) -> Result<Self>199 fn parse(input: ParseStream) -> Result<Self> {
200 Self::parse_terminated(input)
201 }
202 }
203
204 #[cfg(feature = "full")]
205 impl ParseQuote for Vec<Stmt> {
parse(input: ParseStream) -> Result<Self>206 fn parse(input: ParseStream) -> Result<Self> {
207 Block::parse_within(input)
208 }
209 }
210