use crate::parser;
use crate::parser::ParseError;
use std::error::Error;
use std::fmt::Debug;
use std::str::FromStr;
use thiserror::Error;
pub fn eval<T: Eval>(expression: &str) -> Result<T, EvalError<T>> {
parser::parse::<T>(expression)?
.eval()
.map_err(|err| EvalError::EvalError(err))
}
#[derive(Error, Debug, PartialEq)]
pub enum EvalError<T: Eval> {
#[error("could not parse expression: {0}")]
ParseError(#[from] ParseError<T>),
#[error("could not evaluate expression: {0}")]
EvalError(<T as Eval>::ErrEval),
}
pub trait Eval: EvalParse + Clone {
type ErrEval: Error + PartialEq;
fn eq(self, other: Self) -> Result<Self, Self::ErrEval>;
fn neq(self, other: Self) -> Result<Self, Self::ErrEval>;
fn gte(self, other: Self) -> Result<Self, Self::ErrEval>;
fn gt(self, other: Self) -> Result<Self, Self::ErrEval>;
fn lte(self, other: Self) -> Result<Self, Self::ErrEval>;
fn lt(self, other: Self) -> Result<Self, Self::ErrEval>;
fn and(self, other: Self) -> Result<Self, Self::ErrEval>;
fn or(self, other: Self) -> Result<Self, Self::ErrEval>;
fn bit_and(self, other: Self) -> Result<Self, Self::ErrEval>;
fn bit_or(self, other: Self) -> Result<Self, Self::ErrEval>;
fn add(self, other: Self) -> Result<Self, Self::ErrEval>;
fn sub(self, other: Self) -> Result<Self, Self::ErrEval>;
fn mul(self, other: Self) -> Result<Self, Self::ErrEval>;
fn div(self, other: Self) -> Result<Self, Self::ErrEval>;
fn rem(self, other: Self) -> Result<Self, Self::ErrEval>;
fn exp(self, other: Self) -> Result<Self, Self::ErrEval>;
fn plus(self) -> Result<Self, Self::ErrEval>;
fn minus(self) -> Result<Self, Self::ErrEval>;
fn not(self) -> Result<Self, Self::ErrEval>;
fn bit_not(self) -> Result<Self, Self::ErrEval>;
}
pub trait EvalParse: Sized {
type ErrParse: Error + PartialEq;
fn parse(literal: &str) -> Result<Self, Self::ErrParse>;
}
impl<T: FromStr + Sized> EvalParse for T
where
<T as FromStr>::Err: Error + PartialEq,
{
type ErrParse = <T as FromStr>::Err;
fn parse(literal: &str) -> Result<T, Self::ErrParse> {
literal.parse()
}
}
macro_rules! eval_int {
($i:ty) => {
impl Eval for $i {
type ErrEval = IntEvalError;
fn eq(self, other: Self) -> Result<Self, Self::ErrEval> {
match self == other {
true => Ok(1),
false => Ok(0),
}
}
fn neq(self, other: Self) -> Result<Self, Self::ErrEval> {
match self != other {
true => Ok(1),
false => Ok(0),
}
}
fn gte(self, other: Self) -> Result<Self, Self::ErrEval> {
match self >= other {
true => Ok(1),
false => Ok(0),
}
}
fn gt(self, other: Self) -> Result<Self, Self::ErrEval> {
match self > other {
true => Ok(1),
false => Ok(0),
}
}
fn lte(self, other: Self) -> Result<Self, Self::ErrEval> {
match self <= other {
true => Ok(1),
false => Ok(0),
}
}
fn lt(self, other: Self) -> Result<Self, Self::ErrEval> {
match self < other {
true => Ok(1),
false => Ok(0),
}
}
fn and(self, other: Self) -> Result<Self, Self::ErrEval> {
match (self != 0) && (other != 0) {
true => Ok(1),
false => Ok(0),
}
}
fn or(self, other: Self) -> Result<Self, Self::ErrEval> {
match (self != 0) || (other != 0) {
true => Ok(1),
false => Ok(0),
}
}
fn bit_and(self, other: Self) -> Result<Self, Self::ErrEval> {
Ok(self & other)
}
fn bit_or(self, other: Self) -> Result<Self, Self::ErrEval> {
Ok(self | other)
}
fn add(self, other: Self) -> Result<Self, Self::ErrEval> {
self.checked_add(other).ok_or(IntEvalError::Overflow)
}
fn sub(self, other: Self) -> Result<Self, Self::ErrEval> {
self.checked_sub(other).ok_or(IntEvalError::Overflow)
}
fn mul(self, other: Self) -> Result<Self, Self::ErrEval> {
self.checked_mul(other).ok_or(IntEvalError::Overflow)
}
fn div(self, other: Self) -> Result<Self, Self::ErrEval> {
self.checked_div(other).ok_or(IntEvalError::DivideByZero)
}
fn rem(self, other: Self) -> Result<Self, Self::ErrEval> {
self.checked_rem(other).ok_or(IntEvalError::DivideByZero)
}
fn exp(self, other: Self) -> Result<Self, Self::ErrEval> {
self.checked_pow(other.try_into().map_err(|_| IntEvalError::Overflow)?)
.ok_or(IntEvalError::Overflow)
}
fn plus(self) -> Result<Self, Self::ErrEval> {
Ok(self)
}
fn minus(self) -> Result<Self, Self::ErrEval> {
self.checked_neg().ok_or(IntEvalError::Overflow)
}
fn not(self) -> Result<Self, Self::ErrEval> {
match self {
0 => Ok(1),
_ => Ok(0),
}
}
fn bit_not(self) -> Result<Self, Self::ErrEval> {
Ok(!self)
}
}
};
}
#[derive(Error, Debug, PartialEq)]
pub enum IntEvalError {
#[error("division by zero")]
DivideByZero,
#[error("operation resulted in overflow")]
Overflow,
}
eval_int!(u8);
eval_int!(u16);
eval_int!(u32);
eval_int!(u64);
eval_int!(u128);
eval_int!(usize);
eval_int!(i8);
eval_int!(i16);
eval_int!(i32);
eval_int!(i64);
eval_int!(i128);
eval_int!(isize);
macro_rules! eval_float {
($i:ty) => {
impl Eval for $i {
type ErrEval = FloatEvalError;
fn eq(self, other: Self) -> Result<Self, Self::ErrEval> {
match self == other {
true => Ok(1.),
false => Ok(0.),
}
}
fn neq(self, other: Self) -> Result<Self, Self::ErrEval> {
match self != other {
true => Ok(1.),
false => Ok(0.),
}
}
fn gte(self, other: Self) -> Result<Self, Self::ErrEval> {
match self >= other {
true => Ok(1.),
false => Ok(0.),
}
}
fn gt(self, other: Self) -> Result<Self, Self::ErrEval> {
match self > other {
true => Ok(1.),
false => Ok(0.),
}
}
fn lte(self, other: Self) -> Result<Self, Self::ErrEval> {
match self <= other {
true => Ok(1.),
false => Ok(0.),
}
}
fn lt(self, other: Self) -> Result<Self, Self::ErrEval> {
match self < other {
true => Ok(1.),
false => Ok(0.),
}
}
fn and(self, other: Self) -> Result<Self, Self::ErrEval> {
match (self != 0.) && (other != 0.) {
true => Ok(1.),
false => Ok(0.),
}
}
fn or(self, other: Self) -> Result<Self, Self::ErrEval> {
match (self != 0.) || (other != 0.) {
true => Ok(1.),
false => Ok(0.),
}
}
fn bit_and(self, _other: Self) -> Result<Self, Self::ErrEval> {
Err(FloatEvalError::UnsupportedOperation("&"))
}
fn bit_or(self, _other: Self) -> Result<Self, Self::ErrEval> {
Err(FloatEvalError::UnsupportedOperation("|"))
}
fn add(self, other: Self) -> Result<Self, Self::ErrEval> {
Ok(self + other)
}
fn sub(self, other: Self) -> Result<Self, Self::ErrEval> {
Ok(self - other)
}
fn mul(self, other: Self) -> Result<Self, Self::ErrEval> {
Ok(self * other)
}
fn div(self, other: Self) -> Result<Self, Self::ErrEval> {
Ok(self / other)
}
fn rem(self, other: Self) -> Result<Self, Self::ErrEval> {
Ok(self % other)
}
fn exp(self, other: Self) -> Result<Self, Self::ErrEval> {
Ok(self.powf(other))
}
fn plus(self) -> Result<Self, Self::ErrEval> {
Ok(self)
}
fn minus(self) -> Result<Self, Self::ErrEval> {
Ok(-self)
}
fn not(self) -> Result<Self, Self::ErrEval> {
match self == 0. {
true => Ok(1.),
false => Ok(0.),
}
}
fn bit_not(self) -> Result<Self, Self::ErrEval> {
Err(FloatEvalError::UnsupportedOperation("!"))
}
}
};
}
#[derive(Error, Debug, PartialEq)]
pub enum FloatEvalError {
#[error("use of unsupported operator: {0}")]
UnsupportedOperation(&'static str),
}
eval_float!(f32);
eval_float!(f64);