Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/rust/syn/custom_keyword.rs
38271 views
1
// SPDX-License-Identifier: Apache-2.0 OR MIT
2
3
/// Define a type that supports parsing and printing a given identifier as if it
4
/// were a keyword.
5
///
6
/// # Usage
7
///
8
/// As a convention, it is recommended that this macro be invoked within a
9
/// module called `kw` or `keyword` and that the resulting parser be invoked
10
/// with a `kw::` or `keyword::` prefix.
11
///
12
/// ```
13
/// mod kw {
14
/// syn::custom_keyword!(whatever);
15
/// }
16
/// ```
17
///
18
/// The generated syntax tree node supports the following operations just like
19
/// any built-in keyword token.
20
///
21
/// - [Peeking] — `input.peek(kw::whatever)`
22
///
23
/// - [Parsing] — `input.parse::<kw::whatever>()?`
24
///
25
/// - [Printing] — `quote!( ... #whatever_token ... )`
26
///
27
/// - Construction from a [`Span`] — `let whatever_token = kw::whatever(sp)`
28
///
29
/// - Field access to its span — `let sp = whatever_token.span`
30
///
31
/// [Peeking]: crate::parse::ParseBuffer::peek
32
/// [Parsing]: crate::parse::ParseBuffer::parse
33
/// [Printing]: quote::ToTokens
34
/// [`Span`]: proc_macro2::Span
35
///
36
/// # Example
37
///
38
/// This example parses input that looks like `bool = true` or `str = "value"`.
39
/// The key must be either the identifier `bool` or the identifier `str`. If
40
/// `bool`, the value may be either `true` or `false`. If `str`, the value may
41
/// be any string literal.
42
///
43
/// The symbols `bool` and `str` are not reserved keywords in Rust so these are
44
/// not considered keywords in the `syn::token` module. Like any other
45
/// identifier that is not a keyword, these can be declared as custom keywords
46
/// by crates that need to use them as such.
47
///
48
/// ```
49
/// use syn::{LitBool, LitStr, Result, Token};
50
/// use syn::parse::{Parse, ParseStream};
51
///
52
/// mod kw {
53
/// syn::custom_keyword!(bool);
54
/// syn::custom_keyword!(str);
55
/// }
56
///
57
/// enum Argument {
58
/// Bool {
59
/// bool_token: kw::bool,
60
/// eq_token: Token![=],
61
/// value: LitBool,
62
/// },
63
/// Str {
64
/// str_token: kw::str,
65
/// eq_token: Token![=],
66
/// value: LitStr,
67
/// },
68
/// }
69
///
70
/// impl Parse for Argument {
71
/// fn parse(input: ParseStream) -> Result<Self> {
72
/// let lookahead = input.lookahead1();
73
/// if lookahead.peek(kw::bool) {
74
/// Ok(Argument::Bool {
75
/// bool_token: input.parse::<kw::bool>()?,
76
/// eq_token: input.parse()?,
77
/// value: input.parse()?,
78
/// })
79
/// } else if lookahead.peek(kw::str) {
80
/// Ok(Argument::Str {
81
/// str_token: input.parse::<kw::str>()?,
82
/// eq_token: input.parse()?,
83
/// value: input.parse()?,
84
/// })
85
/// } else {
86
/// Err(lookahead.error())
87
/// }
88
/// }
89
/// }
90
/// ```
91
#[macro_export]
92
macro_rules! custom_keyword {
93
($ident:ident) => {
94
#[allow(non_camel_case_types)]
95
pub struct $ident {
96
#[allow(dead_code)]
97
pub span: $crate::__private::Span,
98
}
99
100
#[doc(hidden)]
101
#[allow(dead_code, non_snake_case)]
102
pub fn $ident<__S: $crate::__private::IntoSpans<$crate::__private::Span>>(
103
span: __S,
104
) -> $ident {
105
$ident {
106
span: $crate::__private::IntoSpans::into_spans(span),
107
}
108
}
109
110
const _: () = {
111
impl $crate::__private::Default for $ident {
112
fn default() -> Self {
113
$ident {
114
span: $crate::__private::Span::call_site(),
115
}
116
}
117
}
118
119
$crate::impl_parse_for_custom_keyword!($ident);
120
$crate::impl_to_tokens_for_custom_keyword!($ident);
121
$crate::impl_clone_for_custom_keyword!($ident);
122
$crate::impl_extra_traits_for_custom_keyword!($ident);
123
};
124
};
125
}
126
127
// Not public API.
128
#[cfg(feature = "parsing")]
129
#[doc(hidden)]
130
#[macro_export]
131
macro_rules! impl_parse_for_custom_keyword {
132
($ident:ident) => {
133
// For peek.
134
impl $crate::__private::CustomToken for $ident {
135
fn peek(cursor: $crate::buffer::Cursor) -> $crate::__private::bool {
136
if let $crate::__private::Some((ident, _rest)) = cursor.ident() {
137
ident == $crate::__private::stringify!($ident)
138
} else {
139
false
140
}
141
}
142
143
fn display() -> &'static $crate::__private::str {
144
$crate::__private::concat!("`", $crate::__private::stringify!($ident), "`")
145
}
146
}
147
148
impl $crate::parse::Parse for $ident {
149
fn parse(input: $crate::parse::ParseStream) -> $crate::parse::Result<$ident> {
150
input.step(|cursor| {
151
if let $crate::__private::Some((ident, rest)) = cursor.ident() {
152
if ident == $crate::__private::stringify!($ident) {
153
return $crate::__private::Ok(($ident { span: ident.span() }, rest));
154
}
155
}
156
$crate::__private::Err(cursor.error($crate::__private::concat!(
157
"expected `",
158
$crate::__private::stringify!($ident),
159
"`",
160
)))
161
})
162
}
163
}
164
};
165
}
166
167
// Not public API.
168
#[cfg(not(feature = "parsing"))]
169
#[doc(hidden)]
170
#[macro_export]
171
macro_rules! impl_parse_for_custom_keyword {
172
($ident:ident) => {};
173
}
174
175
// Not public API.
176
#[cfg(feature = "printing")]
177
#[doc(hidden)]
178
#[macro_export]
179
macro_rules! impl_to_tokens_for_custom_keyword {
180
($ident:ident) => {
181
impl $crate::__private::ToTokens for $ident {
182
fn to_tokens(&self, tokens: &mut $crate::__private::TokenStream2) {
183
let ident = $crate::Ident::new($crate::__private::stringify!($ident), self.span);
184
$crate::__private::TokenStreamExt::append(tokens, ident);
185
}
186
}
187
};
188
}
189
190
// Not public API.
191
#[cfg(not(feature = "printing"))]
192
#[doc(hidden)]
193
#[macro_export]
194
macro_rules! impl_to_tokens_for_custom_keyword {
195
($ident:ident) => {};
196
}
197
198
// Not public API.
199
#[cfg(feature = "clone-impls")]
200
#[doc(hidden)]
201
#[macro_export]
202
macro_rules! impl_clone_for_custom_keyword {
203
($ident:ident) => {
204
impl $crate::__private::Copy for $ident {}
205
206
#[allow(clippy::expl_impl_clone_on_copy)]
207
impl $crate::__private::Clone for $ident {
208
fn clone(&self) -> Self {
209
*self
210
}
211
}
212
};
213
}
214
215
// Not public API.
216
#[cfg(not(feature = "clone-impls"))]
217
#[doc(hidden)]
218
#[macro_export]
219
macro_rules! impl_clone_for_custom_keyword {
220
($ident:ident) => {};
221
}
222
223
// Not public API.
224
#[cfg(feature = "extra-traits")]
225
#[doc(hidden)]
226
#[macro_export]
227
macro_rules! impl_extra_traits_for_custom_keyword {
228
($ident:ident) => {
229
impl $crate::__private::Debug for $ident {
230
fn fmt(&self, f: &mut $crate::__private::Formatter) -> $crate::__private::FmtResult {
231
$crate::__private::Formatter::write_str(
232
f,
233
$crate::__private::concat!(
234
"Keyword [",
235
$crate::__private::stringify!($ident),
236
"]",
237
),
238
)
239
}
240
}
241
242
impl $crate::__private::Eq for $ident {}
243
244
impl $crate::__private::PartialEq for $ident {
245
fn eq(&self, _other: &Self) -> $crate::__private::bool {
246
true
247
}
248
}
249
250
impl $crate::__private::Hash for $ident {
251
fn hash<__H: $crate::__private::Hasher>(&self, _state: &mut __H) {}
252
}
253
};
254
}
255
256
// Not public API.
257
#[cfg(not(feature = "extra-traits"))]
258
#[doc(hidden)]
259
#[macro_export]
260
macro_rules! impl_extra_traits_for_custom_keyword {
261
($ident:ident) => {};
262
}
263
264