diff options
author | Greg Brown <gmb60@cam.ac.uk> | 2021-01-30 13:49:28 +0000 |
---|---|---|
committer | Greg Brown <gmb60@cam.ac.uk> | 2021-02-03 14:30:16 +0000 |
commit | 3f30676b59d69b1d658f734db458fd06e6b3ed75 (patch) | |
tree | 93c63327822dc8610f66dd05a1887b49da8ee8fd | |
parent | 228e7a26f692334bc09d533cfa975a3738233f59 (diff) |
Add convenience methods for hand-writing parsers.
-rw-r--r-- | chewed/src/parse.rs | 75 |
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> { |