From 1170009b4f39b3936e3a1eb0b220ee713fe3f70a Mon Sep 17 00:00:00 2001 From: Joscha Date: Mon, 29 Nov 2021 11:14:48 +0000 Subject: [PATCH] Carry source spans for error messages --- src/eval/date_spec.rs | 6 ++- src/eval/delta.rs | 14 ++++--- src/eval/formula_spec.rs | 18 ++++++--- src/files/commands.rs | 56 +++++++++++++++++++++++--- src/files/format.rs | 10 ++++- src/files/parse.rs | 87 ++++++++++++++++++++++------------------ 6 files changed, 132 insertions(+), 59 deletions(-) diff --git a/src/eval/date_spec.rs b/src/eval/date_spec.rs index db8871d..377afb4 100644 --- a/src/eval/date_spec.rs +++ b/src/eval/date_spec.rs @@ -1,6 +1,6 @@ use chrono::NaiveDate; -use crate::files::commands::{self, DoneDate, Time}; +use crate::files::commands::{self, DoneDate, Spanned, Time}; use crate::files::Source; use super::delta::{Delta, DeltaStep}; @@ -29,7 +29,9 @@ impl From<&commands::DateSpec> for DateSpec { .map(|delta| delta.into()) .unwrap_or_default(); if let Some(time) = spec.end_time { - end_delta.steps.push(DeltaStep::Time(time)); + end_delta + .steps + .push(Spanned::new(time.span, DeltaStep::Time(time.value))); } let repeat: Option = spec.repeat.as_ref().map(|repeat| (&repeat.delta).into()); diff --git a/src/eval/delta.rs b/src/eval/delta.rs index f9ddc05..0080074 100644 --- a/src/eval/delta.rs +++ b/src/eval/delta.rs @@ -1,6 +1,6 @@ use std::cmp::Ordering; -use crate::files::commands::{self, Time, Weekday}; +use crate::files::commands::{self, Spanned, Time, Weekday}; /// Like [`commands::DeltaStep`] but includes a new constructor, /// [`DeltaStep::Time`]. @@ -122,23 +122,27 @@ impl DeltaStep { #[derive(Debug, Default)] pub struct Delta { - pub steps: Vec, + pub steps: Vec>, } impl From<&commands::Delta> for Delta { fn from(delta: &commands::Delta) -> Self { Self { - steps: delta.0.iter().map(|&step| step.into()).collect(), + steps: delta + .0 + .iter() + .map(|step| Spanned::new(step.span, step.value.into())) + .collect(), } } } impl Delta { pub fn lower_bound(&self) -> i32 { - self.steps.iter().map(DeltaStep::lower_bound).sum() + self.steps.iter().map(|step| step.value.lower_bound()).sum() } pub fn upper_bound(&self) -> i32 { - self.steps.iter().map(DeltaStep::upper_bound).sum() + self.steps.iter().map(|step| step.value.upper_bound()).sum() } } diff --git a/src/eval/formula_spec.rs b/src/eval/formula_spec.rs index 3660a70..7321b2f 100644 --- a/src/eval/formula_spec.rs +++ b/src/eval/formula_spec.rs @@ -1,4 +1,4 @@ -use crate::files::commands::{self, DoneDate, Expr, Time, Var}; +use crate::files::commands::{self, DoneDate, Expr, Spanned, Time, Var}; use crate::files::Source; use super::delta::{Delta, DeltaStep}; @@ -28,7 +28,9 @@ impl From<&commands::FormulaSpec> for FormulaSpec { .map(|delta| delta.into()) .unwrap_or_default(); if let Some(time) = spec.end_time { - end_delta.steps.push(DeltaStep::Time(time)); + end_delta + .steps + .push(Spanned::new(time.span, DeltaStep::Time(time.value))); } Self { @@ -49,15 +51,21 @@ impl From<&commands::WeekdaySpec> for FormulaSpec { let mut end_delta = Delta::default(); if let Some(wd) = spec.end { - end_delta.steps.push(DeltaStep::Weekday(1, wd)); + end_delta + .steps + .push(Spanned::new(wd.span, DeltaStep::Weekday(1, wd.value))); } if let Some(delta) = &spec.end_delta { for step in &delta.0 { - end_delta.steps.push((*step).into()); + end_delta + .steps + .push(Spanned::new(step.span, step.value.into())); } } if let Some(time) = spec.end_time { - end_delta.steps.push(DeltaStep::Time(time)); + end_delta + .steps + .push(Spanned::new(time.span, DeltaStep::Time(time.value))); } Self { diff --git a/src/files/commands.rs b/src/files/commands.rs index 178c106..f5be0a0 100644 --- a/src/files/commands.rs +++ b/src/files/commands.rs @@ -1,5 +1,48 @@ +use std::fmt; + use chrono::NaiveDate; +#[derive(Debug, Clone, Copy)] +pub struct Span { + pub start: usize, + pub end: usize, +} + +impl<'a> From<&pest::Span<'a>> for Span { + fn from(pspan: &pest::Span<'a>) -> Self { + Self { + start: pspan.start(), + end: pspan.end(), + } + } +} + +#[derive(Clone, Copy)] +pub struct Spanned { + pub span: Span, + pub value: T, +} + +impl fmt::Debug for Spanned { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + self.value.fmt(f) + } +} + +impl Spanned { + pub fn new(span: Span, value: T) -> Self { + Self { span, value } + } +} + +// I don't know how one would write this. It works as a polymorphic standalone +// function, but not in an impl block. +// impl> Spanned { +// pub fn convert(&self) -> Spanned { +// Self::new(self.span, self.value.into()) +// } +// } + #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct Time { pub hour: u8, @@ -95,7 +138,7 @@ impl DeltaStep { } #[derive(Debug, Default)] -pub struct Delta(pub Vec); +pub struct Delta(pub Vec>); #[derive(Debug)] pub struct Repeat { @@ -110,9 +153,9 @@ pub struct DateSpec { pub start: NaiveDate, pub start_delta: Option, pub start_time: Option