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 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 /// - [`Vec<Stmt>`] — parses the same as `Block::parse_within`
60 ///
61 /// [`Punctuated<T, P>`]: crate::punctuated::Punctuated
62 /// [`Vec<Stmt>`]: Block::parse_within
63 ///
64 /// # Panics
65 ///
66 /// Panics if the tokens fail to parse as the expected syntax tree type. The
67 /// caller is responsible for ensuring that the input tokens are syntactically
68 /// valid.
69 //
70 // TODO: allow Punctuated to be inferred as intra doc link, currently blocked on
71 // https://github.com/rust-lang/rust/issues/62834
72 #[cfg_attr(doc_cfg, doc(cfg(all(feature = "parsing", feature = "printing"))))]
73 #[macro_export]
74 macro_rules! parse_quote {
75     ($($tt:tt)*) => {
76         $crate::parse_quote::parse(
77             $crate::__private::From::from(
78                 $crate::__private::quote::quote!($($tt)*)
79             )
80         )
81     };
82 }
83 
84 ////////////////////////////////////////////////////////////////////////////////
85 // Can parse any type that implements Parse.
86 
87 use crate::parse::{Parse, ParseStream, Parser, Result};
88 use proc_macro2::TokenStream;
89 
90 // Not public API.
91 #[doc(hidden)]
parse<T: ParseQuote>(token_stream: TokenStream) -> T92 pub fn parse<T: ParseQuote>(token_stream: TokenStream) -> T {
93     let parser = T::parse;
94     match parser.parse2(token_stream) {
95         Ok(t) => t,
96         Err(err) => panic!("{}", err),
97     }
98 }
99 
100 // Not public API.
101 #[doc(hidden)]
102 pub trait ParseQuote: Sized {
parse(input: ParseStream) -> Result<Self>103     fn parse(input: ParseStream) -> Result<Self>;
104 }
105 
106 impl<T: Parse> ParseQuote for T {
parse(input: ParseStream) -> Result<Self>107     fn parse(input: ParseStream) -> Result<Self> {
108         <T as Parse>::parse(input)
109     }
110 }
111 
112 ////////////////////////////////////////////////////////////////////////////////
113 // Any other types that we want `parse_quote!` to be able to parse.
114 
115 use crate::punctuated::Punctuated;
116 #[cfg(any(feature = "full", feature = "derive"))]
117 use crate::{attr, Attribute};
118 #[cfg(feature = "full")]
119 use crate::{Block, Stmt};
120 
121 #[cfg(any(feature = "full", feature = "derive"))]
122 impl ParseQuote for Attribute {
parse(input: ParseStream) -> Result<Self>123     fn parse(input: ParseStream) -> Result<Self> {
124         if input.peek(Token![#]) && input.peek2(Token![!]) {
125             attr::parsing::single_parse_inner(input)
126         } else {
127             attr::parsing::single_parse_outer(input)
128         }
129     }
130 }
131 
132 impl<T: Parse, P: Parse> ParseQuote for Punctuated<T, P> {
parse(input: ParseStream) -> Result<Self>133     fn parse(input: ParseStream) -> Result<Self> {
134         Self::parse_terminated(input)
135     }
136 }
137 
138 #[cfg(feature = "full")]
139 impl ParseQuote for Vec<Stmt> {
parse(input: ParseStream) -> Result<Self>140     fn parse(input: ParseStream) -> Result<Self> {
141         Block::parse_within(input)
142     }
143 }
144