1
Fork 0

Refactor the second half of parse_tt.

The current structure makes it hard to tell that there are just four
distinct code paths, depending on how many items there are in `bb_items`
and `next_items`. This commit introduces a `match` that clarifies
things.
This commit is contained in:
Nicholas Nethercote 2022-03-09 14:18:32 +11:00
parent 352e621368
commit 09c3e82050

View file

@ -744,70 +744,77 @@ pub(super) fn parse_tt(
// unnecessary implicit clone later in `Rc::make_mut`. // unnecessary implicit clone later in `Rc::make_mut`.
drop(eof_items); drop(eof_items);
// If there are no possible next positions AND we aren't waiting for the black-box parser, match (next_items.len(), bb_items.len()) {
// then there is a syntax error. (0, 0) => {
if bb_items.is_empty() && next_items.is_empty() { // There are no possible next positions AND we aren't waiting for the black-box
return Failure(parser.token.clone(), "no rules expected this token in macro call"); // parser: syntax error.
} return Failure(parser.token.clone(), "no rules expected this token in macro call");
}
if (!bb_items.is_empty() && !next_items.is_empty()) || bb_items.len() > 1 {
// We need to call out to parse some rust nonterminal (black-box) parser. But something (_, 0) => {
// is wrong, because there is not EXACTLY ONE of these. // Dump all possible `next_items` into `cur_items` for the next iteration. Then
let nts = bb_items // process the next token.
.iter() cur_items.extend(next_items.drain(..));
.map(|item| match item.top_elts.get_tt(item.idx) { parser.to_mut().bump();
TokenTree::MetaVarDecl(_, bind, Some(kind)) => format!("{} ('{}')", kind, bind), }
_ => panic!(),
}) (0, 1) => {
.collect::<Vec<String>>() // We need to call the black-box parser to get some nonterminal.
.join(" or "); let mut item = bb_items.pop().unwrap();
if let TokenTree::MetaVarDecl(span, _, Some(kind)) = item.top_elts.get_tt(item.idx)
return Error( {
parser.token.span, let match_cur = item.match_cur;
format!( // We use the span of the metavariable declaration to determine any
"local ambiguity when calling macro `{macro_name}`: multiple parsing options: {}", // edition-specific matching behavior for non-terminals.
match next_items.len() { let nt = match parser.to_mut().parse_nonterminal(kind) {
0 => format!("built-in NTs {}.", nts), Err(mut err) => {
1 => format!("built-in NTs {} or 1 other option.", nts), err.span_label(
n => format!("built-in NTs {} or {} other options.", nts, n), span,
} format!(
), "while parsing argument for this `{}` macro fragment",
); kind
} ),
)
if !next_items.is_empty() { .emit();
// Dump all possible `next_items` into `cur_items` for the next iteration. Then process return ErrorReported;
// the next token. }
cur_items.extend(next_items.drain(..)); Ok(nt) => nt,
parser.to_mut().bump(); };
} else { item.push_match(match_cur, MatchedNonterminal(Lrc::new(nt)));
// Finally, we have the case where we need to call the black-box parser to get some item.idx += 1;
// nonterminal. item.match_cur += 1;
assert_eq!(bb_items.len(), 1); } else {
unreachable!()
let mut item = bb_items.pop().unwrap(); }
if let TokenTree::MetaVarDecl(span, _, Some(kind)) = item.top_elts.get_tt(item.idx) { cur_items.push(item);
let match_cur = item.match_cur; }
// We use the span of the metavariable declaration to determine any
// edition-specific matching behavior for non-terminals. (_, _) => {
let nt = match parser.to_mut().parse_nonterminal(kind) { // We need to call the black-box parser to get some nonterminal, but something is
Err(mut err) => { // wrong.
err.span_label( let nts = bb_items
span, .iter()
format!("while parsing argument for this `{}` macro fragment", kind), .map(|item| match item.top_elts.get_tt(item.idx) {
) TokenTree::MetaVarDecl(_, bind, Some(kind)) => {
.emit(); format!("{} ('{}')", kind, bind)
return ErrorReported; }
} _ => panic!(),
Ok(nt) => nt, })
}; .collect::<Vec<String>>()
item.push_match(match_cur, MatchedNonterminal(Lrc::new(nt))); .join(" or ");
item.idx += 1;
item.match_cur += 1; return Error(
} else { parser.token.span,
unreachable!() format!(
"local ambiguity when calling macro `{macro_name}`: multiple parsing options: {}",
match next_items.len() {
0 => format!("built-in NTs {}.", nts),
1 => format!("built-in NTs {} or 1 other option.", nts),
n => format!("built-in NTs {} or {} other options.", nts, n),
}
),
);
} }
cur_items.push(item);
} }
assert!(!cur_items.is_empty()); assert!(!cur_items.is_empty());