use crate::{
ast::{Duration, RelativeTime, TimeAnchor, Value},
parser::{
keyword,
utils::{int16, IResult, LocatedSpan},
},
};
use nom::{
branch::alt,
bytes::complete::tag,
character::complete::{multispace0, multispace1},
combinator::map,
sequence::tuple,
};
pub(crate) fn relative_time_value(i: LocatedSpan) -> IResult<Value> {
map(relative_time, Value::RelativeTime)(i)
}
fn relative_time(i: LocatedSpan) -> IResult<RelativeTime> {
alt((now, relative_time_duration))(i)
}
fn now(i: LocatedSpan) -> IResult<RelativeTime> {
map(keyword("now"), |_| RelativeTime::Now)(i)
}
fn relative_time_duration(i: LocatedSpan) -> IResult<RelativeTime> {
map(
tuple((duration, multispace1, time_anchor)),
|(duration, _, time_anchor)| RelativeTime::Duration(duration, time_anchor),
)(i)
}
fn duration(i: LocatedSpan) -> IResult<Duration> {
alt((
duration_seconds,
duration_minutes,
duration_hours,
duration_days,
duration_weeks,
duration_months,
duration_years,
))(i)
}
fn duration_seconds(i: LocatedSpan) -> IResult<Duration> {
map(
tuple((int16, multispace0, alt((tag("seconds"), tag("second"))))),
|(amount, _, _)| Duration::Seconds(amount),
)(i)
}
fn duration_minutes(i: LocatedSpan) -> IResult<Duration> {
map(
tuple((int16, multispace0, alt((tag("minutes"), tag("minute"))))),
|(amount, _, _)| Duration::Minutes(amount),
)(i)
}
fn duration_hours(i: LocatedSpan) -> IResult<Duration> {
map(
tuple((int16, multispace0, alt((tag("hours"), tag("hour"))))),
|(amount, _, _)| Duration::Hours(amount),
)(i)
}
fn duration_days(i: LocatedSpan) -> IResult<Duration> {
map(
tuple((int16, multispace0, alt((tag("days"), tag("day"))))),
|(amount, _, _)| Duration::Days(amount),
)(i)
}
fn duration_weeks(i: LocatedSpan) -> IResult<Duration> {
map(
tuple((int16, multispace0, alt((tag("weeks"), tag("week"))))),
|(amount, _, _)| Duration::Weeks(amount),
)(i)
}
fn duration_months(i: LocatedSpan) -> IResult<Duration> {
map(
tuple((int16, multispace0, alt((tag("months"), tag("month"))))),
|(amount, _, _)| Duration::Months(amount),
)(i)
}
fn duration_years(i: LocatedSpan) -> IResult<Duration> {
map(
tuple((int16, multispace0, alt((tag("years"), tag("year"))))),
|(amount, _, _)| Duration::Years(amount),
)(i)
}
fn time_anchor(i: LocatedSpan) -> IResult<TimeAnchor> {
map(tag("ago"), |_| TimeAnchor::Ago)(i)
}
#[cfg(test)]
mod tests {
use super::relative_time;
use crate::{
ast::{Duration, RelativeTime, TimeAnchor},
parser::utils::{span, unwrap_span},
};
#[test]
fn test_relative_time() {
assert_eq!(
relative_time(span("now")).map(unwrap_span),
Ok(("", RelativeTime::Now))
);
assert_eq!(
relative_time(span("1second ago")).map(unwrap_span),
Ok((
"",
RelativeTime::Duration(Duration::Seconds(1), TimeAnchor::Ago)
))
);
assert_eq!(
relative_time(span("2 seconds ago")).map(unwrap_span),
Ok((
"",
RelativeTime::Duration(Duration::Seconds(2), TimeAnchor::Ago)
))
);
assert_eq!(
relative_time(span("1 minute ago")).map(unwrap_span),
Ok((
"",
RelativeTime::Duration(Duration::Minutes(1), TimeAnchor::Ago)
))
);
assert_eq!(
relative_time(span("2 minutes ago")).map(unwrap_span),
Ok((
"",
RelativeTime::Duration(Duration::Minutes(2), TimeAnchor::Ago)
))
);
assert_eq!(
relative_time(span("1 hour ago")).map(unwrap_span),
Ok((
"",
RelativeTime::Duration(Duration::Hours(1), TimeAnchor::Ago)
))
);
assert_eq!(
relative_time(span("2 hours ago")).map(unwrap_span),
Ok((
"",
RelativeTime::Duration(Duration::Hours(2), TimeAnchor::Ago)
))
);
assert_eq!(
relative_time(span("1 day ago")).map(unwrap_span),
Ok((
"",
RelativeTime::Duration(Duration::Days(1), TimeAnchor::Ago)
))
);
assert_eq!(
relative_time(span("2 days ago")).map(unwrap_span),
Ok((
"",
RelativeTime::Duration(Duration::Days(2), TimeAnchor::Ago)
))
);
assert_eq!(
relative_time(span("1 week ago")).map(unwrap_span),
Ok((
"",
RelativeTime::Duration(Duration::Weeks(1), TimeAnchor::Ago)
))
);
assert_eq!(
relative_time(span("2 weeks ago")).map(unwrap_span),
Ok((
"",
RelativeTime::Duration(Duration::Weeks(2), TimeAnchor::Ago)
))
);
assert_eq!(
relative_time(span("1 month ago")).map(unwrap_span),
Ok((
"",
RelativeTime::Duration(Duration::Months(1), TimeAnchor::Ago)
))
);
assert_eq!(
relative_time(span("2 months ago")).map(unwrap_span),
Ok((
"",
RelativeTime::Duration(Duration::Months(2), TimeAnchor::Ago)
))
);
assert_eq!(
relative_time(span("1 year ago")).map(unwrap_span),
Ok((
"",
RelativeTime::Duration(Duration::Years(1), TimeAnchor::Ago)
))
);
assert_eq!(
relative_time(span("2 years ago")).map(unwrap_span),
Ok((
"",
RelativeTime::Duration(Duration::Years(2), TimeAnchor::Ago)
))
);
}
}