changeset 6:7873119002f7

Implement Transform combinator.
author Lewin Bormann <lewin@lewin-bormann.info>
date Thu, 30 May 2019 14:27:11 +0200
parents fe1259c95911
children 1f30f2d25d5e
files src/combinators.rs src/parser.rs
diffstat 2 files changed, 31 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/src/combinators.rs	Thu May 30 14:10:26 2019 +0200
+++ b/src/combinators.rs	Thu May 30 14:27:11 2019 +0200
@@ -1,6 +1,32 @@
 use crate::parser::{ParseError, ParseResult, Parser};
 use crate::state::ParseState;
 
+/// Transform applies a function (which may fail) to the result of a parser. Transform only
+/// succeeds if the applied function succeeds, too.
+pub struct Transform<R, R2, P: Parser<Result = R>, F: Fn(R) -> ParseResult<R2>> {
+    f: F,
+    p: P,
+}
+
+impl<R, R2, P: Parser<Result = R>, F: Fn(R) -> ParseResult<R2>> Transform<R, R2, P, F> {
+    pub fn new(p: P, f: F) -> Transform<R, R2, P, F> {
+        Transform { f: f, p: p }
+    }
+}
+
+impl<R, R2, P: Parser<Result = R>, F: Fn(R) -> ParseResult<R2>> Parser for Transform<R, R2, P, F> {
+    type Result = R2;
+    fn parse(
+        &mut self,
+        st: &mut ParseState<impl Iterator<Item = char>>,
+    ) -> ParseResult<Self::Result> {
+        match self.p.parse(st) {
+            Ok(o) => (self.f)(o),
+            Err(e) => Err(e),
+        }
+    }
+}
+
 pub struct Alternative<T>(T);
 
 impl<T> Alternative<T> {
@@ -189,9 +215,11 @@
             StringParser::new("ab"),
             StringParser::new("de"),
             StringParser::new(" "),
+            Transform::new(Int, |i| Ok(i.to_string())),
         ));
         let mut ps = ParseState::new("de 34");
         assert_eq!(Ok("de".to_string()), p.parse(&mut ps));
         assert_eq!(Ok(" ".to_string()), p.parse(&mut ps));
+        assert_eq!(Ok("34".to_string()), p.parse(&mut ps));
     }
 }
--- a/src/parser.rs	Thu May 30 14:10:26 2019 +0200
+++ b/src/parser.rs	Thu May 30 14:27:11 2019 +0200
@@ -6,6 +6,8 @@
 pub enum ParseError {
     EOF,
     Fail(&'static str, usize),
+    /// Error during application of Transform.
+    TransformFail(&'static str, usize),
 }
 
 impl fmt::Display for ParseError {
@@ -13,6 +15,7 @@
         match self {
             ParseError::EOF => f.write_str("EOF"),
             ParseError::Fail(s, pos) => write!(f, "Parse fail: {} at {}", s, pos),
+            ParseError::TransformFail(s, pos) => write!(f, "Transform fail: {} at {}", s, pos),
         }
     }
 }