• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 the `"parsing"` feature,
28 /// although interpolation of syntax tree nodes into the quoted tokens is only
29 /// supported if Syn is built with the `"printing"` feature as well.*
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 /// - [`Punctuated<T, P>`] — parses zero or more `T` separated by punctuation
58 ///   `P` with optional trailing punctuation
59 /// - [`Vec<Stmt>`] — parses the same as `Block::parse_within`
60 ///
61 /// [`Vec<Stmt>`]: Block::parse_within
62 ///
63 /// # Panics
64 ///
65 /// Panics if the tokens fail to parse as the expected syntax tree type. The
66 /// caller is responsible for ensuring that the input tokens are syntactically
67 /// valid.
68 #[cfg_attr(doc_cfg, doc(cfg(all(feature = "parsing", feature = "printing"))))]
69 #[macro_export]
70 macro_rules! parse_quote {
71     ($($tt:tt)*) => {
72         $crate::parse_quote::parse($crate::__private::quote::quote!($($tt)*))
73     };
74 }
75 
76 /// This macro is [`parse_quote!`] + [`quote_spanned!`][quote::quote_spanned].
77 ///
78 /// Please refer to each of their documentation.
79 ///
80 /// # Example
81 ///
82 /// ```
83 /// use quote::{quote, quote_spanned};
84 /// use syn::spanned::Spanned;
85 /// use syn::{parse_quote_spanned, ReturnType, Signature};
86 ///
87 /// // Changes `fn()` to `fn() -> Pin<Box<dyn Future<Output = ()>>>`,
88 /// // and `fn() -> T` to `fn() -> Pin<Box<dyn Future<Output = T>>>`,
89 /// // without introducing any call_site() spans.
90 /// fn make_ret_pinned_future(sig: &mut Signature) {
91 ///     let ret = match &sig.output {
92 ///         ReturnType::Default => quote_spanned!(sig.paren_token.span=> ()),
93 ///         ReturnType::Type(_, ret) => quote!(#ret),
94 ///     };
95 ///     sig.output = parse_quote_spanned! {ret.span()=>
96 ///         -> ::std::pin::Pin<::std::boxed::Box<dyn ::std::future::Future<Output = #ret>>>
97 ///     };
98 /// }
99 /// ```
100 #[cfg_attr(doc_cfg, doc(cfg(all(feature = "parsing", feature = "printing"))))]
101 #[macro_export]
102 macro_rules! parse_quote_spanned {
103     ($span:expr=> $($tt:tt)*) => {
104         $crate::parse_quote::parse($crate::__private::quote::quote_spanned!($span=> $($tt)*))
105     };
106 }
107 
108 ////////////////////////////////////////////////////////////////////////////////
109 // Can parse any type that implements Parse.
110 
111 use crate::parse::{Parse, ParseStream, Parser, Result};
112 use proc_macro2::TokenStream;
113 
114 // Not public API.
115 #[doc(hidden)]
parse<T: ParseQuote>(token_stream: TokenStream) -> T116 pub fn parse<T: ParseQuote>(token_stream: TokenStream) -> T {
117     let parser = T::parse;
118     match parser.parse2(token_stream) {
119         Ok(t) => t,
120         Err(err) => panic!("{}", err),
121     }
122 }
123 
124 // Not public API.
125 #[doc(hidden)]
126 pub trait ParseQuote: Sized {
parse(input: ParseStream) -> Result<Self>127     fn parse(input: ParseStream) -> Result<Self>;
128 }
129 
130 impl<T: Parse> ParseQuote for T {
parse(input: ParseStream) -> Result<Self>131     fn parse(input: ParseStream) -> Result<Self> {
132         <T as Parse>::parse(input)
133     }
134 }
135 
136 ////////////////////////////////////////////////////////////////////////////////
137 // Any other types that we want `parse_quote!` to be able to parse.
138 
139 use crate::punctuated::Punctuated;
140 #[cfg(any(feature = "full", feature = "derive"))]
141 use crate::{attr, Attribute};
142 #[cfg(feature = "full")]
143 use crate::{Block, Stmt};
144 
145 #[cfg(any(feature = "full", feature = "derive"))]
146 impl ParseQuote for Attribute {
parse(input: ParseStream) -> Result<Self>147     fn parse(input: ParseStream) -> Result<Self> {
148         if input.peek(Token![#]) && input.peek2(Token![!]) {
149             attr::parsing::single_parse_inner(input)
150         } else {
151             attr::parsing::single_parse_outer(input)
152         }
153     }
154 }
155 
156 impl<T: Parse, P: Parse> ParseQuote for Punctuated<T, P> {
parse(input: ParseStream) -> Result<Self>157     fn parse(input: ParseStream) -> Result<Self> {
158         Self::parse_terminated(input)
159     }
160 }
161 
162 #[cfg(feature = "full")]
163 impl ParseQuote for Vec<Stmt> {
parse(input: ParseStream) -> Result<Self>164     fn parse(input: ParseStream) -> Result<Self> {
165         Block::parse_within(input)
166     }
167 }
168