blob: 93e2759218955f36a29388522dc197f73202f789 [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 Tolnaye0ba9202018-10-06 20:09:08 -070041#[cfg_attr(
42 not(syn_can_call_macro_by_path),
43 doc = " #[macro_use]"
44)]
45#[cfg_attr(
46 not(syn_can_call_macro_by_path),
47 doc = " extern crate quote;"
48)]
David Tolnaya1c98072018-09-06 08:58:10 -070049/// #[macro_use]
50/// extern crate syn;
51///
David Tolnay9b00f652018-09-01 10:31:02 -070052/// use syn::{Generics, GenericParam};
53///
David Tolnaye83ef5a2018-01-11 15:18:36 -080054/// // Add a bound `T: HeapSize` to every type parameter T.
55/// fn add_trait_bounds(mut generics: Generics) -> Generics {
56/// for param in &mut generics.params {
57/// if let GenericParam::Type(ref mut type_param) = *param {
58/// type_param.bounds.push(parse_quote!(HeapSize));
59/// }
60/// }
61/// generics
62/// }
63/// #
64/// # fn main() {}
65/// ```
66///
67/// # Special cases
68///
69/// This macro can parse the following additional types as a special case even
David Tolnayd85a8812018-08-31 11:09:57 -070070/// though they do not implement the `Parse` trait.
David Tolnaye83ef5a2018-01-11 15:18:36 -080071///
72/// - [`Attribute`] — parses one attribute, allowing either outer like `#[...]`
73/// or inner like `#![...]`
74/// - [`Punctuated<T, P>`] — parses zero or more `T` separated by punctuation
75/// `P` with optional trailing punctuation
76///
77/// [`Attribute`]: struct.Attribute.html
78/// [`Punctuated<T, P>`]: punctuated/struct.Punctuated.html
79///
80/// # Panics
81///
82/// Panics if the tokens fail to parse as the expected syntax tree type. The
83/// caller is responsible for ensuring that the input tokens are syntactically
84/// valid.
David Tolnaye0ba9202018-10-06 20:09:08 -070085#[macro_export(local_inner_macros)]
David Tolnaye83ef5a2018-01-11 15:18:36 -080086macro_rules! parse_quote {
87 ($($tt:tt)*) => {
David Tolnaye0ba9202018-10-06 20:09:08 -070088 $crate::parse_quote::parse($crate::export::From::from(quote_impl!($($tt)*)))
89 };
90}
91
92#[cfg(not(syn_can_call_macro_by_path))]
93#[doc(hidden)]
94#[macro_export]
95macro_rules! quote_impl {
96 ($($tt:tt)*) => {
97 // Require caller to have their own `#[macro_use] extern crate quote`.
98 quote!($($tt)*)
99 };
100}
101
102#[cfg(syn_can_call_macro_by_path)]
103#[doc(hidden)]
104#[macro_export]
105macro_rules! quote_impl {
106 ($($tt:tt)*) => {
107 $crate::export::quote::quote!($($tt)*)
David Tolnaye83ef5a2018-01-11 15:18:36 -0800108 };
109}
110
111////////////////////////////////////////////////////////////////////////////////
David Tolnay06faaca2018-09-01 20:25:04 -0700112// Can parse any type that implements Parse.
David Tolnaye83ef5a2018-01-11 15:18:36 -0800113
David Tolnay4ac232d2018-08-31 10:18:03 -0700114use parse::{Parse, ParseStream, Parser, Result};
David Tolnaye82a2b12018-08-30 16:31:10 -0700115use proc_macro2::TokenStream;
David Tolnaye83ef5a2018-01-11 15:18:36 -0800116
117// Not public API.
118#[doc(hidden)]
David Tolnay7d6a7b82018-01-23 00:42:22 -0800119pub fn parse<T: ParseQuote>(token_stream: TokenStream) -> T {
David Tolnaye83ef5a2018-01-11 15:18:36 -0800120 let parser = T::parse;
121 match parser.parse2(token_stream) {
122 Ok(t) => t,
David Tolnay40c06112018-08-30 16:14:50 -0700123 Err(err) => panic!("{}", err),
David Tolnaye83ef5a2018-01-11 15:18:36 -0800124 }
125}
126
127// Not public API.
128#[doc(hidden)]
129pub trait ParseQuote: Sized {
David Tolnay40c06112018-08-30 16:14:50 -0700130 fn parse(input: ParseStream) -> Result<Self>;
David Tolnaye83ef5a2018-01-11 15:18:36 -0800131}
132
David Tolnay40c06112018-08-30 16:14:50 -0700133impl<T: Parse> ParseQuote for T {
134 fn parse(input: ParseStream) -> Result<Self> {
135 <T as Parse>::parse(input)
David Tolnaye83ef5a2018-01-11 15:18:36 -0800136 }
137}
138
139////////////////////////////////////////////////////////////////////////////////
140// Any other types that we want `parse_quote!` to be able to parse.
141
David Tolnay70f30e92018-09-01 02:04:17 -0700142use punctuated::Punctuated;
David Tolnaye83ef5a2018-01-11 15:18:36 -0800143#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay40c06112018-08-30 16:14:50 -0700144use {attr, Attribute};
David Tolnaye83ef5a2018-01-11 15:18:36 -0800145
David Tolnaye83ef5a2018-01-11 15:18:36 -0800146#[cfg(any(feature = "full", feature = "derive"))]
147impl ParseQuote for Attribute {
David Tolnay40c06112018-08-30 16:14:50 -0700148 fn parse(input: ParseStream) -> Result<Self> {
149 if input.peek(Token![#]) && input.peek2(Token![!]) {
150 attr::parsing::single_parse_inner(input)
151 } else {
152 attr::parsing::single_parse_outer(input)
153 }
David Tolnaye83ef5a2018-01-11 15:18:36 -0800154 }
155}
David Tolnay024b5762018-08-31 11:11:53 -0700156
157impl<T: Parse, P: Parse> ParseQuote for Punctuated<T, P> {
158 fn parse(input: ParseStream) -> Result<Self> {
159 Self::parse_terminated(input)
160 }
161}