1 | //! Tokens representing Rust punctuation, keywords, and delimiters. |
2 | //! |
3 | //! The type names in this module can be difficult to keep straight, so we |
4 | //! prefer to use the [`Token!`] macro instead. This is a type-macro that |
5 | //! expands to the token type of the given token. |
6 | //! |
7 | //! [`Token!`]: crate::Token |
8 | //! |
9 | //! # Example |
10 | //! |
11 | //! The [`ItemStatic`] syntax tree node is defined like this. |
12 | //! |
13 | //! [`ItemStatic`]: crate::ItemStatic |
14 | //! |
15 | //! ``` |
16 | //! # use syn::{Attribute, Expr, Ident, Token, Type, Visibility}; |
17 | //! # |
18 | //! pub struct ItemStatic { |
19 | //! pub attrs: Vec<Attribute>, |
20 | //! pub vis: Visibility, |
21 | //! pub static_token: Token![static], |
22 | //! pub mutability: Option<Token![mut]>, |
23 | //! pub ident: Ident, |
24 | //! pub colon_token: Token![:], |
25 | //! pub ty: Box<Type>, |
26 | //! pub eq_token: Token![=], |
27 | //! pub expr: Box<Expr>, |
28 | //! pub semi_token: Token![;], |
29 | //! } |
30 | //! ``` |
31 | //! |
32 | //! # Parsing |
33 | //! |
34 | //! Keywords and punctuation can be parsed through the [`ParseStream::parse`] |
35 | //! method. Delimiter tokens are parsed using the [`parenthesized!`], |
36 | //! [`bracketed!`] and [`braced!`] macros. |
37 | //! |
38 | //! [`ParseStream::parse`]: crate::parse::ParseBuffer::parse() |
39 | //! [`parenthesized!`]: crate::parenthesized! |
40 | //! [`bracketed!`]: crate::bracketed! |
41 | //! [`braced!`]: crate::braced! |
42 | //! |
43 | //! ``` |
44 | //! use syn::{Attribute, Result}; |
45 | //! use syn::parse::{Parse, ParseStream}; |
46 | //! # |
47 | //! # enum ItemStatic {} |
48 | //! |
49 | //! // Parse the ItemStatic struct shown above. |
50 | //! impl Parse for ItemStatic { |
51 | //! fn parse(input: ParseStream) -> Result<Self> { |
52 | //! # use syn::ItemStatic; |
53 | //! # fn parse(input: ParseStream) -> Result<ItemStatic> { |
54 | //! Ok(ItemStatic { |
55 | //! attrs: input.call(Attribute::parse_outer)?, |
56 | //! vis: input.parse()?, |
57 | //! static_token: input.parse()?, |
58 | //! mutability: input.parse()?, |
59 | //! ident: input.parse()?, |
60 | //! colon_token: input.parse()?, |
61 | //! ty: input.parse()?, |
62 | //! eq_token: input.parse()?, |
63 | //! expr: input.parse()?, |
64 | //! semi_token: input.parse()?, |
65 | //! }) |
66 | //! # } |
67 | //! # unimplemented!() |
68 | //! } |
69 | //! } |
70 | //! ``` |
71 | //! |
72 | //! # Other operations |
73 | //! |
74 | //! Every keyword and punctuation token supports the following operations. |
75 | //! |
76 | //! - [Peeking] — `input.peek(Token![...])` |
77 | //! |
78 | //! - [Parsing] — `input.parse::<Token![...]>()?` |
79 | //! |
80 | //! - [Printing] — `quote!( ... #the_token ... )` |
81 | //! |
82 | //! - Construction from a [`Span`] — `let the_token = Token![...](sp)` |
83 | //! |
84 | //! - Field access to its span — `let sp = the_token.span` |
85 | //! |
86 | //! [Peeking]: crate::parse::ParseBuffer::peek() |
87 | //! [Parsing]: crate::parse::ParseBuffer::parse() |
88 | //! [Printing]: https://docs.rs/quote/1.0/quote/trait.ToTokens.html |
89 | //! [`Span`]: https://docs.rs/proc-macro2/1.0/proc_macro2/struct.Span.html |
90 | |
91 | use self::private::WithSpan; |
92 | #[cfg (feature = "parsing" )] |
93 | use crate::buffer::Cursor; |
94 | #[cfg (feature = "parsing" )] |
95 | use crate::error::Result; |
96 | #[cfg (feature = "parsing" )] |
97 | use crate::lifetime::Lifetime; |
98 | #[cfg (feature = "parsing" )] |
99 | use crate::lit::{Lit, LitBool, LitByte, LitByteStr, LitChar, LitFloat, LitInt, LitStr}; |
100 | #[cfg (feature = "parsing" )] |
101 | use crate::lookahead; |
102 | #[cfg (feature = "parsing" )] |
103 | use crate::parse::{Parse, ParseStream}; |
104 | use crate::span::IntoSpans; |
105 | use proc_macro2::extra::DelimSpan; |
106 | use proc_macro2::Span; |
107 | #[cfg (feature = "printing" )] |
108 | use proc_macro2::TokenStream; |
109 | #[cfg (any(feature = "parsing" , feature = "printing" ))] |
110 | use proc_macro2::{Delimiter, Ident}; |
111 | #[cfg (feature = "parsing" )] |
112 | use proc_macro2::{Literal, Punct, TokenTree}; |
113 | #[cfg (feature = "printing" )] |
114 | use quote::{ToTokens, TokenStreamExt}; |
115 | #[cfg (feature = "extra-traits" )] |
116 | use std::cmp; |
117 | #[cfg (feature = "extra-traits" )] |
118 | use std::fmt::{self, Debug}; |
119 | #[cfg (feature = "extra-traits" )] |
120 | use std::hash::{Hash, Hasher}; |
121 | use std::ops::{Deref, DerefMut}; |
122 | |
123 | /// Marker trait for types that represent single tokens. |
124 | /// |
125 | /// This trait is sealed and cannot be implemented for types outside of Syn. |
126 | #[cfg (feature = "parsing" )] |
127 | pub trait Token: private::Sealed { |
128 | // Not public API. |
129 | #[doc (hidden)] |
130 | fn peek(cursor: Cursor) -> bool; |
131 | |
132 | // Not public API. |
133 | #[doc (hidden)] |
134 | fn display() -> &'static str; |
135 | } |
136 | |
137 | mod private { |
138 | use proc_macro2::Span; |
139 | |
140 | #[cfg (feature = "parsing" )] |
141 | pub trait Sealed {} |
142 | |
143 | /// Support writing `token.span` rather than `token.spans[0]` on tokens that |
144 | /// hold a single span. |
145 | #[repr (transparent)] |
146 | pub struct WithSpan { |
147 | pub span: Span, |
148 | } |
149 | } |
150 | |
151 | #[cfg (feature = "parsing" )] |
152 | impl private::Sealed for Ident {} |
153 | |
154 | #[cfg (feature = "parsing" )] |
155 | fn peek_impl(cursor: Cursor, peek: fn(ParseStream) -> bool) -> bool { |
156 | use crate::parse::Unexpected; |
157 | use std::cell::Cell; |
158 | use std::rc::Rc; |
159 | |
160 | let scope: Span = Span::call_site(); |
161 | let unexpected: Rc> | = Rc::new(Cell::new(Unexpected::None)); |
162 | let buffer: ParseBuffer<'_> = crate::parse::new_parse_buffer(scope, cursor, unexpected); |
163 | peek(&buffer) |
164 | } |
165 | |
166 | macro_rules! impl_token { |
167 | ($display:literal $name:ty) => { |
168 | #[cfg(feature = "parsing" )] |
169 | impl Token for $name { |
170 | fn peek(cursor: Cursor) -> bool { |
171 | fn peek(input: ParseStream) -> bool { |
172 | <$name as Parse>::parse(input).is_ok() |
173 | } |
174 | peek_impl(cursor, peek) |
175 | } |
176 | |
177 | fn display() -> &'static str { |
178 | $display |
179 | } |
180 | } |
181 | |
182 | #[cfg(feature = "parsing" )] |
183 | impl private::Sealed for $name {} |
184 | }; |
185 | } |
186 | |
187 | impl_token!("lifetime" Lifetime); |
188 | impl_token!("literal" Lit); |
189 | impl_token!("string literal" LitStr); |
190 | impl_token!("byte string literal" LitByteStr); |
191 | impl_token!("byte literal" LitByte); |
192 | impl_token!("character literal" LitChar); |
193 | impl_token!("integer literal" LitInt); |
194 | impl_token!("floating point literal" LitFloat); |
195 | impl_token!("boolean literal" LitBool); |
196 | impl_token!("group token" proc_macro2::Group); |
197 | |
198 | macro_rules! impl_low_level_token { |
199 | ($display:literal $ty:ident $get:ident) => { |
200 | #[cfg(feature = "parsing" )] |
201 | impl Token for $ty { |
202 | fn peek(cursor: Cursor) -> bool { |
203 | cursor.$get().is_some() |
204 | } |
205 | |
206 | fn display() -> &'static str { |
207 | $display |
208 | } |
209 | } |
210 | |
211 | #[cfg(feature = "parsing" )] |
212 | impl private::Sealed for $ty {} |
213 | }; |
214 | } |
215 | |
216 | impl_low_level_token!("punctuation token" Punct punct); |
217 | impl_low_level_token!("literal" Literal literal); |
218 | impl_low_level_token!("token" TokenTree token_tree); |
219 | |
220 | // Not public API. |
221 | #[doc (hidden)] |
222 | #[cfg (feature = "parsing" )] |
223 | pub trait CustomToken { |
224 | fn peek(cursor: Cursor) -> bool; |
225 | fn display() -> &'static str; |
226 | } |
227 | |
228 | #[cfg (feature = "parsing" )] |
229 | impl<T: CustomToken> private::Sealed for T {} |
230 | |
231 | #[cfg (feature = "parsing" )] |
232 | impl<T: CustomToken> Token for T { |
233 | fn peek(cursor: Cursor) -> bool { |
234 | <Self as CustomToken>::peek(cursor) |
235 | } |
236 | |
237 | fn display() -> &'static str { |
238 | <Self as CustomToken>::display() |
239 | } |
240 | } |
241 | |
242 | macro_rules! define_keywords { |
243 | ($($token:literal pub struct $name:ident)*) => { |
244 | $( |
245 | #[doc = concat!('`' , $token, '`' )] |
246 | /// |
247 | /// Don't try to remember the name of this type — use the |
248 | /// [`Token!`] macro instead. |
249 | /// |
250 | /// [`Token!`]: crate::token |
251 | pub struct $name { |
252 | pub span: Span, |
253 | } |
254 | |
255 | #[doc(hidden)] |
256 | #[allow(non_snake_case)] |
257 | pub fn $name<S: IntoSpans<Span>>(span: S) -> $name { |
258 | $name { |
259 | span: span.into_spans(), |
260 | } |
261 | } |
262 | |
263 | impl std::default::Default for $name { |
264 | fn default() -> Self { |
265 | $name { |
266 | span: Span::call_site(), |
267 | } |
268 | } |
269 | } |
270 | |
271 | #[cfg(feature = "clone-impls" )] |
272 | #[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls" )))] |
273 | impl Copy for $name {} |
274 | |
275 | #[cfg(feature = "clone-impls" )] |
276 | #[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls" )))] |
277 | impl Clone for $name { |
278 | fn clone(&self) -> Self { |
279 | *self |
280 | } |
281 | } |
282 | |
283 | #[cfg(feature = "extra-traits" )] |
284 | #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits" )))] |
285 | impl Debug for $name { |
286 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
287 | f.write_str(stringify!($name)) |
288 | } |
289 | } |
290 | |
291 | #[cfg(feature = "extra-traits" )] |
292 | #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits" )))] |
293 | impl cmp::Eq for $name {} |
294 | |
295 | #[cfg(feature = "extra-traits" )] |
296 | #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits" )))] |
297 | impl PartialEq for $name { |
298 | fn eq(&self, _other: &$name) -> bool { |
299 | true |
300 | } |
301 | } |
302 | |
303 | #[cfg(feature = "extra-traits" )] |
304 | #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits" )))] |
305 | impl Hash for $name { |
306 | fn hash<H: Hasher>(&self, _state: &mut H) {} |
307 | } |
308 | |
309 | #[cfg(feature = "printing" )] |
310 | #[cfg_attr(doc_cfg, doc(cfg(feature = "printing" )))] |
311 | impl ToTokens for $name { |
312 | fn to_tokens(&self, tokens: &mut TokenStream) { |
313 | printing::keyword($token, self.span, tokens); |
314 | } |
315 | } |
316 | |
317 | #[cfg(feature = "parsing" )] |
318 | #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing" )))] |
319 | impl Parse for $name { |
320 | fn parse(input: ParseStream) -> Result<Self> { |
321 | Ok($name { |
322 | span: parsing::keyword(input, $token)?, |
323 | }) |
324 | } |
325 | } |
326 | |
327 | #[cfg(feature = "parsing" )] |
328 | impl Token for $name { |
329 | fn peek(cursor: Cursor) -> bool { |
330 | parsing::peek_keyword(cursor, $token) |
331 | } |
332 | |
333 | fn display() -> &'static str { |
334 | concat!("`" , $token, "`" ) |
335 | } |
336 | } |
337 | |
338 | #[cfg(feature = "parsing" )] |
339 | impl private::Sealed for $name {} |
340 | )* |
341 | }; |
342 | } |
343 | |
344 | macro_rules! impl_deref_if_len_is_1 { |
345 | ($name:ident/1) => { |
346 | impl Deref for $name { |
347 | type Target = WithSpan; |
348 | |
349 | fn deref(&self) -> &Self::Target { |
350 | unsafe { &*(self as *const Self).cast::<WithSpan>() } |
351 | } |
352 | } |
353 | |
354 | impl DerefMut for $name { |
355 | fn deref_mut(&mut self) -> &mut Self::Target { |
356 | unsafe { &mut *(self as *mut Self).cast::<WithSpan>() } |
357 | } |
358 | } |
359 | }; |
360 | |
361 | ($name:ident/$len:literal) => {}; |
362 | } |
363 | |
364 | macro_rules! define_punctuation_structs { |
365 | ($($token:literal pub struct $name:ident/$len:tt #[doc = $usage:literal])*) => { |
366 | $( |
367 | #[cfg_attr(not(doc), repr(transparent))] |
368 | #[doc = concat!('`' , $token, '`' )] |
369 | /// |
370 | /// Usage: |
371 | #[doc = concat!($usage, '.' )] |
372 | /// |
373 | /// Don't try to remember the name of this type — use the |
374 | /// [`Token!`] macro instead. |
375 | /// |
376 | /// [`Token!`]: crate::token |
377 | pub struct $name { |
378 | pub spans: [Span; $len], |
379 | } |
380 | |
381 | #[doc(hidden)] |
382 | #[allow(non_snake_case)] |
383 | pub fn $name<S: IntoSpans<[Span; $len]>>(spans: S) -> $name { |
384 | $name { |
385 | spans: spans.into_spans(), |
386 | } |
387 | } |
388 | |
389 | impl std::default::Default for $name { |
390 | fn default() -> Self { |
391 | $name { |
392 | spans: [Span::call_site(); $len], |
393 | } |
394 | } |
395 | } |
396 | |
397 | #[cfg(feature = "clone-impls" )] |
398 | #[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls" )))] |
399 | impl Copy for $name {} |
400 | |
401 | #[cfg(feature = "clone-impls" )] |
402 | #[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls" )))] |
403 | impl Clone for $name { |
404 | fn clone(&self) -> Self { |
405 | *self |
406 | } |
407 | } |
408 | |
409 | #[cfg(feature = "extra-traits" )] |
410 | #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits" )))] |
411 | impl Debug for $name { |
412 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
413 | f.write_str(stringify!($name)) |
414 | } |
415 | } |
416 | |
417 | #[cfg(feature = "extra-traits" )] |
418 | #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits" )))] |
419 | impl cmp::Eq for $name {} |
420 | |
421 | #[cfg(feature = "extra-traits" )] |
422 | #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits" )))] |
423 | impl PartialEq for $name { |
424 | fn eq(&self, _other: &$name) -> bool { |
425 | true |
426 | } |
427 | } |
428 | |
429 | #[cfg(feature = "extra-traits" )] |
430 | #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits" )))] |
431 | impl Hash for $name { |
432 | fn hash<H: Hasher>(&self, _state: &mut H) {} |
433 | } |
434 | |
435 | impl_deref_if_len_is_1!($name/$len); |
436 | )* |
437 | }; |
438 | } |
439 | |
440 | macro_rules! define_punctuation { |
441 | ($($token:literal pub struct $name:ident/$len:tt #[doc = $usage:literal])*) => { |
442 | $( |
443 | define_punctuation_structs! { |
444 | $token pub struct $name/$len #[doc = $usage] |
445 | } |
446 | |
447 | #[cfg(feature = "printing" )] |
448 | #[cfg_attr(doc_cfg, doc(cfg(feature = "printing" )))] |
449 | impl ToTokens for $name { |
450 | fn to_tokens(&self, tokens: &mut TokenStream) { |
451 | printing::punct($token, &self.spans, tokens); |
452 | } |
453 | } |
454 | |
455 | #[cfg(feature = "parsing" )] |
456 | #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing" )))] |
457 | impl Parse for $name { |
458 | fn parse(input: ParseStream) -> Result<Self> { |
459 | Ok($name { |
460 | spans: parsing::punct(input, $token)?, |
461 | }) |
462 | } |
463 | } |
464 | |
465 | #[cfg(feature = "parsing" )] |
466 | impl Token for $name { |
467 | fn peek(cursor: Cursor) -> bool { |
468 | parsing::peek_punct(cursor, $token) |
469 | } |
470 | |
471 | fn display() -> &'static str { |
472 | concat!("`" , $token, "`" ) |
473 | } |
474 | } |
475 | |
476 | #[cfg(feature = "parsing" )] |
477 | impl private::Sealed for $name {} |
478 | )* |
479 | }; |
480 | } |
481 | |
482 | macro_rules! define_delimiters { |
483 | ($($delim:ident pub struct $name:ident #[$doc:meta])*) => { |
484 | $( |
485 | #[$doc] |
486 | pub struct $name { |
487 | pub span: DelimSpan, |
488 | } |
489 | |
490 | #[doc(hidden)] |
491 | #[allow(non_snake_case)] |
492 | pub fn $name<S: IntoSpans<DelimSpan>>(span: S) -> $name { |
493 | $name { |
494 | span: span.into_spans(), |
495 | } |
496 | } |
497 | |
498 | impl std::default::Default for $name { |
499 | fn default() -> Self { |
500 | $name(Span::call_site()) |
501 | } |
502 | } |
503 | |
504 | #[cfg(feature = "clone-impls" )] |
505 | #[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls" )))] |
506 | impl Copy for $name {} |
507 | |
508 | #[cfg(feature = "clone-impls" )] |
509 | #[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls" )))] |
510 | impl Clone for $name { |
511 | fn clone(&self) -> Self { |
512 | *self |
513 | } |
514 | } |
515 | |
516 | #[cfg(feature = "extra-traits" )] |
517 | #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits" )))] |
518 | impl Debug for $name { |
519 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
520 | f.write_str(stringify!($name)) |
521 | } |
522 | } |
523 | |
524 | #[cfg(feature = "extra-traits" )] |
525 | #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits" )))] |
526 | impl cmp::Eq for $name {} |
527 | |
528 | #[cfg(feature = "extra-traits" )] |
529 | #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits" )))] |
530 | impl PartialEq for $name { |
531 | fn eq(&self, _other: &$name) -> bool { |
532 | true |
533 | } |
534 | } |
535 | |
536 | #[cfg(feature = "extra-traits" )] |
537 | #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits" )))] |
538 | impl Hash for $name { |
539 | fn hash<H: Hasher>(&self, _state: &mut H) {} |
540 | } |
541 | |
542 | impl $name { |
543 | #[cfg(feature = "printing" )] |
544 | pub fn surround<F>(&self, tokens: &mut TokenStream, f: F) |
545 | where |
546 | F: FnOnce(&mut TokenStream), |
547 | { |
548 | let mut inner = TokenStream::new(); |
549 | f(&mut inner); |
550 | printing::delim(Delimiter::$delim, self.span.join(), tokens, inner); |
551 | } |
552 | } |
553 | |
554 | #[cfg(feature = "parsing" )] |
555 | impl private::Sealed for $name {} |
556 | )* |
557 | }; |
558 | } |
559 | |
560 | define_punctuation_structs! { |
561 | "_" pub struct Underscore/1 /// wildcard patterns, inferred types, unnamed items in constants, extern crates, use declarations, and destructuring assignment |
562 | } |
563 | |
564 | #[cfg (feature = "printing" )] |
565 | #[cfg_attr (doc_cfg, doc(cfg(feature = "printing" )))] |
566 | impl ToTokens for Underscore { |
567 | fn to_tokens(&self, tokens: &mut TokenStream) { |
568 | tokens.append(token:Ident::new(string:"_" , self.span)); |
569 | } |
570 | } |
571 | |
572 | #[cfg (feature = "parsing" )] |
573 | #[cfg_attr (doc_cfg, doc(cfg(feature = "parsing" )))] |
574 | impl Parse for Underscore { |
575 | fn parse(input: ParseStream) -> Result<Self> { |
576 | input.step(|cursor: StepCursor<'_, '_>| { |
577 | if let Some((ident: Ident, rest: Cursor<'_>)) = cursor.ident() { |
578 | if ident == "_" { |
579 | return Ok((Underscore(spans:ident.span()), rest)); |
580 | } |
581 | } |
582 | if let Some((punct: Punct, rest: Cursor<'_>)) = cursor.punct() { |
583 | if punct.as_char() == '_' { |
584 | return Ok((Underscore(spans:punct.span()), rest)); |
585 | } |
586 | } |
587 | Err(cursor.error(message:"expected `_`" )) |
588 | }) |
589 | } |
590 | } |
591 | |
592 | #[cfg (feature = "parsing" )] |
593 | impl Token for Underscore { |
594 | fn peek(cursor: Cursor) -> bool { |
595 | if let Some((ident: Ident, _rest: Cursor<'_>)) = cursor.ident() { |
596 | return ident == "_" ; |
597 | } |
598 | if let Some((punct: Punct, _rest: Cursor<'_>)) = cursor.punct() { |
599 | return punct.as_char() == '_' ; |
600 | } |
601 | false |
602 | } |
603 | |
604 | fn display() -> &'static str { |
605 | "`_`" |
606 | } |
607 | } |
608 | |
609 | #[cfg (feature = "parsing" )] |
610 | impl private::Sealed for Underscore {} |
611 | |
612 | /// None-delimited group |
613 | pub struct Group { |
614 | pub span: Span, |
615 | } |
616 | |
617 | #[doc (hidden)] |
618 | #[allow (non_snake_case)] |
619 | pub fn Group<S: IntoSpans<Span>>(span: S) -> Group { |
620 | Group { |
621 | span: span.into_spans(), |
622 | } |
623 | } |
624 | |
625 | impl std::default::Default for Group { |
626 | fn default() -> Self { |
627 | Group { |
628 | span: Span::call_site(), |
629 | } |
630 | } |
631 | } |
632 | |
633 | #[cfg (feature = "clone-impls" )] |
634 | #[cfg_attr (doc_cfg, doc(cfg(feature = "clone-impls" )))] |
635 | impl Copy for Group {} |
636 | |
637 | #[cfg (feature = "clone-impls" )] |
638 | #[cfg_attr (doc_cfg, doc(cfg(feature = "clone-impls" )))] |
639 | impl Clone for Group { |
640 | fn clone(&self) -> Self { |
641 | *self |
642 | } |
643 | } |
644 | |
645 | #[cfg (feature = "extra-traits" )] |
646 | #[cfg_attr (doc_cfg, doc(cfg(feature = "extra-traits" )))] |
647 | impl Debug for Group { |
648 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
649 | f.write_str(data:"Group" ) |
650 | } |
651 | } |
652 | |
653 | #[cfg (feature = "extra-traits" )] |
654 | #[cfg_attr (doc_cfg, doc(cfg(feature = "extra-traits" )))] |
655 | impl cmp::Eq for Group {} |
656 | |
657 | #[cfg (feature = "extra-traits" )] |
658 | #[cfg_attr (doc_cfg, doc(cfg(feature = "extra-traits" )))] |
659 | impl PartialEq for Group { |
660 | fn eq(&self, _other: &Group) -> bool { |
661 | true |
662 | } |
663 | } |
664 | |
665 | #[cfg (feature = "extra-traits" )] |
666 | #[cfg_attr (doc_cfg, doc(cfg(feature = "extra-traits" )))] |
667 | impl Hash for Group { |
668 | fn hash<H: Hasher>(&self, _state: &mut H) {} |
669 | } |
670 | |
671 | impl Group { |
672 | #[cfg (feature = "printing" )] |
673 | pub fn surround<F>(&self, tokens: &mut TokenStream, f: F) |
674 | where |
675 | F: FnOnce(&mut TokenStream), |
676 | { |
677 | let mut inner: TokenStream = TokenStream::new(); |
678 | f(&mut inner); |
679 | printing::delim(delim:Delimiter::None, self.span, tokens, inner); |
680 | } |
681 | } |
682 | |
683 | #[cfg (feature = "parsing" )] |
684 | impl private::Sealed for Group {} |
685 | |
686 | #[cfg (feature = "parsing" )] |
687 | impl Token for Paren { |
688 | fn peek(cursor: Cursor) -> bool { |
689 | lookahead::is_delimiter(cursor, Delimiter::Parenthesis) |
690 | } |
691 | |
692 | fn display() -> &'static str { |
693 | "parentheses" |
694 | } |
695 | } |
696 | |
697 | #[cfg (feature = "parsing" )] |
698 | impl Token for Brace { |
699 | fn peek(cursor: Cursor) -> bool { |
700 | lookahead::is_delimiter(cursor, Delimiter::Brace) |
701 | } |
702 | |
703 | fn display() -> &'static str { |
704 | "curly braces" |
705 | } |
706 | } |
707 | |
708 | #[cfg (feature = "parsing" )] |
709 | impl Token for Bracket { |
710 | fn peek(cursor: Cursor) -> bool { |
711 | lookahead::is_delimiter(cursor, Delimiter::Bracket) |
712 | } |
713 | |
714 | fn display() -> &'static str { |
715 | "square brackets" |
716 | } |
717 | } |
718 | |
719 | #[cfg (feature = "parsing" )] |
720 | impl Token for Group { |
721 | fn peek(cursor: Cursor) -> bool { |
722 | lookahead::is_delimiter(cursor, Delimiter::None) |
723 | } |
724 | |
725 | fn display() -> &'static str { |
726 | "invisible group" |
727 | } |
728 | } |
729 | |
730 | define_keywords! { |
731 | "abstract" pub struct Abstract |
732 | "as" pub struct As |
733 | "async" pub struct Async |
734 | "auto" pub struct Auto |
735 | "await" pub struct Await |
736 | "become" pub struct Become |
737 | "box" pub struct Box |
738 | "break" pub struct Break |
739 | "const" pub struct Const |
740 | "continue" pub struct Continue |
741 | "crate" pub struct Crate |
742 | "default" pub struct Default |
743 | "do" pub struct Do |
744 | "dyn" pub struct Dyn |
745 | "else" pub struct Else |
746 | "enum" pub struct Enum |
747 | "extern" pub struct Extern |
748 | "final" pub struct Final |
749 | "fn" pub struct Fn |
750 | "for" pub struct For |
751 | "if" pub struct If |
752 | "impl" pub struct Impl |
753 | "in" pub struct In |
754 | "let" pub struct Let |
755 | "loop" pub struct Loop |
756 | "macro" pub struct Macro |
757 | "match" pub struct Match |
758 | "mod" pub struct Mod |
759 | "move" pub struct Move |
760 | "mut" pub struct Mut |
761 | "override" pub struct Override |
762 | "priv" pub struct Priv |
763 | "pub" pub struct Pub |
764 | "ref" pub struct Ref |
765 | "return" pub struct Return |
766 | "Self" pub struct SelfType |
767 | "self" pub struct SelfValue |
768 | "static" pub struct Static |
769 | "struct" pub struct Struct |
770 | "super" pub struct Super |
771 | "trait" pub struct Trait |
772 | "try" pub struct Try |
773 | "type" pub struct Type |
774 | "typeof" pub struct Typeof |
775 | "union" pub struct Union |
776 | "unsafe" pub struct Unsafe |
777 | "unsized" pub struct Unsized |
778 | "use" pub struct Use |
779 | "virtual" pub struct Virtual |
780 | "where" pub struct Where |
781 | "while" pub struct While |
782 | "yield" pub struct Yield |
783 | } |
784 | |
785 | define_punctuation! { |
786 | "&" pub struct And/1 /// bitwise and logical AND, borrow, references, reference patterns |
787 | "&&" pub struct AndAnd/2 /// lazy AND, borrow, references, reference patterns |
788 | "&=" pub struct AndEq/2 /// bitwise AND assignment |
789 | "@" pub struct At/1 /// subpattern binding |
790 | "^" pub struct Caret/1 /// bitwise and logical XOR |
791 | "^=" pub struct CaretEq/2 /// bitwise XOR assignment |
792 | ":" pub struct Colon/1 /// various separators |
793 | "," pub struct Comma/1 /// various separators |
794 | "$" pub struct Dollar/1 /// macros |
795 | "." pub struct Dot/1 /// field access, tuple index |
796 | ".." pub struct DotDot/2 /// range, struct expressions, patterns, range patterns |
797 | "..." pub struct DotDotDot/3 /// variadic functions, range patterns |
798 | "..=" pub struct DotDotEq/3 /// inclusive range, range patterns |
799 | "=" pub struct Eq/1 /// assignment, attributes, various type definitions |
800 | "==" pub struct EqEq/2 /// equal |
801 | "=>" pub struct FatArrow/2 /// match arms, macros |
802 | ">=" pub struct Ge/2 /// greater than or equal to, generics |
803 | ">" pub struct Gt/1 /// greater than, generics, paths |
804 | "<-" pub struct LArrow/2 /// unused |
805 | "<=" pub struct Le/2 /// less than or equal to |
806 | "<" pub struct Lt/1 /// less than, generics, paths |
807 | "-" pub struct Minus/1 /// subtraction, negation |
808 | "-=" pub struct MinusEq/2 /// subtraction assignment |
809 | "!=" pub struct Ne/2 /// not equal |
810 | "!" pub struct Not/1 /// bitwise and logical NOT, macro calls, inner attributes, never type, negative impls |
811 | "|" pub struct Or/1 /// bitwise and logical OR, closures, patterns in match, if let, and while let |
812 | "|=" pub struct OrEq/2 /// bitwise OR assignment |
813 | "||" pub struct OrOr/2 /// lazy OR, closures |
814 | "::" pub struct PathSep/2 /// path separator |
815 | "%" pub struct Percent/1 /// remainder |
816 | "%=" pub struct PercentEq/2 /// remainder assignment |
817 | "+" pub struct Plus/1 /// addition, trait bounds, macro Kleene matcher |
818 | "+=" pub struct PlusEq/2 /// addition assignment |
819 | "#" pub struct Pound/1 /// attributes |
820 | "?" pub struct Question/1 /// question mark operator, questionably sized, macro Kleene matcher |
821 | "->" pub struct RArrow/2 /// function return type, closure return type, function pointer type |
822 | ";" pub struct Semi/1 /// terminator for various items and statements, array types |
823 | "<<" pub struct Shl/2 /// shift left, nested generics |
824 | "<<=" pub struct ShlEq/3 /// shift left assignment |
825 | ">>" pub struct Shr/2 /// shift right, nested generics |
826 | ">>=" pub struct ShrEq/3 /// shift right assignment, nested generics |
827 | "/" pub struct Slash/1 /// division |
828 | "/=" pub struct SlashEq/2 /// division assignment |
829 | "*" pub struct Star/1 /// multiplication, dereference, raw pointers, macro Kleene matcher, use wildcards |
830 | "*=" pub struct StarEq/2 /// multiplication assignment |
831 | "~" pub struct Tilde/1 /// unused since before Rust 1.0 |
832 | } |
833 | |
834 | define_delimiters! { |
835 | Brace pub struct Brace /// `{`…`}` |
836 | Bracket pub struct Bracket /// `[`…`]` |
837 | Parenthesis pub struct Paren /// `(`…`)` |
838 | } |
839 | |
840 | /// A type-macro that expands to the name of the Rust type representation of a |
841 | /// given token. |
842 | /// |
843 | /// See the [token module] documentation for details and examples. |
844 | /// |
845 | /// [token module]: crate::token |
846 | #[macro_export ] |
847 | macro_rules! Token { |
848 | [abstract] => { $crate::token::Abstract }; |
849 | [as] => { $crate::token::As }; |
850 | [async] => { $crate::token::Async }; |
851 | [auto] => { $crate::token::Auto }; |
852 | [await] => { $crate::token::Await }; |
853 | [become] => { $crate::token::Become }; |
854 | [box] => { $crate::token::Box }; |
855 | [break] => { $crate::token::Break }; |
856 | [const] => { $crate::token::Const }; |
857 | [continue] => { $crate::token::Continue }; |
858 | [crate] => { $crate::token::Crate }; |
859 | [default] => { $crate::token::Default }; |
860 | [do] => { $crate::token::Do }; |
861 | [dyn] => { $crate::token::Dyn }; |
862 | [else] => { $crate::token::Else }; |
863 | [enum] => { $crate::token::Enum }; |
864 | [extern] => { $crate::token::Extern }; |
865 | [final] => { $crate::token::Final }; |
866 | [fn] => { $crate::token::Fn }; |
867 | [for] => { $crate::token::For }; |
868 | [if] => { $crate::token::If }; |
869 | [impl] => { $crate::token::Impl }; |
870 | [in] => { $crate::token::In }; |
871 | [let] => { $crate::token::Let }; |
872 | [loop] => { $crate::token::Loop }; |
873 | [macro] => { $crate::token::Macro }; |
874 | [match] => { $crate::token::Match }; |
875 | [mod] => { $crate::token::Mod }; |
876 | [move] => { $crate::token::Move }; |
877 | [mut] => { $crate::token::Mut }; |
878 | [override] => { $crate::token::Override }; |
879 | [priv] => { $crate::token::Priv }; |
880 | [pub] => { $crate::token::Pub }; |
881 | [ref] => { $crate::token::Ref }; |
882 | [return] => { $crate::token::Return }; |
883 | [Self] => { $crate::token::SelfType }; |
884 | [self] => { $crate::token::SelfValue }; |
885 | [static] => { $crate::token::Static }; |
886 | [struct] => { $crate::token::Struct }; |
887 | [super] => { $crate::token::Super }; |
888 | [trait] => { $crate::token::Trait }; |
889 | [try] => { $crate::token::Try }; |
890 | [type] => { $crate::token::Type }; |
891 | [typeof] => { $crate::token::Typeof }; |
892 | [union] => { $crate::token::Union }; |
893 | [unsafe] => { $crate::token::Unsafe }; |
894 | [unsized] => { $crate::token::Unsized }; |
895 | [use] => { $crate::token::Use }; |
896 | [virtual] => { $crate::token::Virtual }; |
897 | [where] => { $crate::token::Where }; |
898 | [while] => { $crate::token::While }; |
899 | [yield] => { $crate::token::Yield }; |
900 | [&] => { $crate::token::And }; |
901 | [&&] => { $crate::token::AndAnd }; |
902 | [&=] => { $crate::token::AndEq }; |
903 | [@] => { $crate::token::At }; |
904 | [^] => { $crate::token::Caret }; |
905 | [^=] => { $crate::token::CaretEq }; |
906 | [:] => { $crate::token::Colon }; |
907 | [,] => { $crate::token::Comma }; |
908 | [$] => { $crate::token::Dollar }; |
909 | [.] => { $crate::token::Dot }; |
910 | [..] => { $crate::token::DotDot }; |
911 | [...] => { $crate::token::DotDotDot }; |
912 | [..=] => { $crate::token::DotDotEq }; |
913 | [=] => { $crate::token::Eq }; |
914 | [==] => { $crate::token::EqEq }; |
915 | [=>] => { $crate::token::FatArrow }; |
916 | [>=] => { $crate::token::Ge }; |
917 | [>] => { $crate::token::Gt }; |
918 | [<-] => { $crate::token::LArrow }; |
919 | [<=] => { $crate::token::Le }; |
920 | [<] => { $crate::token::Lt }; |
921 | [-] => { $crate::token::Minus }; |
922 | [-=] => { $crate::token::MinusEq }; |
923 | [!=] => { $crate::token::Ne }; |
924 | [!] => { $crate::token::Not }; |
925 | [|] => { $crate::token::Or }; |
926 | [|=] => { $crate::token::OrEq }; |
927 | [||] => { $crate::token::OrOr }; |
928 | [::] => { $crate::token::PathSep }; |
929 | [%] => { $crate::token::Percent }; |
930 | [%=] => { $crate::token::PercentEq }; |
931 | [+] => { $crate::token::Plus }; |
932 | [+=] => { $crate::token::PlusEq }; |
933 | [#] => { $crate::token::Pound }; |
934 | [?] => { $crate::token::Question }; |
935 | [->] => { $crate::token::RArrow }; |
936 | [;] => { $crate::token::Semi }; |
937 | [<<] => { $crate::token::Shl }; |
938 | [<<=] => { $crate::token::ShlEq }; |
939 | [>>] => { $crate::token::Shr }; |
940 | [>>=] => { $crate::token::ShrEq }; |
941 | [/] => { $crate::token::Slash }; |
942 | [/=] => { $crate::token::SlashEq }; |
943 | [*] => { $crate::token::Star }; |
944 | [*=] => { $crate::token::StarEq }; |
945 | [~] => { $crate::token::Tilde }; |
946 | [_] => { $crate::token::Underscore }; |
947 | } |
948 | |
949 | // Not public API. |
950 | #[doc (hidden)] |
951 | #[cfg (feature = "parsing" )] |
952 | pub(crate) mod parsing { |
953 | use crate::buffer::Cursor; |
954 | use crate::error::{Error, Result}; |
955 | use crate::parse::ParseStream; |
956 | use proc_macro2::{Spacing, Span}; |
957 | |
958 | pub(crate) fn keyword(input: ParseStream, token: &str) -> Result<Span> { |
959 | input.step(|cursor| { |
960 | if let Some((ident, rest)) = cursor.ident() { |
961 | if ident == token { |
962 | return Ok((ident.span(), rest)); |
963 | } |
964 | } |
965 | Err(cursor.error(format!("expected ` {}`" , token))) |
966 | }) |
967 | } |
968 | |
969 | pub(crate) fn peek_keyword(cursor: Cursor, token: &str) -> bool { |
970 | if let Some((ident, _rest)) = cursor.ident() { |
971 | ident == token |
972 | } else { |
973 | false |
974 | } |
975 | } |
976 | |
977 | #[doc (hidden)] |
978 | pub fn punct<const N: usize>(input: ParseStream, token: &str) -> Result<[Span; N]> { |
979 | let mut spans = [input.span(); N]; |
980 | punct_helper(input, token, &mut spans)?; |
981 | Ok(spans) |
982 | } |
983 | |
984 | fn punct_helper(input: ParseStream, token: &str, spans: &mut [Span]) -> Result<()> { |
985 | input.step(|cursor| { |
986 | let mut cursor = *cursor; |
987 | assert_eq!(token.len(), spans.len()); |
988 | |
989 | for (i, ch) in token.chars().enumerate() { |
990 | match cursor.punct() { |
991 | Some((punct, rest)) => { |
992 | spans[i] = punct.span(); |
993 | if punct.as_char() != ch { |
994 | break; |
995 | } else if i == token.len() - 1 { |
996 | return Ok(((), rest)); |
997 | } else if punct.spacing() != Spacing::Joint { |
998 | break; |
999 | } |
1000 | cursor = rest; |
1001 | } |
1002 | None => break, |
1003 | } |
1004 | } |
1005 | |
1006 | Err(Error::new(spans[0], format!("expected ` {}`" , token))) |
1007 | }) |
1008 | } |
1009 | |
1010 | #[doc (hidden)] |
1011 | pub fn peek_punct(mut cursor: Cursor, token: &str) -> bool { |
1012 | for (i, ch) in token.chars().enumerate() { |
1013 | match cursor.punct() { |
1014 | Some((punct, rest)) => { |
1015 | if punct.as_char() != ch { |
1016 | break; |
1017 | } else if i == token.len() - 1 { |
1018 | return true; |
1019 | } else if punct.spacing() != Spacing::Joint { |
1020 | break; |
1021 | } |
1022 | cursor = rest; |
1023 | } |
1024 | None => break, |
1025 | } |
1026 | } |
1027 | false |
1028 | } |
1029 | } |
1030 | |
1031 | // Not public API. |
1032 | #[doc (hidden)] |
1033 | #[cfg (feature = "printing" )] |
1034 | pub(crate) mod printing { |
1035 | use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream}; |
1036 | use quote::TokenStreamExt; |
1037 | |
1038 | #[doc (hidden)] |
1039 | pub fn punct(s: &str, spans: &[Span], tokens: &mut TokenStream) { |
1040 | assert_eq!(s.len(), spans.len()); |
1041 | |
1042 | let mut chars = s.chars(); |
1043 | let mut spans = spans.iter(); |
1044 | let ch = chars.next_back().unwrap(); |
1045 | let span = spans.next_back().unwrap(); |
1046 | for (ch, span) in chars.zip(spans) { |
1047 | let mut op = Punct::new(ch, Spacing::Joint); |
1048 | op.set_span(*span); |
1049 | tokens.append(op); |
1050 | } |
1051 | |
1052 | let mut op = Punct::new(ch, Spacing::Alone); |
1053 | op.set_span(*span); |
1054 | tokens.append(op); |
1055 | } |
1056 | |
1057 | pub(crate) fn keyword(s: &str, span: Span, tokens: &mut TokenStream) { |
1058 | tokens.append(Ident::new(s, span)); |
1059 | } |
1060 | |
1061 | pub(crate) fn delim( |
1062 | delim: Delimiter, |
1063 | span: Span, |
1064 | tokens: &mut TokenStream, |
1065 | inner: TokenStream, |
1066 | ) { |
1067 | let mut g = Group::new(delim, inner); |
1068 | g.set_span(span); |
1069 | tokens.append(g); |
1070 | } |
1071 | } |
1072 | |