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 {
|
MetaVarDecl {
|
||||||
span: Span,
|
span: Span,
|
||||||
bind: Ident,
|
bind: Ident,
|
||||||
kind: NonterminalKind,
|
kind: Option<NonterminalKind>,
|
||||||
next_metavar: usize,
|
next_metavar: usize,
|
||||||
seq_depth: usize,
|
seq_depth: usize,
|
||||||
},
|
},
|
||||||
|
@ -337,18 +337,14 @@ impl TtParser {
|
||||||
/// recursive. This conversion is fairly cheap and the representation is sufficiently better
|
/// 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.
|
/// 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.
|
/// But it might be possible to move the conversion outwards so it only occurs once per macro.
|
||||||
fn compute_locs(
|
fn compute_locs(&mut self, sess: &ParseSess, matcher: &[TokenTree]) -> usize {
|
||||||
&mut self,
|
|
||||||
sess: &ParseSess,
|
|
||||||
matcher: &[TokenTree],
|
|
||||||
) -> Result<usize, (Span, String)> {
|
|
||||||
fn inner(
|
fn inner(
|
||||||
sess: &ParseSess,
|
sess: &ParseSess,
|
||||||
tts: &[TokenTree],
|
tts: &[TokenTree],
|
||||||
locs: &mut Vec<MatcherLoc>,
|
locs: &mut Vec<MatcherLoc>,
|
||||||
next_metavar: &mut usize,
|
next_metavar: &mut usize,
|
||||||
seq_depth: usize,
|
seq_depth: usize,
|
||||||
) -> Result<(), (Span, String)> {
|
) {
|
||||||
for tt in tts {
|
for tt in tts {
|
||||||
match tt {
|
match tt {
|
||||||
TokenTree::Token(token) => {
|
TokenTree::Token(token) => {
|
||||||
|
@ -356,7 +352,7 @@ impl TtParser {
|
||||||
}
|
}
|
||||||
TokenTree::Delimited(_, delimited) => {
|
TokenTree::Delimited(_, delimited) => {
|
||||||
locs.push(MatcherLoc::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) => {
|
TokenTree::Sequence(_, seq) => {
|
||||||
// We can't determine `idx_first_after` and construct the final
|
// We can't determine `idx_first_after` and construct the final
|
||||||
|
@ -370,7 +366,7 @@ impl TtParser {
|
||||||
let op = seq.kleene.op;
|
let op = seq.kleene.op;
|
||||||
let idx_first = locs.len();
|
let idx_first = locs.len();
|
||||||
let idx_seq = idx_first - 1;
|
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 {
|
if let Some(separator) = &seq.separator {
|
||||||
locs.push(MatcherLoc::SequenceSep { separator: separator.clone() });
|
locs.push(MatcherLoc::SequenceSep { separator: separator.clone() });
|
||||||
|
@ -389,40 +385,29 @@ impl TtParser {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
&TokenTree::MetaVarDecl(span, bind, kind) => {
|
&TokenTree::MetaVarDecl(span, bind, kind) => {
|
||||||
if let Some(kind) = kind {
|
locs.push(MatcherLoc::MetaVarDecl {
|
||||||
locs.push(MatcherLoc::MetaVarDecl {
|
span,
|
||||||
span,
|
bind,
|
||||||
bind,
|
kind,
|
||||||
kind,
|
next_metavar: *next_metavar,
|
||||||
next_metavar: *next_metavar,
|
seq_depth,
|
||||||
seq_depth,
|
});
|
||||||
});
|
*next_metavar += 1;
|
||||||
*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()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
TokenTree::MetaVar(..) | TokenTree::MetaVarExpr(..) => unreachable!(),
|
TokenTree::MetaVar(..) | TokenTree::MetaVarExpr(..) => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.locs.clear();
|
self.locs.clear();
|
||||||
let mut next_metavar = 0;
|
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.
|
// A final entry is needed for eof.
|
||||||
self.locs.push(MatcherLoc::Eof);
|
self.locs.push(MatcherLoc::Eof);
|
||||||
|
|
||||||
// This is the number of metavar decls.
|
// 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
|
/// 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.
|
/// track of through the mps generated.
|
||||||
fn parse_tt_inner(
|
fn parse_tt_inner(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
sess: &ParseSess,
|
||||||
num_metavar_decls: usize,
|
num_metavar_decls: usize,
|
||||||
token: &Token,
|
token: &Token,
|
||||||
) -> Option<NamedParseResult> {
|
) -> Option<NamedParseResult> {
|
||||||
|
@ -532,12 +518,20 @@ impl TtParser {
|
||||||
mp.idx = idx_first;
|
mp.idx = idx_first;
|
||||||
self.cur_mps.push(mp);
|
self.cur_mps.push(mp);
|
||||||
}
|
}
|
||||||
MatcherLoc::MetaVarDecl { kind, .. } => {
|
&MatcherLoc::MetaVarDecl { span, kind, .. } => {
|
||||||
// Built-in nonterminals never start with these tokens, so we can eliminate
|
// Built-in nonterminals never start with these tokens, so we can eliminate
|
||||||
// them from consideration. We use the span of the metavariable declaration
|
// them from consideration. We use the span of the metavariable declaration
|
||||||
// to determine any edition-specific matching behavior for non-terminals.
|
// to determine any edition-specific matching behavior for non-terminals.
|
||||||
if Parser::nonterminal_may_begin_with(*kind, token) {
|
if let Some(kind) = kind {
|
||||||
self.bb_mps.push(mp);
|
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 => {
|
MatcherLoc::Eof => {
|
||||||
|
@ -564,7 +558,7 @@ impl TtParser {
|
||||||
// Need to take ownership of the matches from within the `Lrc`.
|
// Need to take ownership of the matches from within the `Lrc`.
|
||||||
Lrc::make_mut(&mut eof_mp.matches);
|
Lrc::make_mut(&mut eof_mp.matches);
|
||||||
let matches = Lrc::try_unwrap(eof_mp.matches).unwrap().into_iter();
|
let matches = Lrc::try_unwrap(eof_mp.matches).unwrap().into_iter();
|
||||||
self.nameize(matches)
|
self.nameize(sess, matches)
|
||||||
}
|
}
|
||||||
EofMatcherPositions::Multiple => {
|
EofMatcherPositions::Multiple => {
|
||||||
Error(token.span, "ambiguity: multiple successful parses".to_string())
|
Error(token.span, "ambiguity: multiple successful parses".to_string())
|
||||||
|
@ -588,10 +582,7 @@ impl TtParser {
|
||||||
parser: &mut Cow<'_, Parser<'_>>,
|
parser: &mut Cow<'_, Parser<'_>>,
|
||||||
matcher: &[TokenTree],
|
matcher: &[TokenTree],
|
||||||
) -> NamedParseResult {
|
) -> NamedParseResult {
|
||||||
let num_metavar_decls = match self.compute_locs(parser.sess, matcher) {
|
let num_metavar_decls = self.compute_locs(parser.sess, matcher);
|
||||||
Ok(num_metavar_decls) => num_metavar_decls,
|
|
||||||
Err((span, msg)) => return Error(span, msg),
|
|
||||||
};
|
|
||||||
|
|
||||||
// A queue of possible matcher positions. We initialize it with the matcher position in
|
// 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`.
|
// 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
|
// Process `cur_mps` until either we have finished the input or we need to get some
|
||||||
// parsing from the black-box parser done.
|
// 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;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -637,7 +628,11 @@ impl TtParser {
|
||||||
let mut mp = self.bb_mps.pop().unwrap();
|
let mut mp = self.bb_mps.pop().unwrap();
|
||||||
let loc = &self.locs[mp.idx];
|
let loc = &self.locs[mp.idx];
|
||||||
if let &MatcherLoc::MetaVarDecl {
|
if let &MatcherLoc::MetaVarDecl {
|
||||||
span, kind, next_metavar, seq_depth, ..
|
span,
|
||||||
|
kind: Some(kind),
|
||||||
|
next_metavar,
|
||||||
|
seq_depth,
|
||||||
|
..
|
||||||
} = loc
|
} = loc
|
||||||
{
|
{
|
||||||
// We use the span of the metavariable declaration to determine any
|
// We use the span of the metavariable declaration to determine any
|
||||||
|
@ -682,7 +677,9 @@ impl TtParser {
|
||||||
.bb_mps
|
.bb_mps
|
||||||
.iter()
|
.iter()
|
||||||
.map(|mp| match &self.locs[mp.idx] {
|
.map(|mp| match &self.locs[mp.idx] {
|
||||||
MatcherLoc::MetaVarDecl { bind, kind, .. } => format!("{} ('{}')", kind, bind),
|
MatcherLoc::MetaVarDecl { bind, kind: Some(kind), .. } => {
|
||||||
|
format!("{} ('{}')", kind, bind)
|
||||||
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
})
|
})
|
||||||
.collect::<Vec<String>>()
|
.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
|
// Make that each metavar has _exactly one_ binding. If so, insert the binding into the
|
||||||
// `NamedParseResult`. Otherwise, it's an error.
|
// `NamedParseResult`. Otherwise, it's an error.
|
||||||
let mut ret_val = FxHashMap::default();
|
let mut ret_val = FxHashMap::default();
|
||||||
for loc in self.locs.iter() {
|
for loc in self.locs.iter() {
|
||||||
if let &MatcherLoc::MetaVarDecl { span, bind, .. } = loc {
|
if let &MatcherLoc::MetaVarDecl { span, bind, kind, .. } = loc {
|
||||||
match ret_val.entry(MacroRulesNormalizedIdent::new(bind)) {
|
if kind.is_some() {
|
||||||
Vacant(spot) => spot.insert(res.next().unwrap()),
|
match ret_val.entry(MacroRulesNormalizedIdent::new(bind)) {
|
||||||
Occupied(..) => return Error(span, format!("duplicated bind name: {}", 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)
|
Success(ret_val)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue