• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 /// - [`Vec<Attribute>`] — parses multiple attributes, including mixed kinds in
57 ///   any order
58 /// - [`Punctuated<T, P>`] — parses zero or more `T` separated by punctuation
59 ///   `P` with optional trailing punctuation
60 /// - [`Vec<Arm>`] — parses arms separated by optional commas according to the
61 ///   same grammar as the inside of a `match` expression
62 /// - [`Vec<Stmt>`] — parses the same as `Block::parse_within`
63 /// - [`Pat`], [`Box<Pat>`] — parses the same as
64 ///   `Pat::parse_multi_with_leading_vert`
65 /// - [`Field`] — parses a named or unnamed struct field
66 ///
67 /// [`Vec<Attribute>`]: Attribute
68 /// [`Vec<Arm>`]: Arm
69 /// [`Vec<Stmt>`]: Block::parse_within
70 /// [`Pat`]: Pat::parse_multi_with_leading_vert
71 /// [`Box<Pat>`]: Pat::parse_multi_with_leading_vert
72 ///
73 /// # Panics
74 ///
75 /// Panics if the tokens fail to parse as the expected syntax tree type. The
76 /// caller is responsible for ensuring that the input tokens are syntactically
77 /// valid.
78 #[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "printing"))))]
79 #[macro_export]
80 macro_rules! parse_quote {
81     ($($tt:tt)*) => {
82         $crate::__private::parse_quote($crate::__private::quote::quote!($($tt)*))
83     };
84 }
85 
86 /// This macro is [`parse_quote!`] + [`quote_spanned!`][quote::quote_spanned].
87 ///
88 /// Please refer to each of their documentation.
89 ///
90 /// # Example
91 ///
92 /// ```
93 /// use quote::{quote, quote_spanned};
94 /// use syn::spanned::Spanned;
95 /// use syn::{parse_quote_spanned, ReturnType, Signature};
96 ///
97 /// // Changes `fn()` to `fn() -> Pin<Box<dyn Future<Output = ()>>>`,
98 /// // and `fn() -> T` to `fn() -> Pin<Box<dyn Future<Output = T>>>`,
99 /// // without introducing any call_site() spans.
100 /// fn make_ret_pinned_future(sig: &mut Signature) {
101 ///     let ret = match &sig.output {
102 ///         ReturnType::Default => quote_spanned!(sig.paren_token.span=> ()),
103 ///         ReturnType::Type(_, ret) => quote!(#ret),
104 ///     };
105 ///     sig.output = parse_quote_spanned! {ret.span()=>
106 ///         -> ::std::pin::Pin<::std::boxed::Box<dyn ::std::future::Future<Output = #ret>>>
107 ///     };
108 /// }
109 /// ```
110 #[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "printing"))))]
111 #[macro_export]
112 macro_rules! parse_quote_spanned {
113     ($span:expr=> $($tt:tt)*) => {
114         $crate::__private::parse_quote($crate::__private::quote::quote_spanned!($span=> $($tt)*))
115     };
116 }
117 
118 ////////////////////////////////////////////////////////////////////////////////
119 // Can parse any type that implements Parse.
120 
121 use crate::error::Result;
122 use crate::parse::{Parse, ParseStream, Parser};
123 use proc_macro2::TokenStream;
124 
125 // Not public API.
126 #[doc(hidden)]
127 #[track_caller]
parse<T: ParseQuote>(token_stream: TokenStream) -> T128 pub fn parse<T: ParseQuote>(token_stream: TokenStream) -> T {
129     let parser = T::parse;
130     match parser.parse2(token_stream) {
131         Ok(t) => t,
132         Err(err) => panic!("{}", err),
133     }
134 }
135 
136 #[doc(hidden)]
137 pub trait ParseQuote: Sized {
parse(input: ParseStream) -> Result<Self>138     fn parse(input: ParseStream) -> Result<Self>;
139 }
140 
141 impl<T: Parse> ParseQuote for T {
parse(input: ParseStream) -> Result<Self>142     fn parse(input: ParseStream) -> Result<Self> {
143         <T as Parse>::parse(input)
144     }
145 }
146 
147 ////////////////////////////////////////////////////////////////////////////////
148 // Any other types that we want `parse_quote!` to be able to parse.
149 
150 use crate::punctuated::Punctuated;
151 #[cfg(any(feature = "full", feature = "derive"))]
152 use crate::{attr, Attribute, Field, FieldMutability, Ident, Type, Visibility};
153 #[cfg(feature = "full")]
154 use crate::{Arm, Block, Pat, Stmt};
155 
156 #[cfg(any(feature = "full", feature = "derive"))]
157 impl ParseQuote for Attribute {
parse(input: ParseStream) -> Result<Self>158     fn parse(input: ParseStream) -> Result<Self> {
159         if input.peek(Token![#]) && input.peek2(Token![!]) {
160             attr::parsing::single_parse_inner(input)
161         } else {
162             attr::parsing::single_parse_outer(input)
163         }
164     }
165 }
166 
167 #[cfg(any(feature = "full", feature = "derive"))]
168 impl ParseQuote for Vec<Attribute> {
parse(input: ParseStream) -> Result<Self>169     fn parse(input: ParseStream) -> Result<Self> {
170         let mut attrs = Vec::new();
171         while !input.is_empty() {
172             attrs.push(ParseQuote::parse(input)?);
173         }
174         Ok(attrs)
175     }
176 }
177 
178 #[cfg(any(feature = "full", feature = "derive"))]
179 impl ParseQuote for Field {
parse(input: ParseStream) -> Result<Self>180     fn parse(input: ParseStream) -> Result<Self> {
181         let attrs = input.call(Attribute::parse_outer)?;
182         let vis: Visibility = input.parse()?;
183 
184         let ident: Option<Ident>;
185         let colon_token: Option<Token![:]>;
186         let is_named = input.peek(Ident) && input.peek2(Token![:]) && !input.peek2(Token![::]);
187         if is_named {
188             ident = Some(input.parse()?);
189             colon_token = Some(input.parse()?);
190         } else {
191             ident = None;
192             colon_token = None;
193         }
194 
195         let ty: Type = input.parse()?;
196 
197         Ok(Field {
198             attrs,
199             vis,
200             mutability: FieldMutability::None,
201             ident,
202             colon_token,
203             ty,
204         })
205     }
206 }
207 
208 #[cfg(feature = "full")]
209 impl ParseQuote for Pat {
parse(input: ParseStream) -> Result<Self>210     fn parse(input: ParseStream) -> Result<Self> {
211         Pat::parse_multi_with_leading_vert(input)
212     }
213 }
214 
215 #[cfg(feature = "full")]
216 impl ParseQuote for Box<Pat> {
parse(input: ParseStream) -> Result<Self>217     fn parse(input: ParseStream) -> Result<Self> {
218         <Pat as ParseQuote>::parse(input).map(Box::new)
219     }
220 }
221 
222 impl<T: Parse, P: Parse> ParseQuote for Punctuated<T, P> {
parse(input: ParseStream) -> Result<Self>223     fn parse(input: ParseStream) -> Result<Self> {
224         Self::parse_terminated(input)
225     }
226 }
227 
228 #[cfg(feature = "full")]
229 impl ParseQuote for Vec<Stmt> {
parse(input: ParseStream) -> Result<Self>230     fn parse(input: ParseStream) -> Result<Self> {
231         Block::parse_within(input)
232     }
233 }
234 
235 #[cfg(feature = "full")]
236 impl ParseQuote for Vec<Arm> {
parse(input: ParseStream) -> Result<Self>237     fn parse(input: ParseStream) -> Result<Self> {
238         Arm::parse_multiple(input)
239     }
240 }
241