Add eval representation of FormulaSpec

This commit is contained in:
Joscha 2021-11-25 02:32:08 +01:00
parent 21739c7314
commit e827556c84
5 changed files with 165 additions and 10 deletions

View file

@ -1,8 +1,41 @@
use std::cmp::Ordering;
use crate::files::commands::{Delta, DeltaStep};
use crate::files::commands::{self, Time, Weekday};
/// Like [`commands::DeltaStep`] but includes a new constructor,
/// [`DeltaStep::Time`].
#[derive(Debug, Clone, Copy)]
pub enum DeltaStep {
Year(i32),
Month(i32),
MonthReverse(i32),
Day(i32),
Week(i32),
Hour(i32),
Minute(i32),
Weekday(i32, Weekday),
/// Set the time to the next occurrence of the specified time. Useful to
/// unify the end delta and end time for different specs.
Time(Time),
}
impl From<commands::DeltaStep> for DeltaStep {
fn from(step: commands::DeltaStep) -> Self {
match step {
commands::DeltaStep::Year(n) => Self::Year(n),
commands::DeltaStep::Month(n) => Self::Month(n),
commands::DeltaStep::MonthReverse(n) => Self::MonthReverse(n),
commands::DeltaStep::Day(n) => Self::Day(n),
commands::DeltaStep::Week(n) => Self::Week(n),
commands::DeltaStep::Hour(n) => Self::Hour(n),
commands::DeltaStep::Minute(n) => Self::Minute(n),
commands::DeltaStep::Weekday(n, wd) => Self::Weekday(n, wd),
}
}
}
impl DeltaStep {
/// A lower bound on days
fn lower_bound(&self) -> i32 {
match self {
DeltaStep::Year(n) => {
@ -40,9 +73,11 @@ impl DeltaStep {
Ordering::Equal => 0,
Ordering::Greater => *n * 7 - 7,
},
DeltaStep::Time(_) => 0,
}
}
/// An upper bound on days
fn upper_bound(&self) -> i32 {
match self {
DeltaStep::Year(n) => {
@ -80,16 +115,30 @@ impl DeltaStep {
Ordering::Equal => 0,
Ordering::Greater => *n * 7 - 1,
},
DeltaStep::Time(_) => 1,
}
}
}
#[derive(Debug, Default)]
pub struct Delta {
pub steps: Vec<DeltaStep>,
}
impl From<&commands::Delta> for Delta {
fn from(delta: &commands::Delta) -> Self {
Self {
steps: delta.0.iter().map(|&step| step.into()).collect(),
}
}
}
impl Delta {
pub fn lower_bound(&self) -> i32 {
self.0.iter().map(DeltaStep::lower_bound).sum()
self.steps.iter().map(DeltaStep::lower_bound).sum()
}
pub fn upper_bound(&self) -> i32 {
self.0.iter().map(DeltaStep::upper_bound).sum()
self.steps.iter().map(DeltaStep::upper_bound).sum()
}
}

View file

@ -2,7 +2,7 @@ use std::collections::HashMap;
use chrono::NaiveDate;
use crate::files::commands::{DoneDate, Time};
use crate::files::commands::DoneDate;
use crate::files::Source;
use super::range::DateRange;

68
src/eval/formula_spec.rs Normal file
View file

@ -0,0 +1,68 @@
use crate::files::commands::{self, Expr, Time, Var};
use super::delta::{Delta, DeltaStep};
pub struct FormulaSpec {
// TODO Implement more efficient exprs and expr evaluation
pub start: Expr,
pub start_delta: Delta,
pub start_time: Option<Time>,
pub end_delta: Delta,
}
impl From<&commands::FormulaSpec> for FormulaSpec {
fn from(spec: &commands::FormulaSpec) -> Self {
let start: Expr = spec.start.as_ref().cloned().unwrap_or(Expr::Lit(1));
let start_delta: Delta = spec
.start_delta
.as_ref()
.map(|delta| delta.into())
.unwrap_or_default();
let mut end_delta: Delta = spec
.end_delta
.as_ref()
.map(|delta| delta.into())
.unwrap_or_default();
if let Some(time) = spec.end_time {
end_delta.steps.push(DeltaStep::Time(time));
}
Self {
start,
start_delta,
start_time: spec.start_time,
end_delta,
}
}
}
impl From<&commands::WeekdaySpec> for FormulaSpec {
fn from(spec: &commands::WeekdaySpec) -> Self {
let start = Expr::Eq(
Box::new(Expr::Var(Var::Weekday)),
Box::new(Expr::Var(spec.start.into())),
);
let mut end_delta = Delta::default();
if let Some(wd) = spec.end {
end_delta.steps.push(DeltaStep::Weekday(1, wd));
}
if let Some(delta) = &spec.end_delta {
for step in &delta.0 {
end_delta.steps.push((*step).into());
}
}
if let Some(time) = spec.end_time {
end_delta.steps.push(DeltaStep::Time(time));
}
Self {
start,
start_delta: Default::default(),
start_time: spec.start_time,
end_delta,
}
}
}