1//! This is an NFA-based parser, which calls out to the main Rust parser for named non-terminals
2//! (which it commits to fully when it hits one in a grammar). There's a set of current NFA threads
3//! and a set of next ones. Instead of NTs, we have a special case for Kleene star. The big-O, in
4//! pathological cases, is worse than traditional use of NFA or Earley parsing, but it's an easier
5//! fit for Macro-by-Example-style rules.
6//!
7//! (In order to prevent the pathological case, we'd need to lazily construct the resulting
8//! `NamedMatch`es at the very end. It'd be a pain, and require more memory to keep around old
9//! matcher positions, but it would also save overhead)
10//!
11//! We don't say this parser uses the Earley algorithm, because it's unnecessarily inaccurate.
12//! The macro parser restricts itself to the features of finite state automata. Earley parsers
13//! can be described as an extension of NFAs with completion rules, prediction rules, and recursion.
14//!
15//! Quick intro to how the parser works:
16//!
17//! A "matcher position" (a.k.a. "position" or "mp") is a dot in the middle of a matcher, usually
18//! written as a `·`. For example `· a $( a )* a b` is one, as is `a $( · a )* a b`.
19//!
20//! The parser walks through the input a token at a time, maintaining a list
21//! of threads consistent with the current position in the input string: `cur_mps`.
22//!
23//! As it processes them, it fills up `eof_mps` with threads that would be valid if
24//! the macro invocation is now over, `bb_mps` with threads that are waiting on
25//! a Rust non-terminal like `$e:expr`, and `next_mps` with threads that are waiting
26//! on a particular token. Most of the logic concerns moving the · through the
27//! repetitions indicated by Kleene stars. The rules for moving the · without
28//! consuming any input are called epsilon transitions. It only advances or calls
29//! out to the real Rust parser when no `cur_mps` threads remain.
30//!
31//! Example:
32//!
33//! ```text, ignore
34//! Start parsing a a a a b against [· a $( a )* a b].
35//!
36//! Remaining input: a a a a b
37//! next: [· a $( a )* a b]
38//!
39//! - - - Advance over an a. - - -
40//!
41//! Remaining input: a a a b
42//! cur: [a · $( a )* a b]
43//! Descend/Skip (first position).
44//! next: [a $( · a )* a b] [a $( a )* · a b].
45//!
46//! - - - Advance over an a. - - -
47//!
48//! Remaining input: a a b
49//! cur: [a $( a · )* a b] [a $( a )* a · b]
50//! Follow epsilon transition: Finish/Repeat (first position)
51//! next: [a $( a )* · a b] [a $( · a )* a b] [a $( a )* a · b]
52//!
53//! - - - Advance over an a. - - - (this looks exactly like the last step)
54//!
55//! Remaining input: a b
56//! cur: [a $( a · )* a b] [a $( a )* a · b]
57//! Follow epsilon transition: Finish/Repeat (first position)
58//! next: [a $( a )* · a b] [a $( · a )* a b] [a $( a )* a · b]
59//!
60//! - - - Advance over an a. - - - (this looks exactly like the last step)
61//!
62//! Remaining input: b
63//! cur: [a $( a · )* a b] [a $( a )* a · b]
64//! Follow epsilon transition: Finish/Repeat (first position)
65//! next: [a $( a )* · a b] [a $( · a )* a b] [a $( a )* a · b]
66//!
67//! - - - Advance over a b. - - -
68//!
69//! Remaining input: ''
70//! eof: [a $( a )* a b ·]
71//! ```
7273use std::borrow::Cow;
74use std::fmt::Display;
75use std::ops::ControlFlow;
76use std::rc::Rc;
7778pub(crate) use NamedMatch::*;
79pub(crate) use ParseResult::*;
80use rustc_ast::token::{self, DocComment, NonterminalKind, Token, TokenKind};
81use rustc_data_structures::fx::FxHashMap;
82use rustc_errors::{Diag, ErrorGuaranteed};
83use rustc_middle::span_bug;
84use rustc_parse::parser::{ParseNtResult, Parser, token_descr};
85use rustc_span::{Ident, MacroRulesNormalizedIdent, Span};
8687use crate::mbe::macro_rules::Tracker;
88use crate::mbe::{KleeneOp, TokenTree};
8990/// A unit within a matcher that a `MatcherPos` can refer to. Similar to (and derived from)
91/// `mbe::TokenTree`, but designed specifically for fast and easy traversal during matching.
92/// Notable differences to `mbe::TokenTree`:
93/// - It is non-recursive, i.e. there is no nesting.
94/// - The end pieces of each sequence (the separator, if present, and the Kleene op) are
95/// represented explicitly, as is the very end of the matcher.
96///
97/// This means a matcher can be represented by `&[MatcherLoc]`, and traversal mostly involves
98/// simply incrementing the current matcher position index by one.
99#[derive(#[automatically_derived]
impl ::core::fmt::Debug for MatcherLoc {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
MatcherLoc::Token { token: __self_0 } =>
::core::fmt::Formatter::debug_struct_field1_finish(f, "Token",
"token", &__self_0),
MatcherLoc::Delimited =>
::core::fmt::Formatter::write_str(f, "Delimited"),
MatcherLoc::Sequence {
op: __self_0,
num_metavar_decls: __self_1,
idx_first_after: __self_2,
next_metavar: __self_3,
seq_depth: __self_4 } =>
::core::fmt::Formatter::debug_struct_field5_finish(f,
"Sequence", "op", __self_0, "num_metavar_decls", __self_1,
"idx_first_after", __self_2, "next_metavar", __self_3,
"seq_depth", &__self_4),
MatcherLoc::SequenceKleeneOpNoSep {
op: __self_0, idx_first: __self_1 } =>
::core::fmt::Formatter::debug_struct_field2_finish(f,
"SequenceKleeneOpNoSep", "op", __self_0, "idx_first",
&__self_1),
MatcherLoc::SequenceSep { separator: __self_0 } =>
::core::fmt::Formatter::debug_struct_field1_finish(f,
"SequenceSep", "separator", &__self_0),
MatcherLoc::SequenceKleeneOpAfterSep { idx_first: __self_0 } =>
::core::fmt::Formatter::debug_struct_field1_finish(f,
"SequenceKleeneOpAfterSep", "idx_first", &__self_0),
MatcherLoc::MetaVarDecl {
span: __self_0,
bind: __self_1,
kind: __self_2,
next_metavar: __self_3,
seq_depth: __self_4 } =>
::core::fmt::Formatter::debug_struct_field5_finish(f,
"MetaVarDecl", "span", __self_0, "bind", __self_1, "kind",
__self_2, "next_metavar", __self_3, "seq_depth", &__self_4),
MatcherLoc::Eof => ::core::fmt::Formatter::write_str(f, "Eof"),
}
}
}Debug, #[automatically_derived]
impl ::core::cmp::PartialEq for MatcherLoc {
#[inline]
fn eq(&self, other: &MatcherLoc) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr &&
match (self, other) {
(MatcherLoc::Token { token: __self_0 }, MatcherLoc::Token {
token: __arg1_0 }) => __self_0 == __arg1_0,
(MatcherLoc::Sequence {
op: __self_0,
num_metavar_decls: __self_1,
idx_first_after: __self_2,
next_metavar: __self_3,
seq_depth: __self_4 }, MatcherLoc::Sequence {
op: __arg1_0,
num_metavar_decls: __arg1_1,
idx_first_after: __arg1_2,
next_metavar: __arg1_3,
seq_depth: __arg1_4 }) =>
__self_0 == __arg1_0 && __self_1 == __arg1_1 &&
__self_2 == __arg1_2 && __self_3 == __arg1_3 &&
__self_4 == __arg1_4,
(MatcherLoc::SequenceKleeneOpNoSep {
op: __self_0, idx_first: __self_1 },
MatcherLoc::SequenceKleeneOpNoSep {
op: __arg1_0, idx_first: __arg1_1 }) =>
__self_0 == __arg1_0 && __self_1 == __arg1_1,
(MatcherLoc::SequenceSep { separator: __self_0 },
MatcherLoc::SequenceSep { separator: __arg1_0 }) =>
__self_0 == __arg1_0,
(MatcherLoc::SequenceKleeneOpAfterSep { idx_first: __self_0 },
MatcherLoc::SequenceKleeneOpAfterSep { idx_first: __arg1_0
}) => __self_0 == __arg1_0,
(MatcherLoc::MetaVarDecl {
span: __self_0,
bind: __self_1,
kind: __self_2,
next_metavar: __self_3,
seq_depth: __self_4 }, MatcherLoc::MetaVarDecl {
span: __arg1_0,
bind: __arg1_1,
kind: __arg1_2,
next_metavar: __arg1_3,
seq_depth: __arg1_4 }) =>
__self_0 == __arg1_0 && __self_1 == __arg1_1 &&
__self_2 == __arg1_2 && __self_3 == __arg1_3 &&
__self_4 == __arg1_4,
_ => true,
}
}
}PartialEq, #[automatically_derived]
impl ::core::clone::Clone for MatcherLoc {
#[inline]
fn clone(&self) -> MatcherLoc {
match self {
MatcherLoc::Token { token: __self_0 } =>
MatcherLoc::Token {
token: ::core::clone::Clone::clone(__self_0),
},
MatcherLoc::Delimited => MatcherLoc::Delimited,
MatcherLoc::Sequence {
op: __self_0,
num_metavar_decls: __self_1,
idx_first_after: __self_2,
next_metavar: __self_3,
seq_depth: __self_4 } =>
MatcherLoc::Sequence {
op: ::core::clone::Clone::clone(__self_0),
num_metavar_decls: ::core::clone::Clone::clone(__self_1),
idx_first_after: ::core::clone::Clone::clone(__self_2),
next_metavar: ::core::clone::Clone::clone(__self_3),
seq_depth: ::core::clone::Clone::clone(__self_4),
},
MatcherLoc::SequenceKleeneOpNoSep {
op: __self_0, idx_first: __self_1 } =>
MatcherLoc::SequenceKleeneOpNoSep {
op: ::core::clone::Clone::clone(__self_0),
idx_first: ::core::clone::Clone::clone(__self_1),
},
MatcherLoc::SequenceSep { separator: __self_0 } =>
MatcherLoc::SequenceSep {
separator: ::core::clone::Clone::clone(__self_0),
},
MatcherLoc::SequenceKleeneOpAfterSep { idx_first: __self_0 } =>
MatcherLoc::SequenceKleeneOpAfterSep {
idx_first: ::core::clone::Clone::clone(__self_0),
},
MatcherLoc::MetaVarDecl {
span: __self_0,
bind: __self_1,
kind: __self_2,
next_metavar: __self_3,
seq_depth: __self_4 } =>
MatcherLoc::MetaVarDecl {
span: ::core::clone::Clone::clone(__self_0),
bind: ::core::clone::Clone::clone(__self_1),
kind: ::core::clone::Clone::clone(__self_2),
next_metavar: ::core::clone::Clone::clone(__self_3),
seq_depth: ::core::clone::Clone::clone(__self_4),
},
MatcherLoc::Eof => MatcherLoc::Eof,
}
}
}Clone)]
100pub(crate) enum MatcherLoc {
101 Token {
102 token: Token,
103 },
104 Delimited,
105 Sequence {
106 op: KleeneOp,
107 num_metavar_decls: usize,
108 idx_first_after: usize,
109 next_metavar: usize,
110 seq_depth: usize,
111 },
112 SequenceKleeneOpNoSep {
113 op: KleeneOp,
114 idx_first: usize,
115 },
116 SequenceSep {
117 separator: Token,
118 },
119 SequenceKleeneOpAfterSep {
120 idx_first: usize,
121 },
122 MetaVarDecl {
123 span: Span,
124 bind: Ident,
125 kind: NonterminalKind,
126 next_metavar: usize,
127 seq_depth: usize,
128 },
129 Eof,
130}
131132impl MatcherLoc {
133pub(super) fn span(&self) -> Option<Span> {
134match self {
135 MatcherLoc::Token { token } => Some(token.span),
136 MatcherLoc::Delimited => None,
137 MatcherLoc::Sequence { .. } => None,
138 MatcherLoc::SequenceKleeneOpNoSep { .. } => None,
139 MatcherLoc::SequenceSep { .. } => None,
140 MatcherLoc::SequenceKleeneOpAfterSep { .. } => None,
141 MatcherLoc::MetaVarDecl { span, .. } => Some(*span),
142 MatcherLoc::Eof => None,
143 }
144 }
145}
146147impl Displayfor MatcherLoc {
148fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
149match self {
150 MatcherLoc::Token { token } | MatcherLoc::SequenceSep { separator: token } => {
151f.write_fmt(format_args!("{0}", token_descr(token)))write!(f, "{}", token_descr(token))152 }
153 MatcherLoc::MetaVarDecl { bind, kind, .. } => {
154f.write_fmt(format_args!("meta-variable `${0}:{1}`", bind, kind))write!(f, "meta-variable `${bind}:{kind}`")155 }
156 MatcherLoc::Eof => f.write_str("end of macro"),
157158// These are not printed in the diagnostic
159MatcherLoc::Delimited => f.write_str("delimiter"),
160 MatcherLoc::Sequence { .. } => f.write_str("sequence start"),
161 MatcherLoc::SequenceKleeneOpNoSep { .. } => f.write_str("sequence end"),
162 MatcherLoc::SequenceKleeneOpAfterSep { .. } => f.write_str("sequence end"),
163 }
164 }
165}
166167pub(super) fn compute_locs(matcher: &[TokenTree]) -> Vec<MatcherLoc> {
168fn inner(
169 tts: &[TokenTree],
170 locs: &mut Vec<MatcherLoc>,
171 next_metavar: &mut usize,
172 seq_depth: usize,
173 ) {
174for tt in tts {
175match tt {
176 TokenTree::Token(token) => {
177 locs.push(MatcherLoc::Token { token: *token });
178 }
179 TokenTree::Delimited(span, _, delimited) => {
180let open_token = Token::new(delimited.delim.as_open_token_kind(), span.open);
181let close_token = Token::new(delimited.delim.as_close_token_kind(), span.close);
182183 locs.push(MatcherLoc::Delimited);
184 locs.push(MatcherLoc::Token { token: open_token });
185 inner(&delimited.tts, locs, next_metavar, seq_depth);
186 locs.push(MatcherLoc::Token { token: close_token });
187 }
188 TokenTree::Sequence(_, seq) => {
189// We can't determine `idx_first_after` and construct the final
190 // `MatcherLoc::Sequence` until after `inner()` is called and the sequence end
191 // pieces are processed. So we push a dummy value (`Eof` is cheapest to
192 // construct) now, and overwrite it with the proper value below.
193let dummy = MatcherLoc::Eof;
194 locs.push(dummy);
195196let next_metavar_orig = *next_metavar;
197let op = seq.kleene.op;
198let idx_first = locs.len();
199let idx_seq = idx_first - 1;
200 inner(&seq.tts, locs, next_metavar, seq_depth + 1);
201202if let Some(separator) = seq.separator {
203 locs.push(MatcherLoc::SequenceSep { separator });
204 locs.push(MatcherLoc::SequenceKleeneOpAfterSep { idx_first });
205 } else {
206 locs.push(MatcherLoc::SequenceKleeneOpNoSep { op, idx_first });
207 }
208209// Overwrite the dummy value pushed above with the proper value.
210locs[idx_seq] = MatcherLoc::Sequence {
211 op,
212 num_metavar_decls: seq.num_captures,
213 idx_first_after: locs.len(),
214 next_metavar: next_metavar_orig,
215 seq_depth,
216 };
217 }
218&TokenTree::MetaVarDecl { span, name: bind, kind } => {
219 locs.push(MatcherLoc::MetaVarDecl {
220 span,
221 bind,
222 kind,
223 next_metavar: *next_metavar,
224 seq_depth,
225 });
226*next_metavar += 1;
227 }
228 TokenTree::MetaVar(..) | TokenTree::MetaVarExpr(..) => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
229 }
230 }
231 }
232233let mut locs = ::alloc::vec::Vec::new()vec![];
234let mut next_metavar = 0;
235inner(matcher, &mut locs, &mut next_metavar, /* seq_depth */ 0);
236237// A final entry is needed for eof.
238locs.push(MatcherLoc::Eof);
239240locs241}
242243/// A single matcher position, representing the state of matching.
244#[derive(#[automatically_derived]
impl ::core::fmt::Debug for MatcherPos {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f, "MatcherPos",
"idx", &self.idx, "matches", &&self.matches)
}
}Debug)]
245struct MatcherPos {
246/// The index into `TtParser::locs`, which represents the "dot".
247idx: usize,
248249/// The matches made against metavar decls so far. On a successful match, this vector ends up
250 /// with one element per metavar decl in the matcher. Each element records token trees matched
251 /// against the relevant metavar by the black box parser. An element will be a `MatchedSeq` if
252 /// the corresponding metavar decl is within a sequence.
253 ///
254 /// It is critical to performance that this is an `Rc`, because it gets cloned frequently when
255 /// processing sequences. Mostly for sequence-ending possibilities that must be tried but end
256 /// up failing.
257matches: Rc<Vec<NamedMatch>>,
258}
259260// This type is used a lot. Make sure it doesn't unintentionally get bigger.
261#[cfg(target_pointer_width = "64")]
262const _: [(); 16] = [(); ::std::mem::size_of::<MatcherPos>()];rustc_data_structures::static_assert_size!(MatcherPos, 16);
263264impl MatcherPos {
265/// Adds `m` as a named match for the `metavar_idx`-th metavar. There are only two call sites,
266 /// and both are hot enough to be always worth inlining.
267#[inline(always)]
268fn push_match(&mut self, metavar_idx: usize, seq_depth: usize, m: NamedMatch) {
269let matches = Rc::make_mut(&mut self.matches);
270match seq_depth {
2710 => {
272// We are not within a sequence. Just append `m`.
273{
match (&metavar_idx, &matches.len()) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(metavar_idx, matches.len());
274matches.push(m);
275 }
276_ => {
277// We are within a sequence. Find the final `MatchedSeq` at the appropriate depth
278 // and append `m` to its vector.
279let mut curr = &mut matches[metavar_idx];
280for _ in 0..seq_depth - 1 {
281match curr {
282 MatchedSeq(seq) => curr = seq.last_mut().unwrap(),
283_ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
284 }
285 }
286match curr {
287MatchedSeq(seq) => seq.push(m),
288_ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
289 }
290 }
291 }
292 }
293}
294295/// Represents the possible results of an attempted parse.
296#[derive(#[automatically_derived]
impl<T: ::core::fmt::Debug> ::core::fmt::Debug for ParseResult<T> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
ParseResult::Success(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"Success", &__self_0),
ParseResult::Failure =>
::core::fmt::Formatter::write_str(f, "Failure"),
ParseResult::Ambiguity =>
::core::fmt::Formatter::write_str(f, "Ambiguity"),
ParseResult::ErrorReported(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"ErrorReported", &__self_0),
}
}
}Debug)]
297pub(crate) enum ParseResult<T> {
298/// Parsed successfully.
299Success(T),
300/// Arm failed to match.
301 ///
302 /// [`Tracker::failure()`] will be called beforehand.
303Failure,
304/// The input could be parsed in multiple distinct ways.
305 ///
306 /// [`Tracker::ambiguity()`] will be called beforehand.
307Ambiguity,
308 ErrorReported(ErrorGuaranteed),
309}
310311/// A `ParseResult` where the `Success` variant contains a mapping of
312/// `MacroRulesNormalizedIdent`s to `NamedMatch`es. This represents the mapping
313/// of metavars to the token trees they bind to.
314pub(crate) type NamedParseResult = ParseResult<NamedMatches>;
315316/// Contains a mapping of `MacroRulesNormalizedIdent`s to `NamedMatch`es.
317/// This represents the mapping of metavars to the token trees they bind to.
318pub(crate) type NamedMatches = FxHashMap<MacroRulesNormalizedIdent, NamedMatch>;
319320/// Count how many metavars declarations are in `matcher`.
321pub(super) fn count_metavar_decls(matcher: &[TokenTree]) -> usize {
322matcher323 .iter()
324 .map(|tt| match tt {
325 TokenTree::MetaVarDecl { .. } => 1,
326 TokenTree::Sequence(_, seq) => seq.num_captures,
327 TokenTree::Delimited(.., delim) => count_metavar_decls(&delim.tts),
328 TokenTree::Token(..) => 0,
329 TokenTree::MetaVar(..) | TokenTree::MetaVarExpr(..) => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
330 })
331 .sum()
332}
333334/// `NamedMatch` is a pattern-match result for a single metavar. All
335/// `MatchedNonterminal`s in the `NamedMatch` have the same non-terminal type
336/// (expr, item, etc).
337///
338/// The in-memory structure of a particular `NamedMatch` represents the match
339/// that occurred when a particular subset of a matcher was applied to a
340/// particular token tree.
341///
342/// The width of each `MatchedSeq` in the `NamedMatch`, and the identity of
343/// the `MatchedNtNonTts`s, will depend on the token tree it was applied
344/// to: each `MatchedSeq` corresponds to a single repetition in the originating
345/// token tree. The depth of the `NamedMatch` structure will therefore depend
346/// only on the nesting depth of repetitions in the originating token tree it
347/// was derived from.
348///
349/// In layperson's terms: `NamedMatch` will form a tree representing nested matches of a particular
350/// meta variable. For example, if we are matching the following macro against the following
351/// invocation...
352///
353/// ```rust
354/// macro_rules! foo {
355/// ($($($x:ident),+);+) => {}
356/// }
357///
358/// foo!(a, b, c, d; a, b, c, d, e);
359/// ```
360///
361/// Then, the tree will have the following shape:
362///
363/// ```ignore (private-internal)
364/// # use NamedMatch::*;
365/// MatchedSeq([
366/// MatchedSeq([
367/// MatchedNonterminal(a),
368/// MatchedNonterminal(b),
369/// MatchedNonterminal(c),
370/// MatchedNonterminal(d),
371/// ]),
372/// MatchedSeq([
373/// MatchedNonterminal(a),
374/// MatchedNonterminal(b),
375/// MatchedNonterminal(c),
376/// MatchedNonterminal(d),
377/// MatchedNonterminal(e),
378/// ])
379/// ])
380/// ```
381#[derive(#[automatically_derived]
impl ::core::fmt::Debug for NamedMatch {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
NamedMatch::MatchedSeq(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"MatchedSeq", &__self_0),
NamedMatch::MatchedSingle(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"MatchedSingle", &__self_0),
}
}
}Debug, #[automatically_derived]
impl ::core::clone::Clone for NamedMatch {
#[inline]
fn clone(&self) -> NamedMatch {
match self {
NamedMatch::MatchedSeq(__self_0) =>
NamedMatch::MatchedSeq(::core::clone::Clone::clone(__self_0)),
NamedMatch::MatchedSingle(__self_0) =>
NamedMatch::MatchedSingle(::core::clone::Clone::clone(__self_0)),
}
}
}Clone)]
382pub(crate) enum NamedMatch {
383 MatchedSeq(Vec<NamedMatch>),
384 MatchedSingle(ParseNtResult),
385}
386387impl NamedMatch {
388pub(super) fn is_repeatable(&self) -> bool {
389match self {
390 NamedMatch::MatchedSeq(_) => true,
391 NamedMatch::MatchedSingle(_) => false,
392 }
393 }
394}
395396/// Performs a token equality check, ignoring syntax context (that is, an unhygienic comparison)
397fn token_name_eq(t1: &Token, t2: &Token) -> bool {
398if let (Some((ident1, is_raw1)), Some((ident2, is_raw2))) = (t1.ident(), t2.ident()) {
399ident1.name == ident2.name && is_raw1 == is_raw2400 } else if let (Some((ident1, is_raw1)), Some((ident2, is_raw2))) =
401 (t1.lifetime(), t2.lifetime())
402 {
403ident1.name == ident2.name && is_raw1 == is_raw2404 } else {
405// Note: we SHOULD NOT use `t1.kind == t2.kind` here, and we should instead compare the
406 // tokens using the special comparison logic below.
407 // It makes sure that variants containing `InvisibleOrigin` will
408 // never compare equal to one another.
409 //
410 // When we had AST-based nonterminals we couldn't compare them, and the
411 // old `Nonterminal` type had an `eq` that always returned false,
412 // resulting in this restriction:
413 // <https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment>
414 // This comparison logic emulates that behaviour. We could consider lifting this
415 // restriction now but there are still cases involving invisible
416 // delimiters that make it harder than it first appears.
417match (t1.kind, t2.kind) {
418 (TokenKind::OpenInvisible(_) | TokenKind::CloseInvisible(_), _)
419 | (_, TokenKind::OpenInvisible(_) | TokenKind::CloseInvisible(_)) => false,
420 (a, b) => a == b,
421 }
422 }
423}
424425// Note: the vectors could be created and dropped within `parse_tt`, but to avoid excess
426// allocations we have a single vector for each kind that is cleared and reused repeatedly.
427pub(crate) struct TtParser {
428/// The set of current mps to be processed. This should be empty by the end of a successful
429 /// execution of `parse_tt_inner`.
430cur_mps: Vec<MatcherPos>,
431432/// The set of newly generated mps. These are used to replenish `cur_mps` in the function
433 /// `parse_tt`.
434next_mps: Vec<MatcherPos>,
435436/// Pre-allocate an empty match array, so it can be cloned cheaply for macros with many rules
437 /// that have no metavars.
438empty_matches: Rc<Vec<NamedMatch>>,
439440/// Whether an ambiguity error has occurred.
441found_ambiguity: bool,
442}
443444impl TtParser {
445pub(super) fn new() -> TtParser {
446TtParser {
447 cur_mps: ::alloc::vec::Vec::new()vec![],
448 next_mps: ::alloc::vec::Vec::new()vec![],
449 empty_matches: Rc::new(::alloc::vec::Vec::new()vec![]),
450 found_ambiguity: false,
451 }
452 }
453454pub(super) fn has_no_remaining_items_for_step(&self) -> bool {
455self.cur_mps.is_empty()
456 }
457458/// Process the matcher positions of `cur_mps` until it is empty. In the process, this will
459 /// produce more mps in `next_mps` and `bb_mps`.
460 ///
461 /// # Returns
462 ///
463 /// `Some(result)` if everything is finished, `None` otherwise. Note that matches are kept
464 /// track of through the mps generated.
465fn parse_tt_inner<'matcher, T: Tracker<'matcher>>(
466&mut self,
467 parser: &mut Cow<'_, Parser<'_>>,
468 matcher: &'matcher [MatcherLoc],
469 track: &mut T,
470 ) -> Option<NamedParseResult> {
471while let Some(mp) = self.cur_mps.pop() {
472if let Some(result) = self.match_one(parser, matcher, mp, track, false) {
473return Some(result);
474 }
475 }
476477// FIXME: Error messages here could be improved with links to original rules.
478479if self.next_mps.is_empty() {
480// There are no possible next positions: syntax error.
481track.failure(parser);
482return Some(Failure);
483 }
484485// Dump all possible `next_mps` into `cur_mps` for the next iteration. Then
486 // process the next token.
487self.cur_mps.append(&mut self.next_mps);
488parser.to_mut().bump();
489490None491 }
492493/// Match a single [`MatcherPos`].
494 ///
495 /// If a meta-variable is encountered and `checking_for_ambiguity` is `false`, `cur_mps` will be
496 /// drained to eagerly check for ambiguity, and `parser` will be modified.
497#[inline(always)] // must be inlined in `parse_tt_inner()`
498fn match_one<'matcher, T: Tracker<'matcher>>(
499&mut self,
500 parser: &mut Cow<'_, Parser<'_>>,
501 matcher: &'matcher [MatcherLoc],
502mut mp: MatcherPos,
503 track: &mut T,
504 checking_for_ambiguity: bool,
505 ) -> Option<NamedParseResult> {
506let matcher_loc = &matcher[mp.idx];
507track.before_match_loc(self, matcher_loc);
508let token = &parser.token;
509510match matcher_loc {
511 MatcherLoc::Token { token: t } => {
512// If it's a doc comment, we just ignore it and move on to the next tt in the
513 // matcher. This is a bug, but #95267 showed that existing programs rely on this
514 // behaviour, and changing it would require some care and a transition period.
515 //
516 // If the token matches, we can just advance the parser.
517 //
518 // Otherwise, this match has failed, there is nothing to do, and hopefully another
519 // mp in `cur_mps` will match.
520if #[allow(non_exhaustive_omitted_patterns)] match t {
Token { kind: DocComment(..), .. } => true,
_ => false,
}matches!(t, Token { kind: DocComment(..), .. }) {
521mp.idx += 1;
522self.cur_mps.push(mp);
523 } else if token_name_eq(t, token) {
524track.matched_one(parser, mp.idx);
525mp.idx += 1;
526self.next_mps.push(mp);
527 }
528 }
529 MatcherLoc::Delimited => {
530// Entering the delimiter is trivial.
531mp.idx += 1;
532self.cur_mps.push(mp);
533 }
534&MatcherLoc::Sequence {
535 op,
536 num_metavar_decls,
537 idx_first_after,
538 next_metavar,
539 seq_depth,
540 } => {
541// Install an empty vec for each metavar within the sequence.
542for metavar_idx in next_metavar..next_metavar + num_metavar_decls {
543 mp.push_match(metavar_idx, seq_depth, MatchedSeq(::alloc::vec::Vec::new()vec![]));
544 }
545546if #[allow(non_exhaustive_omitted_patterns)] match op {
KleeneOp::ZeroOrMore | KleeneOp::ZeroOrOne => true,
_ => false,
}matches!(op, KleeneOp::ZeroOrMore | KleeneOp::ZeroOrOne) {
547// Try zero matches of this sequence, by skipping over it.
548self.cur_mps
549 .push(MatcherPos { idx: idx_first_after, matches: Rc::clone(&mp.matches) });
550 }
551552// Try one or more matches of this sequence, by entering it.
553mp.idx += 1;
554self.cur_mps.push(mp);
555 }
556&MatcherLoc::SequenceKleeneOpNoSep { op, idx_first } => {
557// We are past the end of a sequence with no separator. Try ending the sequence. If
558 // that's not possible, `ending_mp` will fail quietly when it is processed next time
559 // around the loop.
560let ending_mp = MatcherPos {
561 idx: mp.idx + 1, // +1 skips the Kleene op
562matches: Rc::clone(&mp.matches),
563 };
564self.cur_mps.push(ending_mp);
565566if op != KleeneOp::ZeroOrOne {
567// Try another repetition.
568mp.idx = idx_first;
569self.cur_mps.push(mp);
570 }
571 }
572 MatcherLoc::SequenceSep { separator } => {
573// We are past the end of a sequence with a separator but we haven't seen the
574 // separator yet. Try ending the sequence. If that's not possible, `ending_mp` will
575 // fail quietly when it is processed next time around the loop.
576let ending_mp = MatcherPos {
577 idx: mp.idx + 2, // +2 skips the separator and the Kleene op
578matches: Rc::clone(&mp.matches),
579 };
580self.cur_mps.push(ending_mp);
581582if token_name_eq(token, separator) {
583// The separator matches the current token. Advance past it.
584track.matched_one(parser, mp.idx);
585mp.idx += 1;
586self.next_mps.push(mp);
587 }
588 }
589&MatcherLoc::SequenceKleeneOpAfterSep { idx_first } => {
590// We are past the sequence separator. This can't be a `?` Kleene op, because they
591 // don't permit separators. Try another repetition.
592mp.idx = idx_first;
593self.cur_mps.push(mp);
594 }
595&MatcherLoc::MetaVarDecl { kind, next_metavar, seq_depth, .. } => {
596// Built-in nonterminals never start with these tokens, so we can eliminate them
597 // from consideration. We use the span of the metavariable declaration to determine
598 // any edition-specific matching behavior for non-terminals.
599if !Parser::nonterminal_may_begin_with(kind, token) {
600return None;
601 }
602603// EOF tokens would cause unexpected processing in `match_one()`.
604if true {
if !(parser.token != token::Eof) {
{
::core::panicking::panic_fmt(format_args!("{0:?} should not accept EOF tokens",
kind));
}
};
};debug_assert!(parser.token != token::Eof, "{kind:?} should not accept EOF tokens");
605606track.matched_one(parser, mp.idx);
607608if let ControlFlow::Break(result) =
609self.check_for_ambiguity(parser, matcher, track, checking_for_ambiguity)
610 {
611return result;
612 }
613614// We use the span of the metavariable declaration to determine any
615 // edition-specific matching behavior for non-terminals.
616let nt = match parser.to_mut().parse_nonterminal(kind) {
617Err(err) => return Some(self.nt_parsing_error(matcher_loc, err)),
618Ok(nt) => nt,
619 };
620mp.push_match(next_metavar, seq_depth, MatchedSingle(nt));
621622mp.idx += 1;
623self.cur_mps.push(mp);
624 }
625 MatcherLoc::Eof => {
626// We are past the matcher's end, and not in a sequence. Try to end things.
627if true {
{
match (&mp.idx, &(matcher.len() - 1)) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};
};debug_assert_eq!(mp.idx, matcher.len() - 1);
628629if *token != token::Eof {
630return None;
631 }
632633track.matched_one(parser, mp.idx);
634635if let ControlFlow::Break(result) =
636self.check_for_ambiguity(parser, matcher, track, checking_for_ambiguity)
637 {
638return result;
639 }
640641let matches = Rc::unwrap_or_clone(mp.matches).into_iter();
642return Some(Success(self.nameize(matcher, matches)));
643 }
644 }
645646None647 }
648649/// Look for ambiguity before parsing a non-terminal.
650 ///
651 /// - When `checking_for_ambiguity`: immediately an ambiguity error.
652 /// - Otherwise: eagerly consumes [`Self::cur_mps`] to check for ambiguity.
653 ///
654 /// If [`ControlFlow::Continue`] is returned, ambiguity has not been detected.
655fn check_for_ambiguity<'matcher, R, T: Tracker<'matcher>>(
656&mut self,
657 parser: &mut Cow<'_, Parser<'_>>,
658 matcher: &'matcher [MatcherLoc],
659 track: &mut T,
660 checking_for_ambiguity: bool,
661 ) -> ControlFlow<Option<ParseResult<R>>> {
662if checking_for_ambiguity {
663// This was called in the context of a _different_ `MatcherLoc` that was about to be
664 // matched. Prevent the caller from doing more work, but don't prepare the actual error
665 // yet; let the outer `check_for_ambiguity()` do that.
666self.found_ambiguity = true;
667return ControlFlow::Break(None);
668 }
669670if !!self.found_ambiguity {
::core::panicking::panic("assertion failed: !self.found_ambiguity")
};assert!(!self.found_ambiguity);
671672// Consume all pending mps at the current input position.
673while let Some(mp) = self.cur_mps.pop() {
674let result = self.match_one(parser, matcher, mp, track, true);
675// A result cannot be returned when `check_for_ambiguity` is `true`.
676if !result.is_none() {
::core::panicking::panic("assertion failed: result.is_none()")
};assert!(result.is_none());
677 }
678679if std::mem::take(&mut self.found_ambiguity) || !self.next_mps.is_empty() {
680track.ambiguity(parser);
681 ControlFlow::Break(Some(Ambiguity))
682 } else {
683 ControlFlow::Continue(())
684 }
685 }
686687/// Match the token stream from `parser` against `matcher`.
688pub(super) fn parse_tt<'matcher, T: Tracker<'matcher>>(
689&mut self,
690 parser: &mut Cow<'_, Parser<'_>>,
691 matcher: &'matcher [MatcherLoc],
692 track: &mut T,
693 ) -> NamedParseResult {
694// A queue of possible matcher positions. We initialize it with the matcher position in
695 // which the "dot" is before the first token of the first token tree in `matcher`.
696 // `parse_tt_inner` then processes all of these possible matcher positions and produces
697 // possible next positions into `next_mps`. After some post-processing, the contents of
698 // `next_mps` replenish `cur_mps` and we start over again.
699self.cur_mps.clear();
700self.cur_mps.push(MatcherPos { idx: 0, matches: Rc::clone(&self.empty_matches) });
701702loop {
703if !!self.cur_mps.is_empty() {
::core::panicking::panic("assertion failed: !self.cur_mps.is_empty()")
};assert!(!self.cur_mps.is_empty());
704self.next_mps.clear();
705706// Parse all mps at the current input position, then progress the parser.
707let res = self.parse_tt_inner(parser, matcher, track);
708709if let Some(res) = res {
710return res;
711 }
712 }
713 }
714715fn nt_parsing_error<R>(&self, loc: &MatcherLoc, err: Diag<'_>) -> ParseResult<R> {
716let &MatcherLoc::MetaVarDecl { span, kind, .. } = locelse { ::core::panicking::panic("internal error: entered unreachable code")unreachable!() };
717let guarantee = err718 .with_span_label(
719span,
720::alloc::__export::must_use({
::alloc::fmt::format(format_args!("while parsing argument for this `{0}` macro fragment",
kind))
})format!("while parsing argument for this `{kind}` macro fragment"),
721 )
722 .emit();
723ErrorReported(guarantee)
724 }
725726fn nameize<I: Iterator<Item = NamedMatch>>(
727&self,
728 matcher: &[MatcherLoc],
729mut res: I,
730 ) -> NamedMatches {
731// Make that each metavar has _exactly one_ binding. If so, insert the binding into the
732 // `NamedParseResult`. Otherwise, it's an error.
733let mut ret_val = FxHashMap::default();
734for loc in matcher {
735if let &MatcherLoc::MetaVarDecl { span, bind, .. } = loc
736 && ret_val
737 .insert(MacroRulesNormalizedIdent::new(bind), res.next().unwrap())
738 .is_some()
739 {
740// Duplicate binds are checked for when the macro definition is processed,
741 // and should have prevented the definition from ever being used.
742::rustc_middle::util::bug::span_bug_fmt(span,
format_args!("duplicate meta-variable binding went undetected at macro definition"))span_bug!(
743 span,
744"duplicate meta-variable binding went undetected at macro definition"
745)746 }
747 }
748ret_val749 }
750}