Mike Gerwitz

Activist for User Freedom

aboutsummaryrefslogtreecommitdiffstats
path: root/tamer
diff options
context:
space:
mode:
authorMike Gerwitz <mike.gerwitz@ryansg.com>2022-03-22 10:10:59 -0400
committerMike Gerwitz <mike.gerwitz@ryansg.com>2022-03-22 10:10:59 -0400
commitf6957ff0286215bf091ee7d3d36e62ff61916c07 (patch)
tree40a4d89fbd3060b80cef378d61377560eab7b314 /tamer
parentceb00c4df56b8d41a288f1b81e966e84f62cd8eb (diff)
downloadtame-f6957ff0286215bf091ee7d3d36e62ff61916c07.tar.gz
tame-f6957ff0286215bf091ee7d3d36e62ff61916c07.tar.bz2
tame-f6957ff0286215bf091ee7d3d36e62ff61916c07.zip
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-10863
Diffstat (limited to 'tamer')
-rw-r--r--tamer/src/parse.rs77
1 files changed, 43 insertions, 34 deletions
diff --git a/tamer/src/parse.rs b/tamer/src/parse.rs
index 55ed993..0b95e21 100644
--- a/tamer/src/parse.rs
+++ b/tamer/src/parse.rs
@@ -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,
-
- // 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())),
- }
- }
+ None => match self.assert_accepting() {
+ Ok(()) => None,
+ Err(e) => Some(Err(e)),
+ },
+
+ Some(tok) => Some(self.feed_tok(tok)),
}
}
}