at master 7.3 kB view raw
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] 82macro_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] 114macro_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 123use crate::error::Result; 124use crate::parse::{Parse, ParseStream, Parser}; 125use proc_macro2::TokenStream; 126 127// Not public API. 128#[doc(hidden)] 129#[track_caller] 130pub 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)] 139pub trait ParseQuote: Sized { 140 fn parse(input: ParseStream) -> Result<Self>; 141} 142 143impl<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 152use crate::punctuated::Punctuated; 153#[cfg(any(feature = "full", feature = "derive"))] 154use crate::{attr, Attribute, Field, FieldMutability, Ident, Type, Visibility}; 155#[cfg(feature = "full")] 156use crate::{Arm, Block, Pat, Stmt}; 157 158#[cfg(any(feature = "full", feature = "derive"))] 159impl 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"))] 170impl 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"))] 181impl 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")] 211impl 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")] 218impl ParseQuote for Box<Pat> { 219 fn parse(input: ParseStream) -> Result<Self> { 220 <Pat as ParseQuote>::parse(input).map(Box::new) 221 } 222} 223 224impl<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")] 231impl ParseQuote for Vec<Stmt> { 232 fn parse(input: ParseStream) -> Result<Self> { 233 Block::parse_within(input) 234 } 235} 236 237#[cfg(feature = "full")] 238impl ParseQuote for Vec<Arm> { 239 fn parse(input: ParseStream) -> Result<Self> { 240 Arm::parse_multiple(input) 241 } 242}