blob: d354be6f756f0ee1637f5847324de3e51d54e948 [file] [log] [blame]
David Tolnaye83ef5a2018-01-11 15:18:36 -08001/// 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///
David Tolnay442cf762018-08-31 11:08:24 -07004/// [`quote!`]: https://docs.rs/quote/0.6/quote/index.html
David Tolnaye83ef5a2018-01-11 15:18:36 -08005///
David Tolnayd85a8812018-08-31 11:09:57 -07006/// The return type can be any syntax tree node that implements the [`Parse`]
David Tolnaye83ef5a2018-01-11 15:18:36 -08007/// trait.
8///
David Tolnayd85a8812018-08-31 11:09:57 -07009/// [`Parse`]: parse/trait.Parse.html
David Tolnaye83ef5a2018-01-11 15:18:36 -080010///
11/// ```
David Tolnay9b00f652018-09-01 10:31:02 -070012/// # extern crate syn;
13/// # extern crate quote;
14/// #
15/// use quote::quote;
16/// use syn::{parse_quote, Stmt};
David Tolnaye83ef5a2018-01-11 15:18:36 -080017///
18/// fn main() {
19/// let name = quote!(v);
20/// let ty = quote!(u8);
21///
22/// let stmt: Stmt = parse_quote! {
23/// let #name: #ty = Default::default();
24/// };
25///
26/// println!("{:#?}", stmt);
27/// }
28/// ```
29///
David Tolnay491680a2018-01-23 00:34:40 -080030/// *This macro is available if Syn is built with the `"parsing"` feature,
31/// although interpolation of syntax tree nodes into the quoted tokens is only
32/// supported if Syn is built with the `"printing"` feature as well.*
David Tolnaye83ef5a2018-01-11 15:18:36 -080033///
34/// # Example
35///
36/// The following helper function adds a bound `T: HeapSize` to every type
37/// parameter `T` in the input generics.
38///
39/// ```
David Tolnay9b00f652018-09-01 10:31:02 -070040/// # extern crate quote;
David Tolnaye83ef5a2018-01-11 15:18:36 -080041/// # extern crate syn;
42/// #
David Tolnay9b00f652018-09-01 10:31:02 -070043/// # use quote::quote;
44/// # use syn::parse_quote;
David Tolnaye83ef5a2018-01-11 15:18:36 -080045/// #
David Tolnay9b00f652018-09-01 10:31:02 -070046/// use syn::{Generics, GenericParam};
47///
David Tolnaye83ef5a2018-01-11 15:18:36 -080048/// // Add a bound `T: HeapSize` to every type parameter T.
49/// fn add_trait_bounds(mut generics: Generics) -> Generics {
50/// for param in &mut generics.params {
51/// if let GenericParam::Type(ref mut type_param) = *param {
52/// type_param.bounds.push(parse_quote!(HeapSize));
53/// }
54/// }
55/// generics
56/// }
57/// #
58/// # fn main() {}
59/// ```
60///
61/// # Special cases
62///
63/// This macro can parse the following additional types as a special case even
David Tolnayd85a8812018-08-31 11:09:57 -070064/// though they do not implement the `Parse` trait.
David Tolnaye83ef5a2018-01-11 15:18:36 -080065///
66/// - [`Attribute`] — parses one attribute, allowing either outer like `#[...]`
67/// or inner like `#![...]`
68/// - [`Punctuated<T, P>`] — parses zero or more `T` separated by punctuation
69/// `P` with optional trailing punctuation
70///
71/// [`Attribute`]: struct.Attribute.html
72/// [`Punctuated<T, P>`]: punctuated/struct.Punctuated.html
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#[macro_export]
80macro_rules! parse_quote {
81 ($($tt:tt)*) => {
David Tolnay94f06632018-08-31 10:17:17 -070082 $crate::parse_quote::parse($crate::export::From::from(quote!($($tt)*)))
David Tolnaye83ef5a2018-01-11 15:18:36 -080083 };
84}
85
86////////////////////////////////////////////////////////////////////////////////
David Tolnay06faaca2018-09-01 20:25:04 -070087// Can parse any type that implements Parse.
David Tolnaye83ef5a2018-01-11 15:18:36 -080088
David Tolnay4ac232d2018-08-31 10:18:03 -070089use parse::{Parse, ParseStream, Parser, Result};
David Tolnaye82a2b12018-08-30 16:31:10 -070090use proc_macro2::TokenStream;
David Tolnaye83ef5a2018-01-11 15:18:36 -080091
92// Not public API.
93#[doc(hidden)]
David Tolnay7d6a7b82018-01-23 00:42:22 -080094pub fn parse<T: ParseQuote>(token_stream: TokenStream) -> T {
David Tolnaye83ef5a2018-01-11 15:18:36 -080095 let parser = T::parse;
96 match parser.parse2(token_stream) {
97 Ok(t) => t,
David Tolnay40c06112018-08-30 16:14:50 -070098 Err(err) => panic!("{}", err),
David Tolnaye83ef5a2018-01-11 15:18:36 -080099 }
100}
101
102// Not public API.
103#[doc(hidden)]
104pub trait ParseQuote: Sized {
David Tolnay40c06112018-08-30 16:14:50 -0700105 fn parse(input: ParseStream) -> Result<Self>;
David Tolnaye83ef5a2018-01-11 15:18:36 -0800106}
107
David Tolnay40c06112018-08-30 16:14:50 -0700108impl<T: Parse> ParseQuote for T {
109 fn parse(input: ParseStream) -> Result<Self> {
110 <T as Parse>::parse(input)
David Tolnaye83ef5a2018-01-11 15:18:36 -0800111 }
112}
113
114////////////////////////////////////////////////////////////////////////////////
115// Any other types that we want `parse_quote!` to be able to parse.
116
David Tolnay70f30e92018-09-01 02:04:17 -0700117use punctuated::Punctuated;
David Tolnaye83ef5a2018-01-11 15:18:36 -0800118#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay40c06112018-08-30 16:14:50 -0700119use {attr, Attribute};
David Tolnaye83ef5a2018-01-11 15:18:36 -0800120
David Tolnaye83ef5a2018-01-11 15:18:36 -0800121#[cfg(any(feature = "full", feature = "derive"))]
122impl ParseQuote for Attribute {
David Tolnay40c06112018-08-30 16:14:50 -0700123 fn parse(input: ParseStream) -> Result<Self> {
124 if input.peek(Token![#]) && input.peek2(Token![!]) {
125 attr::parsing::single_parse_inner(input)
126 } else {
127 attr::parsing::single_parse_outer(input)
128 }
David Tolnaye83ef5a2018-01-11 15:18:36 -0800129 }
130}
David Tolnay024b5762018-08-31 11:11:53 -0700131
132impl<T: Parse, P: Parse> ParseQuote for Punctuated<T, P> {
133 fn parse(input: ParseStream) -> Result<Self> {
134 Self::parse_terminated(input)
135 }
136}