xref: /linux/rust/syn/parse_quote.rs (revision 69942c0a8965f311ed7ddf842f160c9cfdcda73a)
1 // SPDX-License-Identifier: Apache-2.0 OR MIT
2 
3 /// Quasi-quotation macro that accepts input like the [`quote!`] macro but uses
4 /// type inference to figure out a return type for those tokens.
5 ///
6 /// [`quote!`]: https://docs.rs/quote/1.0/quote/index.html
7 ///
8 /// The return type can be any syntax tree node that implements the [`Parse`]
9 /// trait.
10 ///
11 /// [`Parse`]: crate::parse::Parse
12 ///
13 /// ```
14 /// use quote::quote;
15 /// use syn::{parse_quote, Stmt};
16 ///
17 /// fn main() {
18 ///     let name = quote!(v);
19 ///     let ty = quote!(u8);
20 ///
21 ///     let stmt: Stmt = parse_quote! {
22 ///         let #name: #ty = Default::default();
23 ///     };
24 ///
25 ///     println!("{:#?}", stmt);
26 /// }
27 /// ```
28 ///
29 /// *This macro is available only if Syn is built with both the `"parsing"` and
30 /// `"printing"` features.*
31 ///
32 /// # Example
33 ///
34 /// The following helper function adds a bound `T: HeapSize` to every type
35 /// parameter `T` in the input generics.
36 ///
37 /// ```
38 /// use syn::{parse_quote, Generics, GenericParam};
39 ///
40 /// // Add a bound `T: HeapSize` to every type parameter T.
41 /// fn add_trait_bounds(mut generics: Generics) -> Generics {
42 ///     for param in &mut generics.params {
43 ///         if let GenericParam::Type(type_param) = param {
44 ///             type_param.bounds.push(parse_quote!(HeapSize));
45 ///         }
46 ///     }
47 ///     generics
48 /// }
49 /// ```
50 ///
51 /// # Special cases
52 ///
53 /// This macro can parse the following additional types as a special case even
54 /// though they do not implement the `Parse` trait.
55 ///
56 /// - [`Attribute`] — parses one attribute, allowing either outer like `#[...]`
57 ///   or inner like `#![...]`
58 /// - [`Vec<Attribute>`] — parses multiple attributes, including mixed kinds in
59 ///   any order
60 /// - [`Punctuated<T, P>`] — parses zero or more `T` separated by punctuation
61 ///   `P` with optional trailing punctuation
62 /// - [`Vec<Arm>`] — parses arms separated by optional commas according to the
63 ///   same grammar as the inside of a `match` expression
64 /// - [`Vec<Stmt>`] — parses the same as `Block::parse_within`
65 /// - [`Pat`], [`Box<Pat>`] — parses the same as
66 ///   `Pat::parse_multi_with_leading_vert`
67 /// - [`Field`] — parses a named or unnamed struct field
68 ///
69 /// [`Vec<Attribute>`]: Attribute
70 /// [`Vec<Arm>`]: Arm
71 /// [`Vec<Stmt>`]: Block::parse_within
72 /// [`Pat`]: Pat::parse_multi_with_leading_vert
73 /// [`Box<Pat>`]: Pat::parse_multi_with_leading_vert
74 ///
75 /// # Panics
76 ///
77 /// Panics if the tokens fail to parse as the expected syntax tree type. The
78 /// caller is responsible for ensuring that the input tokens are syntactically
79 /// valid.
80 #[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "printing"))))]
81 #[macro_export]
82 macro_rules! parse_quote {
83     ($($tt:tt)*) => {
84         $crate::__private::parse_quote($crate::__private::quote::quote!($($tt)*))
85     };
86 }
87 
88 /// This macro is [`parse_quote!`] + [`quote_spanned!`][quote::quote_spanned].
89 ///
90 /// Please refer to each of their documentation.
91 ///
92 /// # Example
93 ///
94 /// ```
95 /// use quote::{quote, quote_spanned};
96 /// use syn::spanned::Spanned;
97 /// use syn::{parse_quote_spanned, ReturnType, Signature};
98 ///
99 /// // Changes `fn()` to `fn() -> Pin<Box<dyn Future<Output = ()>>>`,
100 /// // and `fn() -> T` to `fn() -> Pin<Box<dyn Future<Output = T>>>`,
101 /// // without introducing any call_site() spans.
102 /// fn make_ret_pinned_future(sig: &mut Signature) {
103 ///     let ret = match &sig.output {
104 ///         ReturnType::Default => quote_spanned!(sig.paren_token.span=> ()),
105 ///         ReturnType::Type(_, ret) => quote!(#ret),
106 ///     };
107 ///     sig.output = parse_quote_spanned! {ret.span()=>
108 ///         -> ::std::pin::Pin<::std::boxed::Box<dyn ::std::future::Future<Output = #ret>>>
109 ///     };
110 /// }
111 /// ```
112 #[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "printing"))))]
113 #[macro_export]
114 macro_rules! parse_quote_spanned {
115     ($span:expr=> $($tt:tt)*) => {
116         $crate::__private::parse_quote($crate::__private::quote::quote_spanned!($span=> $($tt)*))
117     };
118 }
119 
120 ////////////////////////////////////////////////////////////////////////////////
121 // Can parse any type that implements Parse.
122 
123 use crate::error::Result;
124 use crate::parse::{Parse, ParseStream, Parser};
125 use proc_macro2::TokenStream;
126 
127 // Not public API.
128 #[doc(hidden)]
129 #[track_caller]
130 pub fn parse<T: ParseQuote>(token_stream: TokenStream) -> T {
131     let parser = T::parse;
132     match parser.parse2(token_stream) {
133         Ok(t) => t,
134         Err(err) => panic!("{}", err),
135     }
136 }
137 
138 #[doc(hidden)]
139 pub trait ParseQuote: Sized {
140     fn parse(input: ParseStream) -> Result<Self>;
141 }
142 
143 impl<T: Parse> ParseQuote for T {
144     fn parse(input: ParseStream) -> Result<Self> {
145         <T as Parse>::parse(input)
146     }
147 }
148 
149 ////////////////////////////////////////////////////////////////////////////////
150 // Any other types that we want `parse_quote!` to be able to parse.
151 
152 use crate::punctuated::Punctuated;
153 #[cfg(any(feature = "full", feature = "derive"))]
154 use crate::{attr, Attribute, Field, FieldMutability, Ident, Type, Visibility};
155 #[cfg(feature = "full")]
156 use crate::{Arm, Block, Pat, Stmt};
157 
158 #[cfg(any(feature = "full", feature = "derive"))]
159 impl ParseQuote for Attribute {
160     fn parse(input: ParseStream) -> Result<Self> {
161         if input.peek(Token![#]) && input.peek2(Token![!]) {
162             attr::parsing::single_parse_inner(input)
163         } else {
164             attr::parsing::single_parse_outer(input)
165         }
166     }
167 }
168 
169 #[cfg(any(feature = "full", feature = "derive"))]
170 impl ParseQuote for Vec<Attribute> {
171     fn parse(input: ParseStream) -> Result<Self> {
172         let mut attrs = Vec::new();
173         while !input.is_empty() {
174             attrs.push(ParseQuote::parse(input)?);
175         }
176         Ok(attrs)
177     }
178 }
179 
180 #[cfg(any(feature = "full", feature = "derive"))]
181 impl ParseQuote for Field {
182     fn parse(input: ParseStream) -> Result<Self> {
183         let attrs = input.call(Attribute::parse_outer)?;
184         let vis: Visibility = input.parse()?;
185 
186         let ident: Option<Ident>;
187         let colon_token: Option<Token![:]>;
188         let is_named = input.peek(Ident) && input.peek2(Token![:]) && !input.peek2(Token![::]);
189         if is_named {
190             ident = Some(input.parse()?);
191             colon_token = Some(input.parse()?);
192         } else {
193             ident = None;
194             colon_token = None;
195         }
196 
197         let ty: Type = input.parse()?;
198 
199         Ok(Field {
200             attrs,
201             vis,
202             mutability: FieldMutability::None,
203             ident,
204             colon_token,
205             ty,
206         })
207     }
208 }
209 
210 #[cfg(feature = "full")]
211 impl ParseQuote for Pat {
212     fn parse(input: ParseStream) -> Result<Self> {
213         Pat::parse_multi_with_leading_vert(input)
214     }
215 }
216 
217 #[cfg(feature = "full")]
218 impl ParseQuote for Box<Pat> {
219     fn parse(input: ParseStream) -> Result<Self> {
220         <Pat as ParseQuote>::parse(input).map(Box::new)
221     }
222 }
223 
224 impl<T: Parse, P: Parse> ParseQuote for Punctuated<T, P> {
225     fn parse(input: ParseStream) -> Result<Self> {
226         Self::parse_terminated(input)
227     }
228 }
229 
230 #[cfg(feature = "full")]
231 impl ParseQuote for Vec<Stmt> {
232     fn parse(input: ParseStream) -> Result<Self> {
233         Block::parse_within(input)
234     }
235 }
236 
237 #[cfg(feature = "full")]
238 impl ParseQuote for Vec<Arm> {
239     fn parse(input: ParseStream) -> Result<Self> {
240         Arm::parse_multiple(input)
241     }
242 }
243