]>
Commit | Line | Data |
---|---|---|
e74abb32 XL |
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 | ||
e74abb32 XL |
6 | crate mod macro_check; |
7 | crate mod macro_parser; | |
8 | crate mod macro_rules; | |
9 | crate mod quoted; | |
dfeec247 | 10 | crate mod transcribe; |
e74abb32 | 11 | |
3dfed10e | 12 | use rustc_ast::token::{self, NonterminalKind, Token, TokenKind}; |
74b04a01 | 13 | use rustc_ast::tokenstream::DelimSpan; |
e74abb32 | 14 | |
f9f354fc | 15 | use rustc_span::symbol::Ident; |
dfeec247 | 16 | use rustc_span::Span; |
e74abb32 XL |
17 | |
18 | use rustc_data_structures::sync::Lrc; | |
19 | ||
20 | /// Contains the sub-token-trees of a "delimited" token tree, such as the contents of `(`. Note | |
21 | /// that the delimiter itself might be `NoDelim`. | |
3dfed10e | 22 | #[derive(Clone, PartialEq, Encodable, Decodable, Debug)] |
e74abb32 XL |
23 | struct Delimited { |
24 | delim: token::DelimToken, | |
25 | tts: Vec<TokenTree>, | |
26 | } | |
27 | ||
28 | impl Delimited { | |
29 | /// Returns a `self::TokenTree` with a `Span` corresponding to the opening delimiter. | |
60c5eb7d XL |
30 | fn open_tt(&self, span: DelimSpan) -> TokenTree { |
31 | TokenTree::token(token::OpenDelim(self.delim), span.open) | |
e74abb32 XL |
32 | } |
33 | ||
34 | /// Returns a `self::TokenTree` with a `Span` corresponding to the closing delimiter. | |
60c5eb7d XL |
35 | fn close_tt(&self, span: DelimSpan) -> TokenTree { |
36 | TokenTree::token(token::CloseDelim(self.delim), span.close) | |
e74abb32 XL |
37 | } |
38 | } | |
39 | ||
3dfed10e | 40 | #[derive(Clone, PartialEq, Encodable, Decodable, Debug)] |
e74abb32 XL |
41 | struct SequenceRepetition { |
42 | /// The sequence of token trees | |
43 | tts: Vec<TokenTree>, | |
44 | /// The optional separator | |
45 | separator: Option<Token>, | |
46 | /// Whether the sequence can be repeated zero (*), or one or more times (+) | |
47 | kleene: KleeneToken, | |
48 | /// The number of `Match`s that appear in the sequence (and subsequences) | |
49 | num_captures: usize, | |
50 | } | |
51 | ||
3dfed10e | 52 | #[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy)] |
e74abb32 XL |
53 | struct KleeneToken { |
54 | span: Span, | |
55 | op: KleeneOp, | |
56 | } | |
57 | ||
58 | impl KleeneToken { | |
59 | fn new(op: KleeneOp, span: Span) -> KleeneToken { | |
60 | KleeneToken { span, op } | |
61 | } | |
62 | } | |
63 | ||
3dfed10e | 64 | /// A Kleene-style [repetition operator](https://en.wikipedia.org/wiki/Kleene_star) |
e74abb32 | 65 | /// for token sequences. |
3dfed10e | 66 | #[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy)] |
e74abb32 XL |
67 | enum KleeneOp { |
68 | /// Kleene star (`*`) for zero or more repetitions | |
69 | ZeroOrMore, | |
70 | /// Kleene plus (`+`) for one or more repetitions | |
71 | OneOrMore, | |
72 | /// Kleene optional (`?`) for zero or one reptitions | |
73 | ZeroOrOne, | |
74 | } | |
75 | ||
76 | /// Similar to `tokenstream::TokenTree`, except that `$i`, `$i:ident`, and `$(...)` | |
77 | /// are "first-class" token trees. Useful for parsing macros. | |
3dfed10e | 78 | #[derive(Debug, Clone, PartialEq, Encodable, Decodable)] |
e74abb32 XL |
79 | enum TokenTree { |
80 | Token(Token), | |
81 | Delimited(DelimSpan, Lrc<Delimited>), | |
82 | /// A kleene-style repetition sequence | |
83 | Sequence(DelimSpan, Lrc<SequenceRepetition>), | |
84 | /// e.g., `$var` | |
f9f354fc | 85 | MetaVar(Span, Ident), |
e74abb32 | 86 | /// e.g., `$var:expr`. This is only used in the left hand side of MBE macros. |
6c58768f | 87 | MetaVarDecl(Span, Ident /* name to bind */, Option<NonterminalKind>), |
e74abb32 XL |
88 | } |
89 | ||
90 | impl TokenTree { | |
91 | /// Return the number of tokens in the tree. | |
92 | fn len(&self) -> usize { | |
93 | match *self { | |
94 | TokenTree::Delimited(_, ref delimed) => match delimed.delim { | |
95 | token::NoDelim => delimed.tts.len(), | |
96 | _ => delimed.tts.len() + 2, | |
97 | }, | |
98 | TokenTree::Sequence(_, ref seq) => seq.tts.len(), | |
99 | _ => 0, | |
100 | } | |
101 | } | |
102 | ||
103 | /// Returns `true` if the given token tree is delimited. | |
104 | fn is_delimited(&self) -> bool { | |
105 | match *self { | |
106 | TokenTree::Delimited(..) => true, | |
107 | _ => false, | |
108 | } | |
109 | } | |
110 | ||
111 | /// Returns `true` if the given token tree is a token of the given kind. | |
112 | fn is_token(&self, expected_kind: &TokenKind) -> bool { | |
113 | match self { | |
114 | TokenTree::Token(Token { kind: actual_kind, .. }) => actual_kind == expected_kind, | |
115 | _ => false, | |
116 | } | |
117 | } | |
118 | ||
119 | /// Gets the `index`-th sub-token-tree. This only makes sense for delimited trees and sequences. | |
120 | fn get_tt(&self, index: usize) -> TokenTree { | |
121 | match (self, index) { | |
122 | (&TokenTree::Delimited(_, ref delimed), _) if delimed.delim == token::NoDelim => { | |
123 | delimed.tts[index].clone() | |
124 | } | |
125 | (&TokenTree::Delimited(span, ref delimed), _) => { | |
126 | if index == 0 { | |
60c5eb7d | 127 | return delimed.open_tt(span); |
e74abb32 XL |
128 | } |
129 | if index == delimed.tts.len() + 1 { | |
60c5eb7d | 130 | return delimed.close_tt(span); |
e74abb32 XL |
131 | } |
132 | delimed.tts[index - 1].clone() | |
133 | } | |
134 | (&TokenTree::Sequence(_, ref seq), _) => seq.tts[index].clone(), | |
135 | _ => panic!("Cannot expand a token tree"), | |
136 | } | |
137 | } | |
138 | ||
139 | /// Retrieves the `TokenTree`'s span. | |
140 | fn span(&self) -> Span { | |
141 | match *self { | |
142 | TokenTree::Token(Token { span, .. }) | |
143 | | TokenTree::MetaVar(span, _) | |
144 | | TokenTree::MetaVarDecl(span, _, _) => span, | |
145 | TokenTree::Delimited(span, _) | TokenTree::Sequence(span, _) => span.entire(), | |
146 | } | |
147 | } | |
148 | ||
149 | fn token(kind: TokenKind, span: Span) -> TokenTree { | |
150 | TokenTree::Token(Token::new(kind, span)) | |
151 | } | |
152 | } |