1*69942c0aSMiguel Ojeda // SPDX-License-Identifier: Apache-2.0 OR MIT
2*69942c0aSMiguel Ojeda
3808c999fSMiguel Ojeda /// Quasi-quotation macro that accepts input like the [`quote!`] macro but uses
4808c999fSMiguel Ojeda /// type inference to figure out a return type for those tokens.
5808c999fSMiguel Ojeda ///
6808c999fSMiguel Ojeda /// [`quote!`]: https://docs.rs/quote/1.0/quote/index.html
7808c999fSMiguel Ojeda ///
8808c999fSMiguel Ojeda /// The return type can be any syntax tree node that implements the [`Parse`]
9808c999fSMiguel Ojeda /// trait.
10808c999fSMiguel Ojeda ///
11808c999fSMiguel Ojeda /// [`Parse`]: crate::parse::Parse
12808c999fSMiguel Ojeda ///
13808c999fSMiguel Ojeda /// ```
14808c999fSMiguel Ojeda /// use quote::quote;
15808c999fSMiguel Ojeda /// use syn::{parse_quote, Stmt};
16808c999fSMiguel Ojeda ///
17808c999fSMiguel Ojeda /// fn main() {
18808c999fSMiguel Ojeda /// let name = quote!(v);
19808c999fSMiguel Ojeda /// let ty = quote!(u8);
20808c999fSMiguel Ojeda ///
21808c999fSMiguel Ojeda /// let stmt: Stmt = parse_quote! {
22808c999fSMiguel Ojeda /// let #name: #ty = Default::default();
23808c999fSMiguel Ojeda /// };
24808c999fSMiguel Ojeda ///
25808c999fSMiguel Ojeda /// println!("{:#?}", stmt);
26808c999fSMiguel Ojeda /// }
27808c999fSMiguel Ojeda /// ```
28808c999fSMiguel Ojeda ///
29808c999fSMiguel Ojeda /// *This macro is available only if Syn is built with both the `"parsing"` and
30808c999fSMiguel Ojeda /// `"printing"` features.*
31808c999fSMiguel Ojeda ///
32808c999fSMiguel Ojeda /// # Example
33808c999fSMiguel Ojeda ///
34808c999fSMiguel Ojeda /// The following helper function adds a bound `T: HeapSize` to every type
35808c999fSMiguel Ojeda /// parameter `T` in the input generics.
36808c999fSMiguel Ojeda ///
37808c999fSMiguel Ojeda /// ```
38808c999fSMiguel Ojeda /// use syn::{parse_quote, Generics, GenericParam};
39808c999fSMiguel Ojeda ///
40808c999fSMiguel Ojeda /// // Add a bound `T: HeapSize` to every type parameter T.
41808c999fSMiguel Ojeda /// fn add_trait_bounds(mut generics: Generics) -> Generics {
42808c999fSMiguel Ojeda /// for param in &mut generics.params {
43808c999fSMiguel Ojeda /// if let GenericParam::Type(type_param) = param {
44808c999fSMiguel Ojeda /// type_param.bounds.push(parse_quote!(HeapSize));
45808c999fSMiguel Ojeda /// }
46808c999fSMiguel Ojeda /// }
47808c999fSMiguel Ojeda /// generics
48808c999fSMiguel Ojeda /// }
49808c999fSMiguel Ojeda /// ```
50808c999fSMiguel Ojeda ///
51808c999fSMiguel Ojeda /// # Special cases
52808c999fSMiguel Ojeda ///
53808c999fSMiguel Ojeda /// This macro can parse the following additional types as a special case even
54808c999fSMiguel Ojeda /// though they do not implement the `Parse` trait.
55808c999fSMiguel Ojeda ///
56808c999fSMiguel Ojeda /// - [`Attribute`] — parses one attribute, allowing either outer like `#[...]`
57808c999fSMiguel Ojeda /// or inner like `#![...]`
58808c999fSMiguel Ojeda /// - [`Vec<Attribute>`] — parses multiple attributes, including mixed kinds in
59808c999fSMiguel Ojeda /// any order
60808c999fSMiguel Ojeda /// - [`Punctuated<T, P>`] — parses zero or more `T` separated by punctuation
61808c999fSMiguel Ojeda /// `P` with optional trailing punctuation
62808c999fSMiguel Ojeda /// - [`Vec<Arm>`] — parses arms separated by optional commas according to the
63808c999fSMiguel Ojeda /// same grammar as the inside of a `match` expression
64808c999fSMiguel Ojeda /// - [`Vec<Stmt>`] — parses the same as `Block::parse_within`
65808c999fSMiguel Ojeda /// - [`Pat`], [`Box<Pat>`] — parses the same as
66808c999fSMiguel Ojeda /// `Pat::parse_multi_with_leading_vert`
67808c999fSMiguel Ojeda /// - [`Field`] — parses a named or unnamed struct field
68808c999fSMiguel Ojeda ///
69808c999fSMiguel Ojeda /// [`Vec<Attribute>`]: Attribute
70808c999fSMiguel Ojeda /// [`Vec<Arm>`]: Arm
71808c999fSMiguel Ojeda /// [`Vec<Stmt>`]: Block::parse_within
72808c999fSMiguel Ojeda /// [`Pat`]: Pat::parse_multi_with_leading_vert
73808c999fSMiguel Ojeda /// [`Box<Pat>`]: Pat::parse_multi_with_leading_vert
74808c999fSMiguel Ojeda ///
75808c999fSMiguel Ojeda /// # Panics
76808c999fSMiguel Ojeda ///
77808c999fSMiguel Ojeda /// Panics if the tokens fail to parse as the expected syntax tree type. The
78808c999fSMiguel Ojeda /// caller is responsible for ensuring that the input tokens are syntactically
79808c999fSMiguel Ojeda /// valid.
80808c999fSMiguel Ojeda #[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "printing"))))]
81808c999fSMiguel Ojeda #[macro_export]
82808c999fSMiguel Ojeda macro_rules! parse_quote {
83808c999fSMiguel Ojeda ($($tt:tt)*) => {
84808c999fSMiguel Ojeda $crate::__private::parse_quote($crate::__private::quote::quote!($($tt)*))
85808c999fSMiguel Ojeda };
86808c999fSMiguel Ojeda }
87808c999fSMiguel Ojeda
88808c999fSMiguel Ojeda /// This macro is [`parse_quote!`] + [`quote_spanned!`][quote::quote_spanned].
89808c999fSMiguel Ojeda ///
90808c999fSMiguel Ojeda /// Please refer to each of their documentation.
91808c999fSMiguel Ojeda ///
92808c999fSMiguel Ojeda /// # Example
93808c999fSMiguel Ojeda ///
94808c999fSMiguel Ojeda /// ```
95808c999fSMiguel Ojeda /// use quote::{quote, quote_spanned};
96808c999fSMiguel Ojeda /// use syn::spanned::Spanned;
97808c999fSMiguel Ojeda /// use syn::{parse_quote_spanned, ReturnType, Signature};
98808c999fSMiguel Ojeda ///
99808c999fSMiguel Ojeda /// // Changes `fn()` to `fn() -> Pin<Box<dyn Future<Output = ()>>>`,
100808c999fSMiguel Ojeda /// // and `fn() -> T` to `fn() -> Pin<Box<dyn Future<Output = T>>>`,
101808c999fSMiguel Ojeda /// // without introducing any call_site() spans.
102808c999fSMiguel Ojeda /// fn make_ret_pinned_future(sig: &mut Signature) {
103808c999fSMiguel Ojeda /// let ret = match &sig.output {
104808c999fSMiguel Ojeda /// ReturnType::Default => quote_spanned!(sig.paren_token.span=> ()),
105808c999fSMiguel Ojeda /// ReturnType::Type(_, ret) => quote!(#ret),
106808c999fSMiguel Ojeda /// };
107808c999fSMiguel Ojeda /// sig.output = parse_quote_spanned! {ret.span()=>
108808c999fSMiguel Ojeda /// -> ::std::pin::Pin<::std::boxed::Box<dyn ::std::future::Future<Output = #ret>>>
109808c999fSMiguel Ojeda /// };
110808c999fSMiguel Ojeda /// }
111808c999fSMiguel Ojeda /// ```
112808c999fSMiguel Ojeda #[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "printing"))))]
113808c999fSMiguel Ojeda #[macro_export]
114808c999fSMiguel Ojeda macro_rules! parse_quote_spanned {
115808c999fSMiguel Ojeda ($span:expr=> $($tt:tt)*) => {
116808c999fSMiguel Ojeda $crate::__private::parse_quote($crate::__private::quote::quote_spanned!($span=> $($tt)*))
117808c999fSMiguel Ojeda };
118808c999fSMiguel Ojeda }
119808c999fSMiguel Ojeda
120808c999fSMiguel Ojeda ////////////////////////////////////////////////////////////////////////////////
121808c999fSMiguel Ojeda // Can parse any type that implements Parse.
122808c999fSMiguel Ojeda
123808c999fSMiguel Ojeda use crate::error::Result;
124808c999fSMiguel Ojeda use crate::parse::{Parse, ParseStream, Parser};
125808c999fSMiguel Ojeda use proc_macro2::TokenStream;
126808c999fSMiguel Ojeda
127808c999fSMiguel Ojeda // Not public API.
128808c999fSMiguel Ojeda #[doc(hidden)]
129808c999fSMiguel Ojeda #[track_caller]
parse<T: ParseQuote>(token_stream: TokenStream) -> T130808c999fSMiguel Ojeda pub fn parse<T: ParseQuote>(token_stream: TokenStream) -> T {
131808c999fSMiguel Ojeda let parser = T::parse;
132808c999fSMiguel Ojeda match parser.parse2(token_stream) {
133808c999fSMiguel Ojeda Ok(t) => t,
134808c999fSMiguel Ojeda Err(err) => panic!("{}", err),
135808c999fSMiguel Ojeda }
136808c999fSMiguel Ojeda }
137808c999fSMiguel Ojeda
138808c999fSMiguel Ojeda #[doc(hidden)]
139808c999fSMiguel Ojeda pub trait ParseQuote: Sized {
parse(input: ParseStream) -> Result<Self>140808c999fSMiguel Ojeda fn parse(input: ParseStream) -> Result<Self>;
141808c999fSMiguel Ojeda }
142808c999fSMiguel Ojeda
143808c999fSMiguel Ojeda impl<T: Parse> ParseQuote for T {
parse(input: ParseStream) -> Result<Self>144808c999fSMiguel Ojeda fn parse(input: ParseStream) -> Result<Self> {
145808c999fSMiguel Ojeda <T as Parse>::parse(input)
146808c999fSMiguel Ojeda }
147808c999fSMiguel Ojeda }
148808c999fSMiguel Ojeda
149808c999fSMiguel Ojeda ////////////////////////////////////////////////////////////////////////////////
150808c999fSMiguel Ojeda // Any other types that we want `parse_quote!` to be able to parse.
151808c999fSMiguel Ojeda
152808c999fSMiguel Ojeda use crate::punctuated::Punctuated;
153808c999fSMiguel Ojeda #[cfg(any(feature = "full", feature = "derive"))]
154808c999fSMiguel Ojeda use crate::{attr, Attribute, Field, FieldMutability, Ident, Type, Visibility};
155808c999fSMiguel Ojeda #[cfg(feature = "full")]
156808c999fSMiguel Ojeda use crate::{Arm, Block, Pat, Stmt};
157808c999fSMiguel Ojeda
158808c999fSMiguel Ojeda #[cfg(any(feature = "full", feature = "derive"))]
159808c999fSMiguel Ojeda impl ParseQuote for Attribute {
parse(input: ParseStream) -> Result<Self>160808c999fSMiguel Ojeda fn parse(input: ParseStream) -> Result<Self> {
161808c999fSMiguel Ojeda if input.peek(Token![#]) && input.peek2(Token![!]) {
162808c999fSMiguel Ojeda attr::parsing::single_parse_inner(input)
163808c999fSMiguel Ojeda } else {
164808c999fSMiguel Ojeda attr::parsing::single_parse_outer(input)
165808c999fSMiguel Ojeda }
166808c999fSMiguel Ojeda }
167808c999fSMiguel Ojeda }
168808c999fSMiguel Ojeda
169808c999fSMiguel Ojeda #[cfg(any(feature = "full", feature = "derive"))]
170808c999fSMiguel Ojeda impl ParseQuote for Vec<Attribute> {
parse(input: ParseStream) -> Result<Self>171808c999fSMiguel Ojeda fn parse(input: ParseStream) -> Result<Self> {
172808c999fSMiguel Ojeda let mut attrs = Vec::new();
173808c999fSMiguel Ojeda while !input.is_empty() {
174808c999fSMiguel Ojeda attrs.push(ParseQuote::parse(input)?);
175808c999fSMiguel Ojeda }
176808c999fSMiguel Ojeda Ok(attrs)
177808c999fSMiguel Ojeda }
178808c999fSMiguel Ojeda }
179808c999fSMiguel Ojeda
180808c999fSMiguel Ojeda #[cfg(any(feature = "full", feature = "derive"))]
181808c999fSMiguel Ojeda impl ParseQuote for Field {
parse(input: ParseStream) -> Result<Self>182808c999fSMiguel Ojeda fn parse(input: ParseStream) -> Result<Self> {
183808c999fSMiguel Ojeda let attrs = input.call(Attribute::parse_outer)?;
184808c999fSMiguel Ojeda let vis: Visibility = input.parse()?;
185808c999fSMiguel Ojeda
186808c999fSMiguel Ojeda let ident: Option<Ident>;
187808c999fSMiguel Ojeda let colon_token: Option<Token![:]>;
188808c999fSMiguel Ojeda let is_named = input.peek(Ident) && input.peek2(Token![:]) && !input.peek2(Token![::]);
189808c999fSMiguel Ojeda if is_named {
190808c999fSMiguel Ojeda ident = Some(input.parse()?);
191808c999fSMiguel Ojeda colon_token = Some(input.parse()?);
192808c999fSMiguel Ojeda } else {
193808c999fSMiguel Ojeda ident = None;
194808c999fSMiguel Ojeda colon_token = None;
195808c999fSMiguel Ojeda }
196808c999fSMiguel Ojeda
197808c999fSMiguel Ojeda let ty: Type = input.parse()?;
198808c999fSMiguel Ojeda
199808c999fSMiguel Ojeda Ok(Field {
200808c999fSMiguel Ojeda attrs,
201808c999fSMiguel Ojeda vis,
202808c999fSMiguel Ojeda mutability: FieldMutability::None,
203808c999fSMiguel Ojeda ident,
204808c999fSMiguel Ojeda colon_token,
205808c999fSMiguel Ojeda ty,
206808c999fSMiguel Ojeda })
207808c999fSMiguel Ojeda }
208808c999fSMiguel Ojeda }
209808c999fSMiguel Ojeda
210808c999fSMiguel Ojeda #[cfg(feature = "full")]
211808c999fSMiguel Ojeda impl ParseQuote for Pat {
parse(input: ParseStream) -> Result<Self>212808c999fSMiguel Ojeda fn parse(input: ParseStream) -> Result<Self> {
213808c999fSMiguel Ojeda Pat::parse_multi_with_leading_vert(input)
214808c999fSMiguel Ojeda }
215808c999fSMiguel Ojeda }
216808c999fSMiguel Ojeda
217808c999fSMiguel Ojeda #[cfg(feature = "full")]
218808c999fSMiguel Ojeda impl ParseQuote for Box<Pat> {
parse(input: ParseStream) -> Result<Self>219808c999fSMiguel Ojeda fn parse(input: ParseStream) -> Result<Self> {
220808c999fSMiguel Ojeda <Pat as ParseQuote>::parse(input).map(Box::new)
221808c999fSMiguel Ojeda }
222808c999fSMiguel Ojeda }
223808c999fSMiguel Ojeda
224808c999fSMiguel Ojeda impl<T: Parse, P: Parse> ParseQuote for Punctuated<T, P> {
parse(input: ParseStream) -> Result<Self>225808c999fSMiguel Ojeda fn parse(input: ParseStream) -> Result<Self> {
226808c999fSMiguel Ojeda Self::parse_terminated(input)
227808c999fSMiguel Ojeda }
228808c999fSMiguel Ojeda }
229808c999fSMiguel Ojeda
230808c999fSMiguel Ojeda #[cfg(feature = "full")]
231808c999fSMiguel Ojeda impl ParseQuote for Vec<Stmt> {
parse(input: ParseStream) -> Result<Self>232808c999fSMiguel Ojeda fn parse(input: ParseStream) -> Result<Self> {
233808c999fSMiguel Ojeda Block::parse_within(input)
234808c999fSMiguel Ojeda }
235808c999fSMiguel Ojeda }
236808c999fSMiguel Ojeda
237808c999fSMiguel Ojeda #[cfg(feature = "full")]
238808c999fSMiguel Ojeda impl ParseQuote for Vec<Arm> {
parse(input: ParseStream) -> Result<Self>239808c999fSMiguel Ojeda fn parse(input: ParseStream) -> Result<Self> {
240808c999fSMiguel Ojeda Arm::parse_multiple(input)
241808c999fSMiguel Ojeda }
242808c999fSMiguel Ojeda }
243