changeset 3:ff95584ff3c9

Implement Sequence combinator
author Lewin Bormann <lewin@lewin-bormann.info>
date Thu, 30 May 2019 11:18:31 +0200
parents 24646d806b4d
children 88dc74ffd497
files src/combinators.rs src/primitives.rs src/state.rs
diffstat 3 files changed, 98 insertions(+), 25 deletions(-) [+]
line wrap: on
line diff
--- a/src/combinators.rs	Thu May 30 00:40:34 2019 +0200
+++ b/src/combinators.rs	Thu May 30 11:18:31 2019 +0200
@@ -1,41 +1,110 @@
-use crate::parser::{ParseError, ParseResult, Parser};
+use crate::parser::{ParseResult, Parser};
 use crate::state::ParseState;
 
 pub struct Sequence<T> {
     t: T,
 }
 
-impl<P1: Parser, P2: Parser> Parser for Sequence<(P1, P2)> {
-    type Result = (P1::Result, P2::Result);
-    fn parse(
-        &mut self,
-        st: &mut ParseState<impl Iterator<Item = char>>,
-    ) -> ParseResult<Self::Result> {
-        let hold = st.hold();
-        let r1 = self.t.0.parse(st);
-        if r1.is_err() {
-            st.reset(hold);
-            return Err(r1.err().unwrap());
+impl<T> Sequence<T> {
+    pub fn new(tuple: T) -> Sequence<T> {
+        Sequence { t: tuple }
+    }
+}
+
+macro_rules! seq_impl {
+    ( ( $($ptype:ident/$ix:tt),+ ) ) => {
+        impl<$($ptype : Parser<Result=impl Default>, )*> Parser for Sequence<($($ptype,)*)> {
+            type Result = ($($ptype::Result,)*);
+            fn parse(&mut self, st: &mut ParseState<impl Iterator<Item = char>>) -> ParseResult<Self::Result> {
+                let hold = st.hold();
+                let mut result = Self::Result::default();
+                $(
+                    let r = (self.t.$ix).parse(st);
+                    if r.is_err() {
+                        st.reset(hold);
+                        return Err(r.err().unwrap());
+                    }
+                    result.$ix = r.unwrap();
+                )*
+                st.release(hold);
+                return Ok(result);
+            }
         }
-        let r2 = self.t.1.parse(st);
-        if r2.is_err() {
-            st.reset(hold);
-            return Err(r2.err().unwrap());
-        }
-        st.release(hold);
-        return Ok((r1.unwrap(), r2.unwrap()));
     }
 }
 
+seq_impl!((P0 / 0, P1 / 1));
+seq_impl!((P0 / 0, P1 / 1, P2 / 2));
+seq_impl!((P0 / 0, P1 / 1, P2 / 2, P3 / 3));
+seq_impl!((P0 / 0, P1 / 1, P2 / 2, P3 / 3, P4 / 4));
+seq_impl!((P0 / 0, P1 / 1, P2 / 2, P3 / 3, P4 / 4, P5 / 5));
+seq_impl!((P0 / 0, P1 / 1, P2 / 2, P3 / 3, P4 / 4, P5 / 5, P6 / 6));
+seq_impl!((
+    P0 / 0,
+    P1 / 1,
+    P2 / 2,
+    P3 / 3,
+    P4 / 4,
+    P5 / 5,
+    P6 / 6,
+    P7 / 7
+));
+seq_impl!((
+    P0 / 0,
+    P1 / 1,
+    P2 / 2,
+    P3 / 3,
+    P4 / 4,
+    P5 / 5,
+    P6 / 6,
+    P7 / 7,
+    P8 / 8
+));
+seq_impl!((
+    P0 / 0,
+    P1 / 1,
+    P2 / 2,
+    P3 / 3,
+    P4 / 4,
+    P5 / 5,
+    P6 / 6,
+    P7 / 7,
+    P8 / 8,
+    P9 / 9
+));
+
 #[cfg(test)]
 mod tests {
     use super::*;
+    use crate::parser::Parser;
     use crate::primitives::*;
 
     #[test]
     fn test_pair() {
-        let mut p = (Int, StringParser(" aaa".to_string()));
+        let mut p = Sequence::new((Int, StringParser::new(" aba".to_string())));
         let mut ps = ParseState::new("123 aba");
-        assert_eq!(Ok((123, " aaa".to_string())), p.parse(&mut ps));
+        assert_eq!(Ok((123, " aba".to_string())), p.parse(&mut ps));
+    }
+
+    #[test]
+    fn test_long_seq() {
+        let s = (|| StringParser::new("a"));
+        let mut p = Sequence::new((s(), s(), s(), s(), s(), s(), s(), s(), s(), s()));
+        let mut ps = ParseState::new("aaaaaaaaaa");
+        assert_eq!(
+            Ok((
+                "a".to_string(),
+                "a".to_string(),
+                "a".to_string(),
+                "a".to_string(),
+                "a".to_string(),
+                "a".to_string(),
+                "a".to_string(),
+                "a".to_string(),
+                "a".to_string(),
+                "a".to_string()
+            )),
+            p.parse(&mut ps)
+        );
     }
 }
--- a/src/primitives.rs	Thu May 30 00:40:34 2019 +0200
+++ b/src/primitives.rs	Thu May 30 11:18:31 2019 +0200
@@ -1,7 +1,11 @@
 use crate::parser::{ParseError, ParseResult, Parser};
 use crate::state::ParseState;
 
-pub struct StringParser(pub String);
+pub struct StringParser(String);
+
+impl StringParser {
+    pub fn new<S: AsRef<str>>(s: S) -> StringParser { StringParser(s.as_ref().to_owned()) }
+}
 
 impl Parser for StringParser {
     type Result = String;
@@ -76,7 +80,7 @@
     #[test]
     fn test_parse_string() {
         let mut s = ParseState::new("abc def");
-        let mut p = StringParser("abc ".to_owned());
+        let mut p = StringParser::new("abc ".to_owned());
         assert_eq!(Ok("abc ".to_owned()), p.parse(&mut s));
         assert_eq!(4, s.index());
     }
@@ -85,7 +89,7 @@
     fn test_parse_int() {
         let mut s = ParseState::new("-1252 353");
         let mut ip = Int;
-        let mut sp = StringParser(" ".to_string());
+        let mut sp = StringParser::new(" ".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	Thu May 30 00:40:34 2019 +0200
+++ b/src/state.rs	Thu May 30 11:18:31 2019 +0200
@@ -151,7 +151,7 @@
         assert_eq!(Some('H'), ps.next());
         assert_eq!(
             Ok("üð".to_string()),
-            primitives::StringParser("üð".to_string()).parse(&mut ps)
+            primitives::StringParser::new("üð".to_string()).parse(&mut ps)
         );
     }
 }