Move the missing fragment identifier checking.
In #95555 this was moved out of `parse_tt_inner` and `nameize` into `compute_locs`. But the next commit will be moving `compute_locs` outwards to a place that isn't suitable for the missing fragment identifier checking. So this reinstates the old checking.
This commit is contained in:
parent
896d8f5905
commit
7300bd6a38
1 changed files with 58 additions and 47 deletions
|
@ -131,7 +131,7 @@ enum MatcherLoc {
|
|||
MetaVarDecl {
|
||||
span: Span,
|
||||
bind: Ident,
|
||||
kind: NonterminalKind,
|
||||
kind: Option<NonterminalKind>,
|
||||
next_metavar: usize,
|
||||
seq_depth: usize,
|
||||
},
|
||||
|
@ -337,18 +337,14 @@ impl TtParser {
|
|||
/// recursive. This conversion is fairly cheap and the representation is sufficiently better
|
||||
/// for matching than `&[TokenTree]` that it's a clear performance win even with the overhead.
|
||||
/// But it might be possible to move the conversion outwards so it only occurs once per macro.
|
||||
fn compute_locs(
|
||||
&mut self,
|
||||
sess: &ParseSess,
|
||||
matcher: &[TokenTree],
|
||||
) -> Result<usize, (Span, String)> {
|
||||
fn compute_locs(&mut self, sess: &ParseSess, matcher: &[TokenTree]) -> usize {
|
||||
fn inner(
|
||||
sess: &ParseSess,
|
||||
tts: &[TokenTree],
|
||||
locs: &mut Vec<MatcherLoc>,
|
||||
next_metavar: &mut usize,
|
||||
seq_depth: usize,
|
||||
) -> Result<(), (Span, String)> {
|
||||
) {
|
||||
for tt in tts {
|
||||
match tt {
|
||||
TokenTree::Token(token) => {
|
||||
|
@ -356,7 +352,7 @@ impl TtParser {
|
|||
}
|
||||
TokenTree::Delimited(_, delimited) => {
|
||||
locs.push(MatcherLoc::Delimited);
|
||||
inner(sess, &delimited.all_tts, locs, next_metavar, seq_depth)?;
|
||||
inner(sess, &delimited.all_tts, locs, next_metavar, seq_depth);
|
||||
}
|
||||
TokenTree::Sequence(_, seq) => {
|
||||
// We can't determine `idx_first_after` and construct the final
|
||||
|
@ -370,7 +366,7 @@ impl TtParser {
|
|||
let op = seq.kleene.op;
|
||||
let idx_first = locs.len();
|
||||
let idx_seq = idx_first - 1;
|
||||
inner(sess, &seq.tts, locs, next_metavar, seq_depth + 1)?;
|
||||
inner(sess, &seq.tts, locs, next_metavar, seq_depth + 1);
|
||||
|
||||
if let Some(separator) = &seq.separator {
|
||||
locs.push(MatcherLoc::SequenceSep { separator: separator.clone() });
|
||||
|
@ -389,40 +385,29 @@ impl TtParser {
|
|||
};
|
||||
}
|
||||
&TokenTree::MetaVarDecl(span, bind, kind) => {
|
||||
if let Some(kind) = kind {
|
||||
locs.push(MatcherLoc::MetaVarDecl {
|
||||
span,
|
||||
bind,
|
||||
kind,
|
||||
next_metavar: *next_metavar,
|
||||
seq_depth,
|
||||
});
|
||||
*next_metavar += 1;
|
||||
} else if sess
|
||||
.missing_fragment_specifiers
|
||||
.borrow_mut()
|
||||
.remove(&span)
|
||||
.is_some()
|
||||
{
|
||||
// E.g. `$e` instead of `$e:expr`.
|
||||
return Err((span, "missing fragment specifier".to_string()));
|
||||
}
|
||||
locs.push(MatcherLoc::MetaVarDecl {
|
||||
span,
|
||||
bind,
|
||||
kind,
|
||||
next_metavar: *next_metavar,
|
||||
seq_depth,
|
||||
});
|
||||
*next_metavar += 1;
|
||||
}
|
||||
TokenTree::MetaVar(..) | TokenTree::MetaVarExpr(..) => unreachable!(),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
self.locs.clear();
|
||||
let mut next_metavar = 0;
|
||||
inner(sess, matcher, &mut self.locs, &mut next_metavar, /* seq_depth */ 0)?;
|
||||
inner(sess, matcher, &mut self.locs, &mut next_metavar, /* seq_depth */ 0);
|
||||
|
||||
// A final entry is needed for eof.
|
||||
self.locs.push(MatcherLoc::Eof);
|
||||
|
||||
// This is the number of metavar decls.
|
||||
Ok(next_metavar)
|
||||
next_metavar
|
||||
}
|
||||
|
||||
/// Process the matcher positions of `cur_mps` until it is empty. In the process, this will
|
||||
|
@ -434,6 +419,7 @@ impl TtParser {
|
|||
/// track of through the mps generated.
|
||||
fn parse_tt_inner(
|
||||
&mut self,
|
||||
sess: &ParseSess,
|
||||
num_metavar_decls: usize,
|
||||
token: &Token,
|
||||
) -> Option<NamedParseResult> {
|
||||
|
@ -532,12 +518,20 @@ impl TtParser {
|
|||
mp.idx = idx_first;
|
||||
self.cur_mps.push(mp);
|
||||
}
|
||||
MatcherLoc::MetaVarDecl { kind, .. } => {
|
||||
&MatcherLoc::MetaVarDecl { span, kind, .. } => {
|
||||
// Built-in nonterminals never start with these tokens, so we can eliminate
|
||||
// them from consideration. We use the span of the metavariable declaration
|
||||
// to determine any edition-specific matching behavior for non-terminals.
|
||||
if Parser::nonterminal_may_begin_with(*kind, token) {
|
||||
self.bb_mps.push(mp);
|
||||
if let Some(kind) = kind {
|
||||
if Parser::nonterminal_may_begin_with(kind, token) {
|
||||
self.bb_mps.push(mp);
|
||||
}
|
||||
} else {
|
||||
// Both this check and the one in `nameize` are necessary, surprisingly.
|
||||
if sess.missing_fragment_specifiers.borrow_mut().remove(&span).is_some() {
|
||||
// E.g. `$e` instead of `$e:expr`.
|
||||
return Some(Error(span, "missing fragment specifier".to_string()));
|
||||
}
|
||||
}
|
||||
}
|
||||
MatcherLoc::Eof => {
|
||||
|
@ -564,7 +558,7 @@ impl TtParser {
|
|||
// Need to take ownership of the matches from within the `Lrc`.
|
||||
Lrc::make_mut(&mut eof_mp.matches);
|
||||
let matches = Lrc::try_unwrap(eof_mp.matches).unwrap().into_iter();
|
||||
self.nameize(matches)
|
||||
self.nameize(sess, matches)
|
||||
}
|
||||
EofMatcherPositions::Multiple => {
|
||||
Error(token.span, "ambiguity: multiple successful parses".to_string())
|
||||
|
@ -588,10 +582,7 @@ impl TtParser {
|
|||
parser: &mut Cow<'_, Parser<'_>>,
|
||||
matcher: &[TokenTree],
|
||||
) -> NamedParseResult {
|
||||
let num_metavar_decls = match self.compute_locs(parser.sess, matcher) {
|
||||
Ok(num_metavar_decls) => num_metavar_decls,
|
||||
Err((span, msg)) => return Error(span, msg),
|
||||
};
|
||||
let num_metavar_decls = self.compute_locs(parser.sess, matcher);
|
||||
|
||||
// A queue of possible matcher positions. We initialize it with the matcher position in
|
||||
// which the "dot" is before the first token of the first token tree in `matcher`.
|
||||
|
@ -607,7 +598,7 @@ impl TtParser {
|
|||
|
||||
// Process `cur_mps` until either we have finished the input or we need to get some
|
||||
// parsing from the black-box parser done.
|
||||
if let Some(res) = self.parse_tt_inner(num_metavar_decls, &parser.token) {
|
||||
if let Some(res) = self.parse_tt_inner(&parser.sess, num_metavar_decls, &parser.token) {
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -637,7 +628,11 @@ impl TtParser {
|
|||
let mut mp = self.bb_mps.pop().unwrap();
|
||||
let loc = &self.locs[mp.idx];
|
||||
if let &MatcherLoc::MetaVarDecl {
|
||||
span, kind, next_metavar, seq_depth, ..
|
||||
span,
|
||||
kind: Some(kind),
|
||||
next_metavar,
|
||||
seq_depth,
|
||||
..
|
||||
} = loc
|
||||
{
|
||||
// We use the span of the metavariable declaration to determine any
|
||||
|
@ -682,7 +677,9 @@ impl TtParser {
|
|||
.bb_mps
|
||||
.iter()
|
||||
.map(|mp| match &self.locs[mp.idx] {
|
||||
MatcherLoc::MetaVarDecl { bind, kind, .. } => format!("{} ('{}')", kind, bind),
|
||||
MatcherLoc::MetaVarDecl { bind, kind: Some(kind), .. } => {
|
||||
format!("{} ('{}')", kind, bind)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
})
|
||||
.collect::<Vec<String>>()
|
||||
|
@ -702,16 +699,30 @@ impl TtParser {
|
|||
)
|
||||
}
|
||||
|
||||
fn nameize<I: Iterator<Item = NamedMatch>>(&self, mut res: I) -> NamedParseResult {
|
||||
fn nameize<I: Iterator<Item = NamedMatch>>(
|
||||
&self,
|
||||
sess: &ParseSess,
|
||||
mut res: I,
|
||||
) -> NamedParseResult {
|
||||
// Make that each metavar has _exactly one_ binding. If so, insert the binding into the
|
||||
// `NamedParseResult`. Otherwise, it's an error.
|
||||
let mut ret_val = FxHashMap::default();
|
||||
for loc in self.locs.iter() {
|
||||
if let &MatcherLoc::MetaVarDecl { span, bind, .. } = loc {
|
||||
match ret_val.entry(MacroRulesNormalizedIdent::new(bind)) {
|
||||
Vacant(spot) => spot.insert(res.next().unwrap()),
|
||||
Occupied(..) => return Error(span, format!("duplicated bind name: {}", bind)),
|
||||
};
|
||||
if let &MatcherLoc::MetaVarDecl { span, bind, kind, .. } = loc {
|
||||
if kind.is_some() {
|
||||
match ret_val.entry(MacroRulesNormalizedIdent::new(bind)) {
|
||||
Vacant(spot) => spot.insert(res.next().unwrap()),
|
||||
Occupied(..) => {
|
||||
return Error(span, format!("duplicated bind name: {}", bind));
|
||||
}
|
||||
};
|
||||
} else {
|
||||
// Both this check and the one in `parse_tt_inner` are necessary, surprisingly.
|
||||
if sess.missing_fragment_specifiers.borrow_mut().remove(&span).is_some() {
|
||||
// E.g. `$e` instead of `$e:expr`.
|
||||
return Error(span, "missing fragment specifier".to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Success(ret_val)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue