summaryrefslogtreecommitdiffstats
path: root/src/parser
diff options
context:
space:
mode:
Diffstat (limited to 'src/parser')
-rw-r--r--src/parser/iterator.rs315
-rw-r--r--src/parser/mod.rs45
-rw-r--r--src/parser/timetype.rs610
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)),
},