blob: 7be6039cb9e71221b44e9945da55beb4fd29cf02 [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 Tolnaya1c98072018-09-06 08:58:10 -070012/// #[macro_use]
13/// extern crate quote;
14/// #[macro_use]
15/// extern crate syn;
16///
17/// use syn::Stmt;
David Tolnaye83ef5a2018-01-11 15:18:36 -080018///
19/// fn main() {
20/// let name = quote!(v);
21/// let ty = quote!(u8);
22///
23/// let stmt: Stmt = parse_quote! {
24/// let #name: #ty = Default::default();
25/// };
26///
27/// println!("{:#?}", stmt);
28/// }
29/// ```
30///
David Tolnay491680a2018-01-23 00:34:40 -080031/// *This macro is available if Syn is built with the `"parsing"` feature,
32/// although interpolation of syntax tree nodes into the quoted tokens is only
33/// supported if Syn is built with the `"printing"` feature as well.*
David Tolnaye83ef5a2018-01-11 15:18:36 -080034///
35/// # Example
36///
37/// The following helper function adds a bound `T: HeapSize` to every type
38/// parameter `T` in the input generics.
39///
40/// ```
David Tolnayf1a10262018-10-13 15:33:50 -070041#[cfg_attr(not(syn_can_call_macro_by_path), doc = " #[macro_use]")]
David Tolnaye0ba9202018-10-06 20:09:08 -070042#[cfg_attr(
43 not(syn_can_call_macro_by_path),
44 doc = " extern crate quote;"
45)]
David Tolnaya1c98072018-09-06 08:58:10 -070046/// #[macro_use]
47/// extern crate syn;
48///
David Tolnay9b00f652018-09-01 10:31:02 -070049/// use syn::{Generics, GenericParam};
50///
David Tolnaye83ef5a2018-01-11 15:18:36 -080051/// // Add a bound `T: HeapSize` to every type parameter T.
52/// fn add_trait_bounds(mut generics: Generics) -> Generics {
53/// for param in &mut generics.params {
54/// if let GenericParam::Type(ref mut type_param) = *param {
55/// type_param.bounds.push(parse_quote!(HeapSize));
56/// }
57/// }
58/// generics
59/// }
60/// #
61/// # fn main() {}
62/// ```
63///
64/// # Special cases
65///
66/// This macro can parse the following additional types as a special case even
David Tolnayd85a8812018-08-31 11:09:57 -070067/// though they do not implement the `Parse` trait.
David Tolnaye83ef5a2018-01-11 15:18:36 -080068///
69/// - [`Attribute`] — parses one attribute, allowing either outer like `#[...]`
70/// or inner like `#![...]`
71/// - [`Punctuated<T, P>`] — parses zero or more `T` separated by punctuation
72/// `P` with optional trailing punctuation
73///
74/// [`Attribute`]: struct.Attribute.html
75/// [`Punctuated<T, P>`]: punctuated/struct.Punctuated.html
76///
77/// # Panics
78///
79/// Panics if the tokens fail to parse as the expected syntax tree type. The
80/// caller is responsible for ensuring that the input tokens are syntactically
81/// valid.
David Tolnaye0ba9202018-10-06 20:09:08 -070082#[macro_export(local_inner_macros)]
David Tolnaye83ef5a2018-01-11 15:18:36 -080083macro_rules! parse_quote {
84 ($($tt:tt)*) => {
David Tolnaye0ba9202018-10-06 20:09:08 -070085 $crate::parse_quote::parse($crate::export::From::from(quote_impl!($($tt)*)))
86 };
87}
88
89#[cfg(not(syn_can_call_macro_by_path))]
90#[doc(hidden)]
91#[macro_export]
92macro_rules! quote_impl {
93 ($($tt:tt)*) => {
94 // Require caller to have their own `#[macro_use] extern crate quote`.
95 quote!($($tt)*)
96 };
97}
98
99#[cfg(syn_can_call_macro_by_path)]
100#[doc(hidden)]
101#[macro_export]
102macro_rules! quote_impl {
103 ($($tt:tt)*) => {
104 $crate::export::quote::quote!($($tt)*)
David Tolnaye83ef5a2018-01-11 15:18:36 -0800105 };
106}
107
108////////////////////////////////////////////////////////////////////////////////
David Tolnay06faaca2018-09-01 20:25:04 -0700109// Can parse any type that implements Parse.
David Tolnaye83ef5a2018-01-11 15:18:36 -0800110
David Tolnay4ac232d2018-08-31 10:18:03 -0700111use parse::{Parse, ParseStream, Parser, Result};
David Tolnaye82a2b12018-08-30 16:31:10 -0700112use proc_macro2::TokenStream;
David Tolnaye83ef5a2018-01-11 15:18:36 -0800113
114// Not public API.
115#[doc(hidden)]
David Tolnay7d6a7b82018-01-23 00:42:22 -0800116pub fn parse<T: ParseQuote>(token_stream: TokenStream) -> T {
David Tolnaye83ef5a2018-01-11 15:18:36 -0800117 let parser = T::parse;
118 match parser.parse2(token_stream) {
119 Ok(t) => t,
David Tolnay40c06112018-08-30 16:14:50 -0700120 Err(err) => panic!("{}", err),
David Tolnaye83ef5a2018-01-11 15:18:36 -0800121 }
122}
123
124// Not public API.
125#[doc(hidden)]
126pub trait ParseQuote: Sized {
David Tolnay40c06112018-08-30 16:14:50 -0700127 fn parse(input: ParseStream) -> Result<Self>;
David Tolnaye83ef5a2018-01-11 15:18:36 -0800128}
129
David Tolnay40c06112018-08-30 16:14:50 -0700130impl<T: Parse> ParseQuote for T {
131 fn parse(input: ParseStream) -> Result<Self> {
132 <T as Parse>::parse(input)
David Tolnaye83ef5a2018-01-11 15:18:36 -0800133 }
134}
135
136////////////////////////////////////////////////////////////////////////////////
137// Any other types that we want `parse_quote!` to be able to parse.
138
David Tolnay70f30e92018-09-01 02:04:17 -0700139use punctuated::Punctuated;
David Tolnaye83ef5a2018-01-11 15:18:36 -0800140#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay40c06112018-08-30 16:14:50 -0700141use {attr, Attribute};
David Tolnaye83ef5a2018-01-11 15:18:36 -0800142
David Tolnaye83ef5a2018-01-11 15:18:36 -0800143#[cfg(any(feature = "full", feature = "derive"))]
144impl ParseQuote for Attribute {
David Tolnay40c06112018-08-30 16:14:50 -0700145 fn parse(input: ParseStream) -> Result<Self> {
146 if input.peek(Token![#]) && input.peek2(Token![!]) {
147 attr::parsing::single_parse_inner(input)
148 } else {
149 attr::parsing::single_parse_outer(input)
150 }
David Tolnaye83ef5a2018-01-11 15:18:36 -0800151 }
152}
David Tolnay024b5762018-08-31 11:11:53 -0700153
154impl<T: Parse, P: Parse> ParseQuote for Punctuated<T, P> {
155 fn parse(input: ParseStream) -> Result<Self> {
156 Self::parse_terminated(input)
157 }
158}