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 /// [`Vec<Stmt>`]: Block::parse_within
62 ///
63 /// # Panics
64 ///
65 /// Panics if the tokens fail to parse as the expected syntax tree type. The
66 /// caller is responsible for ensuring that the input tokens are syntactically
67 /// valid.
68 #[cfg_attr(doc_cfg, doc(cfg(all(feature = "parsing", feature = "printing"))))]
69 #[macro_export]
70 macro_rules! parse_quote {
71 ($($tt:tt)*) => {
72 $crate::parse_quote::parse($crate::__private::quote::quote!($($tt)*))
73 };
74 }
75
76 /// This macro is [`parse_quote!`] + [`quote_spanned!`][quote::quote_spanned].
77 ///
78 /// Please refer to each of their documentation.
79 ///
80 /// # Example
81 ///
82 /// ```
83 /// use quote::{quote, quote_spanned};
84 /// use syn::spanned::Spanned;
85 /// use syn::{parse_quote_spanned, ReturnType, Signature};
86 ///
87 /// // Changes `fn()` to `fn() -> Pin<Box<dyn Future<Output = ()>>>`,
88 /// // and `fn() -> T` to `fn() -> Pin<Box<dyn Future<Output = T>>>`,
89 /// // without introducing any call_site() spans.
90 /// fn make_ret_pinned_future(sig: &mut Signature) {
91 /// let ret = match &sig.output {
92 /// ReturnType::Default => quote_spanned!(sig.paren_token.span=> ()),
93 /// ReturnType::Type(_, ret) => quote!(#ret),
94 /// };
95 /// sig.output = parse_quote_spanned! {ret.span()=>
96 /// -> ::std::pin::Pin<::std::boxed::Box<dyn ::std::future::Future<Output = #ret>>>
97 /// };
98 /// }
99 /// ```
100 #[cfg_attr(doc_cfg, doc(cfg(all(feature = "parsing", feature = "printing"))))]
101 #[macro_export]
102 macro_rules! parse_quote_spanned {
103 ($span:expr=> $($tt:tt)*) => {
104 $crate::parse_quote::parse($crate::__private::quote::quote_spanned!($span=> $($tt)*))
105 };
106 }
107
108 ////////////////////////////////////////////////////////////////////////////////
109 // Can parse any type that implements Parse.
110
111 use crate::parse::{Parse, ParseStream, Parser, Result};
112 use proc_macro2::TokenStream;
113
114 // Not public API.
115 #[doc(hidden)]
parse<T: ParseQuote>(token_stream: TokenStream) -> T116 pub fn parse<T: ParseQuote>(token_stream: TokenStream) -> T {
117 let parser = T::parse;
118 match parser.parse2(token_stream) {
119 Ok(t) => t,
120 Err(err) => panic!("{}", err),
121 }
122 }
123
124 // Not public API.
125 #[doc(hidden)]
126 pub trait ParseQuote: Sized {
parse(input: ParseStream) -> Result<Self>127 fn parse(input: ParseStream) -> Result<Self>;
128 }
129
130 impl<T: Parse> ParseQuote for T {
parse(input: ParseStream) -> Result<Self>131 fn parse(input: ParseStream) -> Result<Self> {
132 <T as Parse>::parse(input)
133 }
134 }
135
136 ////////////////////////////////////////////////////////////////////////////////
137 // Any other types that we want `parse_quote!` to be able to parse.
138
139 use crate::punctuated::Punctuated;
140 #[cfg(any(feature = "full", feature = "derive"))]
141 use crate::{attr, Attribute};
142 #[cfg(feature = "full")]
143 use crate::{Block, Stmt};
144
145 #[cfg(any(feature = "full", feature = "derive"))]
146 impl ParseQuote for Attribute {
parse(input: ParseStream) -> Result<Self>147 fn parse(input: ParseStream) -> Result<Self> {
148 if input.peek(Token![#]) && input.peek2(Token![!]) {
149 attr::parsing::single_parse_inner(input)
150 } else {
151 attr::parsing::single_parse_outer(input)
152 }
153 }
154 }
155
156 impl<T: Parse, P: Parse> ParseQuote for Punctuated<T, P> {
parse(input: ParseStream) -> Result<Self>157 fn parse(input: ParseStream) -> Result<Self> {
158 Self::parse_terminated(input)
159 }
160 }
161
162 #[cfg(feature = "full")]
163 impl ParseQuote for Vec<Stmt> {
parse(input: ParseStream) -> Result<Self>164 fn parse(input: ParseStream) -> Result<Self> {
165 Block::parse_within(input)
166 }
167 }
168