summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGreg Brown <gmb60@cam.ac.uk>2021-01-30 13:49:28 +0000
committerGreg Brown <gmb60@cam.ac.uk>2021-02-03 14:30:16 +0000
commit3f30676b59d69b1d658f734db458fd06e6b3ed75 (patch)
tree93c63327822dc8610f66dd05a1887b49da8ee8fd
parent228e7a26f692334bc09d533cfa975a3738233f59 (diff)
Add convenience methods for hand-writing parsers.
-rw-r--r--chewed/src/parse.rs75
1 files changed, 75 insertions, 0 deletions
diff --git a/chewed/src/parse.rs b/chewed/src/parse.rs
index 2d01757..3d37739 100644
--- a/chewed/src/parse.rs
+++ b/chewed/src/parse.rs
@@ -44,6 +44,81 @@ pub trait Parser {
Ok(())
}
+
+ fn skip_while<F: FnMut(char) -> bool>(&mut self, mut f: F) {
+ while self.peek().map_or(false, &mut f) {
+ self.next();
+ }
+ }
+
+ fn take_chars_from(&mut self, set: &'static [char], buffer: &mut [char]) -> Result<(), TakeError> {
+ for pos in buffer {
+ match self.next() {
+ None => return Err(TakeError::EndOfStream(self.pos())),
+ Some(c) if set.contains(&c) => *pos = c,
+ Some(c) => return Err(TakeError::BadBranch(self.pos(), c, set))
+ }
+ }
+
+ Ok(())
+ }
+
+ fn iter_strict<F: FnMut(&mut Self) -> Result<R, TakeError>, R>(
+ &mut self,
+ item_parse: F,
+ sep: char,
+ stop: char,
+ sep_stop_set: &'static [char],
+ first: &'static [char],
+ ) -> Iter<Self, F> {
+ Iter {
+ iter: self,
+ parse: item_parse,
+ strict_sep: true,
+ sep,
+ stop,
+ sep_stop_set,
+ first,
+ }
+ }
+}
+
+pub struct Iter<'a, P: ?Sized, F> {
+ iter: &'a mut P,
+ parse: F,
+ strict_sep: bool,
+ sep: char,
+ stop: char,
+ sep_stop_set: &'static [char],
+ first: &'static [char],
+}
+
+impl<P: Parser + ?Sized, F: FnMut(&mut P) -> Result<R, TakeError>, R> Iterator for Iter<'_, P, F> {
+ type Item = Result<R, TakeError>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let c = self.iter.peek()?;
+ if c == self.stop {
+ None
+ } else {
+ let res = (self.parse)(self.iter).map(Some).transpose()?;
+
+ match self.iter.peek() {
+ None => Some(Err(TakeError::EndOfStream(self.iter.pos()))),
+ Some(c) if c == self.sep => {
+ self.next();
+ match self.iter.peek() {
+ None => Some(Err(TakeError::EndOfStream(self.iter.pos()))),
+ Some(c) if self.first.contains(&c) => Some(res),
+ Some(c) if !self.strict_sep && c == self.stop => Some(res),
+ Some(c) => Some(Err(TakeError::BadBranch(self.iter.pos(), c, self.first))),
+ }
+ }
+ Some(c) if c == self.stop => Some(res),
+ Some(c) => Some(Err(TakeError::BadBranch(self.iter.pos(), c, self.sep_stop_set)))
+ }
+ }
+ }
}
pub struct IterWrapper<T: ?Sized> {