From 279bf4a4d104a7e0e9d5b73120b6132e58e7aaa6 Mon Sep 17 00:00:00 2001 From: Joscha Date: Sat, 18 Dec 2021 22:21:17 +0100 Subject: [PATCH] Parse range for --range --- src/files.rs | 1 + src/files/arguments.rs | 94 ++++++++++++++++++++++++++++++++++++++++++ src/files/grammar.pest | 5 +++ src/files/parse.rs | 6 +-- 4 files changed, 103 insertions(+), 3 deletions(-) create mode 100644 src/files/arguments.rs diff --git a/src/files.rs b/src/files.rs index 7ec38c0..38cc135 100644 --- a/src/files.rs +++ b/src/files.rs @@ -8,6 +8,7 @@ use tzfile::Tz; use self::commands::{Command, Done, File}; pub use self::error::{Error, Result}; +pub mod arguments; pub mod commands; mod error; mod format; diff --git a/src/files/arguments.rs b/src/files/arguments.rs new file mode 100644 index 0000000..0878692 --- /dev/null +++ b/src/files/arguments.rs @@ -0,0 +1,94 @@ +use std::str::FromStr; + +use chrono::NaiveDate; +use pest::iterators::Pair; +use pest::Parser; + +use super::commands::Delta; +use super::parse::{self, Error, Result, Rule, TodayfileParser}; + +#[derive(Debug)] +pub enum RangeDate { + Date(NaiveDate), + Today, +} + +#[derive(Debug)] +pub struct Range { + pub start: RangeDate, + pub start_delta: Option, + pub end: Option, + pub end_delta: Option, +} + +/* Parsing */ + +fn parse_range_date(p: Pair<'_, Rule>) -> Result { + assert!(matches!(p.as_rule(), Rule::datum | Rule::today)); + Ok(match p.as_rule() { + Rule::datum => RangeDate::Date(parse::parse_datum(p)?.value), + Rule::today => RangeDate::Today, + _ => unreachable!(), + }) +} + +fn parse_range_start(p: Pair<'_, Rule>) -> Result<(RangeDate, Option)> { + assert_eq!(p.as_rule(), Rule::range_start); + let mut p = p.into_inner(); + + let start = parse_range_date(p.next().unwrap())?; + let start_delta = match p.next() { + None => None, + Some(p) => Some(parse::parse_delta(p)?.value), + }; + + assert_eq!(p.next(), None); + + Ok((start, start_delta)) +} + +fn parse_range_end(p: Pair<'_, Rule>) -> Result<(Option, Option)> { + assert_eq!(p.as_rule(), Rule::range_end); + + let mut end = None; + let mut end_delta = None; + + for p in p.into_inner() { + match p.as_rule() { + Rule::datum | Rule::today => end = Some(parse_range_date(p)?), + Rule::delta => end_delta = Some(parse::parse_delta(p)?.value), + _ => unreachable!(), + } + } + + Ok((end, end_delta)) +} + +fn parse_range(p: Pair<'_, Rule>) -> Result { + assert_eq!(p.as_rule(), Rule::range); + let mut p = p.into_inner(); + + let (start, start_delta) = parse_range_start(p.next().unwrap())?; + let (end, end_delta) = parse_range_end(p.next().unwrap())?; + + assert_eq!(p.next(), None); + + Ok(Range { + start, + start_delta, + end, + end_delta, + }) +} + +impl FromStr for Range { + type Err = Error; + + fn from_str(s: &str) -> Result { + let mut pairs = TodayfileParser::parse(Rule::range, s)?; + let p = pairs.next().unwrap(); + assert_eq!(pairs.next(), None); + + parse_range(p) + } +} diff --git a/src/files/grammar.pest b/src/files/grammar.pest index 32186a2..227e32b 100644 --- a/src/files/grammar.pest +++ b/src/files/grammar.pest @@ -142,3 +142,8 @@ empty_line = _{ WHITESPACE* ~ NEWLINE } command = { include | timezone | task | note } file = ${ SOI ~ (empty_line* ~ command)* ~ empty_line* ~ WHITESPACE* ~ EOI } + +today = { "today" } +range_start = { (datum | today) ~ delta? } +range_end = { (datum | today) ~ delta? | delta } +range = { range_start ~ ("--" ~ range_end)? } diff --git a/src/files/parse.rs b/src/files/parse.rs index a1f5eef..e7a4590 100644 --- a/src/files/parse.rs +++ b/src/files/parse.rs @@ -15,7 +15,7 @@ use super::primitives::{Spanned, Time, Weekday}; #[derive(pest_derive::Parser)] #[grammar = "files/grammar.pest"] -struct TodayfileParser; +pub struct TodayfileParser; pub type Error = pest::error::Error; pub type Result = result::Result; @@ -55,7 +55,7 @@ fn parse_title(p: Pair<'_, Rule>) -> String { p.as_str().trim().to_string() } -fn parse_datum(p: Pair<'_, Rule>) -> Result> { +pub fn parse_datum(p: Pair<'_, Rule>) -> Result> { assert_eq!(p.as_rule(), Rule::datum); let pspan = p.as_span(); let span = (&pspan).into(); @@ -203,7 +203,7 @@ fn parse_delta_step( Ok(Spanned::new(span, f(value))) } -fn parse_delta(p: Pair<'_, Rule>) -> Result> { +pub fn parse_delta(p: Pair<'_, Rule>) -> Result> { assert_eq!(p.as_rule(), Rule::delta); let span = (&p.as_span()).into();