today/src/eval/error.rs

177 lines
6.6 KiB
Rust

use chrono::NaiveDate;
use codespan_reporting::diagnostic::{Diagnostic, Label};
use codespan_reporting::files::Files;
use codespan_reporting::term::Config;
use crate::error::Eprint;
use crate::files::primitives::{Span, Time};
#[derive(Debug, thiserror::Error)]
pub enum Error<S> {
/// A delta step resulted in an invalid date.
#[error("delta step resulted in invalid date")]
DeltaInvalidStep {
index: S,
span: Span,
start: NaiveDate,
start_time: Option<Time>,
prev: NaiveDate,
prev_time: Option<Time>,
},
/// A time-based delta step was applied to a date without time.
#[error("time-based delta step applied to date without time")]
DeltaNoTime {
index: S,
span: Span,
start: NaiveDate,
prev: NaiveDate,
},
/// A `DATE`'s repeat delta did not move the date forwards in time. Instead,
/// it either remained at the current date (`to == from`) or moved backwards
/// in time (`to < from`).
#[error("repeat delta did not move forwards")]
RepeatDidNotMoveForwards {
index: S,
span: Span,
from: NaiveDate,
to: NaiveDate,
},
/// A `REMIND`'s delta did not move backwards in time from the entry's start
/// date. Instead, it either remained at the start date (`to == from`) or
/// moved forwards in time (`from < to`).
#[error("remind delta did not move backwards")]
RemindDidNotMoveBackwards {
index: S,
span: Span,
from: NaiveDate,
to: NaiveDate,
},
/// A `MOVE a TO b` statement was executed, but there was no entry at the
/// date `a`.
#[error("tried to move nonexisting entry")]
MoveWithoutSource { index: S, span: Span },
/// A `MOVE a TO b` statement was executed where `b` contains a time but `a`
/// doesn't was executed.
#[error("tried to move un-timed entry to new time")]
TimedMoveWithoutTime { index: S, span: Span },
/// A division by zero has occurred.
#[error("tried to divide by zero")]
DivByZero {
index: S,
span: Span,
date: NaiveDate,
},
/// A modulo operation by zero has occurred.
#[error("tried to modulo by zero")]
ModByZero {
index: S,
span: Span,
date: NaiveDate,
},
/// Easter calculation failed.
#[error("easter calculation failed")]
Easter {
index: S,
span: Span,
date: NaiveDate,
msg: &'static str,
},
}
impl<S> Error<S> {
fn fmt_date_time(date: NaiveDate, time: Option<Time>) -> String {
match time {
None => format!("{}", date),
Some(time) => format!("{} {}", date, time),
}
}
}
impl<'a, F: Files<'a>> Eprint<'a, F> for Error<F::FileId> {
fn eprint<'f: 'a>(&self, files: &'f F, config: &Config) {
let diagnostic = match self {
Error::DeltaInvalidStep {
index,
span,
start,
start_time,
prev,
prev_time,
} => {
let start_str = Self::fmt_date_time(*start, *start_time);
let prev_str = Self::fmt_date_time(*prev, *prev_time);
Diagnostic::error()
.with_message("Delta step resulted in invalid date")
.with_labels(vec![
Label::primary(*index, span).with_message("At this step")
])
.with_notes(vec![
format!("Date before applying delta: {start_str}"),
format!("Date before applying this step: {prev_str}"),
])
}
Error::DeltaNoTime {
index,
span,
start,
prev,
} => Diagnostic::error()
.with_message("Time-based delta step applied to date without time")
.with_labels(vec![
Label::primary(*index, span).with_message("At this step")
])
.with_notes(vec![
format!("Date before applying delta: {start}"),
format!("Date before applying this step: {prev}"),
]),
Error::RepeatDidNotMoveForwards {
index,
span,
from,
to,
} => Diagnostic::error()
.with_message("Repeat delta did not move forwards")
.with_labels(vec![Label::primary(*index, span).with_message("This delta")])
.with_notes(vec![format!("Moved from {from} to {to}")]),
Error::RemindDidNotMoveBackwards {
index,
span,
from,
to,
} => Diagnostic::error()
.with_message("Remind delta did not move backwards")
.with_labels(vec![Label::primary(*index, span).with_message("This delta")])
.with_notes(vec![format!("Moved from {from} to {to}")]),
Error::MoveWithoutSource { index, span } => Diagnostic::error()
.with_message("Tried to move nonexistent entry")
.with_labels(vec![Label::primary(*index, span).with_message("Here")]),
Error::TimedMoveWithoutTime { index, span } => Diagnostic::error()
.with_message("Tried to move un-timed entry to new time")
.with_labels(vec![Label::primary(*index, span).with_message("Here")]),
Error::DivByZero { index, span, date } => Diagnostic::error()
.with_message("Tried to divide by zero")
.with_labels(vec![
Label::primary(*index, span).with_message("This expression")
])
.with_notes(vec![format!("At date: {date}")]),
Error::ModByZero { index, span, date } => Diagnostic::error()
.with_message("Tried to modulo by zero")
.with_labels(vec![
Label::primary(*index, span).with_message("This expression")
])
.with_notes(vec![format!("At date: {date}")]),
Error::Easter {
index,
span,
date,
msg,
} => Diagnostic::error()
.with_message("Failed to calculate easter")
.with_labels(vec![
Label::primary(*index, span).with_message("This expression")
])
.with_notes(vec![format!("At date: {date}"), format!("Reason: {msg}")]),
};
Self::eprint_diagnostic(files, config, &diagnostic);
}
}