Mercurial > lbo > hg > rcombinators
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); } }