1 // SPDX-License-Identifier: Apache-2.0 OR MIT 2 3 /// Quasi-quotation macro that accepts input like the [`quote!`] macro but uses 4 /// type inference to figure out a return type for those tokens. 5 /// 6 /// [`quote!`]: https://docs.rs/quote/1.0/quote/index.html 7 /// 8 /// The return type can be any syntax tree node that implements the [`Parse`] 9 /// trait. 10 /// 11 /// [`Parse`]: crate::parse::Parse 12 /// 13 /// ``` 14 /// use quote::quote; 15 /// use syn::{parse_quote, Stmt}; 16 /// 17 /// fn main() { 18 /// let name = quote!(v); 19 /// let ty = quote!(u8); 20 /// 21 /// let stmt: Stmt = parse_quote! { 22 /// let #name: #ty = Default::default(); 23 /// }; 24 /// 25 /// println!("{:#?}", stmt); 26 /// } 27 /// ``` 28 /// 29 /// *This macro is available only if Syn is built with both the `"parsing"` and 30 /// `"printing"` features.* 31 /// 32 /// # Example 33 /// 34 /// The following helper function adds a bound `T: HeapSize` to every type 35 /// parameter `T` in the input generics. 36 /// 37 /// ``` 38 /// use syn::{parse_quote, Generics, GenericParam}; 39 /// 40 /// // Add a bound `T: HeapSize` to every type parameter T. 41 /// fn add_trait_bounds(mut generics: Generics) -> Generics { 42 /// for param in &mut generics.params { 43 /// if let GenericParam::Type(type_param) = param { 44 /// type_param.bounds.push(parse_quote!(HeapSize)); 45 /// } 46 /// } 47 /// generics 48 /// } 49 /// ``` 50 /// 51 /// # Special cases 52 /// 53 /// This macro can parse the following additional types as a special case even 54 /// though they do not implement the `Parse` trait. 55 /// 56 /// - [`Attribute`] — parses one attribute, allowing either outer like `#[...]` 57 /// or inner like `#![...]` 58 /// - [`Vec<Attribute>`] — parses multiple attributes, including mixed kinds in 59 /// any order 60 /// - [`Punctuated<T, P>`] — parses zero or more `T` separated by punctuation 61 /// `P` with optional trailing punctuation 62 /// - [`Vec<Arm>`] — parses arms separated by optional commas according to the 63 /// same grammar as the inside of a `match` expression 64 /// - [`Vec<Stmt>`] — parses the same as `Block::parse_within` 65 /// - [`Pat`], [`Box<Pat>`] — parses the same as 66 /// `Pat::parse_multi_with_leading_vert` 67 /// - [`Field`] — parses a named or unnamed struct field 68 /// 69 /// [`Vec<Attribute>`]: Attribute 70 /// [`Vec<Arm>`]: Arm 71 /// [`Vec<Stmt>`]: Block::parse_within 72 /// [`Pat`]: Pat::parse_multi_with_leading_vert 73 /// [`Box<Pat>`]: Pat::parse_multi_with_leading_vert 74 /// 75 /// # Panics 76 /// 77 /// Panics if the tokens fail to parse as the expected syntax tree type. The 78 /// caller is responsible for ensuring that the input tokens are syntactically 79 /// valid. 80 #[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "printing"))))] 81 #[macro_export] 82 macro_rules! parse_quote { 83 ($($tt:tt)*) => { 84 $crate::__private::parse_quote($crate::__private::quote::quote!($($tt)*)) 85 }; 86 } 87 88 /// This macro is [`parse_quote!`] + [`quote_spanned!`][quote::quote_spanned]. 89 /// 90 /// Please refer to each of their documentation. 91 /// 92 /// # Example 93 /// 94 /// ``` 95 /// use quote::{quote, quote_spanned}; 96 /// use syn::spanned::Spanned; 97 /// use syn::{parse_quote_spanned, ReturnType, Signature}; 98 /// 99 /// // Changes `fn()` to `fn() -> Pin<Box<dyn Future<Output = ()>>>`, 100 /// // and `fn() -> T` to `fn() -> Pin<Box<dyn Future<Output = T>>>`, 101 /// // without introducing any call_site() spans. 102 /// fn make_ret_pinned_future(sig: &mut Signature) { 103 /// let ret = match &sig.output { 104 /// ReturnType::Default => quote_spanned!(sig.paren_token.span=> ()), 105 /// ReturnType::Type(_, ret) => quote!(#ret), 106 /// }; 107 /// sig.output = parse_quote_spanned! {ret.span()=> 108 /// -> ::std::pin::Pin<::std::boxed::Box<dyn ::std::future::Future<Output = #ret>>> 109 /// }; 110 /// } 111 /// ``` 112 #[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "printing"))))] 113 #[macro_export] 114 macro_rules! parse_quote_spanned { 115 ($span:expr=> $($tt:tt)*) => { 116 $crate::__private::parse_quote($crate::__private::quote::quote_spanned!($span=> $($tt)*)) 117 }; 118 } 119 120 //////////////////////////////////////////////////////////////////////////////// 121 // Can parse any type that implements Parse. 122 123 use crate::error::Result; 124 use crate::parse::{Parse, ParseStream, Parser}; 125 use proc_macro2::TokenStream; 126 127 // Not public API. 128 #[doc(hidden)] 129 #[track_caller] 130 pub fn parse<T: ParseQuote>(token_stream: TokenStream) -> T { 131 let parser = T::parse; 132 match parser.parse2(token_stream) { 133 Ok(t) => t, 134 Err(err) => panic!("{}", err), 135 } 136 } 137 138 #[doc(hidden)] 139 pub trait ParseQuote: Sized { 140 fn parse(input: ParseStream) -> Result<Self>; 141 } 142 143 impl<T: Parse> ParseQuote for T { 144 fn parse(input: ParseStream) -> Result<Self> { 145 <T as Parse>::parse(input) 146 } 147 } 148 149 //////////////////////////////////////////////////////////////////////////////// 150 // Any other types that we want `parse_quote!` to be able to parse. 151 152 use crate::punctuated::Punctuated; 153 #[cfg(any(feature = "full", feature = "derive"))] 154 use crate::{attr, Attribute, Field, FieldMutability, Ident, Type, Visibility}; 155 #[cfg(feature = "full")] 156 use crate::{Arm, Block, Pat, Stmt}; 157 158 #[cfg(any(feature = "full", feature = "derive"))] 159 impl ParseQuote for Attribute { 160 fn parse(input: ParseStream) -> Result<Self> { 161 if input.peek(Token![#]) && input.peek2(Token![!]) { 162 attr::parsing::single_parse_inner(input) 163 } else { 164 attr::parsing::single_parse_outer(input) 165 } 166 } 167 } 168 169 #[cfg(any(feature = "full", feature = "derive"))] 170 impl ParseQuote for Vec<Attribute> { 171 fn parse(input: ParseStream) -> Result<Self> { 172 let mut attrs = Vec::new(); 173 while !input.is_empty() { 174 attrs.push(ParseQuote::parse(input)?); 175 } 176 Ok(attrs) 177 } 178 } 179 180 #[cfg(any(feature = "full", feature = "derive"))] 181 impl ParseQuote for Field { 182 fn parse(input: ParseStream) -> Result<Self> { 183 let attrs = input.call(Attribute::parse_outer)?; 184 let vis: Visibility = input.parse()?; 185 186 let ident: Option<Ident>; 187 let colon_token: Option<Token![:]>; 188 let is_named = input.peek(Ident) && input.peek2(Token![:]) && !input.peek2(Token![::]); 189 if is_named { 190 ident = Some(input.parse()?); 191 colon_token = Some(input.parse()?); 192 } else { 193 ident = None; 194 colon_token = None; 195 } 196 197 let ty: Type = input.parse()?; 198 199 Ok(Field { 200 attrs, 201 vis, 202 mutability: FieldMutability::None, 203 ident, 204 colon_token, 205 ty, 206 }) 207 } 208 } 209 210 #[cfg(feature = "full")] 211 impl ParseQuote for Pat { 212 fn parse(input: ParseStream) -> Result<Self> { 213 Pat::parse_multi_with_leading_vert(input) 214 } 215 } 216 217 #[cfg(feature = "full")] 218 impl ParseQuote for Box<Pat> { 219 fn parse(input: ParseStream) -> Result<Self> { 220 <Pat as ParseQuote>::parse(input).map(Box::new) 221 } 222 } 223 224 impl<T: Parse, P: Parse> ParseQuote for Punctuated<T, P> { 225 fn parse(input: ParseStream) -> Result<Self> { 226 Self::parse_terminated(input) 227 } 228 } 229 230 #[cfg(feature = "full")] 231 impl ParseQuote for Vec<Stmt> { 232 fn parse(input: ParseStream) -> Result<Self> { 233 Block::parse_within(input) 234 } 235 } 236 237 #[cfg(feature = "full")] 238 impl ParseQuote for Vec<Arm> { 239 fn parse(input: ParseStream) -> Result<Self> { 240 Arm::parse_multiple(input) 241 } 242 } 243