diff options
Diffstat (limited to 'src/parser')
-rw-r--r-- | src/parser/iterator.rs | 315 | ||||
-rw-r--r-- | src/parser/mod.rs | 45 | ||||
-rw-r--r-- | src/parser/timetype.rs | 610 |
3 files changed, 493 insertions, 477 deletions
diff --git a/src/parser/iterator.rs b/src/parser/iterator.rs index 7d3007c..06ecc2b 100644 --- a/src/parser/iterator.rs +++ b/src/parser/iterator.rs @@ -1,27 +1,32 @@ -use nom::whitespace::sp; - -use error::Result; -use error::Error; -use parser::timetype::*; -use timetype::IntoTimeType; -use timetype; -use iter; - -named!(pub iter_spec<Iterspec>, alt_complete!( - tag!("secondly") => { |_| Iterspec::Secondly } | - tag!("minutely") => { |_| Iterspec::Minutely } | - tag!("hourly") => { |_| Iterspec::Hourly } | - tag!("daily") => { |_| Iterspec::Daily } | - tag!("weekly") => { |_| Iterspec::Weekly } | - tag!("monthly") => { |_| Iterspec::Monthly } | - tag!("yearly") => { |_| Iterspec::Yearly } | - do_parse!( - tag!("every") >> - number:integer >> - unit:unit_parser >> - (Iterspec::Every(number, unit)) - ) -)); +use nom::branch::alt; +use nom::bytes::complete::tag; +use nom::character::complete::{multispace0, multispace1}; +use nom::combinator::{complete, map, opt}; +use nom::sequence::tuple; +use nom::IResult; + +use crate::error::Error; +use crate::error::Result; +use crate::iter; +use crate::timetype; +use crate::timetype::IntoTimeType; + +use super::timetype::*; + +pub fn iter_spec(i: &[u8]) -> IResult<&[u8], Iterspec> { + complete(alt(( + map(tag("secondly"), |_| Iterspec::Secondly), + map(tag("minutely"), |_| Iterspec::Minutely), + map(tag("hourly"), |_| Iterspec::Hourly), + map(tag("daily"), |_| Iterspec::Daily), + map(tag("weekly"), |_| Iterspec::Weekly), + map(tag("monthly"), |_| Iterspec::Monthly), + map(tag("yearly"), |_| Iterspec::Yearly), + map(tuple((tag("every"), integer, unit_parser)), |(_, number, unit)| { + Iterspec::Every(number, unit) + }), + )))(i) +} #[derive(Debug, PartialEq, Eq)] pub enum Iterspec { @@ -35,31 +40,37 @@ pub enum Iterspec { Every(i64, Unit), } -named!(pub until_spec<UntilSpec>, alt_complete!( - do_parse!( - tag!("until") >> sp >> - exact: exact_date_parser >> - (UntilSpec::Exact(exact)) - ) | - do_parse!( - num: integer >> sp >> - tag!("times") >> - (UntilSpec::Times(num)) - ) -)); +pub fn until_spec(i: &[u8]) -> IResult<&[u8], UntilSpec> { + complete(alt(( + map( + tuple((tag("until"), multispace1, exact_date_parser)), + |(_, _, exact)| UntilSpec::Exact(exact), + ), + map(tuple((integer, multispace1, tag("times"))), |(num, _, _)| { + UntilSpec::Times(num) + }), + )))(i) +} #[derive(Debug, PartialEq, Eq)] pub enum UntilSpec { Exact(ExactDate), - Times(i64) + Times(i64), } -named!(pub iterator<Iterator>, do_parse!( - opt!(sp) >> d: date >> - opt!(sp) >> spec: iter_spec >> - opt!(sp) >> until: opt!(complete!(until_spec)) >> - (Iterator(d, spec, until)) -)); +pub fn iterator(i: &[u8]) -> IResult<&[u8], Iterator> { + map( + tuple(( + multispace0, + date, + multispace0, + iter_spec, + multispace0, + opt(complete(until_spec)), + )), + |(_, d, _, spec, _, until)| Iterator(d, spec, until), + )(i) +} #[derive(Debug, PartialEq, Eq)] pub struct Iterator(Date, Iterspec, Option<UntilSpec>); @@ -72,37 +83,38 @@ impl Iterator { let unit_to_amount = |i, unit| match unit { Unit::Second => timetype::TimeType::seconds(i), Unit::Minute => timetype::TimeType::minutes(i), - Unit::Hour => timetype::TimeType::hours(i), - Unit::Day => timetype::TimeType::days(i), - Unit::Week => timetype::TimeType::weeks(i), - Unit::Month => timetype::TimeType::months(i), - Unit::Year => timetype::TimeType::years(i), + Unit::Hour => timetype::TimeType::hours(i), + Unit::Day => timetype::TimeType::days(i), + Unit::Week => timetype::TimeType::weeks(i), + Unit::Month => timetype::TimeType::months(i), + Unit::Year => timetype::TimeType::years(i), }; let recur = match self.1 { Iterspec::Every(i, unit) => unit_to_amount(i, unit), Iterspec::Secondly => unit_to_amount(1, Unit::Second), Iterspec::Minutely => unit_to_amount(1, Unit::Minute), - Iterspec::Hourly => unit_to_amount(1, Unit::Hour), - Iterspec::Daily => unit_to_amount(1, Unit::Day), - Iterspec::Weekly => unit_to_amount(1, Unit::Week), - Iterspec::Monthly => unit_to_amount(1, Unit::Month), - Iterspec::Yearly => unit_to_amount(1, Unit::Year), + Iterspec::Hourly => unit_to_amount(1, Unit::Hour), + Iterspec::Daily => unit_to_amount(1, Unit::Day), + Iterspec::Weekly => unit_to_amount(1, Unit::Week), + Iterspec::Monthly => unit_to_amount(1, Unit::Month), + Iterspec::Yearly => unit_to_amount(1, Unit::Year), }; - let into_ndt = |e: timetype::TimeType| e.calculate()? - .get_moment() - .ok_or(Error::NotADateInsideIterator) - .map_err(Error::from) - .map(Clone::clone); + let into_ndt = |e: timetype::TimeType| { + e.calculate()? + .get_moment() + .ok_or(Error::NotADateInsideIterator) + .map_err(Error::from) + .map(Clone::clone) + }; match self.2 { Some(UntilSpec::Exact(e)) => { let base = into_ndt(self.0.into_timetype()?)?; - let e = into_ndt(e.into_timetype()?)?; + let e = into_ndt(e.into_timetype()?)?; - iter::Iter::build(base, recur) - .map(|it| UserIterator::UntilIterator(it.until(e))) + iter::Iter::build(base, recur).map(|it| UserIterator::UntilIterator(it.until(e))) }, Some(UntilSpec::Times(i)) => { @@ -114,8 +126,7 @@ impl Iterator { None => { let base = into_ndt(self.0.into_timetype()?)?; - iter::Iter::build(base, recur) - .map(UserIterator::Iterator) + iter::Iter::build(base, recur).map(UserIterator::Iterator) }, } } @@ -124,104 +135,110 @@ impl Iterator { // names are hard #[derive(Debug)] pub enum UserIterator<I> - where I: ::std::iter::Iterator<Item = Result<timetype::TimeType>> +where + I: std::iter::Iterator<Item = Result<timetype::TimeType>>, { Iterator(iter::Iter), TimesIter(iter::TimesIter<I>), - UntilIterator(iter::UntilIter<I>) + UntilIterator(iter::UntilIter<I>), } -impl<I> ::std::iter::Iterator for UserIterator<I> - where I: ::std::iter::Iterator<Item = Result<timetype::TimeType>> +impl<I> std::iter::Iterator for UserIterator<I> +where + I: std::iter::Iterator<Item = Result<timetype::TimeType>>, { type Item = Result<timetype::TimeType>; fn next(&mut self) -> Option<Self::Item> { match *self { - UserIterator::Iterator(ref mut i) => i.next(), - UserIterator::TimesIter(ref mut i) => i.next(), + UserIterator::Iterator(ref mut i) => i.next(), + UserIterator::TimesIter(ref mut i) => i.next(), UserIterator::UntilIterator(ref mut i) => i.next(), } } } - #[cfg(test)] mod tests { - use nom::IResult; - use super::*; + use std::iter::Iterator; - use chrono::Timelike; use chrono::Datelike; + use chrono::Timelike; + + use super::*; #[test] fn test_iterspec() { - assert_eq!(iter_spec(&b"secondly"[..]), IResult::Done(&b""[..], Iterspec::Secondly)); - assert_eq!(iter_spec(&b"minutely"[..]), IResult::Done(&b""[..], Iterspec::Minutely)); - assert_eq!(iter_spec(&b"hourly"[..]), IResult::Done(&b""[..], Iterspec::Hourly)); - assert_eq!(iter_spec(&b"daily"[..]), IResult::Done(&b""[..], Iterspec::Daily)); - assert_eq!(iter_spec(&b"weekly"[..]), IResult::Done(&b""[..], Iterspec::Weekly)); - assert_eq!(iter_spec(&b"monthly"[..]), IResult::Done(&b""[..], Iterspec::Monthly)); - assert_eq!(iter_spec(&b"yearly"[..]), IResult::Done(&b""[..], Iterspec::Yearly)); - assert_eq!(iter_spec(&b"every 5min"[..]), IResult::Done(&b""[..], Iterspec::Every(5, Unit::Minute))); + assert_eq!(iter_spec(&b"secondly"[..]), Ok((&b""[..], Iterspec::Secondly))); + assert_eq!(iter_spec(&b"minutely"[..]), Ok((&b""[..], Iterspec::Minutely))); + assert_eq!(iter_spec(&b"hourly"[..]), Ok((&b""[..], Iterspec::Hourly))); + assert_eq!(iter_spec(&b"daily"[..]), Ok((&b""[..], Iterspec::Daily))); + assert_eq!(iter_spec(&b"weekly"[..]), Ok((&b""[..], Iterspec::Weekly))); + assert_eq!(iter_spec(&b"monthly"[..]), Ok((&b""[..], Iterspec::Monthly))); + assert_eq!(iter_spec(&b"yearly"[..]), Ok((&b""[..], Iterspec::Yearly))); + assert_eq!( + iter_spec(&b"every 5min"[..]), + Ok((&b""[..], Iterspec::Every(5, Unit::Minute))) + ); } #[test] fn test_iterator_1() { let res = iterator(&b"2017-01-01 hourly"[..]); - assert!(res.is_done(), format!("Not done: {:?}", res)); + assert!(res.is_ok(), "Not done: {:?}", res); let (_, i) = res.unwrap(); println!("{:#?}", i); - let ui : Result<UserIterator<iter::Iter>> = i.into_user_iterator(); + let ui: Result<UserIterator<iter::Iter>> = i.into_user_iterator(); assert!(ui.is_ok(), "Not okay: {:#?}", ui); let mut ui = ui.unwrap(); - for hour in 0..10 { // 10 is randomly chosen (fair dice roll... ) + for hour in 0..10 { + // 10 is randomly chosen (fair dice roll... ) let n = ui.next().unwrap(); assert!(n.is_ok(), "Not ok: {:#?}", n); let tt = n.unwrap(); - assert_eq!(tt.get_moment().unwrap().year() , 2017); - assert_eq!(tt.get_moment().unwrap().month() , 01); - assert_eq!(tt.get_moment().unwrap().day() , 01); - assert_eq!(tt.get_moment().unwrap().hour() , hour); - assert_eq!(tt.get_moment().unwrap().minute(), 00); - assert_eq!(tt.get_moment().unwrap().second(), 00); + assert_eq!(tt.get_moment().unwrap().year(), 2017); + assert_eq!(tt.get_moment().unwrap().month(), 1); + assert_eq!(tt.get_moment().unwrap().day(), 1); + assert_eq!(tt.get_moment().unwrap().hour(), hour); + assert_eq!(tt.get_moment().unwrap().minute(), 0); + assert_eq!(tt.get_moment().unwrap().second(), 0); } } #[test] fn test_iterator_2() { let res = iterator(&b"2017-01-01 every 2mins"[..]); - assert!(res.is_done(), format!("Not done: {:?}", res)); + assert!(res.is_ok(), "Not done: {:?}", res); let (_, i) = res.unwrap(); println!("{:#?}", i); - let ui : Result<UserIterator<iter::Iter>> = i.into_user_iterator(); + let ui: Result<UserIterator<iter::Iter>> = i.into_user_iterator(); assert!(ui.is_ok(), "Not okay: {:#?}", ui); let mut ui = ui.unwrap(); - for min in (0..60).into_iter().filter(|n| n % 2 == 0) { + for min in (0..60).filter(|n| n % 2 == 0) { let n = ui.next().unwrap(); assert!(n.is_ok(), "Not ok: {:#?}", n); let tt = n.unwrap(); - assert_eq!(tt.get_moment().unwrap().year() , 2017); - assert_eq!(tt.get_moment().unwrap().month() , 01); - assert_eq!(tt.get_moment().unwrap().day() , 01); - assert_eq!(tt.get_moment().unwrap().hour() , 00); + assert_eq!(tt.get_moment().unwrap().year(), 2017); + assert_eq!(tt.get_moment().unwrap().month(), 1); + assert_eq!(tt.get_moment().unwrap().day(), 1); + assert_eq!(tt.get_moment().unwrap().hour(), 0); assert_eq!(tt.get_moment().unwrap().minute(), min); - assert_eq!(tt.get_moment().unwrap().second(), 00); + assert_eq!(tt.get_moment().unwrap().second(), 0); } } #[test] fn test_iterator_3() { let res = iterator(&b"2017-01-01 daily"[..]); - assert!(res.is_done(), format!("Not done: {:?}", res)); + assert!(res.is_ok(), "Not done: {:?}", res); let (_, i) = res.unwrap(); println!("{:#?}", i); - let ui : Result<UserIterator<iter::Iter>> = i.into_user_iterator(); + let ui: Result<UserIterator<iter::Iter>> = i.into_user_iterator(); assert!(ui.is_ok(), "Not okay: {:#?}", ui); let mut ui = ui.unwrap(); @@ -229,23 +246,23 @@ mod tests { let n = ui.next().unwrap(); assert!(n.is_ok(), "Not ok: {:#?}", n); let tt = n.unwrap(); - assert_eq!(tt.get_moment().unwrap().year() , 2017); - assert_eq!(tt.get_moment().unwrap().month() , 01); - assert_eq!(tt.get_moment().unwrap().day() , day); - assert_eq!(tt.get_moment().unwrap().hour() , 00); - assert_eq!(tt.get_moment().unwrap().minute(), 00); - assert_eq!(tt.get_moment().unwrap().second(), 00); + assert_eq!(tt.get_moment().unwrap().year(), 2017); + assert_eq!(tt.get_moment().unwrap().month(), 1); + assert_eq!(tt.get_moment().unwrap().day(), day); + assert_eq!(tt.get_moment().unwrap().hour(), 0); + assert_eq!(tt.get_moment().unwrap().minute(), 0); + assert_eq!(tt.get_moment().unwrap().second(), 0); } } #[test] fn test_iterator_4() { let res = iterator(&b"2017-01-01 weekly"[..]); - assert!(res.is_done(), format!("Not done: {:?}", res)); + assert!(res.is_ok(), "Not done: {:?}", res); let (_, i) = res.unwrap(); println!("{:#?}", i); - let ui : Result<UserIterator<iter::Iter>> = i.into_user_iterator(); + let ui: Result<UserIterator<iter::Iter>> = i.into_user_iterator(); assert!(ui.is_ok(), "Not okay: {:#?}", ui); let mut ui = ui.unwrap(); @@ -253,19 +270,19 @@ mod tests { let n = ui.next().unwrap(); assert!(n.is_ok(), "Not ok: {:#?}", n); let tt = n.unwrap(); - assert_eq!(tt.get_moment().unwrap().year() , 2017); - assert_eq!(tt.get_moment().unwrap().month() , 01); - assert_eq!(tt.get_moment().unwrap().day() , 01 + (week * 7)); - assert_eq!(tt.get_moment().unwrap().hour() , 00); - assert_eq!(tt.get_moment().unwrap().minute(), 00); - assert_eq!(tt.get_moment().unwrap().second(), 00); + assert_eq!(tt.get_moment().unwrap().year(), 2017); + assert_eq!(tt.get_moment().unwrap().month(), 1); + assert_eq!(tt.get_moment().unwrap().day(), 1 + (week * 7)); + assert_eq!(tt.get_moment().unwrap().hour(), 0); + assert_eq!(tt.get_moment().unwrap().minute(), 0); + assert_eq!(tt.get_moment().unwrap().second(), 0); } } #[test] fn test_until_spec_1() { let res = until_spec(&b"until 2017-01-01T05:00:00"[..]); - assert!(res.is_done(), format!("Not done: {:?}", res)); + assert!(res.is_ok(), "Not done: {:?}", res); let (_, i) = res.unwrap(); println!("{:#?}", i); } @@ -273,16 +290,17 @@ mod tests { #[test] fn test_until_iterator_1() { let res = iterator(&b"2017-01-01 hourly until 2017-01-01T05:00:00"[..]); - assert!(res.is_done(), format!("Not done: {:?}", res)); + assert!(res.is_ok(), "Not done: {:?}", res); let (_, i) = res.unwrap(); println!("{:#?}", i); - let ui : Result<UserIterator<iter::Iter>> = i.into_user_iterator(); + let ui: Result<UserIterator<iter::Iter>> = i.into_user_iterator(); assert!(ui.is_ok(), "Not okay: {:#?}", ui); let mut ui = ui.unwrap(); println!("Okay: {:#?}", ui); - for hour in 0..10 { // 10 is randomly chosen (fair dice roll... ) + for hour in 0..10 { + // 10 is randomly chosen (fair dice roll... ) if hour > 4 { let n = ui.next(); assert!(n.is_none(), "Is Some, should be None: {:?}", n); @@ -291,12 +309,12 @@ mod tests { let n = ui.next().unwrap(); assert!(n.is_ok(), "Not ok: {:#?}", n); let tt = n.unwrap(); - assert_eq!(tt.get_moment().unwrap().year() , 2017); - assert_eq!(tt.get_moment().unwrap().month() , 01); - assert_eq!(tt.get_moment().unwrap().day() , 01); - assert_eq!(tt.get_moment().unwrap().hour() , hour); - assert_eq!(tt.get_moment().unwrap().minute(), 00); - assert_eq!(tt.get_moment().unwrap().second(), 00); + assert_eq!(tt.get_moment().unwrap().year(), 2017); + assert_eq!(tt.get_moment().unwrap().month(), 1); + assert_eq!(tt.get_moment().unwrap().day(), 1); + assert_eq!(tt.get_moment().unwrap().hour(), hour); + assert_eq!(tt.get_moment().unwrap().minute(), 0); + assert_eq!(tt.get_moment().unwrap().second(), 0); } } } @@ -304,15 +322,15 @@ mod tests { #[test] fn test_until_iterator_2() { let res = iterator(&b"2017-01-01 every 2mins until 2017-01-01T00:10:00"[..]); - assert!(res.is_done(), format!("Not done: {:?}", res)); + assert!(res.is_ok(), "Not done: {:?}", res); let (_, i) = res.unwrap(); println!("{:#?}", i); - let ui : Result<UserIterator<iter::Iter>> = i.into_user_iterator(); + let ui: Result<UserIterator<iter::Iter>> = i.into_user_iterator(); assert!(ui.is_ok(), "Not okay: {:#?}", ui); let mut ui = ui.unwrap(); - for min in (0..60).into_iter().filter(|n| n % 2 == 0) { + for min in (0..60).filter(|n| n % 2 == 0) { if min > 9 { let n = ui.next(); assert!(n.is_none(), "Is Some, should be None: {:?}", n); @@ -321,12 +339,12 @@ mod tests { let n = ui.next().unwrap(); assert!(n.is_ok(), "Not ok: {:#?}", n); let tt = n.unwrap(); - assert_eq!(tt.get_moment().unwrap().year() , 2017); - assert_eq!(tt.get_moment().unwrap().month() , 01); - assert_eq!(tt.get_moment().unwrap().day() , 01); - assert_eq!(tt.get_moment().unwrap().hour() , 00); + assert_eq!(tt.get_moment().unwrap().year(), 2017); + assert_eq!(tt.get_moment().unwrap().month(), 1); + assert_eq!(tt.get_moment().unwrap().day(), 1); + assert_eq!(tt.get_moment().unwrap().hour(), 0); assert_eq!(tt.get_moment().unwrap().minute(), min); - assert_eq!(tt.get_moment().unwrap().second(), 00); + assert_eq!(tt.get_moment().unwrap().second(), 0); } } } @@ -334,11 +352,11 @@ mod tests { #[test] fn test_until_iterator_3() { let res = iterator(&b"2017-01-01 daily until 2017-01-05"[..]); - assert!(res.is_done(), format!("Not done: {:?}", res)); + assert!(res.is_ok(), "Not done: {:?}", res); let (_, i) = res.unwrap(); println!("{:#?}", i); - let ui : Result<UserIterator<iter::Iter>> = i.into_user_iterator(); + let ui: Result<UserIterator<iter::Iter>> = i.into_user_iterator(); assert!(ui.is_ok(), "Not okay: {:#?}", ui); let mut ui = ui.unwrap(); @@ -351,12 +369,12 @@ mod tests { let n = ui.next().unwrap(); assert!(n.is_ok(), "Not ok: {:#?}", n); let tt = n.unwrap(); - assert_eq!(tt.get_moment().unwrap().year() , 2017); - assert_eq!(tt.get_moment().unwrap().month() , 01); - assert_eq!(tt.get_moment().unwrap().day() , day); - assert_eq!(tt.get_moment().unwrap().hour() , 00); - assert_eq!(tt.get_moment().unwrap().minute(), 00); - assert_eq!(tt.get_moment().unwrap().second(), 00); + assert_eq!(tt.get_moment().unwrap().year(), 2017); + assert_eq!(tt.get_moment().unwrap().month(), 1); + assert_eq!(tt.get_moment().unwrap().day(), day); + assert_eq!(tt.get_moment().unwrap().hour(), 0); + assert_eq!(tt.get_moment().unwrap().minute(), 0); + assert_eq!(tt.get_moment().unwrap().second(), 0); } } } @@ -364,11 +382,11 @@ mod tests { #[test] fn test_until_iterator_4() { let res = iterator(&b"2017-01-01 weekly until 2017-01-14"[..]); - assert!(res.is_done(), format!("Not done: {:?}", res)); + assert!(res.is_ok(), "Not done: {:?}", res); let (_, i) = res.unwrap(); println!("{:#?}", i); - let ui : Result<UserIterator<iter::Iter>> = i.into_user_iterator(); + let ui: Result<UserIterator<iter::Iter>> = i.into_user_iterator(); assert!(ui.is_ok(), "Not okay: {:#?}", ui); let mut ui = ui.unwrap(); @@ -381,14 +399,13 @@ mod tests { let n = ui.next().unwrap(); assert!(n.is_ok(), "Not ok: {:#?}", n); let tt = n.unwrap(); - assert_eq!(tt.get_moment().unwrap().year() , 2017); - assert_eq!(tt.get_moment().unwrap().month() , 01); - assert_eq!(tt.get_moment().unwrap().day() , 01 + (week * 7)); - assert_eq!(tt.get_moment().unwrap().hour() , 00); - assert_eq!(tt.get_moment().unwrap().minute(), 00); - assert_eq!(tt.get_moment().unwrap().second(), 00); + assert_eq!(tt.get_moment().unwrap().year(), 2017); + assert_eq!(tt.get_moment().unwrap().month(), 1); + assert_eq!(tt.get_moment().unwrap().day(), 1 + (week * 7)); + assert_eq!(tt.get_moment().unwrap().hour(), 0); + assert_eq!(tt.get_moment().unwrap().minute(), 0); + assert_eq!(tt.get_moment().unwrap().second(), 0); } } } } - diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 88d0020..7ab2af4 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -43,37 +43,38 @@ //! Be warned! //! -use nom::Needed; +use nom::branch::alt; +use nom::combinator::{complete, map}; use nom::IResult; -mod timetype; -mod iterator; +use iterator::iterator; +use timetype::timetype; -use error::Result; -use error::Error; -use iter::Iter; -use timetype::IntoTimeType; -use parser::timetype::timetype; -use parser::iterator::iterator; +use crate::error::Error; +use crate::error::Result; +use crate::iter::Iter; +use crate::timetype::IntoTimeType; + +mod iterator; +mod timetype; pub enum Parsed { - Iterator(Result<::parser::iterator::UserIterator<Iter>>), - TimeType(::timetype::TimeType) + Iterator(Result<iterator::UserIterator<Iter>>), + TimeType(crate::timetype::TimeType), } -named!(do_parse<Result<Parsed>>, alt_complete!( - do_parse!(it: iterator >> (Ok(Parsed::Iterator(it.into_user_iterator())))) | - do_parse!(tt: timetype >> (tt.into_timetype().map(Parsed::TimeType))) -)); +fn do_parse(input: &[u8]) -> IResult<&[u8], Result<Parsed>> { + complete(alt(( + map(iterator, |it| Ok(Parsed::Iterator(it.into_user_iterator()))), + map(timetype, |tt| tt.into_timetype().map(Parsed::TimeType)), + )))(input) +} pub fn parse(s: &str) -> Result<Parsed> { match do_parse(s.as_bytes()) { - IResult::Done(_, Ok(o)) => Ok(o), - IResult::Done(_, Err(e)) => Err(e), - IResult::Error(e) => Err(e).map_err(From::from), - IResult::Incomplete(Needed::Unknown) => Err(Error::UnknownParserError), - IResult::Incomplete(Needed::Size(_)) => Err(Error::UnknownParserError), - + Ok((_, Ok(o))) => Ok(o), + Ok((_, Err(e))) => Err(e), + Err(nom::Err::Error(e) | nom::Err::Failure(e)) => Err(Error::NomError(e.code.description().to_string())), + Err(nom::Err::Incomplete(_)) => Err(Error::UnknownParserError), } } - diff --git a/src/parser/timetype.rs b/src/parser/timetype.rs index 1437242..904fcc9 100644 --- a/src/parser/timetype.rs +++ b/src/parser/timetype.rs @@ -1,52 +1,41 @@ use std::str; -use std::str::FromStr; -use nom::digit; -use nom::whitespace::sp; use chrono::NaiveDate; - -use timetype::IntoTimeType; -use timetype; -use error::Result; -use error::Error; - -named!(pub integer<i64>, alt!( - map_res!( - map_res!( - ws!(digit), - str::from_utf8 - ), - FromStr::from_str - ) -)); +use iso8601::parsers::{parse_date, parse_datetime}; +use nom::branch::alt; +use nom::bytes::complete::tag; +use nom::character::complete::{digit1, multispace0, multispace1}; +use nom::combinator::{complete, map, map_opt, opt}; +use nom::sequence::{delimited, tuple}; +use nom::IResult; + +use crate::error::Error; +use crate::error::Result; +use crate::timetype::IntoTimeType; + +pub fn integer(input: &[u8]) -> IResult<&[u8], i64> { + map_opt(delimited(multispace0, digit1, multispace0), |digit| { + str::from_utf8(digit).ok().and_then(|s| s.parse().ok()) + })(input) +} // WARNING: Order is important here. Long tags first, shorter tags later -named!(pub unit_parser<Unit>, alt_complete!( - tag!("seconds") => { |_| Unit::Second } | - tag!("second") => { |_| Unit::Second } | - tag!("secs") => { |_| Unit::Second } | - tag!("sec") => { |_| Unit::Second } | - tag!("s") => { |_| Unit::Second } | - tag!("minutes") => { |_| Unit::Minute } | - tag!("minute") => { |_| Unit::Minute } | - tag!("mins") => { |_| Unit::Minute } | - tag!("min") => { |_| Unit::Minute } | - tag!("hours") => { |_| Unit::Hour } | - tag!("hour") => { |_| Unit::Hour } | - tag!("hrs") => { |_| Unit::Hour } | - tag!("hr") => { |_| Unit::Hour } | - tag!("days") => { |_| Unit::Day } | - tag!("day") => { |_| Unit::Day } | - tag!("d") => { |_| Unit::Day } | - tag!("weeks") => { |_| Unit::Week } | - tag!("week") => { |_| Unit::Week } | - tag!("w") => { |_| Unit::Week } | - tag!("months") => { |_| Unit::Month } | - tag!("month") => { |_| Unit::Month } | - tag!("years") => { |_| Unit::Year } | - tag!("year") => { |_| Unit::Year } | - tag!("yrs") => { |_| Unit::Year } -)); +pub fn unit_parser(input: &[u8]) -> IResult<&[u8], Unit> { + complete(alt(( + map( + alt((tag("seconds"), tag("second"), tag("secs"), tag("sec"), tag("s"))), + |_| Unit::Second, + ), + map(alt((tag("minutes"), tag("minute"), tag("mins"), tag("min"))), |_| { + Unit::Minute + }), + map(alt((tag("hours"), tag("hour"), tag("hrs"), tag("hr"))), |_| Unit::Hour), + map(alt((tag("days"), tag("day"), tag("d"))), |_| Unit::Day), + map(alt((tag("weeks"), tag("week"), tag("w"))), |_| Unit::Week), + map(alt((tag("months"), tag("month"))), |_| Unit::Month), + map(alt((tag("years"), tag("year"), tag("yrs"))), |_| Unit::Year), + )))(input) +} #[derive(Debug, PartialEq, Eq)] pub enum Unit { @@ -70,24 +59,23 @@ pub enum UnitAlias { Yearly, } -impl Into<Unit> for UnitAlias { - fn into(self) -> Unit { - match self { +impl From<UnitAlias> for Unit { + fn from(val: UnitAlias) -> Self { + match val { UnitAlias::Secondly => Unit::Second, UnitAlias::Minutely => Unit::Minute, - UnitAlias::Hourly => Unit::Hour, - UnitAlias::Daily => Unit::Day, - UnitAlias::Weekly => Unit::Week, - UnitAlias::Monthly => Unit::Month, - UnitAlias::Yearly => Unit::Year, + UnitAlias::Hourly => Unit::Hour, + UnitAlias::Daily => Unit::Day, + UnitAlias::Weekly => Unit::Week, + UnitAlias::Monthly => Unit::Month, + UnitAlias::Yearly => Unit::Year, } } } -named!(pub operator_parser<Operator>, alt!( - tag!("+") => { |_| Operator::Plus } | - tag!("-") => { |_| Operator::Minus } -)); +pub fn operator_parser(input: &[u8]) -> IResult<&[u8], Operator> { + alt((map(tag("+"), |_| Operator::Plus), map(tag("-"), |_| Operator::Minus)))(input) +} #[derive(Debug, PartialEq, Eq)] pub enum Operator { @@ -95,51 +83,54 @@ pub enum Operator { Minus, } -named!(pub unit_alias<UnitAlias>, alt_complete!( - tag!("secondly") => { |_| UnitAlias::Secondly } | - tag!("minutely") => { |_| UnitAlias::Minutely } | - tag!("hourly") => { |_| UnitAlias::Hourly } | - tag!("daily") => { |_| UnitAlias::Daily } | - tag!("weekly") => { |_| UnitAlias::Weekly } | - tag!("monthly") => { |_| UnitAlias::Monthly } | - tag!("yearly") => { |_| UnitAlias::Yearly } -)); - -named!(pub amount_parser<Amount>, alt!( - do_parse!(number: integer >> unit: unit_parser >> (Amount(number, unit))) | - do_parse!(unitalias: unit_alias >> (Amount(1, unitalias.into()))) -)); +pub fn unit_alias(input: &[u8]) -> IResult<&[u8], UnitAlias> { + complete(alt(( + map(tag("secondly"), |_| UnitAlias::Secondly), + map(tag("minutely"), |_| UnitAlias::Minutely), + map(tag("hourly"), |_| UnitAlias::Hourly), + map(tag("daily"), |_| UnitAlias::Daily), + map(tag("weekly"), |_| UnitAlias::Weekly), + map(tag("monthly"), |_| UnitAlias::Monthly), + map(tag("yearly"), |_| UnitAlias::Yearly), + )))(input) +} + +pub fn amount_parser(input: &[u8]) -> IResult<&[u8], Amount> { + alt(( + map(tuple((integer, unit_parser)), |(number, unit)| Amount(number, unit)), + map(unit_alias, |unit| Amount(1, unit.into())), + ))(input) +} #[derive(Debug, PartialEq, Eq)] pub struct Amount(i64, Unit); impl IntoTimeType for Amount { - fn into_timetype(self) -> Result<timetype::TimeType> { + fn into_timetype(self) -> Result<crate::timetype::TimeType> { Ok(match self.1 { - Unit::Second => timetype::TimeType::seconds(self.0), - Unit::Minute => timetype::TimeType::minutes(self.0), - Unit::Hour => timetype::TimeType::hours(self.0), - Unit::Day => timetype::TimeType::days(self.0), - Unit::Week => timetype::TimeType::weeks(self.0), - Unit::Month => timetype::TimeType::months(self.0), - Unit::Year => timetype::TimeType::years(self.0), + Unit::Second => crate::timetype::TimeType::seconds(self.0), + Unit::Minute => crate::timetype::TimeType::minutes(self.0), + Unit::Hour => crate::timetype::TimeType::hours(self.0), + Unit::Day => crate::timetype::TimeType::days(self.0), + Unit::Week => crate::timetype::TimeType::weeks(self.0), + Unit::Month => crate::timetype::TimeType::months(self.0), + Unit::Year => crate::timetype::TimeType::years(self.0), }) } } -named!(pub amount_expr_next<(Operator, Box<AmountExpr>)>, do_parse!( - op:operator_parser - >> opt!(sp) - >> amexp:amount_expr - >> ((op, Box::new(amexp))) -)); +pub fn amount_expr_next(input: &[u8]) -> IResult<&[u8], (Operator, Box<AmountExpr>)> { + map(tuple((operator_parser, multispace0, amount_expr)), |(op, _, amexp)| { + (op, Box::new(amexp)) + })(input) +} -named!(pub amount_expr<AmountExpr>, do_parse!( - amount:amount_parser >> - opt!(sp) >> - o: opt!(complete!(amount_expr_next)) >> - (AmountExpr { amount: amount, next: o, }) -)); +pub fn amount_expr(input: &[u8]) -> IResult<&[u8], AmountExpr> { + map( + tuple((amount_parser, multispace0, opt(complete(amount_expr_next)))), + |(amount, _, next)| AmountExpr { amount, next }, + )(input) +} #[derive(Debug, PartialEq, Eq)] pub struct AmountExpr { @@ -148,13 +139,13 @@ pub struct AmountExpr { } impl IntoTimeType for AmountExpr { - fn into_timetype(self) -> Result<timetype::TimeType> { + fn into_timetype(self) -> Result<crate::timetype::TimeType> { let mut amount = self.amount.into_timetype()?; if let Some((op, other_amonut_expr)) = self.next { match op { - Operator::Plus => amount = amount + (*other_amonut_expr).into_timetype()?, - Operator::Minus => amount = amount - (*other_amonut_expr).into_timetype()?, + Operator::Plus => amount += (*other_amonut_expr).into_timetype()?, + Operator::Minus => amount -= (*other_amonut_expr).into_timetype()?, } } @@ -162,89 +153,83 @@ impl IntoTimeType for AmountExpr { } } -use iso8601::parsers::parse_date; -use iso8601::parsers::parse_datetime; // The order is relevant here, because datetime is longer than date, we must parse datetime before // date. -named!(pub exact_date_parser<ExactDate>, alt_complete!( - tag!("today") => { |_| ExactDate::Today } | - tag!("yesterday") => { |_| ExactDate::Yesterday } | - tag!("tomorrow") => { |_| ExactDate::Tomorrow } | - do_parse!(d: parse_datetime >> (ExactDate::Iso8601DateTime(d))) | - do_parse!(d: parse_date >> (ExactDate::Iso8601Date(d))) -)); +pub fn exact_date_parser(input: &[u8]) -> IResult<&[u8], ExactDate> { + complete(alt(( + map(tag("today"), |_| ExactDate::Today), + map(tag("yesterday"), |_| ExactDate::Yesterday), + map(tag("tomorrow"), |_| ExactDate::Tomorrow), + map(parse_datetime, ExactDate::Iso8601DateTime), + map(parse_date, ExactDate::Iso8601Date), + )))(input) +} #[derive(Debug, PartialEq, Eq)] pub enum ExactDate { Today, Yesterday, Tomorrow, - Iso8601Date(::iso8601::Date), - Iso8601DateTime(::iso8601::DateTime) + Iso8601Date(iso8601::Date), + Iso8601DateTime(iso8601::DateTime), } impl IntoTimeType for ExactDate { - fn into_timetype(self) -> Result<timetype::TimeType> { + fn into_timetype(self) -> Result<crate::timetype::TimeType> { match self { - ExactDate::Today => Ok(timetype::TimeType::today()), - ExactDate::Yesterday => Ok(timetype::TimeType::today() - timetype::TimeType::days(1)), - ExactDate::Tomorrow => Ok(timetype::TimeType::today() + timetype::TimeType::days(1)), - ExactDate::Iso8601Date(date) => { - match date { - ::iso8601::Date::YMD { year, month, day } => NaiveDate::from_ymd_opt(year, month, day) - .ok_or(Error::OutOfBounds(year, month, day, 0, 0, 0)) - .map(|ndt| ndt.and_hms(0, 0, 0)) - .map(timetype::TimeType::moment), - - ::iso8601::Date::Week { year, ww, d } => NaiveDate::from_ymd_opt(year, 1, 1) - .ok_or(Error::OutOfBounds(year, 1, 1, 0, 0, 0)) - .map(|ndt| ndt.and_hms(0, 0, 0)) - .map(timetype::TimeType::moment) - .map(|m| { - m - + timetype::TimeType::weeks(ww as i64) - + timetype::TimeType::days(d as i64) - }), - - ::iso8601::Date::Ordinal { year, ddd } => NaiveDate::from_ymd_opt(year, 1, 1) - .ok_or(Error::OutOfBounds(year, 1, 1, 0, 0, 0)) - .map(|ndt| ndt.and_hms(0, 0, 0)) - .map(timetype::TimeType::moment) - .map(|m| m + timetype::TimeType::days(ddd as i64)), - } + ExactDate::Today => Ok(crate::timetype::TimeType::today()), + ExactDate::Yesterday => Ok(crate::timetype::TimeType::today() - crate::timetype::TimeType::days(1)), + ExactDate::Tomorrow => Ok(crate::timetype::TimeType::today() + crate::timetype::TimeType::days(1)), + ExactDate::Iso8601Date(date) => match date { + iso8601::Date::YMD { year, month, day } => NaiveDate::from_ymd_opt(year, month, day) + .and_then(|ndt| ndt.and_hms_opt(0, 0, 0)) + .ok_or(Error::OutOfBounds(year, month, day, 0, 0, 0)) + .map(crate::timetype::TimeType::moment), + + iso8601::Date::Week { year, ww, d } => NaiveDate::from_ymd_opt(year, 1, 1) + .and_then(|ndt| ndt.and_hms_opt(0, 0, 0)) + .ok_or(Error::OutOfBounds(year, 1, 1, 0, 0, 0)) + .map(crate::timetype::TimeType::moment) + .map(|m| { + m + crate::timetype::TimeType::weeks(ww as i64) + crate::timetype::TimeType::days(d as i64) + }), + + iso8601::Date::Ordinal { year, ddd } => NaiveDate::from_ymd_opt(year, 1, 1) + .and_then(|ndt| ndt.and_hms_opt(0, 0, 0)) + .ok_or(Error::OutOfBounds(year, 1, 1, 0, 0, 0)) + .map(crate::timetype::TimeType::moment) + .map(|m| m + crate::timetype::TimeType::days(ddd as i64)), }, |