tamer: parse::Parser: Extract logic from Iterator impl
This introduces a (still-private) way to _push_ tokens into the parser, rather than relying purely on a pull-based interface. Not only does this simplify the iterator, but this is also preparing to make the new `feed_tok` public so that parsers can be composed in more contexts. I suspect that this method may also be useful for error recovery, since it can be used to inject tokens into arbitrary points of a token stream. I kept the new method private for now so that I can introduce the new API and docs separate from this refactoring. DEV-10863main
parent
ceb00c4df5
commit
f6957ff028
|
@ -239,11 +239,47 @@ impl<S: ParseState, I: TokenStream<S::Token>> Parser<S, I> {
|
|||
pub fn finalize(
|
||||
self,
|
||||
) -> Result<(), (Self, ParseError<S::Token, S::Error>)> {
|
||||
self.assert_accepting().map_err(|err| (self, err))
|
||||
}
|
||||
|
||||
/// Return [`Ok`] if the parser is in an accepting state,
|
||||
/// otherwise [`Err`] with [`ParseError::UnexpectedEof`].
|
||||
///
|
||||
/// See [`finalize`](Self::finalize) for the public-facing method.
|
||||
fn assert_accepting(&self) -> Result<(), ParseError<S::Token, S::Error>> {
|
||||
if self.state.is_accepting() {
|
||||
Ok(())
|
||||
} else {
|
||||
let span = self.last_span.and_then(|s| s.endpoints().1);
|
||||
Err((self, ParseError::UnexpectedEof(span)))
|
||||
Err(ParseError::UnexpectedEof(span))
|
||||
}
|
||||
}
|
||||
|
||||
/// Feed an input token to the parser.
|
||||
///
|
||||
/// This _pushes_ data into the parser,
|
||||
/// rather than the typical pull system used by [`Parser`]'s
|
||||
/// [`Iterator`] implementation.
|
||||
/// The pull system also uses this method to provided data to the
|
||||
/// parser.
|
||||
fn feed_tok(&mut self, tok: S::Token) -> ParsedResult<S> {
|
||||
// Store the most recently encountered Span for error
|
||||
// reporting in case we encounter an EOF.
|
||||
self.last_span = Some(tok.span());
|
||||
|
||||
let result;
|
||||
(Transition(self.state), result) =
|
||||
take(&mut self.state).parse_token(tok);
|
||||
|
||||
use ParseStatus::*;
|
||||
match result {
|
||||
// Nothing handled this dead state,
|
||||
// and we cannot discard a lookahead token,
|
||||
// so we have no choice but to produce an error.
|
||||
Ok(Dead(invalid)) => Err(ParseError::UnexpectedToken(invalid)),
|
||||
|
||||
Ok(parsed @ (Incomplete | Object(..))) => Ok(parsed.into()),
|
||||
Err(e) => Err(e.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -268,39 +304,12 @@ impl<S: ParseState, I: TokenStream<S::Token>> Iterator for Parser<S, I> {
|
|||
let otok = self.toks.next();
|
||||
|
||||
match otok {
|
||||
None if self.state.is_accepting() => None,
|
||||
None => match self.assert_accepting() {
|
||||
Ok(()) => None,
|
||||
Err(e) => Some(Err(e)),
|
||||
},
|
||||
|
||||
// The EOF occurred at the end of the last encountered span,
|
||||
// if any.
|
||||
None => Some(Err(ParseError::UnexpectedEof(
|
||||
self.last_span.and_then(|s| s.endpoints().1),
|
||||
))),
|
||||
|
||||
Some(tok) => {
|
||||
// Store the most recently encountered Span for error
|
||||
// reporting in case we encounter an EOF.
|
||||
self.last_span = Some(tok.span());
|
||||
|
||||
let result;
|
||||
(Transition(self.state), result) =
|
||||
take(&mut self.state).parse_token(tok);
|
||||
|
||||
use ParseStatus::*;
|
||||
match result {
|
||||
// Nothing handled this dead state,
|
||||
// and we cannot discard a lookahead token,
|
||||
// so we have no choice but to produce an error.
|
||||
Ok(Dead(invalid)) => {
|
||||
Some(Err(ParseError::UnexpectedToken(invalid)))
|
||||
}
|
||||
|
||||
Ok(parsed @ (Incomplete | Object(..))) => {
|
||||
Some(Ok(parsed.into()))
|
||||
}
|
||||
|
||||
Err(e) => Some(Err(e.into())),
|
||||
}
|
||||
}
|
||||
Some(tok) => Some(self.feed_tok(tok)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue