blob: ec551ef9734e5aa473a60efcb25af70032a4b03b [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///
Chih-Hung Hsieh467ea212019-10-31 17:36:47 -07004/// [`quote!`]: https://docs.rs/quote/1.0/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///
Chih-Hung Hsieha0ab7402020-10-26 13:16:52 -07009/// [`Parse`]: crate::parse::Parse
David Tolnaye83ef5a2018-01-11 15:18:36 -080010///
Chih-Hung Hsieh467ea212019-10-31 17:36:47 -070011/// ```
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///
Haibo Huang4fbebf92020-05-26 17:08:50 -070027/// *This macro is available only if Syn is built with the `"parsing"` feature,
David Tolnay491680a2018-01-23 00:34:40 -080028/// 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///
Chih-Hung Hsieh467ea212019-10-31 17:36:47 -070036/// ```
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 {
David Tolnay65336072019-04-22 23:10:52 -070042/// if let GenericParam::Type(type_param) = param {
David Tolnaye83ef5a2018-01-11 15:18:36 -080043/// 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
Chih-Hung Hsieh218e2692020-03-20 13:02:10 -070059/// - [`Vec<Stmt>`] — parses the same as `Block::parse_within`
David Tolnaye83ef5a2018-01-11 15:18:36 -080060///
Chih-Hung Hsieha0ab7402020-10-26 13:16:52 -070061/// [`Punctuated<T, P>`]: crate::punctuated::Punctuated
Chih-Hung Hsieh218e2692020-03-20 13:02:10 -070062/// [`Vec<Stmt>`]: Block::parse_within
David Tolnaye83ef5a2018-01-11 15:18:36 -080063///
64/// # Panics
65///
66/// Panics if the tokens fail to parse as the expected syntax tree type. The
67/// caller is responsible for ensuring that the input tokens are syntactically
68/// valid.
David Tolnayb8dec882019-07-20 09:46:14 -070069//
70// TODO: allow Punctuated to be inferred as intra doc link, currently blocked on
71// https://github.com/rust-lang/rust/issues/62834
Haibo Huangec2e2eb2021-01-05 21:38:44 -080072#[cfg_attr(doc_cfg, doc(cfg(all(feature = "parsing", feature = "printing"))))]
Haibo Huang4fbebf92020-05-26 17:08:50 -070073#[macro_export]
David Tolnaye83ef5a2018-01-11 15:18:36 -080074macro_rules! parse_quote {
75 ($($tt:tt)*) => {
Chih-Hung Hsieh467ea212019-10-31 17:36:47 -070076 $crate::parse_quote::parse(
Haibo Huangec2e2eb2021-01-05 21:38:44 -080077 $crate::__private::From::from(
78 $crate::__private::quote::quote!($($tt)*)
Chih-Hung Hsieh467ea212019-10-31 17:36:47 -070079 )
80 )
David Tolnaye83ef5a2018-01-11 15:18:36 -080081 };
82}
83
84////////////////////////////////////////////////////////////////////////////////
David Tolnay06faaca2018-09-01 20:25:04 -070085// Can parse any type that implements Parse.
David Tolnaye83ef5a2018-01-11 15:18:36 -080086
Chih-Hung Hsieh467ea212019-10-31 17:36:47 -070087use crate::parse::{Parse, ParseStream, Parser, Result};
David Tolnaye82a2b12018-08-30 16:31:10 -070088use proc_macro2::TokenStream;
David Tolnaye83ef5a2018-01-11 15:18:36 -080089
90// Not public API.
91#[doc(hidden)]
David Tolnay7d6a7b82018-01-23 00:42:22 -080092pub fn parse<T: ParseQuote>(token_stream: TokenStream) -> T {
David Tolnaye83ef5a2018-01-11 15:18:36 -080093 let parser = T::parse;
94 match parser.parse2(token_stream) {
95 Ok(t) => t,
David Tolnay40c06112018-08-30 16:14:50 -070096 Err(err) => panic!("{}", err),
David Tolnaye83ef5a2018-01-11 15:18:36 -080097 }
98}
99
100// Not public API.
101#[doc(hidden)]
102pub trait ParseQuote: Sized {
David Tolnay40c06112018-08-30 16:14:50 -0700103 fn parse(input: ParseStream) -> Result<Self>;
David Tolnaye83ef5a2018-01-11 15:18:36 -0800104}
105
David Tolnay40c06112018-08-30 16:14:50 -0700106impl<T: Parse> ParseQuote for T {
107 fn parse(input: ParseStream) -> Result<Self> {
108 <T as Parse>::parse(input)
David Tolnaye83ef5a2018-01-11 15:18:36 -0800109 }
110}
111
112////////////////////////////////////////////////////////////////////////////////
113// Any other types that we want `parse_quote!` to be able to parse.
114
Chih-Hung Hsieh467ea212019-10-31 17:36:47 -0700115use crate::punctuated::Punctuated;
David Tolnaye83ef5a2018-01-11 15:18:36 -0800116#[cfg(any(feature = "full", feature = "derive"))]
Chih-Hung Hsieh467ea212019-10-31 17:36:47 -0700117use crate::{attr, Attribute};
Chih-Hung Hsieh218e2692020-03-20 13:02:10 -0700118#[cfg(feature = "full")]
119use crate::{Block, Stmt};
David Tolnaye83ef5a2018-01-11 15:18:36 -0800120
David Tolnaye83ef5a2018-01-11 15:18:36 -0800121#[cfg(any(feature = "full", feature = "derive"))]
122impl ParseQuote for Attribute {
David Tolnay40c06112018-08-30 16:14:50 -0700123 fn parse(input: ParseStream) -> Result<Self> {
124 if input.peek(Token![#]) && input.peek2(Token![!]) {
125 attr::parsing::single_parse_inner(input)
126 } else {
127 attr::parsing::single_parse_outer(input)
128 }
David Tolnaye83ef5a2018-01-11 15:18:36 -0800129 }
130}
David Tolnay024b5762018-08-31 11:11:53 -0700131
132impl<T: Parse, P: Parse> ParseQuote for Punctuated<T, P> {
133 fn parse(input: ParseStream) -> Result<Self> {
134 Self::parse_terminated(input)
135 }
136}
Chih-Hung Hsieh218e2692020-03-20 13:02:10 -0700137
138#[cfg(feature = "full")]
139impl ParseQuote for Vec<Stmt> {
140 fn parse(input: ParseStream) -> Result<Self> {
141 Block::parse_within(input)
142 }
143}