summaryrefslogtreecommitdiff
path: root/chewed/src/parse.rs
diff options
context:
space:
mode:
authorGreg Brown <gmb60@cam.ac.uk>2021-01-06 16:36:46 +0000
committerGreg Brown <gmb60@cam.ac.uk>2021-01-06 16:36:46 +0000
commiteb280a903f8f20d0b0c0ef5acae955a20929d100 (patch)
tree5e6f38fb41c8c630d3b1e3a1990249f8a98047b8 /chewed/src/parse.rs
parentdc10a278cca74d737e4af0fe034a1caa8abb291d (diff)
Create Chewed, the consumer crate.
Diffstat (limited to 'chewed/src/parse.rs')
-rw-r--r--chewed/src/parse.rs82
1 files changed, 82 insertions, 0 deletions
diff --git a/chewed/src/parse.rs b/chewed/src/parse.rs
new file mode 100644
index 0000000..0687ea5
--- /dev/null
+++ b/chewed/src/parse.rs
@@ -0,0 +1,82 @@
+use super::error::{ParseError, TakeError};
+
+pub trait Parser: Iterator<Item = char> {
+ fn peek(&mut self) -> Option<char>;
+
+ fn take<P: Parse>(&mut self) -> Result<P, TakeError> {
+ P::take(self)
+ }
+
+ fn parse<P: Parse>(self) -> Result<P, ParseError>
+ where
+ Self: Sized,
+ {
+ P::parse(self)
+ }
+
+ fn take_str(&mut self, s: &'static str) -> Result<(), TakeError> {
+ let mut count = 0;
+
+ for exp in s.chars() {
+ if let Some(got) = self.peek() {
+ if got == exp {
+ self.next();
+ count += 1
+ } else {
+ let mut out = String::from(&s[..count]);
+ out.push(got);
+
+ return Err(TakeError::BadString(out, s));
+ }
+ } else {
+ return Err(TakeError::EndOfStream);
+ }
+ }
+
+ Ok(())
+ }
+}
+
+pub trait Parse: Sized {
+ fn take<P: Parser + ?Sized>(input: &mut P) -> Result<Self, TakeError>;
+
+ fn parse<P: Parser>(mut input: P) -> Result<Self, ParseError> {
+ let res = Self::take(&mut input)?;
+
+ if input.peek().is_some() {
+ Err(ParseError::InputContinues)
+ } else {
+ Ok(res)
+ }
+ }
+}
+
+impl Parse for () {
+ fn take<P: Parser + ?Sized>(_: &mut P) -> Result<Self, TakeError> {
+ Ok(())
+ }
+}
+
+impl<A: Parse, B: Parse> Parse for (A, B) {
+ fn take<P: Parser + ?Sized>(input: &mut P) -> Result<Self, TakeError> {
+ let a = input.take()?;
+ let b = input.take()?;
+ Ok((a, b))
+ }
+
+ fn parse<P: Parser>(mut input: P) -> Result<Self, ParseError> {
+ let a = A::take(&mut input)?;
+ let b = B::parse(input)?;
+ Ok((a, b))
+ }
+}
+
+impl<T: Parse + Sized> Parse for Box<T> {
+ fn take<P: Parser + ?Sized>(input: &mut P) -> Result<Self, TakeError> {
+ Ok(Box::new(input.take()?))
+ }
+
+ fn parse<P: Parser>(input: P) -> Result<Self, ParseError> {
+ Ok(Box::new(input.parse()?))
+ }
+}