changeset 1:0ad857b005ae

Implement Int parser
author Lewin Bormann <lewin@lewin-bormann.info>
date Wed, 29 May 2019 23:49:47 +0200
parents 6286f0ed89a7
children 24646d806b4d
files src/parser.rs src/primitives.rs src/state.rs
diffstat 3 files changed, 61 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/src/parser.rs	Wed May 29 23:32:37 2019 +0200
+++ b/src/parser.rs	Wed May 29 23:49:47 2019 +0200
@@ -1,4 +1,3 @@
-
 use std::fmt;
 
 use crate::state::ParseState;
@@ -22,5 +21,8 @@
 
 pub trait Parser {
     type Result;
-    fn parse(&mut self, st: &mut ParseState<impl Iterator<Item=char>>) -> ParseResult<Self::Result>;
+    fn parse(
+        &mut self,
+        st: &mut ParseState<impl Iterator<Item = char>>,
+    ) -> ParseResult<Self::Result>;
 }
--- a/src/primitives.rs	Wed May 29 23:32:37 2019 +0200
+++ b/src/primitives.rs	Wed May 29 23:49:47 2019 +0200
@@ -1,12 +1,14 @@
-
+use crate::parser::{ParseError, ParseResult, Parser};
 use crate::state::ParseState;
-use crate::parser::{Parser, ParseResult, ParseError};
 
 pub struct StringParser(pub String);
 
 impl Parser for StringParser {
     type Result = String;
-    fn parse(&mut self, st: &mut ParseState<impl Iterator<Item=char>>) -> ParseResult<Self::Result> {
+    fn parse(
+        &mut self,
+        st: &mut ParseState<impl Iterator<Item = char>>,
+    ) -> ParseResult<Self::Result> {
         let mut cs = self.0.chars();
         let expect = self.0.len();
         let mut have = 0;
@@ -14,10 +16,10 @@
         loop {
             let (next, pk) = (cs.next(), st.peek());
             if next.is_none() || pk.is_none() {
-                break
+                break;
             }
             if next != pk {
-                break
+                break;
             }
             let c = st.next().unwrap();
             have += c.len_utf8();
@@ -28,10 +30,44 @@
         }
         let ix = st.index();
         st.reset(hold);
-        return Err(ParseError::Fail("string not matched", ix))
+        return Err(ParseError::Fail("string not matched", ix));
     }
 }
 
+pub struct Int;
+
+impl Parser for Int {
+    type Result = i64;
+    fn parse(
+        &mut self,
+        st: &mut ParseState<impl Iterator<Item = char>>,
+    ) -> ParseResult<Self::Result> {
+        let mut negative: i64 = 1;
+        let mut result: i64 = 0;
+
+        match st.peek() {
+            None => return Err(ParseError::EOF),
+            Some('-') => negative = -1,
+            Some(c) if c.is_digit(10) => result = result * 10 + ((c as i64) - ('0' as i64)),
+            Some(_) => return Err(ParseError::Fail("not an int", st.index())),
+        }
+        let hold = st.hold();
+        st.next();
+
+        loop {
+            match st.next() {
+                Some(c) if c.is_digit(10) => result = result * 10 + ((c as i64) - ('0' as i64)),
+                Some(_) => {
+                    st.undo_next();
+                    break;
+                }
+                None => break,
+            }
+        }
+        st.release(hold);
+        return Ok(result * negative);
+    }
+}
 
 #[cfg(test)]
 mod tests {
@@ -39,9 +75,19 @@
 
     #[test]
     fn test_parse_string() {
-        let mut s = super::ParseState::new("abc def");
+        let mut s = ParseState::new("abc def");
         let mut p = StringParser("abc ".to_owned());
         assert_eq!(Ok("abc ".to_owned()), p.parse(&mut s));
         assert_eq!(4, s.index());
     }
+
+    #[test]
+    fn test_parse_int() {
+        let mut s = ParseState::new("-1252 353");
+        let mut ip = Int;
+        let mut sp = StringParser(" ".to_string());
+        assert_eq!(Ok(-1252), ip.parse(&mut s));
+        assert_eq!(Ok(" ".to_string()), sp.parse(&mut s));
+        assert_eq!(Ok(353), ip.parse(&mut s));
+    }
 }
--- a/src/state.rs	Wed May 29 23:32:37 2019 +0200
+++ b/src/state.rs	Wed May 29 23:49:47 2019 +0200
@@ -64,7 +64,10 @@
     pub fn finished(&self) -> bool {
         self.next.is_none() && self.current == self.buf.len()
     }
-
+    pub fn undo_next(&mut self) {
+        assert!(self.current > 0);
+        self.current -= 1;
+    }
     pub fn current(&self) -> Option<Iter::Item> {
         if self.current < self.buf.len() {
             Some(self.buf[self.current])