Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/rust/syn/parse_quote.rs
38271 views
1
// SPDX-License-Identifier: Apache-2.0 OR MIT
2
3
/// Quasi-quotation macro that accepts input like the [`quote!`] macro but uses
4
/// type inference to figure out a return type for those tokens.
5
///
6
/// [`quote!`]: https://docs.rs/quote/1.0/quote/index.html
7
///
8
/// The return type can be any syntax tree node that implements the [`Parse`]
9
/// trait.
10
///
11
/// [`Parse`]: crate::parse::Parse
12
///
13
/// ```
14
/// use quote::quote;
15
/// use syn::{parse_quote, Stmt};
16
///
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
///
29
/// *This macro is available only if Syn is built with both the `"parsing"` and
30
/// `"printing"` features.*
31
///
32
/// # Example
33
///
34
/// The following helper function adds a bound `T: HeapSize` to every type
35
/// parameter `T` in the input generics.
36
///
37
/// ```
38
/// use syn::{parse_quote, Generics, GenericParam};
39
///
40
/// // Add a bound `T: HeapSize` to every type parameter T.
41
/// fn add_trait_bounds(mut generics: Generics) -> Generics {
42
/// for param in &mut generics.params {
43
/// if let GenericParam::Type(type_param) = param {
44
/// type_param.bounds.push(parse_quote!(HeapSize));
45
/// }
46
/// }
47
/// generics
48
/// }
49
/// ```
50
///
51
/// # Special cases
52
///
53
/// This macro can parse the following additional types as a special case even
54
/// though they do not implement the `Parse` trait.
55
///
56
/// - [`Attribute`] — parses one attribute, allowing either outer like `#[...]`
57
/// or inner like `#![...]`
58
/// - [`Vec<Attribute>`] — parses multiple attributes, including mixed kinds in
59
/// any order
60
/// - [`Punctuated<T, P>`] — parses zero or more `T` separated by punctuation
61
/// `P` with optional trailing punctuation
62
/// - [`Vec<Arm>`] — parses arms separated by optional commas according to the
63
/// same grammar as the inside of a `match` expression
64
/// - [`Vec<Stmt>`] — parses the same as `Block::parse_within`
65
/// - [`Pat`], [`Box<Pat>`] — parses the same as
66
/// `Pat::parse_multi_with_leading_vert`
67
/// - [`Field`] — parses a named or unnamed struct field
68
///
69
/// [`Vec<Attribute>`]: Attribute
70
/// [`Vec<Arm>`]: Arm
71
/// [`Vec<Stmt>`]: Block::parse_within
72
/// [`Pat`]: Pat::parse_multi_with_leading_vert
73
/// [`Box<Pat>`]: Pat::parse_multi_with_leading_vert
74
///
75
/// # Panics
76
///
77
/// Panics if the tokens fail to parse as the expected syntax tree type. The
78
/// caller is responsible for ensuring that the input tokens are syntactically
79
/// valid.
80
#[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "printing"))))]
81
#[macro_export]
82
macro_rules! parse_quote {
83
($($tt:tt)*) => {
84
$crate::__private::parse_quote($crate::__private::quote::quote!($($tt)*))
85
};
86
}
87
88
/// This macro is [`parse_quote!`] + [`quote_spanned!`][quote::quote_spanned].
89
///
90
/// Please refer to each of their documentation.
91
///
92
/// # Example
93
///
94
/// ```
95
/// use quote::{quote, quote_spanned};
96
/// use syn::spanned::Spanned;
97
/// use syn::{parse_quote_spanned, ReturnType, Signature};
98
///
99
/// // Changes `fn()` to `fn() -> Pin<Box<dyn Future<Output = ()>>>`,
100
/// // and `fn() -> T` to `fn() -> Pin<Box<dyn Future<Output = T>>>`,
101
/// // without introducing any call_site() spans.
102
/// fn make_ret_pinned_future(sig: &mut Signature) {
103
/// let ret = match &sig.output {
104
/// ReturnType::Default => quote_spanned!(sig.paren_token.span=> ()),
105
/// ReturnType::Type(_, ret) => quote!(#ret),
106
/// };
107
/// sig.output = parse_quote_spanned! {ret.span()=>
108
/// -> ::std::pin::Pin<::std::boxed::Box<dyn ::std::future::Future<Output = #ret>>>
109
/// };
110
/// }
111
/// ```
112
#[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "printing"))))]
113
#[macro_export]
114
macro_rules! parse_quote_spanned {
115
($span:expr=> $($tt:tt)*) => {
116
$crate::__private::parse_quote($crate::__private::quote::quote_spanned!($span=> $($tt)*))
117
};
118
}
119
120
////////////////////////////////////////////////////////////////////////////////
121
// Can parse any type that implements Parse.
122
123
use crate::error::Result;
124
use crate::parse::{Parse, ParseStream, Parser};
125
use proc_macro2::TokenStream;
126
127
// Not public API.
128
#[doc(hidden)]
129
#[track_caller]
130
pub fn parse<T: ParseQuote>(token_stream: TokenStream) -> T {
131
let parser = T::parse;
132
match parser.parse2(token_stream) {
133
Ok(t) => t,
134
Err(err) => panic!("{}", err),
135
}
136
}
137
138
#[doc(hidden)]
139
pub trait ParseQuote: Sized {
140
fn parse(input: ParseStream) -> Result<Self>;
141
}
142
143
impl<T: Parse> ParseQuote for T {
144
fn parse(input: ParseStream) -> Result<Self> {
145
<T as Parse>::parse(input)
146
}
147
}
148
149
////////////////////////////////////////////////////////////////////////////////
150
// Any other types that we want `parse_quote!` to be able to parse.
151
152
use crate::punctuated::Punctuated;
153
#[cfg(any(feature = "full", feature = "derive"))]
154
use crate::{attr, Attribute, Field, FieldMutability, Ident, Type, Visibility};
155
#[cfg(feature = "full")]
156
use crate::{Arm, Block, Pat, Stmt};
157
158
#[cfg(any(feature = "full", feature = "derive"))]
159
impl ParseQuote for Attribute {
160
fn parse(input: ParseStream) -> Result<Self> {
161
if input.peek(Token![#]) && input.peek2(Token![!]) {
162
attr::parsing::single_parse_inner(input)
163
} else {
164
attr::parsing::single_parse_outer(input)
165
}
166
}
167
}
168
169
#[cfg(any(feature = "full", feature = "derive"))]
170
impl ParseQuote for Vec<Attribute> {
171
fn parse(input: ParseStream) -> Result<Self> {
172
let mut attrs = Vec::new();
173
while !input.is_empty() {
174
attrs.push(ParseQuote::parse(input)?);
175
}
176
Ok(attrs)
177
}
178
}
179
180
#[cfg(any(feature = "full", feature = "derive"))]
181
impl ParseQuote for Field {
182
fn parse(input: ParseStream) -> Result<Self> {
183
let attrs = input.call(Attribute::parse_outer)?;
184
let vis: Visibility = input.parse()?;
185
186
let ident: Option<Ident>;
187
let colon_token: Option<Token![:]>;
188
let is_named = input.peek(Ident) && input.peek2(Token![:]) && !input.peek2(Token![::]);
189
if is_named {
190
ident = Some(input.parse()?);
191
colon_token = Some(input.parse()?);
192
} else {
193
ident = None;
194
colon_token = None;
195
}
196
197
let ty: Type = input.parse()?;
198
199
Ok(Field {
200
attrs,
201
vis,
202
mutability: FieldMutability::None,
203
ident,
204
colon_token,
205
ty,
206
})
207
}
208
}
209
210
#[cfg(feature = "full")]
211
impl ParseQuote for Pat {
212
fn parse(input: ParseStream) -> Result<Self> {
213
Pat::parse_multi_with_leading_vert(input)
214
}
215
}
216
217
#[cfg(feature = "full")]
218
impl ParseQuote for Box<Pat> {
219
fn parse(input: ParseStream) -> Result<Self> {
220
<Pat as ParseQuote>::parse(input).map(Box::new)
221
}
222
}
223
224
impl<T: Parse, P: Parse> ParseQuote for Punctuated<T, P> {
225
fn parse(input: ParseStream) -> Result<Self> {
226
Self::parse_terminated(input)
227
}
228
}
229
230
#[cfg(feature = "full")]
231
impl ParseQuote for Vec<Stmt> {
232
fn parse(input: ParseStream) -> Result<Self> {
233
Block::parse_within(input)
234
}
235
}
236
237
#[cfg(feature = "full")]
238
impl ParseQuote for Vec<Arm> {
239
fn parse(input: ParseStream) -> Result<Self> {
240
Arm::parse_multiple(input)
241
}
242
}
243
244