Add eval representation of FormulaSpec
This commit is contained in:
parent
21739c7314
commit
e827556c84
5 changed files with 165 additions and 10 deletions
26
src/eval.rs
26
src/eval.rs
|
|
@ -3,15 +3,18 @@ use std::result;
|
||||||
|
|
||||||
use chrono::{Datelike, NaiveDate};
|
use chrono::{Datelike, NaiveDate};
|
||||||
|
|
||||||
|
use crate::files::commands::DateSpec;
|
||||||
use crate::files::commands::{Birthday, Command, DoneDate, Note, Spec, Task};
|
use crate::files::commands::{Birthday, Command, DoneDate, Note, Spec, Task};
|
||||||
use crate::files::{Files, Source, SourcedCommand};
|
use crate::files::{Files, Source, SourcedCommand};
|
||||||
|
|
||||||
use self::entry::EntryMap;
|
use self::entry::EntryMap;
|
||||||
pub use self::entry::{Entry, EntryKind};
|
pub use self::entry::{Entry, EntryKind};
|
||||||
|
use self::formula_spec::FormulaSpec;
|
||||||
pub use self::range::DateRange;
|
pub use self::range::DateRange;
|
||||||
|
|
||||||
mod delta;
|
mod delta;
|
||||||
mod entry;
|
mod entry;
|
||||||
|
mod formula_spec;
|
||||||
mod range;
|
mod range;
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
|
@ -28,13 +31,34 @@ struct Eval {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eval {
|
impl Eval {
|
||||||
|
fn eval_date_spec(
|
||||||
|
&mut self,
|
||||||
|
spec: &DateSpec,
|
||||||
|
last_done: Option<NaiveDate>,
|
||||||
|
new_entry: impl Fn(Source, Option<DoneDate>) -> Entry,
|
||||||
|
) -> Result<()> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eval_formula_spec(
|
||||||
|
&mut self,
|
||||||
|
spec: FormulaSpec,
|
||||||
|
new_entry: impl Fn(Source, Option<DoneDate>) -> Entry,
|
||||||
|
) -> Result<()> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn eval_spec(
|
fn eval_spec(
|
||||||
&mut self,
|
&mut self,
|
||||||
spec: &Spec,
|
spec: &Spec,
|
||||||
last_done: Option<NaiveDate>,
|
last_done: Option<NaiveDate>,
|
||||||
new_entry: impl Fn(Source, Option<DoneDate>) -> Entry,
|
new_entry: impl Fn(Source, Option<DoneDate>) -> Entry,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
todo!()
|
match spec {
|
||||||
|
Spec::Date(spec) => self.eval_date_spec(spec, last_done, new_entry),
|
||||||
|
Spec::Weekday(spec) => self.eval_formula_spec(spec.into(), new_entry),
|
||||||
|
Spec::Formula(spec) => self.eval_formula_spec(spec.into(), new_entry),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_dones(&mut self, task: &Task) {
|
fn eval_dones(&mut self, task: &Task) {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,41 @@
|
||||||
use std::cmp::Ordering;
|
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 {
|
impl DeltaStep {
|
||||||
|
/// A lower bound on days
|
||||||
fn lower_bound(&self) -> i32 {
|
fn lower_bound(&self) -> i32 {
|
||||||
match self {
|
match self {
|
||||||
DeltaStep::Year(n) => {
|
DeltaStep::Year(n) => {
|
||||||
|
|
@ -40,9 +73,11 @@ impl DeltaStep {
|
||||||
Ordering::Equal => 0,
|
Ordering::Equal => 0,
|
||||||
Ordering::Greater => *n * 7 - 7,
|
Ordering::Greater => *n * 7 - 7,
|
||||||
},
|
},
|
||||||
|
DeltaStep::Time(_) => 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An upper bound on days
|
||||||
fn upper_bound(&self) -> i32 {
|
fn upper_bound(&self) -> i32 {
|
||||||
match self {
|
match self {
|
||||||
DeltaStep::Year(n) => {
|
DeltaStep::Year(n) => {
|
||||||
|
|
@ -80,16 +115,30 @@ impl DeltaStep {
|
||||||
Ordering::Equal => 0,
|
Ordering::Equal => 0,
|
||||||
Ordering::Greater => *n * 7 - 1,
|
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 {
|
impl Delta {
|
||||||
pub fn lower_bound(&self) -> i32 {
|
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 {
|
pub fn upper_bound(&self) -> i32 {
|
||||||
self.0.iter().map(DeltaStep::upper_bound).sum()
|
self.steps.iter().map(DeltaStep::upper_bound).sum()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use std::collections::HashMap;
|
||||||
|
|
||||||
use chrono::NaiveDate;
|
use chrono::NaiveDate;
|
||||||
|
|
||||||
use crate::files::commands::{DoneDate, Time};
|
use crate::files::commands::DoneDate;
|
||||||
use crate::files::Source;
|
use crate::files::Source;
|
||||||
|
|
||||||
use super::range::DateRange;
|
use super::range::DateRange;
|
||||||
|
|
|
||||||
68
src/eval/formula_spec.rs
Normal file
68
src/eval/formula_spec.rs
Normal 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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use chrono::NaiveDate;
|
use chrono::NaiveDate;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct Time {
|
pub struct Time {
|
||||||
pub hour: u8,
|
pub hour: u8,
|
||||||
pub min: u8,
|
pub min: u8,
|
||||||
|
|
@ -44,7 +44,7 @@ impl Weekday {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum DeltaStep {
|
pub enum DeltaStep {
|
||||||
/// `y`, move by a year, keeping the same month and day
|
/// `y`, move by a year, keeping the same month and day
|
||||||
Year(i32),
|
Year(i32),
|
||||||
|
|
@ -94,7 +94,7 @@ impl DeltaStep {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Default)]
|
||||||
pub struct Delta(pub Vec<DeltaStep>);
|
pub struct Delta(pub Vec<DeltaStep>);
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
@ -125,7 +125,7 @@ pub struct WeekdaySpec {
|
||||||
pub end_time: Option<Time>,
|
pub end_time: Option<Time>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum Var {
|
pub enum Var {
|
||||||
/// `true`, always 1
|
/// `true`, always 1
|
||||||
True,
|
True,
|
||||||
|
|
@ -243,7 +243,21 @@ impl Var {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
impl From<Weekday> for Var {
|
||||||
|
fn from(wd: Weekday) -> Self {
|
||||||
|
match wd {
|
||||||
|
Weekday::Monday => Self::Monday,
|
||||||
|
Weekday::Tuesday => Self::Tuesday,
|
||||||
|
Weekday::Wednesday => Self::Wednesday,
|
||||||
|
Weekday::Thursday => Self::Thursday,
|
||||||
|
Weekday::Friday => Self::Friday,
|
||||||
|
Weekday::Saturday => Self::Saturday,
|
||||||
|
Weekday::Sunday => Self::Sunday,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
pub enum Expr {
|
pub enum Expr {
|
||||||
Lit(i64),
|
Lit(i64),
|
||||||
Var(Var),
|
Var(Var),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue