syn/parse_quote.rs
1/// 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///
4/// [`quote!`]: https://docs.rs/quote/1.0/quote/index.html
5///
6/// The return type can be any syntax tree node that implements the [`Parse`]
7/// trait.
8///
9/// [`Parse`]: parse::Parse
10///
11/// ```
12/// use quote::quote;
13/// use syn::{parse_quote, Stmt};
14///
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///
27/// *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.*
30///
31/// # Example
32///
33/// The following helper function adds a bound `T: HeapSize` to every type
34/// parameter `T` in the input generics.
35///
36/// ```
37/// use syn::{parse_quote, Generics, GenericParam};
38///
39/// // 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(type_param) = param {
43/// type_param.bounds.push(parse_quote!(HeapSize));
44/// }
45/// }
46/// generics
47/// }
48/// ```
49///
50/// # Special cases
51///
52/// This macro can parse the following additional types as a special case even
53/// though they do not implement the `Parse` trait.
54///
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/// [`Punctuated<T, P>`]: punctuated::Punctuated
61///
62/// # Panics
63///
64/// Panics if the tokens fail to parse as the expected syntax tree type. The
65/// caller is responsible for ensuring that the input tokens are syntactically
66/// valid.
67//
68// TODO: allow Punctuated to be inferred as intra doc link, currently blocked on
69// https://github.com/rust-lang/rust/issues/62834
70#[macro_export(local_inner_macros)]
71macro_rules! parse_quote {
72 ($($tt:tt)*) => {
73 $crate::parse_quote::parse(
74 $crate::export::From::from(
75 $crate::export::quote::quote!($($tt)*)
76 )
77 )
78 };
79}
80
81////////////////////////////////////////////////////////////////////////////////
82// Can parse any type that implements Parse.
83
84use crate::parse::{Parse, ParseStream, Parser, Result};
85use proc_macro2::TokenStream;
86
87// Not public API.
88#[doc(hidden)]
89pub fn parse<T: ParseQuote>(token_stream: TokenStream) -> T {
90 let parser = T::parse;
91 match parser.parse2(token_stream) {
92 Ok(t) => t,
93 Err(err) => panic!("{}", err),
94 }
95}
96
97// Not public API.
98#[doc(hidden)]
99pub trait ParseQuote: Sized {
100 fn parse(input: ParseStream) -> Result<Self>;
101}
102
103impl<T: Parse> ParseQuote for T {
104 fn parse(input: ParseStream) -> Result<Self> {
105 <T as Parse>::parse(input)
106 }
107}
108
109////////////////////////////////////////////////////////////////////////////////
110// Any other types that we want `parse_quote!` to be able to parse.
111
112use crate::punctuated::Punctuated;
113#[cfg(any(feature = "full", feature = "derive"))]
114use crate::{attr, Attribute};
115
116#[cfg(any(feature = "full", feature = "derive"))]
117impl ParseQuote for Attribute {
118 fn parse(input: ParseStream) -> Result<Self> {
119 if input.peek(Token![#]) && input.peek2(Token![!]) {
120 attr::parsing::single_parse_inner(input)
121 } else {
122 attr::parsing::single_parse_outer(input)
123 }
124 }
125}
126
127impl<T: Parse, P: Parse> ParseQuote for Punctuated<T, P> {
128 fn parse(input: ParseStream) -> Result<Self> {
129 Self::parse_terminated(input)
130 }
131}