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/// - [`Punctuated<T, P>`] — parses zero or more `T` separated by punctuation 57/// `P` with optional trailing punctuation 58/// - [`Vec<Stmt>`] — parses the same as `Block::parse_within` 59/// 60/// [`Vec<Stmt>`]: Block::parse_within 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#[cfg_attr(doc_cfg, doc(cfg(all(feature = "parsing", feature = "printing"))))] 68#[macro_export] 69macro_rules! parse_quote { 70 ($($tt:tt)*) => { 71 $crate::__private::parse_quote($crate::__private::quote::quote!($($tt)*)) 72 }; 73} 74 75/// This macro is [`parse_quote!`] + [`quote_spanned!`][quote::quote_spanned]. 76/// 77/// Please refer to each of their documentation. 78/// 79/// # Example 80/// 81/// ``` 82/// use quote::{quote, quote_spanned}; 83/// use syn::spanned::Spanned; 84/// use syn::{parse_quote_spanned, ReturnType, Signature}; 85/// 86/// // Changes `fn()` to `fn() -> Pin<Box<dyn Future<Output = ()>>>`, 87/// // and `fn() -> T` to `fn() -> Pin<Box<dyn Future<Output = T>>>`, 88/// // without introducing any call_site() spans. 89/// fn make_ret_pinned_future(sig: &mut Signature) { 90/// let ret = match &sig.output { 91/// ReturnType::Default => quote_spanned!(sig.paren_token.span=> ()), 92/// ReturnType::Type(_, ret) => quote!(#ret), 93/// }; 94/// sig.output = parse_quote_spanned! {ret.span()=> 95/// -> ::std::pin::Pin<::std::boxed::Box<dyn ::std::future::Future<Output = #ret>>> 96/// }; 97/// } 98/// ``` 99#[cfg_attr(doc_cfg, doc(cfg(all(feature = "parsing", feature = "printing"))))] 100#[macro_export] 101macro_rules! parse_quote_spanned { 102 ($span:expr=> $($tt:tt)*) => { 103 $crate::__private::parse_quote($crate::__private::quote::quote_spanned!($span=> $($tt)*)) 104 }; 105} 106 107//////////////////////////////////////////////////////////////////////////////// 108// Can parse any type that implements Parse. 109 110use crate::parse::{Parse, ParseStream, Parser, Result}; 111use proc_macro2::TokenStream; 112 113// Not public API. 114#[doc(hidden)] 115pub fn parse<T: ParseQuote>(token_stream: TokenStream) -> T { 116 let parser = T::parse; 117 match parser.parse2(token_stream) { 118 Ok(t) => t, 119 Err(err) => panic!("{}", err), 120 } 121} 122 123#[doc(hidden)] 124pub trait ParseQuote: Sized { 125 fn parse(input: ParseStream) -> Result<Self>; 126} 127 128impl<T: Parse> ParseQuote for T { 129 fn parse(input: ParseStream) -> Result<Self> { 130 <T as Parse>::parse(input) 131 } 132} 133 134//////////////////////////////////////////////////////////////////////////////// 135// Any other types that we want `parse_quote!` to be able to parse. 136 137use crate::punctuated::Punctuated; 138#[cfg(any(feature = "full", feature = "derive"))] 139use crate::{attr, Attribute, Field, FieldMutability, Ident, Type, Visibility}; 140#[cfg(feature = "full")] 141use crate::{Block, Pat, Stmt}; 142 143#[cfg(any(feature = "full", feature = "derive"))] 144impl ParseQuote for Attribute { 145 fn parse(input: ParseStream) -> Result<Self> { 146 if input.peek(Token![#]) && input.peek2(Token![!]) { 147 attr::parsing::single_parse_inner(input) 148 } else { 149 attr::parsing::single_parse_outer(input) 150 } 151 } 152} 153 154#[cfg(any(feature = "full", feature = "derive"))] 155impl ParseQuote for Field { 156 fn parse(input: ParseStream) -> Result<Self> { 157 let attrs = input.call(Attribute::parse_outer)?; 158 let vis: Visibility = input.parse()?; 159 160 let ident: Option<Ident>; 161 let colon_token: Option<Token![:]>; 162 let is_named = input.peek(Ident) && input.peek2(Token![:]) && !input.peek2(Token![::]); 163 if is_named { 164 ident = Some(input.parse()?); 165 colon_token = Some(input.parse()?); 166 } else { 167 ident = None; 168 colon_token = None; 169 } 170 171 let ty: Type = input.parse()?; 172 173 Ok(Field { 174 attrs, 175 vis, 176 mutability: FieldMutability::None, 177 ident, 178 colon_token, 179 ty, 180 }) 181 } 182} 183 184#[cfg(feature = "full")] 185impl ParseQuote for Pat { 186 fn parse(input: ParseStream) -> Result<Self> { 187 Pat::parse_multi_with_leading_vert(input) 188 } 189} 190 191#[cfg(feature = "full")] 192impl ParseQuote for Box<Pat> { 193 fn parse(input: ParseStream) -> Result<Self> { 194 <Pat as ParseQuote>::parse(input).map(Box::new) 195 } 196} 197 198impl<T: Parse, P: Parse> ParseQuote for Punctuated<T, P> { 199 fn parse(input: ParseStream) -> Result<Self> { 200 Self::parse_terminated(input) 201 } 202} 203 204#[cfg(feature = "full")] 205impl ParseQuote for Vec<Stmt> { 206 fn parse(input: ParseStream) -> Result<Self> { 207 Block::parse_within(input) 208 } 209} 210