| //! This module implements declarative macros: old `macro_rules` and the newer |
| //! `macro`. Declarative macros are also known as "macro by example", and that's |
| //! why we call this module `mbe`. For external documentation, prefer the |
| //! official terminology: "declarative macros". |
| |
| pub(crate) mod diagnostics; |
| pub(crate) mod macro_rules; |
| |
| mod macro_check; |
| mod macro_parser; |
| mod metavar_expr; |
| mod quoted; |
| mod transcribe; |
| |
| use metavar_expr::MetaVarExpr; |
| use rustc_ast::token::{Delimiter, NonterminalKind, Token, TokenKind}; |
| use rustc_ast::tokenstream::{DelimSpacing, DelimSpan}; |
| use rustc_macros::{Decodable, Encodable}; |
| use rustc_span::Span; |
| use rustc_span::symbol::Ident; |
| |
| /// Contains the sub-token-trees of a "delimited" token tree such as `(a b c)`. |
| /// The delimiters are not represented explicitly in the `tts` vector. |
| #[derive(PartialEq, Encodable, Decodable, Debug)] |
| struct Delimited { |
| delim: Delimiter, |
| /// FIXME: #67062 has details about why this is sub-optimal. |
| tts: Vec<TokenTree>, |
| } |
| |
| #[derive(PartialEq, Encodable, Decodable, Debug)] |
| struct SequenceRepetition { |
| /// The sequence of token trees |
| tts: Vec<TokenTree>, |
| /// The optional separator |
| separator: Option<Token>, |
| /// Whether the sequence can be repeated zero (*), or one or more times (+) |
| kleene: KleeneToken, |
| /// The number of `Match`s that appear in the sequence (and subsequences) |
| num_captures: usize, |
| } |
| |
| #[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy)] |
| struct KleeneToken { |
| span: Span, |
| op: KleeneOp, |
| } |
| |
| impl KleeneToken { |
| fn new(op: KleeneOp, span: Span) -> KleeneToken { |
| KleeneToken { span, op } |
| } |
| } |
| |
| /// A Kleene-style [repetition operator](https://en.wikipedia.org/wiki/Kleene_star) |
| /// for token sequences. |
| #[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy)] |
| pub(crate) enum KleeneOp { |
| /// Kleene star (`*`) for zero or more repetitions |
| ZeroOrMore, |
| /// Kleene plus (`+`) for one or more repetitions |
| OneOrMore, |
| /// Kleene optional (`?`) for zero or one repetitions |
| ZeroOrOne, |
| } |
| |
| /// Similar to `tokenstream::TokenTree`, except that `Sequence`, `MetaVar`, `MetaVarDecl`, and |
| /// `MetaVarExpr` are "first-class" token trees. Useful for parsing macros. |
| #[derive(Debug, PartialEq, Encodable, Decodable)] |
| enum TokenTree { |
| /// A token. Unlike `tokenstream::TokenTree::Token` this lacks a `Spacing`. |
| /// See the comments about `Spacing` in the `transcribe` function. |
| Token(Token), |
| /// A delimited sequence, e.g. `($e:expr)` (RHS) or `{ $e }` (LHS). |
| Delimited(DelimSpan, DelimSpacing, Delimited), |
| /// A kleene-style repetition sequence, e.g. `$($e:expr)*` (RHS) or `$($e),*` (LHS). |
| Sequence(DelimSpan, SequenceRepetition), |
| /// e.g., `$var`. The span covers the leading dollar and the ident. (The span within the ident |
| /// only covers the ident, e.g. `var`.) |
| MetaVar(Span, Ident), |
| /// e.g., `$var:expr`. Only appears on the LHS. |
| MetaVarDecl(Span, Ident /* name to bind */, Option<NonterminalKind>), |
| /// A meta-variable expression inside `${...}`. |
| MetaVarExpr(DelimSpan, MetaVarExpr), |
| } |
| |
| impl TokenTree { |
| /// Returns `true` if the given token tree is delimited. |
| fn is_delimited(&self) -> bool { |
| matches!(*self, TokenTree::Delimited(..)) |
| } |
| |
| /// Returns `true` if the given token tree is a token of the given kind. |
| fn is_token(&self, expected_kind: &TokenKind) -> bool { |
| match self { |
| TokenTree::Token(Token { kind: actual_kind, .. }) => actual_kind == expected_kind, |
| _ => false, |
| } |
| } |
| |
| /// Retrieves the `TokenTree`'s span. |
| fn span(&self) -> Span { |
| match *self { |
| TokenTree::Token(Token { span, .. }) |
| | TokenTree::MetaVar(span, _) |
| | TokenTree::MetaVarDecl(span, _, _) => span, |
| TokenTree::Delimited(span, ..) |
| | TokenTree::MetaVarExpr(span, _) |
| | TokenTree::Sequence(span, _) => span.entire(), |
| } |
| } |
| |
| fn token(kind: TokenKind, span: Span) -> TokenTree { |
| TokenTree::Token(Token::new(kind, span)) |
| } |
| } |