blob: f6356d042ea6c9c661c68aa233dc465ccf3a600b [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///
David Tolnay95989db2019-01-01 15:05:57 -050011/// ```edition2018
David Tolnayfd5b1172018-12-31 17:54:36 -050012/// # extern crate quote;
13/// #
14/// use quote::quote;
15/// use syn::{parse_quote, Stmt};
David Tolnaye83ef5a2018-01-11 15:18:36 -080016///
17/// fn main() {
18/// let name = quote!(v);
19/// let ty = quote!(u8);
20///
21/// let stmt: Stmt = parse_quote! {
22/// let #name: #ty = Default::default();
23/// };
24///
25/// println!("{:#?}", stmt);
26/// }
27/// ```
28///
David Tolnay491680a2018-01-23 00:34:40 -080029/// *This macro is available if Syn is built with the `"parsing"` feature,
30/// although interpolation of syntax tree nodes into the quoted tokens is only
31/// supported if Syn is built with the `"printing"` feature as well.*
David Tolnaye83ef5a2018-01-11 15:18:36 -080032///
33/// # Example
34///
35/// The following helper function adds a bound `T: HeapSize` to every type
36/// parameter `T` in the input generics.
37///
David Tolnay95989db2019-01-01 15:05:57 -050038/// ```edition2018
David Tolnayfd5b1172018-12-31 17:54:36 -050039/// use syn::{parse_quote, Generics, GenericParam};
David Tolnay9b00f652018-09-01 10:31:02 -070040///
David Tolnaye83ef5a2018-01-11 15:18:36 -080041/// // Add a bound `T: HeapSize` to every type parameter T.
42/// fn add_trait_bounds(mut generics: Generics) -> Generics {
43/// for param in &mut generics.params {
44/// if let GenericParam::Type(ref mut type_param) = *param {
45/// type_param.bounds.push(parse_quote!(HeapSize));
46/// }
47/// }
48/// generics
49/// }
David Tolnaye83ef5a2018-01-11 15:18:36 -080050/// ```
51///
52/// # Special cases
53///
54/// This macro can parse the following additional types as a special case even
David Tolnayd85a8812018-08-31 11:09:57 -070055/// though they do not implement the `Parse` trait.
David Tolnaye83ef5a2018-01-11 15:18:36 -080056///
57/// - [`Attribute`] — parses one attribute, allowing either outer like `#[...]`
58/// or inner like `#![...]`
59/// - [`Punctuated<T, P>`] — parses zero or more `T` separated by punctuation
60/// `P` with optional trailing punctuation
61///
62/// [`Attribute`]: struct.Attribute.html
63/// [`Punctuated<T, P>`]: punctuated/struct.Punctuated.html
64///
65/// # Panics
66///
67/// Panics if the tokens fail to parse as the expected syntax tree type. The
68/// caller is responsible for ensuring that the input tokens are syntactically
69/// valid.
David Tolnaye0ba9202018-10-06 20:09:08 -070070#[macro_export(local_inner_macros)]
David Tolnaye83ef5a2018-01-11 15:18:36 -080071macro_rules! parse_quote {
72 ($($tt:tt)*) => {
David Tolnaye0ba9202018-10-06 20:09:08 -070073 $crate::parse_quote::parse($crate::export::From::from(quote_impl!($($tt)*)))
74 };
75}
76
77#[cfg(not(syn_can_call_macro_by_path))]
78#[doc(hidden)]
79#[macro_export]
80macro_rules! quote_impl {
81 ($($tt:tt)*) => {
82 // Require caller to have their own `#[macro_use] extern crate quote`.
83 quote!($($tt)*)
84 };
85}
86
87#[cfg(syn_can_call_macro_by_path)]
88#[doc(hidden)]
89#[macro_export]
90macro_rules! quote_impl {
91 ($($tt:tt)*) => {
92 $crate::export::quote::quote!($($tt)*)
David Tolnaye83ef5a2018-01-11 15:18:36 -080093 };
94}
95
96////////////////////////////////////////////////////////////////////////////////
David Tolnay06faaca2018-09-01 20:25:04 -070097// Can parse any type that implements Parse.
David Tolnaye83ef5a2018-01-11 15:18:36 -080098
David Tolnay4ac232d2018-08-31 10:18:03 -070099use parse::{Parse, ParseStream, Parser, Result};
David Tolnaye82a2b12018-08-30 16:31:10 -0700100use proc_macro2::TokenStream;
David Tolnaye83ef5a2018-01-11 15:18:36 -0800101
102// Not public API.
103#[doc(hidden)]
David Tolnay7d6a7b82018-01-23 00:42:22 -0800104pub fn parse<T: ParseQuote>(token_stream: TokenStream) -> T {
David Tolnaye83ef5a2018-01-11 15:18:36 -0800105 let parser = T::parse;
106 match parser.parse2(token_stream) {
107 Ok(t) => t,
David Tolnay40c06112018-08-30 16:14:50 -0700108 Err(err) => panic!("{}", err),
David Tolnaye83ef5a2018-01-11 15:18:36 -0800109 }
110}
111
112// Not public API.
113#[doc(hidden)]
114pub trait ParseQuote: Sized {
David Tolnay40c06112018-08-30 16:14:50 -0700115 fn parse(input: ParseStream) -> Result<Self>;
David Tolnaye83ef5a2018-01-11 15:18:36 -0800116}
117
David Tolnay40c06112018-08-30 16:14:50 -0700118impl<T: Parse> ParseQuote for T {
119 fn parse(input: ParseStream) -> Result<Self> {
120 <T as Parse>::parse(input)
David Tolnaye83ef5a2018-01-11 15:18:36 -0800121 }
122}
123
124////////////////////////////////////////////////////////////////////////////////
125// Any other types that we want `parse_quote!` to be able to parse.
126
David Tolnay70f30e92018-09-01 02:04:17 -0700127use punctuated::Punctuated;
David Tolnaye83ef5a2018-01-11 15:18:36 -0800128#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay40c06112018-08-30 16:14:50 -0700129use {attr, Attribute};
David Tolnaye83ef5a2018-01-11 15:18:36 -0800130
David Tolnaye83ef5a2018-01-11 15:18:36 -0800131#[cfg(any(feature = "full", feature = "derive"))]
132impl ParseQuote for Attribute {
David Tolnay40c06112018-08-30 16:14:50 -0700133 fn parse(input: ParseStream) -> Result<Self> {
134 if input.peek(Token![#]) && input.peek2(Token![!]) {
135 attr::parsing::single_parse_inner(input)
136 } else {
137 attr::parsing::single_parse_outer(input)
138 }
David Tolnaye83ef5a2018-01-11 15:18:36 -0800139 }
140}
David Tolnay024b5762018-08-31 11:11:53 -0700141
142impl<T: Parse, P: Parse> ParseQuote for Punctuated<T, P> {
143 fn parse(input: ParseStream) -> Result<Self> {
144 Self::parse_terminated(input)
145 }
146}