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(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]
80macro_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///         -> ::core::pin::Pin<::alloc::boxed::Box<dyn ::core::future::Future<Output = #ret>>>
107///     };
108/// }
109/// ```
110#[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "printing"))))]
111#[macro_export]
112macro_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
121use crate::error::Result;
122use crate::parse::{Parse, ParseStream, Parser};
123#[cfg(feature = "full")]
124use alloc::boxed::Box;
125#[cfg(any(feature = "full", feature = "derive"))]
126use alloc::vec::Vec;
127use proc_macro2::TokenStream;
128
129// Not public API.
130#[doc(hidden)]
131#[track_caller]
132pub fn parse<T: ParseQuote>(token_stream: TokenStream) -> T {
133    let parser = T::parse;
134    match parser.parse2(token_stream) {
135        Ok(t) => t,
136        Err(err) => { ::core::panicking::panic_display(&err); }panic!("{}", err),
137    }
138}
139
140#[doc(hidden)]
141pub trait ParseQuote: Sized {
142    fn parse(input: ParseStream) -> Result<Self>;
143}
144
145impl<T: Parse> ParseQuote for T {
146    fn parse(input: ParseStream) -> Result<Self> {
147        <T as Parse>::parse(input)
148    }
149}
150
151////////////////////////////////////////////////////////////////////////////////
152// Any other types that we want `parse_quote!` to be able to parse.
153
154use crate::punctuated::Punctuated;
155#[cfg(any(feature = "full", feature = "derive"))]
156use crate::{attr, Attribute, Field, FieldMutability, Ident, Type, Visibility};
157#[cfg(feature = "full")]
158use crate::{Arm, Block, Pat, Stmt};
159
160#[cfg(any(feature = "full", feature = "derive"))]
161impl ParseQuote for Attribute {
162    fn parse(input: ParseStream) -> Result<Self> {
163        if input.peek(crate::token::PoundToken![#]) && input.peek2(crate::token::NotToken![!]) {
164            attr::parsing::single_parse_inner(input)
165        } else {
166            attr::parsing::single_parse_outer(input)
167        }
168    }
169}
170
171#[cfg(any(feature = "full", feature = "derive"))]
172impl ParseQuote for Vec<Attribute> {
173    fn parse(input: ParseStream) -> Result<Self> {
174        let mut attrs = Vec::new();
175        while !input.is_empty() {
176            attrs.push(ParseQuote::parse(input)?);
177        }
178        Ok(attrs)
179    }
180}
181
182#[cfg(any(feature = "full", feature = "derive"))]
183impl ParseQuote for Field {
184    fn parse(input: ParseStream) -> Result<Self> {
185        let attrs = input.call(Attribute::parse_outer)?;
186        let vis: Visibility = input.parse()?;
187
188        let ident: Option<Ident>;
189        let colon_token: Option<crate::token::ColonToken![:]>;
190        let is_named = input.peek(Ident) && input.peek2(crate::token::ColonToken![:]) && !input.peek2(crate::token::PathSepToken![::]);
191        if is_named {
192            ident = Some(input.parse()?);
193            colon_token = Some(input.parse()?);
194        } else {
195            ident = None;
196            colon_token = None;
197        }
198
199        let ty: Type = input.parse()?;
200
201        Ok(Field {
202            attrs,
203            vis,
204            mutability: FieldMutability::None,
205            ident,
206            colon_token,
207            ty,
208        })
209    }
210}
211
212#[cfg(feature = "full")]
213impl ParseQuote for Pat {
214    fn parse(input: ParseStream) -> Result<Self> {
215        Pat::parse_multi_with_leading_vert(input)
216    }
217}
218
219#[cfg(feature = "full")]
220impl ParseQuote for Box<Pat> {
221    fn parse(input: ParseStream) -> Result<Self> {
222        <Pat as ParseQuote>::parse(input).map(Box::new)
223    }
224}
225
226impl<T: Parse, P: Parse> ParseQuote for Punctuated<T, P> {
227    fn parse(input: ParseStream) -> Result<Self> {
228        Self::parse_terminated(input)
229    }
230}
231
232#[cfg(feature = "full")]
233impl ParseQuote for Vec<Stmt> {
234    fn parse(input: ParseStream) -> Result<Self> {
235        Block::parse_within(input)
236    }
237}
238
239#[cfg(feature = "full")]
240impl ParseQuote for Vec<Arm> {
241    fn parse(input: ParseStream) -> Result<Self> {
242        Arm::parse_multiple(input)
243    }
244}