|
13 | 13 | //! and a borrowed `TokenStream` is sufficient to build an owned `TokenStream` without taking
|
14 | 14 | //! ownership of the original.
|
15 | 15 |
|
16 |
| -use crate::token::{self, Delimiter, Token, TokenKind}; |
| 16 | +use crate::ast::StmtKind; |
| 17 | +use crate::ast_traits::{HasAttrs, HasSpan, HasTokens}; |
| 18 | +use crate::token::{self, Delimiter, Nonterminal, Token, TokenKind}; |
17 | 19 | use crate::AttrVec;
|
18 | 20 |
|
19 | 21 | use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
@@ -45,12 +47,6 @@ pub enum TokenTree {
|
45 | 47 | Delimited(DelimSpan, Delimiter, TokenStream),
|
46 | 48 | }
|
47 | 49 |
|
48 |
| -#[derive(Copy, Clone)] |
49 |
| -pub enum CanSynthesizeMissingTokens { |
50 |
| - Yes, |
51 |
| - No, |
52 |
| -} |
53 |
| - |
54 | 50 | // Ensure all fields of `TokenTree` is `Send` and `Sync`.
|
55 | 51 | #[cfg(parallel_compiler)]
|
56 | 52 | fn _dummy()
|
@@ -471,6 +467,89 @@ impl TokenStream {
|
471 | 467 | .collect(),
|
472 | 468 | ))
|
473 | 469 | }
|
| 470 | + |
| 471 | + fn opt_from_ast(node: &(impl HasAttrs + HasTokens)) -> Option<TokenStream> { |
| 472 | + let tokens = node.tokens()?; |
| 473 | + let attrs = node.attrs(); |
| 474 | + let attr_annotated = if attrs.is_empty() { |
| 475 | + tokens.create_token_stream() |
| 476 | + } else { |
| 477 | + let attr_data = AttributesData { attrs: attrs.to_vec().into(), tokens: tokens.clone() }; |
| 478 | + AttrAnnotatedTokenStream::new(vec![( |
| 479 | + AttrAnnotatedTokenTree::Attributes(attr_data), |
| 480 | + Spacing::Alone, |
| 481 | + )]) |
| 482 | + }; |
| 483 | + Some(attr_annotated.to_tokenstream()) |
| 484 | + } |
| 485 | + |
| 486 | + pub fn from_ast(node: &(impl HasAttrs + HasSpan + HasTokens + fmt::Debug)) -> TokenStream { |
| 487 | + TokenStream::opt_from_ast(node) |
| 488 | + .unwrap_or_else(|| panic!("missing tokens for node at {:?}: {:?}", node.span(), node)) |
| 489 | + } |
| 490 | + |
| 491 | + pub fn from_nonterminal_ast(nt: &Nonterminal) -> TokenStream { |
| 492 | + match nt { |
| 493 | + Nonterminal::NtIdent(ident, is_raw) => { |
| 494 | + TokenTree::token(token::Ident(ident.name, *is_raw), ident.span).into() |
| 495 | + } |
| 496 | + Nonterminal::NtLifetime(ident) => { |
| 497 | + TokenTree::token(token::Lifetime(ident.name), ident.span).into() |
| 498 | + } |
| 499 | + Nonterminal::NtItem(item) => TokenStream::from_ast(item), |
| 500 | + Nonterminal::NtBlock(block) => TokenStream::from_ast(block), |
| 501 | + Nonterminal::NtStmt(stmt) if let StmtKind::Empty = stmt.kind => { |
| 502 | + // FIXME: Properly collect tokens for empty statements. |
| 503 | + TokenTree::token(token::Semi, stmt.span).into() |
| 504 | + } |
| 505 | + Nonterminal::NtStmt(stmt) => TokenStream::from_ast(stmt), |
| 506 | + Nonterminal::NtPat(pat) => TokenStream::from_ast(pat), |
| 507 | + Nonterminal::NtTy(ty) => TokenStream::from_ast(ty), |
| 508 | + Nonterminal::NtMeta(attr) => TokenStream::from_ast(attr), |
| 509 | + Nonterminal::NtPath(path) => TokenStream::from_ast(path), |
| 510 | + Nonterminal::NtVis(vis) => TokenStream::from_ast(vis), |
| 511 | + Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => TokenStream::from_ast(expr), |
| 512 | + } |
| 513 | + } |
| 514 | + |
| 515 | + fn flatten_token(token: &Token) -> TokenTree { |
| 516 | + match &token.kind { |
| 517 | + token::Interpolated(nt) if let token::NtIdent(ident, is_raw) = **nt => { |
| 518 | + TokenTree::token(token::Ident(ident.name, is_raw), ident.span) |
| 519 | + } |
| 520 | + token::Interpolated(nt) => TokenTree::Delimited( |
| 521 | + DelimSpan::from_single(token.span), |
| 522 | + Delimiter::Invisible, |
| 523 | + TokenStream::from_nonterminal_ast(&nt).flattened(), |
| 524 | + ), |
| 525 | + _ => TokenTree::Token(token.clone()), |
| 526 | + } |
| 527 | + } |
| 528 | + |
| 529 | + fn flatten_token_tree(tree: &TokenTree) -> TokenTree { |
| 530 | + match tree { |
| 531 | + TokenTree::Token(token) => TokenStream::flatten_token(token), |
| 532 | + TokenTree::Delimited(span, delim, tts) => { |
| 533 | + TokenTree::Delimited(*span, *delim, tts.flattened()) |
| 534 | + } |
| 535 | + } |
| 536 | + } |
| 537 | + |
| 538 | + #[must_use] |
| 539 | + pub fn flattened(&self) -> TokenStream { |
| 540 | + fn can_skip(stream: &TokenStream) -> bool { |
| 541 | + stream.trees().all(|tree| match tree { |
| 542 | + TokenTree::Token(token) => !matches!(token.kind, token::Interpolated(_)), |
| 543 | + TokenTree::Delimited(_, _, inner) => can_skip(inner), |
| 544 | + }) |
| 545 | + } |
| 546 | + |
| 547 | + if can_skip(self) { |
| 548 | + return self.clone(); |
| 549 | + } |
| 550 | + |
| 551 | + self.trees().map(|tree| TokenStream::flatten_token_tree(tree)).collect() |
| 552 | + } |
474 | 553 | }
|
475 | 554 |
|
476 | 555 | // 99.5%+ of the time we have 1 or 2 elements in this vector.
|
|
0 commit comments