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`]: 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 if Syn is built with the `"parsing"` feature,
28/// although interpolation of syntax tree nodes into the quoted tokens is only
29/// supported if Syn is built with the `"printing"` feature as well.*
30///
31/// # Example
32///
33/// The following helper function adds a bound `T: HeapSize` to every type
34/// parameter `T` in the input generics.
35///
36/// ```
37/// use syn::{parse_quote, Generics, GenericParam};
38///
39/// // Add a bound `T: HeapSize` to every type parameter T.
40/// fn add_trait_bounds(mut generics: Generics) -> Generics {
41///     for param in &mut generics.params {
42///         if let GenericParam::Type(type_param) = param {
43///             type_param.bounds.push(parse_quote!(HeapSize));
44///         }
45///     }
46///     generics
47/// }
48/// ```
49///
50/// # Special cases
51///
52/// This macro can parse the following additional types as a special case even
53/// though they do not implement the `Parse` trait.
54///
55/// - [`Attribute`] — parses one attribute, allowing either outer like `#[...]`
56///   or inner like `#![...]`
57/// - [`Punctuated<T, P>`] — parses zero or more `T` separated by punctuation
58///   `P` with optional trailing punctuation
59///
60/// [`Punctuated<T, P>`]: punctuated::Punctuated
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//
68// TODO: allow Punctuated to be inferred as intra doc link, currently blocked on
69// https://github.com/rust-lang/rust/issues/62834
70#[macro_export(local_inner_macros)]
71macro_rules! parse_quote {
72    ($($tt:tt)*) => {
73        $crate::parse_quote::parse(
74            $crate::export::From::from(
75                $crate::export::quote::quote!($($tt)*)
76            )
77        )
78    };
79}
80
81////////////////////////////////////////////////////////////////////////////////
82// Can parse any type that implements Parse.
83
84use crate::parse::{Parse, ParseStream, Parser, Result};
85use proc_macro2::TokenStream;
86
87// Not public API.
88#[doc(hidden)]
89pub fn parse<T: ParseQuote>(token_stream: TokenStream) -> T {
90    let parser = T::parse;
91    match parser.parse2(token_stream) {
92        Ok(t) => t,
93        Err(err) => panic!("{}", err),
94    }
95}
96
97// Not public API.
98#[doc(hidden)]
99pub trait ParseQuote: Sized {
100    fn parse(input: ParseStream) -> Result<Self>;
101}
102
103impl<T: Parse> ParseQuote for T {
104    fn parse(input: ParseStream) -> Result<Self> {
105        <T as Parse>::parse(input)
106    }
107}
108
109////////////////////////////////////////////////////////////////////////////////
110// Any other types that we want `parse_quote!` to be able to parse.
111
112use crate::punctuated::Punctuated;
113#[cfg(any(feature = "full", feature = "derive"))]
114use crate::{attr, Attribute};
115
116#[cfg(any(feature = "full", feature = "derive"))]
117impl ParseQuote for Attribute {
118    fn parse(input: ParseStream) -> Result<Self> {
119        if input.peek(Token![#]) && input.peek2(Token![!]) {
120            attr::parsing::single_parse_inner(input)
121        } else {
122            attr::parsing::single_parse_outer(input)
123        }
124    }
125}
126
127impl<T: Parse, P: Parse> ParseQuote for Punctuated<T, P> {
128    fn parse(input: ParseStream) -> Result<Self> {
129        Self::parse_terminated(input)
130    }
131}