| 1 | //! This module implements declarative macros: old `macro_rules` and the newer |
| 2 | //! `macro`. Declarative macros are also known as "macro by example", and that's |
| 3 | //! why we call this module `mbe`. For external documentation, prefer the |
| 4 | //! official terminology: "declarative macros". |
| 5 | |
| 6 | pub(crate) mod diagnostics; |
| 7 | pub(crate) mod macro_rules; |
| 8 | |
| 9 | mod macro_check; |
| 10 | mod macro_parser; |
| 11 | mod metavar_expr; |
| 12 | mod quoted; |
| 13 | mod transcribe; |
| 14 | |
| 15 | use metavar_expr::MetaVarExpr; |
| 16 | use rustc_ast::token::{Delimiter, NonterminalKind, Token, TokenKind}; |
| 17 | use rustc_ast::tokenstream::{DelimSpacing, DelimSpan}; |
| 18 | use rustc_macros::{Decodable, Encodable}; |
| 19 | use rustc_span::{Ident, Span}; |
| 20 | |
| 21 | /// Contains the sub-token-trees of a "delimited" token tree such as `(a b c)`. |
| 22 | /// The delimiters are not represented explicitly in the `tts` vector. |
| 23 | #[derive(PartialEq, Encodable, Decodable, Debug)] |
| 24 | struct Delimited { |
| 25 | delim: Delimiter, |
| 26 | /// FIXME: #67062 has details about why this is sub-optimal. |
| 27 | tts: Vec<TokenTree>, |
| 28 | } |
| 29 | |
| 30 | #[derive(PartialEq, Encodable, Decodable, Debug)] |
| 31 | struct SequenceRepetition { |
| 32 | /// The sequence of token trees |
| 33 | tts: Vec<TokenTree>, |
| 34 | /// The optional separator |
| 35 | separator: Option<Token>, |
| 36 | /// Whether the sequence can be repeated zero (*), or one or more times (+) |
| 37 | kleene: KleeneToken, |
| 38 | /// The number of `Match`s that appear in the sequence (and subsequences) |
| 39 | num_captures: usize, |
| 40 | } |
| 41 | |
| 42 | #[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy)] |
| 43 | struct KleeneToken { |
| 44 | span: Span, |
| 45 | op: KleeneOp, |
| 46 | } |
| 47 | |
| 48 | impl KleeneToken { |
| 49 | fn new(op: KleeneOp, span: Span) -> KleeneToken { |
| 50 | KleeneToken { span, op } |
| 51 | } |
| 52 | } |
| 53 | |
| 54 | /// A Kleene-style [repetition operator](https://en.wikipedia.org/wiki/Kleene_star) |
| 55 | /// for token sequences. |
| 56 | #[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy)] |
| 57 | pub(crate) enum KleeneOp { |
| 58 | /// Kleene star (`*`) for zero or more repetitions |
| 59 | ZeroOrMore, |
| 60 | /// Kleene plus (`+`) for one or more repetitions |
| 61 | OneOrMore, |
| 62 | /// Kleene optional (`?`) for zero or one repetitions |
| 63 | ZeroOrOne, |
| 64 | } |
| 65 | |
| 66 | /// Similar to `tokenstream::TokenTree`, except that `Sequence`, `MetaVar`, `MetaVarDecl`, and |
| 67 | /// `MetaVarExpr` are "first-class" token trees. Useful for parsing macros. |
| 68 | #[derive(Debug, PartialEq, Encodable, Decodable)] |
| 69 | enum TokenTree { |
| 70 | /// A token. Unlike `tokenstream::TokenTree::Token` this lacks a `Spacing`. |
| 71 | /// See the comments about `Spacing` in the `transcribe` function. |
| 72 | Token(Token), |
| 73 | /// A delimited sequence, e.g. `($e:expr)` (RHS) or `{ $e }` (LHS). |
| 74 | Delimited(DelimSpan, DelimSpacing, Delimited), |
| 75 | /// A kleene-style repetition sequence, e.g. `$($e:expr)*` (RHS) or `$($e),*` (LHS). |
| 76 | Sequence(DelimSpan, SequenceRepetition), |
| 77 | /// e.g., `$var`. The span covers the leading dollar and the ident. (The span within the ident |
| 78 | /// only covers the ident, e.g. `var`.) |
| 79 | MetaVar(Span, Ident), |
| 80 | /// e.g., `$var:expr`. Only appears on the LHS. |
| 81 | MetaVarDecl(Span, Ident /* name to bind */, Option<NonterminalKind>), |
| 82 | /// A meta-variable expression inside `${...}`. |
| 83 | MetaVarExpr(DelimSpan, MetaVarExpr), |
| 84 | } |
| 85 | |
| 86 | impl TokenTree { |
| 87 | /// Returns `true` if the given token tree is delimited. |
| 88 | fn is_delimited(&self) -> bool { |
| 89 | matches!(*self, TokenTree::Delimited(..)) |
| 90 | } |
| 91 | |
| 92 | /// Returns `true` if the given token tree is a token of the given kind. |
| 93 | fn is_token(&self, expected_kind: &TokenKind) -> bool { |
| 94 | match self { |
| 95 | TokenTree::Token(Token { kind: actual_kind, .. }) => actual_kind == expected_kind, |
| 96 | _ => false, |
| 97 | } |
| 98 | } |
| 99 | |
| 100 | /// Retrieves the `TokenTree`'s span. |
| 101 | fn span(&self) -> Span { |
| 102 | match *self { |
| 103 | TokenTree::Token(Token { span, .. }) |
| 104 | | TokenTree::MetaVar(span, _) |
| 105 | | TokenTree::MetaVarDecl(span, _, _) => span, |
| 106 | TokenTree::Delimited(span, ..) |
| 107 | | TokenTree::MetaVarExpr(span, _) |
| 108 | | TokenTree::Sequence(span, _) => span.entire(), |
| 109 | } |
| 110 | } |
| 111 | |
| 112 | fn token(kind: TokenKind, span: Span) -> TokenTree { |
| 113 | TokenTree::Token(Token::new(kind, span)) |
| 114 | } |
| 115 | } |
| 116 | |