| // SPDX-License-Identifier: Apache-2.0 OR MIT | |
| /// Quasi-quotation macro that accepts input like the [`quote!`] macro but uses | |
| /// type inference to figure out a return type for those tokens. | |
| /// | |
| /// [`quote!`]: https://docs.rs/quote/1.0/quote/index.html | |
| /// | |
| /// The return type can be any syntax tree node that implements the [`Parse`] | |
| /// trait. | |
| /// | |
| /// [`Parse`]: crate::parse::Parse | |
| /// | |
| /// ``` | |
| /// use quote::quote; | |
| /// use syn::{parse_quote, Stmt}; | |
| /// | |
| /// fn main() { | |
| /// let name = quote!(v); | |
| /// let ty = quote!(u8); | |
| /// | |
| /// let stmt: Stmt = parse_quote! { | |
| /// let #name: #ty = Default::default(); | |
| /// }; | |
| /// | |
| /// println!("{:#?}", stmt); | |
| /// } | |
| /// ``` | |
| /// | |
| /// *This macro is available only if Syn is built with both the `"parsing"` and | |
| /// `"printing"` features.* | |
| /// | |
| /// # Example | |
| /// | |
| /// The following helper function adds a bound `T: HeapSize` to every type | |
| /// parameter `T` in the input generics. | |
| /// | |
| /// ``` | |
| /// use syn::{parse_quote, Generics, GenericParam}; | |
| /// | |
| /// // Add a bound `T: HeapSize` to every type parameter T. | |
| /// fn add_trait_bounds(mut generics: Generics) -> Generics { | |
| /// for param in &mut generics.params { | |
| /// if let GenericParam::Type(type_param) = param { | |
| /// type_param.bounds.push(parse_quote!(HeapSize)); | |
| /// } | |
| /// } | |
| /// generics | |
| /// } | |
| /// ``` | |
| /// | |
| /// # Special cases | |
| /// | |
| /// This macro can parse the following additional types as a special case even | |
| /// though they do not implement the `Parse` trait. | |
| /// | |
| /// - [`Attribute`] — parses one attribute, allowing either outer like `#[...]` | |
| /// or inner like `#![...]` | |
| /// - [`Vec<Attribute>`] — parses multiple attributes, including mixed kinds in | |
| /// any order | |
| /// - [`Punctuated<T, P>`] — parses zero or more `T` separated by punctuation | |
| /// `P` with optional trailing punctuation | |
| /// - [`Vec<Arm>`] — parses arms separated by optional commas according to the | |
| /// same grammar as the inside of a `match` expression | |
| /// - [`Vec<Stmt>`] — parses the same as `Block::parse_within` | |
| /// - [`Pat`], [`Box<Pat>`] — parses the same as | |
| /// `Pat::parse_multi_with_leading_vert` | |
| /// - [`Field`] — parses a named or unnamed struct field | |
| /// | |
| /// [`Vec<Attribute>`]: Attribute | |
| /// [`Vec<Arm>`]: Arm | |
| /// [`Vec<Stmt>`]: Block::parse_within | |
| /// [`Pat`]: Pat::parse_multi_with_leading_vert | |
| /// [`Box<Pat>`]: Pat::parse_multi_with_leading_vert | |
| /// | |
| /// # Panics | |
| /// | |
| /// Panics if the tokens fail to parse as the expected syntax tree type. The | |
| /// caller is responsible for ensuring that the input tokens are syntactically | |
| /// valid. | |
| #[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "printing"))))] | |
| #[macro_export] | |
| macro_rules! parse_quote { | |
| ($($tt:tt)*) => { | |
| $crate::__private::parse_quote($crate::__private::quote::quote!($($tt)*)) | |
| }; | |
| } | |
| /// This macro is [`parse_quote!`] + [`quote_spanned!`][quote::quote_spanned]. | |
| /// | |
| /// Please refer to each of their documentation. | |
| /// | |
| /// # Example | |
| /// | |
| /// ``` | |
| /// use quote::{quote, quote_spanned}; | |
| /// use syn::spanned::Spanned; | |
| /// use syn::{parse_quote_spanned, ReturnType, Signature}; | |
| /// | |
| /// // Changes `fn()` to `fn() -> Pin<Box<dyn Future<Output = ()>>>`, | |
| /// // and `fn() -> T` to `fn() -> Pin<Box<dyn Future<Output = T>>>`, | |
| /// // without introducing any call_site() spans. | |
| /// fn make_ret_pinned_future(sig: &mut Signature) { | |
| /// let ret = match &sig.output { | |
| /// ReturnType::Default => quote_spanned!(sig.paren_token.span=> ()), | |
| /// ReturnType::Type(_, ret) => quote!(#ret), | |
| /// }; | |
| /// sig.output = parse_quote_spanned! {ret.span()=> | |
| /// -> ::std::pin::Pin<::std::boxed::Box<dyn ::std::future::Future<Output = #ret>>> | |
| /// }; | |
| /// } | |
| /// ``` | |
| #[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "printing"))))] | |
| #[macro_export] | |
| macro_rules! parse_quote_spanned { | |
| ($span:expr=> $($tt:tt)*) => { | |
| $crate::__private::parse_quote($crate::__private::quote::quote_spanned!($span=> $($tt)*)) | |
| }; | |
| } | |
| //////////////////////////////////////////////////////////////////////////////// | |
| // Can parse any type that implements Parse. | |
| use crate::error::Result; | |
| use crate::parse::{Parse, ParseStream, Parser}; | |
| use proc_macro2::TokenStream; | |
| // Not public API. | |
| #[doc(hidden)] | |
| #[track_caller] | |
| pub fn parse<T: ParseQuote>(token_stream: TokenStream) -> T { | |
| let parser = T::parse; | |
| match parser.parse2(token_stream) { | |
| Ok(t) => t, | |
| Err(err) => panic!("{}", err), | |
| } | |
| } | |
| #[doc(hidden)] | |
| pub trait ParseQuote: Sized { | |
| fn parse(input: ParseStream) -> Result<Self>; | |
| } | |
| impl<T: Parse> ParseQuote for T { | |
| fn parse(input: ParseStream) -> Result<Self> { | |
| <T as Parse>::parse(input) | |
| } | |
| } | |
| //////////////////////////////////////////////////////////////////////////////// | |
| // Any other types that we want `parse_quote!` to be able to parse. | |
| use crate::punctuated::Punctuated; | |
| #[cfg(any(feature = "full", feature = "derive"))] | |
| use crate::{attr, Attribute, Field, FieldMutability, Ident, Type, Visibility}; | |
| #[cfg(feature = "full")] | |
| use crate::{Arm, Block, Pat, Stmt}; | |
| #[cfg(any(feature = "full", feature = "derive"))] | |
| impl ParseQuote for Attribute { | |
| fn parse(input: ParseStream) -> Result<Self> { | |
| if input.peek(Token![#]) && input.peek2(Token![!]) { | |
| attr::parsing::single_parse_inner(input) | |
| } else { | |
| attr::parsing::single_parse_outer(input) | |
| } | |
| } | |
| } | |
| #[cfg(any(feature = "full", feature = "derive"))] | |
| impl ParseQuote for Vec<Attribute> { | |
| fn parse(input: ParseStream) -> Result<Self> { | |
| let mut attrs = Vec::new(); | |
| while !input.is_empty() { | |
| attrs.push(ParseQuote::parse(input)?); | |
| } | |
| Ok(attrs) | |
| } | |
| } | |
| #[cfg(any(feature = "full", feature = "derive"))] | |
| impl ParseQuote for Field { | |
| fn parse(input: ParseStream) -> Result<Self> { | |
| let attrs = input.call(Attribute::parse_outer)?; | |
| let vis: Visibility = input.parse()?; | |
| let ident: Option<Ident>; | |
| let colon_token: Option<Token![:]>; | |
| let is_named = input.peek(Ident) && input.peek2(Token![:]) && !input.peek2(Token![::]); | |
| if is_named { | |
| ident = Some(input.parse()?); | |
| colon_token = Some(input.parse()?); | |
| } else { | |
| ident = None; | |
| colon_token = None; | |
| } | |
| let ty: Type = input.parse()?; | |
| Ok(Field { | |
| attrs, | |
| vis, | |
| mutability: FieldMutability::None, | |
| ident, | |
| colon_token, | |
| ty, | |
| }) | |
| } | |
| } | |
| #[cfg(feature = "full")] | |
| impl ParseQuote for Pat { | |
| fn parse(input: ParseStream) -> Result<Self> { | |
| Pat::parse_multi_with_leading_vert(input) | |
| } | |
| } | |
| #[cfg(feature = "full")] | |
| impl ParseQuote for Box<Pat> { | |
| fn parse(input: ParseStream) -> Result<Self> { | |
| <Pat as ParseQuote>::parse(input).map(Box::new) | |
| } | |
| } | |
| impl<T: Parse, P: Parse> ParseQuote for Punctuated<T, P> { | |
| fn parse(input: ParseStream) -> Result<Self> { | |
| Self::parse_terminated(input) | |
| } | |
| } | |
| #[cfg(feature = "full")] | |
| impl ParseQuote for Vec<Stmt> { | |
| fn parse(input: ParseStream) -> Result<Self> { | |
| Block::parse_within(input) | |
| } | |
| } | |
| #[cfg(feature = "full")] | |
| impl ParseQuote for Vec<Arm> { | |
| fn parse(input: ParseStream) -> Result<Self> { | |
| Arm::parse_multiple(input) | |
| } | |
| } |