Skip to main content

syn/
parse_quote.rs

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(generics: &mut Generics) {
40///     for param in &mut generics.params {
41///         if let GenericParam::Type(type_param) = param {
42///             type_param.bounds.push(parse_quote!(::heapsize::HeapSize));
43///         }
44///     }
45/// }
46/// ```
47///
48/// # Special cases
49///
50/// This macro can parse the following additional types as a special case even
51/// though they do not implement the `Parse` trait.
52///
53/// - [`Attribute`] — parses one attribute, allowing either outer like `#[...]`
54///   or inner like `#![...]`
55/// - [`Vec<Attribute>`] — parses multiple attributes, including mixed kinds in
56///   any order
57/// - [`Punctuated<T, P>`] — parses zero or more `T` separated by punctuation
58///   `P` with optional trailing punctuation
59/// - [`Vec<Arm>`] — parses arms separated by optional commas according to the
60///   same grammar as the inside of a `match` expression
61/// - [`Vec<Stmt>`] — parses the same as `Block::parse_within`
62/// - [`Pat`], [`Box<Pat>`] — parses the same as
63///   `Pat::parse_multi_with_leading_vert`
64/// - [`Field`] — parses a named or unnamed struct field
65/// - [`Safety`] — parses the same as `Safety::parse_safe_or_unsafe`
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/// [`Safety`]: Safety::parse_safe_or_unsafe
73///
74/// # Panics
75///
76/// Panics if the tokens fail to parse as the expected syntax tree type. The
77/// caller is responsible for ensuring that the input tokens are syntactically
78/// valid.
79#[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "printing"))))]
80#[macro_export]
81macro_rules! parse_quote {
82    ($($tt:tt)*) => {
83        $crate::__private::parse_quote($crate::__private::quote::quote!($($tt)*))
84    };
85}
86
87/// This macro is [`parse_quote!`] + [`quote_spanned!`][quote::quote_spanned].
88///
89/// Please refer to each of their documentation.
90///
91/// # Example
92///
93/// ```
94/// use quote::{quote, quote_spanned};
95/// use syn::spanned::Spanned;
96/// use syn::{parse_quote_spanned, ReturnType, Signature};
97///
98/// // Changes `fn()` to `fn() -> Pin<Box<dyn Future<Output = ()>>>`,
99/// // and `fn() -> T` to `fn() -> Pin<Box<dyn Future<Output = T>>>`,
100/// // without introducing any call_site() spans.
101/// fn make_ret_pinned_future(sig: &mut Signature) {
102///     let ret = match &sig.output {
103///         ReturnType::Default => quote_spanned!(sig.paren_token.span=> ()),
104///         ReturnType::Type(_, ret) => quote!(#ret),
105///     };
106///     sig.output = parse_quote_spanned! {ret.span()=>
107///         -> ::core::pin::Pin<::alloc::boxed::Box<dyn ::core::future::Future<Output = #ret>>>
108///     };
109/// }
110/// ```
111#[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "printing"))))]
112#[macro_export]
113macro_rules! parse_quote_spanned {
114    ($span:expr=> $($tt:tt)*) => {
115        $crate::__private::parse_quote($crate::__private::quote::quote_spanned!($span=> $($tt)*))
116    };
117}
118
119////////////////////////////////////////////////////////////////////////////////
120// Can parse any type that implements Parse.
121
122use crate::error::Result;
123use crate::parse::{Parse, ParseStream, Parser};
124#[cfg(feature = "full")]
125use alloc::boxed::Box;
126#[cfg(any(feature = "full", feature = "derive"))]
127use alloc::vec::Vec;
128use proc_macro2::TokenStream;
129
130// Not public API.
131#[doc(hidden)]
132#[track_caller]
133pub fn parse<T: ParseQuote>(token_stream: TokenStream) -> T {
134    let parser = T::parse;
135    match parser.parse2(token_stream) {
136        Ok(t) => t,
137        Err(err) => { ::core::panicking::panic_display(&err); }panic!("{}", err),
138    }
139}
140
141#[doc(hidden)]
142pub trait ParseQuote: Sized {
143    fn parse(input: ParseStream) -> Result<Self>;
144}
145
146impl<T: Parse> ParseQuote for T {
147    fn parse(input: ParseStream) -> Result<Self> {
148        <T as Parse>::parse(input)
149    }
150}
151
152////////////////////////////////////////////////////////////////////////////////
153// Any other types that we want `parse_quote!` to be able to parse.
154
155use crate::punctuated::Punctuated;
156#[cfg(any(feature = "full", feature = "derive"))]
157use crate::{attr, Attribute, Expr, Field, FieldModifiers, Ident, Type, Visibility};
158#[cfg(feature = "full")]
159use crate::{Arm, Block, Pat, Safety, Stmt};
160
161#[cfg(any(feature = "full", feature = "derive"))]
162impl ParseQuote for Attribute {
163    fn parse(input: ParseStream) -> Result<Self> {
164        if input.peek(crate::token::PoundToken![#]) && input.peek2(crate::token::NotToken![!]) {
165            attr::parsing::single_parse_inner(input)
166        } else {
167            attr::parsing::single_parse_outer(input)
168        }
169    }
170}
171
172#[cfg(any(feature = "full", feature = "derive"))]
173impl ParseQuote for Vec<Attribute> {
174    fn parse(input: ParseStream) -> Result<Self> {
175        let mut attrs = Vec::new();
176        while !input.is_empty() {
177            attrs.push(ParseQuote::parse(input)?);
178        }
179        Ok(attrs)
180    }
181}
182
183#[cfg(any(feature = "full", feature = "derive"))]
184impl ParseQuote for Field {
185    fn parse(input: ParseStream) -> Result<Self> {
186        let attrs = input.call(Attribute::parse_outer)?;
187        let vis: Visibility = input.parse()?;
188
189        let ident: Option<Ident>;
190        let colon_token: Option<crate::token::ColonToken![:]>;
191        let is_named = input.peek(Ident) && input.peek2(crate::token::ColonToken![:]) && !input.peek2(crate::token::PathSepToken![::]);
192        if is_named {
193            ident = Some(input.parse()?);
194            colon_token = Some(input.parse()?);
195        } else {
196            ident = None;
197            colon_token = None;
198        }
199
200        let ty: Type = input.parse()?;
201
202        let default = if is_named && input.peek(crate::token::EqToken![=]) {
203            let eq_token: crate::token::EqToken![=] = input.parse()?;
204            let expr: Expr = input.parse()?;
205            Some((eq_token, expr))
206        } else {
207            None
208        };
209
210        Ok(Field {
211            attrs,
212            vis,
213            modifiers: FieldModifiers {},
214            ident,
215            colon_token,
216            ty,
217            default,
218        })
219    }
220}
221
222#[cfg(feature = "full")]
223impl ParseQuote for Pat {
224    fn parse(input: ParseStream) -> Result<Self> {
225        Pat::parse_multi_with_leading_vert_and_guard(input)
226    }
227}
228
229#[cfg(feature = "full")]
230impl ParseQuote for Box<Pat> {
231    fn parse(input: ParseStream) -> Result<Self> {
232        <Pat as ParseQuote>::parse(input).map(Box::new)
233    }
234}
235
236impl<T: Parse, P: Parse> ParseQuote for Punctuated<T, P> {
237    fn parse(input: ParseStream) -> Result<Self> {
238        Self::parse_terminated(input)
239    }
240}
241
242#[cfg(feature = "full")]
243impl ParseQuote for Safety {
244    fn parse(input: ParseStream) -> Result<Self> {
245        Safety::parse_safe_or_unsafe(input)
246    }
247}
248
249#[cfg(feature = "full")]
250impl ParseQuote for Vec<Stmt> {
251    fn parse(input: ParseStream) -> Result<Self> {
252        Block::parse_within(input)
253    }
254}
255
256#[cfg(feature = "full")]
257impl ParseQuote for Vec<Arm> {
258    fn parse(input: ParseStream) -> Result<Self> {
259        Arm::parse_multiple(input)
260    }
261}