parse_quote.rs 7.2 KB

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