blob: 0b9d4d4598e73003f4180637be4cf8af3c15b9d6 [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/// use quote::quote;
13/// use syn::{parse_quote, Stmt};
David Tolnaye83ef5a2018-01-11 15:18:36 -080014///
15/// fn main() {
16/// let name = quote!(v);
17/// let ty = quote!(u8);
18///
19/// let stmt: Stmt = parse_quote! {
20/// let #name: #ty = Default::default();
21/// };
22///
23/// println!("{:#?}", stmt);
24/// }
25/// ```
26///
David Tolnay491680a2018-01-23 00:34:40 -080027/// *This macro is available if Syn is built with the `"parsing"` feature,
28/// although interpolation of syntax tree nodes into the quoted tokens is only
29/// supported if Syn is built with the `"printing"` feature as well.*
David Tolnaye83ef5a2018-01-11 15:18:36 -080030///
31/// # Example
32///
33/// The following helper function adds a bound `T: HeapSize` to every type
34/// parameter `T` in the input generics.
35///
David Tolnay95989db2019-01-01 15:05:57 -050036/// ```edition2018
David Tolnayfd5b1172018-12-31 17:54:36 -050037/// use syn::{parse_quote, Generics, GenericParam};
David Tolnay9b00f652018-09-01 10:31:02 -070038///
David Tolnaye83ef5a2018-01-11 15:18:36 -080039/// // Add a bound `T: HeapSize` to every type parameter T.
40/// fn add_trait_bounds(mut generics: Generics) -> Generics {
41/// for param in &mut generics.params {
42/// if let GenericParam::Type(ref mut type_param) = *param {
43/// type_param.bounds.push(parse_quote!(HeapSize));
44/// }
45/// }
46/// generics
47/// }
David Tolnaye83ef5a2018-01-11 15:18:36 -080048/// ```
49///
50/// # Special cases
51///
52/// This macro can parse the following additional types as a special case even
David Tolnayd85a8812018-08-31 11:09:57 -070053/// though they do not implement the `Parse` trait.
David Tolnaye83ef5a2018-01-11 15:18:36 -080054///
55/// - [`Attribute`] — parses one attribute, allowing either outer like `#[...]`
56/// or inner like `#![...]`
57/// - [`Punctuated<T, P>`] — parses zero or more `T` separated by punctuation
58/// `P` with optional trailing punctuation
59///
60/// [`Attribute`]: struct.Attribute.html
61/// [`Punctuated<T, P>`]: punctuated/struct.Punctuated.html
62///
63/// # Panics
64///
65/// Panics if the tokens fail to parse as the expected syntax tree type. The
66/// caller is responsible for ensuring that the input tokens are syntactically
67/// valid.
David Tolnaye0ba9202018-10-06 20:09:08 -070068#[macro_export(local_inner_macros)]
David Tolnaye83ef5a2018-01-11 15:18:36 -080069macro_rules! parse_quote {
70 ($($tt:tt)*) => {
David Tolnaye0ba9202018-10-06 20:09:08 -070071 $crate::parse_quote::parse($crate::export::From::from(quote_impl!($($tt)*)))
72 };
73}
74
75#[cfg(not(syn_can_call_macro_by_path))]
76#[doc(hidden)]
77#[macro_export]
78macro_rules! quote_impl {
79 ($($tt:tt)*) => {
80 // Require caller to have their own `#[macro_use] extern crate quote`.
81 quote!($($tt)*)
82 };
83}
84
85#[cfg(syn_can_call_macro_by_path)]
86#[doc(hidden)]
87#[macro_export]
88macro_rules! quote_impl {
89 ($($tt:tt)*) => {
90 $crate::export::quote::quote!($($tt)*)
David Tolnaye83ef5a2018-01-11 15:18:36 -080091 };
92}
93
94////////////////////////////////////////////////////////////////////////////////
David Tolnay06faaca2018-09-01 20:25:04 -070095// Can parse any type that implements Parse.
David Tolnaye83ef5a2018-01-11 15:18:36 -080096
David Tolnay4ac232d2018-08-31 10:18:03 -070097use parse::{Parse, ParseStream, Parser, Result};
David Tolnaye82a2b12018-08-30 16:31:10 -070098use proc_macro2::TokenStream;
David Tolnaye83ef5a2018-01-11 15:18:36 -080099
100// Not public API.
101#[doc(hidden)]
David Tolnay7d6a7b82018-01-23 00:42:22 -0800102pub fn parse<T: ParseQuote>(token_stream: TokenStream) -> T {
David Tolnaye83ef5a2018-01-11 15:18:36 -0800103 let parser = T::parse;
104 match parser.parse2(token_stream) {
105 Ok(t) => t,
David Tolnay40c06112018-08-30 16:14:50 -0700106 Err(err) => panic!("{}", err),
David Tolnaye83ef5a2018-01-11 15:18:36 -0800107 }
108}
109
110// Not public API.
111#[doc(hidden)]
112pub trait ParseQuote: Sized {
David Tolnay40c06112018-08-30 16:14:50 -0700113 fn parse(input: ParseStream) -> Result<Self>;
David Tolnaye83ef5a2018-01-11 15:18:36 -0800114}
115
David Tolnay40c06112018-08-30 16:14:50 -0700116impl<T: Parse> ParseQuote for T {
117 fn parse(input: ParseStream) -> Result<Self> {
118 <T as Parse>::parse(input)
David Tolnaye83ef5a2018-01-11 15:18:36 -0800119 }
120}
121
122////////////////////////////////////////////////////////////////////////////////
123// Any other types that we want `parse_quote!` to be able to parse.
124
David Tolnay70f30e92018-09-01 02:04:17 -0700125use punctuated::Punctuated;
David Tolnaye83ef5a2018-01-11 15:18:36 -0800126#[cfg(any(feature = "full", feature = "derive"))]
David Tolnay40c06112018-08-30 16:14:50 -0700127use {attr, Attribute};
David Tolnaye83ef5a2018-01-11 15:18:36 -0800128
David Tolnaye83ef5a2018-01-11 15:18:36 -0800129#[cfg(any(feature = "full", feature = "derive"))]
130impl ParseQuote for Attribute {
David Tolnay40c06112018-08-30 16:14:50 -0700131 fn parse(input: ParseStream) -> Result<Self> {
132 if input.peek(Token![#]) && input.peek2(Token![!]) {
133 attr::parsing::single_parse_inner(input)
134 } else {
135 attr::parsing::single_parse_outer(input)
136 }
David Tolnaye83ef5a2018-01-11 15:18:36 -0800137 }
138}
David Tolnay024b5762018-08-31 11:11:53 -0700139
140impl<T: Parse, P: Parse> ParseQuote for Punctuated<T, P> {
141 fn parse(input: ParseStream) -> Result<Self> {
142 Self::parse_terminated(input)
143 }
144}