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