use std::fmt::Display;
use super::types::{Arity, ColumIndexationBy, DynamicValue};
fn format_column_indexation_error(
f: &mut std::fmt::Formatter,
indexation: &ColumIndexationBy,
) -> std::fmt::Result {
match indexation {
ColumIndexationBy::Name(name) => write!(f, "cannot find column \"{}\"", name),
ColumIndexationBy::Pos(pos) => write!(f, "column {} out of range", pos),
ColumIndexationBy::ReversePos(pos) => write!(f, "column {} out of range", -(*pos as isize)),
ColumIndexationBy::NameAndNth((name, nth)) => {
write!(f, "cannot find column (\"{}\", {})", name, nth)
}
}
}
#[derive(Debug, PartialEq)]
pub enum ConcretizationError {
ParseError(String),
ColumnNotFound(ColumIndexationBy),
InvalidRegex(String),
UnknownFunction(String),
InvalidArity(String, InvalidArity),
TooManyArguments(usize),
UnknownArgumentName(String),
StaticEvaluationError(SpecifiedEvaluationError),
NotStaticallyAnalyzable,
}
impl Display for ConcretizationError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Self::ColumnNotFound(indexation) => format_column_indexation_error(f, indexation),
Self::UnknownFunction(name) => write!(f, "unknown function \"{}\"", name),
Self::UnknownArgumentName(arg_name) => write!(f, "unknown argument \"{}\"", arg_name),
Self::ParseError(expr) => write!(f, "could not parse expression: {}", expr),
Self::InvalidRegex(pattern) => write!(f, "invalid regex {}", pattern),
Self::InvalidArity(name, arity) => write!(f, "{}: {}", name, arity),
Self::TooManyArguments(actual) => {
write!(f, "got {} arguments. Cannot exceed 8.", actual)
}
Self::StaticEvaluationError(error) => error.fmt(f),
Self::NotStaticallyAnalyzable => write!(f, "not statically analyzable"),
}
}
}
#[derive(Debug, PartialEq)]
pub struct InvalidArity {
expected: Arity,
got: usize,
}
impl InvalidArity {
pub fn from_arity(arity: Arity, got: usize) -> Self {
Self {
expected: arity,
got,
}
}
}
impl Display for InvalidArity {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self.expected {
Arity::Min(min) => write!(
f,
"expected at least {} argument{} but got {}",
min,
if min > &1 { "s" } else { "" },
self.got
),
Arity::Strict(arity) => write!(
f,
"expected {} argument{} but got {}",
arity,
if arity > &1 { "s" } else { "" },
self.got
),
Arity::Range(range) => write!(
f,
"expected between {} and {} arguments but got {}",
range.start(),
range.end(),
self.got
),
}
}
}
#[derive(Debug, PartialEq)]
pub struct SpecifiedEvaluationError {
pub function_name: String,
pub reason: EvaluationError,
}
impl SpecifiedEvaluationError {
pub fn new(name: &str, reason: EvaluationError) -> Self {
Self {
function_name: name.to_string(),
reason,
}
}
}
impl Display for SpecifiedEvaluationError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"error when calling function \"{}\": {}",
self.function_name, self.reason
)
}
}
#[derive(Debug, PartialEq)]
pub enum EvaluationError {
InvalidArity(InvalidArity),
InvalidPath,
InvalidLambda,
NotImplemented(String),
IO(String),
DateTime(String),
Cast(String, String),
Custom(String),
UnsupportedEncoding(String),
UnsupportedDecoderTrap(String),
DecodeError,
ColumnNotFound(ColumIndexationBy),
ColumnOutOfRange(usize),
UnicodeDecodeError,
JSONParseError,
}
impl EvaluationError {
pub fn from_cast(from_value: &DynamicValue, expected: &str) -> Self {
Self::Cast(from_value.type_of().to_string(), expected.to_string())
}
pub fn specify(self, function_name: &str) -> SpecifiedEvaluationError {
SpecifiedEvaluationError {
function_name: function_name.to_string(),
reason: self,
}
}
pub fn anonymous(self) -> SpecifiedEvaluationError {
SpecifiedEvaluationError {
function_name: "<expr>".to_string(),
reason: self,
}
}
}
impl Display for EvaluationError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::InvalidPath => write!(f, "invalid posix path"),
Self::InvalidArity(arity) => arity.fmt(f),
Self::InvalidLambda => write!(f, "provided argument is not a lambda"),
Self::IO(msg) => write!(f, "{}", msg),
Self::DateTime(msg) => write!(f, "{}", msg),
Self::Custom(msg) => write!(f, "{}", msg),
Self::Cast(from_type, to_type) => write!(
f,
"cannot safely cast from type \"{}\" to type \"{}\"",
from_type, to_type
),
Self::NotImplemented(t) => {
write!(f, "not implemented for values of type \"{}\" as of yet", t)
}
Self::UnsupportedEncoding(name) => write!(f, "unsupported encoding \"{}\"", name),
Self::UnsupportedDecoderTrap(name) => {
write!(
f,
"unsupported encoder trap \"{}\". Must be one of strict, replace, ignore.",
name
)
}
Self::DecodeError => write!(f, "could not decode"),
Self::ColumnNotFound(indexation) => format_column_indexation_error(f, indexation),
Self::ColumnOutOfRange(idx) => write!(f, "column \"{}\" is out of range", idx),
Self::UnicodeDecodeError => write!(f, "unicode decode error"),
Self::JSONParseError => write!(f, "json parse error"),
}
}
}
#[cfg(test)]
#[derive(Debug, PartialEq)]
pub enum RunError {
Prepare(ConcretizationError),
Evaluation(SpecifiedEvaluationError),
}