Use a better return type for inner_parse_loop.

Because `inner_parse_loop` has only one way to not succeed, not three.
This commit is contained in:
Nicholas Nethercote 2022-03-03 11:10:21 +11:00
parent 643ba50004
commit e5f3fd6250

View File

@ -266,6 +266,12 @@ fn deref_mut(&mut self) -> &mut MatcherPos<'root, 'tt> {
} }
} }
enum EofItems<'root, 'tt> {
None,
One(MatcherPosHandle<'root, 'tt>),
Multiple,
}
/// Represents the possible results of an attempted parse. /// Represents the possible results of an attempted parse.
crate enum ParseResult<T> { crate enum ParseResult<T> {
/// Parsed successfully. /// Parsed successfully.
@ -449,10 +455,10 @@ fn inner_parse_loop<'root, 'tt>(
sess: &ParseSess, sess: &ParseSess,
cur_items: &mut SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>, cur_items: &mut SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>,
next_items: &mut Vec<MatcherPosHandle<'root, 'tt>>, next_items: &mut Vec<MatcherPosHandle<'root, 'tt>>,
eof_items: &mut SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>,
bb_items: &mut SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>, bb_items: &mut SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>,
eof_items: &mut EofItems<'root, 'tt>,
token: &Token, token: &Token,
) -> ParseResult<()> { ) -> Result<(), (rustc_span::Span, String)> {
// Pop items from `cur_items` until it is empty. // Pop items from `cur_items` until it is empty.
while let Some(mut item) = cur_items.pop() { while let Some(mut item) = cur_items.pop() {
// When unzipped trees end, remove them. This corresponds to backtracking out of a // When unzipped trees end, remove them. This corresponds to backtracking out of a
@ -522,7 +528,10 @@ fn inner_parse_loop<'root, 'tt>(
} else { } else {
// If we are not in a repetition, then being at the end of a matcher means that we // If we are not in a repetition, then being at the end of a matcher means that we
// have reached the potential end of the input. // have reached the potential end of the input.
eof_items.push(item); *eof_items = match eof_items {
EofItems::None => EofItems::One(item),
EofItems::One(_) | EofItems::Multiple => EofItems::Multiple,
}
} }
} else { } else {
// We are in the middle of a matcher. Look at what token in the matcher we are trying // We are in the middle of a matcher. Look at what token in the matcher we are trying
@ -567,7 +576,7 @@ fn inner_parse_loop<'root, 'tt>(
// We need to match a metavar (but the identifier is invalid)... this is an error // We need to match a metavar (but the identifier is invalid)... this is an error
TokenTree::MetaVarDecl(span, _, None) => { TokenTree::MetaVarDecl(span, _, None) => {
if sess.missing_fragment_specifiers.borrow_mut().remove(&span).is_some() { if sess.missing_fragment_specifiers.borrow_mut().remove(&span).is_some() {
return Error(span, "missing fragment specifier".to_string()); return Err((span, "missing fragment specifier".to_string()));
} }
} }
@ -615,7 +624,7 @@ fn inner_parse_loop<'root, 'tt>(
} }
// Yay a successful parse (so far)! // Yay a successful parse (so far)!
Success(()) Ok(())
} }
/// Use the given sequence of token trees (`ms`) as a matcher. Match the token /// Use the given sequence of token trees (`ms`) as a matcher. Match the token
@ -638,12 +647,13 @@ pub(super) fn parse_tt(
let mut next_items = Vec::new(); let mut next_items = Vec::new();
loop { loop {
assert!(next_items.is_empty());
// Matcher positions black-box parsed by parser.rs (`parser`) // Matcher positions black-box parsed by parser.rs (`parser`)
let mut bb_items = SmallVec::new(); let mut bb_items = SmallVec::new();
// Matcher positions that would be valid if the macro invocation was over now // Matcher positions that would be valid if the macro invocation was over now
let mut eof_items = SmallVec::new(); let mut eof_items = EofItems::None;
assert!(next_items.is_empty());
// Process `cur_items` until either we have finished the input or we need to get some // Process `cur_items` until either we have finished the input or we need to get some
// parsing from the black-box parser done. The result is that `next_items` will contain a // parsing from the black-box parser done. The result is that `next_items` will contain a
@ -652,34 +662,34 @@ pub(super) fn parse_tt(
parser.sess, parser.sess,
&mut cur_items, &mut cur_items,
&mut next_items, &mut next_items,
&mut eof_items,
&mut bb_items, &mut bb_items,
&mut eof_items,
&parser.token, &parser.token,
) { ) {
Success(_) => {} Ok(()) => {}
Failure(token, msg) => return Failure(token, msg), Err((sp, msg)) => return Error(sp, msg),
Error(sp, msg) => return Error(sp, msg),
ErrorReported => return ErrorReported,
} }
// inner parse loop handled all cur_items, so it's empty // inner parse loop handled all cur_items, so it's empty
assert!(cur_items.is_empty()); assert!(cur_items.is_empty());
// We need to do some post processing after the `inner_parser_loop`. // We need to do some post processing after the `inner_parse_loop`.
// //
// Error messages here could be improved with links to original rules. // Error messages here could be improved with links to original rules.
// If we reached the EOF, check that there is EXACTLY ONE possible matcher. Otherwise, // If we reached the EOF, check that there is EXACTLY ONE possible matcher. Otherwise,
// either the parse is ambiguous (which should never happen) or there is a syntax error. // either the parse is ambiguous (which should never happen) or there is a syntax error.
if parser.token == token::Eof { if parser.token == token::Eof {
return if eof_items.len() == 1 { return match eof_items {
let matches = EofItems::One(mut eof_item) => {
eof_items[0].matches.iter_mut().map(|dv| Lrc::make_mut(dv).pop().unwrap()); let matches =
nameize(parser.sess, ms, matches) eof_item.matches.iter_mut().map(|dv| Lrc::make_mut(dv).pop().unwrap());
} else if eof_items.len() > 1 { nameize(parser.sess, ms, matches)
Error(parser.token.span, "ambiguity: multiple successful parses".to_string()) }
} else { EofItems::Multiple => {
Failure( Error(parser.token.span, "ambiguity: multiple successful parses".to_string())
}
EofItems::None => Failure(
Token::new( Token::new(
token::Eof, token::Eof,
if parser.token.span.is_dummy() { if parser.token.span.is_dummy() {
@ -689,12 +699,12 @@ pub(super) fn parse_tt(
}, },
), ),
"missing tokens in macro arguments", "missing tokens in macro arguments",
) ),
}; };
} }
// Performance hack: eof_items may share matchers via Rc with other things that we want // Performance hack: `eof_items` may share matchers via `Rc` with other things that we want
// to modify. Dropping eof_items now may drop these refcounts to 1, preventing an // to modify. Dropping `eof_items` now may drop these refcounts to 1, preventing an
// 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, // If there are no possible next positions AND we aren't waiting for the black-box parser,