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