blob: 9d65555a2b9abed46bde50e1838701fde6e9a5ae [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 Tolnay7d6a7b82018-01-23 00:42:22 -080084 $crate::parse_quote::parse($crate::parse_quote::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 Tolnay40c06112018-08-30 16:14:50 -070091use parse::{Parse, ParseStream, Result};
David Tolnaye82a2b12018-08-30 16:31:10 -070092use proc_macro2::TokenStream;
93use synom::Parser;
David Tolnaye83ef5a2018-01-11 15:18:36 -080094
95// Not public API.
96#[doc(hidden)]
David Tolnay7d6a7b82018-01-23 00:42:22 -080097pub use std::convert::From;
98
99// Not public API.
100#[doc(hidden)]
101pub fn parse<T: ParseQuote>(token_stream: TokenStream) -> T {
David Tolnaye83ef5a2018-01-11 15:18:36 -0800102 let parser = T::parse;
103 match parser.parse2(token_stream) {
104 Ok(t) => t,
David Tolnay40c06112018-08-30 16:14:50 -0700105 Err(err) => panic!("{}", err),
David Tolnaye83ef5a2018-01-11 15:18:36 -0800106 }
107}
108
109// Not public API.
110#[doc(hidden)]
111pub trait ParseQuote: Sized {
David Tolnay40c06112018-08-30 16:14:50 -0700112 fn parse(input: ParseStream) -> Result<Self>;
David Tolnaye83ef5a2018-01-11 15:18:36 -0800113}
114
David Tolnay40c06112018-08-30 16:14:50 -0700115impl<T: Parse> ParseQuote for T {
116 fn parse(input: ParseStream) -> Result<Self> {
117 <T as Parse>::parse(input)
David Tolnaye83ef5a2018-01-11 15:18:36 -0800118 }
119}
120
121////////////////////////////////////////////////////////////////////////////////
122// Any other types that we want `parse_quote!` to be able to parse.
123
David Tolnaye83ef5a2018-01-11 15:18:36 -0800124#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay40c06112018-08-30 16:14:50 -0700125use {attr, Attribute};
David Tolnaye83ef5a2018-01-11 15:18:36 -0800126
David Tolnaye83ef5a2018-01-11 15:18:36 -0800127#[cfg(any(feature = "full", feature = "derive"))]
128impl ParseQuote for Attribute {
David Tolnay40c06112018-08-30 16:14:50 -0700129 fn parse(input: ParseStream) -> Result<Self> {
130 if input.peek(Token![#]) && input.peek2(Token![!]) {
131 attr::parsing::single_parse_inner(input)
132 } else {
133 attr::parsing::single_parse_outer(input)
134 }
David Tolnaye83ef5a2018-01-11 15:18:36 -0800135 }
136}