blob: 0c70b0834d9e5b01807f684aa4beb66da66c6d02 [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///
4/// [`quote!`]: https://docs.rs/quote/0.4/quote/index.html
5///
6/// The return type can be any syntax tree node that implements the [`Synom`]
7/// trait.
8///
9/// [`Synom`]: synom/trait.Synom.html
10///
11/// ```
12/// #[macro_use]
13/// extern crate syn;
14///
15/// #[macro_use]
16/// extern crate quote;
17///
18/// use syn::Stmt;
19///
20/// fn main() {
21/// let name = quote!(v);
22/// let ty = quote!(u8);
23///
24/// let stmt: Stmt = parse_quote! {
25/// let #name: #ty = Default::default();
26/// };
27///
28/// println!("{:#?}", stmt);
29/// }
30/// ```
31///
David Tolnay491680a2018-01-23 00:34:40 -080032/// *This macro is available if Syn is built with the `"parsing"` feature,
33/// although interpolation of syntax tree nodes into the quoted tokens is only
34/// supported if Syn is built with the `"printing"` feature as well.*
David Tolnaye83ef5a2018-01-11 15:18:36 -080035///
36/// # Example
37///
38/// The following helper function adds a bound `T: HeapSize` to every type
39/// parameter `T` in the input generics.
40///
41/// ```
42/// # #[macro_use]
43/// # extern crate syn;
44/// #
45/// # #[macro_use]
46/// # extern crate quote;
47/// #
48/// # use syn::{Generics, GenericParam};
49/// #
50/// // Add a bound `T: HeapSize` to every type parameter T.
51/// fn add_trait_bounds(mut generics: Generics) -> Generics {
52/// for param in &mut generics.params {
53/// if let GenericParam::Type(ref mut type_param) = *param {
54/// type_param.bounds.push(parse_quote!(HeapSize));
55/// }
56/// }
57/// generics
58/// }
59/// #
60/// # fn main() {}
61/// ```
62///
63/// # Special cases
64///
65/// This macro can parse the following additional types as a special case even
66/// though they do not implement the `Synom` trait.
67///
68/// - [`Attribute`] — parses one attribute, allowing either outer like `#[...]`
69/// or inner like `#![...]`
70/// - [`Punctuated<T, P>`] — parses zero or more `T` separated by punctuation
71/// `P` with optional trailing punctuation
72///
73/// [`Attribute`]: struct.Attribute.html
74/// [`Punctuated<T, P>`]: punctuated/struct.Punctuated.html
75///
76/// # Panics
77///
78/// Panics if the tokens fail to parse as the expected syntax tree type. The
79/// caller is responsible for ensuring that the input tokens are syntactically
80/// valid.
81#[macro_export]
82macro_rules! parse_quote {
83 ($($tt:tt)*) => {
David Tolnay94f06632018-08-31 10:17:17 -070084 $crate::parse_quote::parse($crate::export::From::from(quote!($($tt)*)))
David Tolnaye83ef5a2018-01-11 15:18:36 -080085 };
86}
87
88////////////////////////////////////////////////////////////////////////////////
89// Can parse any type that implements Synom.
90
David Tolnay4ac232d2018-08-31 10:18:03 -070091use parse::{Parse, ParseStream, Parser, Result};
David Tolnaye82a2b12018-08-30 16:31:10 -070092use proc_macro2::TokenStream;
David Tolnaye83ef5a2018-01-11 15:18:36 -080093
94// Not public API.
95#[doc(hidden)]
David Tolnay7d6a7b82018-01-23 00:42:22 -080096pub fn parse<T: ParseQuote>(token_stream: TokenStream) -> T {
David Tolnaye83ef5a2018-01-11 15:18:36 -080097 let parser = T::parse;
98 match parser.parse2(token_stream) {
99 Ok(t) => t,
David Tolnay40c06112018-08-30 16:14:50 -0700100 Err(err) => panic!("{}", err),
David Tolnaye83ef5a2018-01-11 15:18:36 -0800101 }
102}
103
104// Not public API.
105#[doc(hidden)]
106pub trait ParseQuote: Sized {
David Tolnay40c06112018-08-30 16:14:50 -0700107 fn parse(input: ParseStream) -> Result<Self>;
David Tolnaye83ef5a2018-01-11 15:18:36 -0800108}
109
David Tolnay40c06112018-08-30 16:14:50 -0700110impl<T: Parse> ParseQuote for T {
111 fn parse(input: ParseStream) -> Result<Self> {
112 <T as Parse>::parse(input)
David Tolnaye83ef5a2018-01-11 15:18:36 -0800113 }
114}
115
116////////////////////////////////////////////////////////////////////////////////
117// Any other types that we want `parse_quote!` to be able to parse.
118
David Tolnaye83ef5a2018-01-11 15:18:36 -0800119#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay40c06112018-08-30 16:14:50 -0700120use {attr, Attribute};
David Tolnaye83ef5a2018-01-11 15:18:36 -0800121
David Tolnaye83ef5a2018-01-11 15:18:36 -0800122#[cfg(any(feature = "full", feature = "derive"))]
123impl ParseQuote for Attribute {
David Tolnay40c06112018-08-30 16:14:50 -0700124 fn parse(input: ParseStream) -> Result<Self> {
125 if input.peek(Token![#]) && input.peek2(Token![!]) {
126 attr::parsing::single_parse_inner(input)
127 } else {
128 attr::parsing::single_parse_outer(input)
129 }
David Tolnaye83ef5a2018-01-11 15:18:36 -0800130 }
131}