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:
parent
643ba50004
commit
e5f3fd6250
@ -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,
|
||||||
|
Loading…
Reference in New Issue
Block a user