changeset 17:0427da45a728

Implement Float parser. And raise buffer for Int parser to 16 bytes.
author Lewin Bormann <lewin@lewin-bormann.info>
date Mon, 03 Jun 2019 23:51:32 +0200
parents 9ad913fdbef1
children d9f4c7963c9f
files src/lib.rs src/primitives.rs
diffstat 2 files changed, 87 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib.rs	Mon Jun 03 23:51:15 2019 +0200
+++ b/src/lib.rs	Mon Jun 03 23:51:32 2019 +0200
@@ -1,5 +1,6 @@
 #![allow(dead_code)]
 
+#[allow(unused_imports)]
 #[macro_use]
 extern crate time_test;
 
--- a/src/primitives.rs	Mon Jun 03 23:51:15 2019 +0200
+++ b/src/primitives.rs	Mon Jun 03 23:51:32 2019 +0200
@@ -1,11 +1,11 @@
-use crate::combinators::{Repeat, RepeatSpec};
-use crate::parser::{ParseError, ParseResult, Parser};
+use crate::combinators::{Maybe, Repeat, RepeatSpec, Sequence};
+use crate::parser::{execerr, ParseError, ParseResult, Parser};
 use crate::state::ParseState;
 
 use std::collections::HashSet;
 use std::error::Error;
 use std::iter::FromIterator;
-use std::str;
+use std::str::{self, FromStr};
 
 pub struct StringParser(String);
 
@@ -74,7 +74,7 @@
         st: &mut ParseState<impl Iterator<Item = char>>,
     ) -> ParseResult<Self::Result> {
         // Optimization for most ints.
-        const BUFSIZE: usize = 8;
+        const BUFSIZE: usize = 16;
         let mut buf: [char; BUFSIZE] = [' '; BUFSIZE];
         let mut widebuf: Option<Vec<char>> = None;
         let mut i = 0;
@@ -145,6 +145,53 @@
     }
 }
 
+fn assemble_float(s: Option<String>, big: String, dot: Option<String>, mut little: Option<String>) -> ParseResult<f64> {
+    if dot.is_some() && little.is_none() {
+        little = Some("0".to_string());
+    }
+    assert!((dot.is_some() && little.is_some()) || (dot.is_none() && little.is_none()));
+    let bigf = match f64::from_str(&big) {
+        Ok(f) => f,
+        Err(e) => return Err(execerr(e.description())),
+    };
+    let mut littlef = 0.;
+    if let Some(mut d) = dot {
+        d.push_str(little.as_ref().unwrap());
+        littlef = match f64::from_str(&d) {
+            Ok(f) => f,
+            Err(e) => return Err(execerr(e.description())),
+        }
+    }
+    let minus = if s.is_some() {
+        -1.
+    } else {
+        1.
+    };
+    return Ok(minus * (bigf + littlef))
+}
+
+/// float parses floats in the format of `[-]dd[.[dd]]`. Currently, `e` notation is not supported.
+///
+/// TODO: Compare with "native" parser, i.e. without combinators, and keep this as example.
+pub fn float() -> impl Parser<Result=f64> {
+        let minus = Maybe::new(StringParser::new("-"));
+        let digits = string_of("0123456789", RepeatSpec::Min(1));
+        let point = Maybe::new(StringParser::new("."));
+        let smalldigits = Maybe::new(string_of("0123456789", RepeatSpec::Min(1)));
+        let parser = Sequence::new((minus, digits, point, smalldigits)).apply(|(m,d,p,sd)| assemble_float(m, d, p, sd));
+        parser
+}
+
+/// Nothing is a parser that always succeeds.
+pub struct Nothing;
+
+impl Parser for Nothing {
+    type Result = ();
+    fn parse(&mut self, _: &mut ParseState<impl Iterator<Item=char>>) -> ParseResult<Self::Result> {
+        Ok(())
+    }
+}
+
 /// OneOf matches any character that is in its specification.
 pub struct OneOf(HashSet<char>, bool);
 
@@ -242,6 +289,17 @@
     }
 
     #[test]
+    fn test_parse_floats() {
+        let mut ps = ParseState::new("1 1. 1.5 -1.5 -1.75");
+        let mut p = float();
+        let want = vec![1., 1., 1.5, -1.5, -1.75];
+        for &f in want.iter() {
+            assert_eq!(Ok(f), p.parse(&mut ps));
+            let _ = StringParser::new(" ").parse(&mut ps);
+        }
+    }
+
+    #[test]
     fn test_string_of() {
         let mut st = ParseState::new("aaabcxxzy");
         let mut p = string_of("abcd", RepeatSpec::Min(1));
@@ -259,7 +317,7 @@
 
     #[test]
     fn bench_integer_medium() {
-        let piece = "-422345 ";
+        let piece = "-422345812310928 ";
         let repeats = 1000;
         let mut input = String::with_capacity(piece.len() * repeats);
         input.extend(iter::repeat(piece).take(repeats));
@@ -267,22 +325,40 @@
         let mut p = Sequence::new((Int64::new(), StringParser::new(" ")));
         {
             time_test!("parse-int with static buffer");
-            for i in 0..1000 {
+            for _ in 0..1000 {
                 let h = ps.hold();
-                let r = p.parse(&mut ps);
+                let _ = p.parse(&mut ps);
                 ps.reset(h);
             }
         }
 
-        let piece = "-42234511 ";
+        let piece = "-4223458123109289 ";
         let mut input = String::with_capacity(piece.len() * repeats);
         input.extend(iter::repeat(piece).take(repeats));
         let mut ps = ParseState::new(&input);
         {
             time_test!("parse-int with dynamic buffer");
-            for i in 0..1000 {
+            for _ in 0..1000 {
                 let h = ps.hold();
-                let r = p.parse(&mut ps);
+                let _ = p.parse(&mut ps);
+                ps.reset(h);
+            }
+        }
+    }
+
+    #[test]
+    fn bench_float() {
+        let piece = "-32.334 ";
+        let repeats = 1000;
+        let mut input = String::with_capacity(piece.len() * repeats);
+        input.extend(iter::repeat(piece).take(repeats));
+        let mut ps = ParseState::new(&input);
+        let mut p = Sequence::new((float(), StringParser::new(" ")));
+        {
+            time_test!("parse-float with combinators");
+            for _ in 0..1000 {
+                let h = ps.hold();
+                let _ = p.parse(&mut ps);
                 ps.reset(h);
             }
         }