use crate::function::builtin::builtin_function;
use crate::{
context::Context,
error::*,
value::{
numeric_types::{
default_numeric_types::DefaultNumericTypes, EvalexprFloat, EvalexprInt,
EvalexprNumericTypes,
},
Value,
},
ContextWithMutableVariables,
};
mod display;
#[derive(Debug, PartialEq, Clone)]
pub enum Operator<NumericTypes: EvalexprNumericTypes = DefaultNumericTypes> {
RootNode,
Add,
Sub,
Neg,
Mul,
Div,
Mod,
Exp,
Eq,
Neq,
Gt,
Lt,
Geq,
Leq,
And,
Or,
Not,
Assign,
AddAssign,
SubAssign,
MulAssign,
DivAssign,
ModAssign,
ExpAssign,
AndAssign,
OrAssign,
Tuple,
Chain,
Const {
value: Value<NumericTypes>,
},
VariableIdentifierWrite {
identifier: String,
},
VariableIdentifierRead {
identifier: String,
},
FunctionIdentifier {
identifier: String,
},
}
impl<NumericTypes: EvalexprNumericTypes> Operator<NumericTypes> {
pub(crate) fn value(value: Value<NumericTypes>) -> Self {
Operator::Const { value }
}
pub(crate) fn variable_identifier_write(identifier: String) -> Self {
Operator::VariableIdentifierWrite { identifier }
}
pub(crate) fn variable_identifier_read(identifier: String) -> Self {
Operator::VariableIdentifierRead { identifier }
}
pub(crate) fn function_identifier(identifier: String) -> Self {
Operator::FunctionIdentifier { identifier }
}
pub(crate) const fn precedence(&self) -> i32 {
use crate::operator::Operator::*;
match self {
RootNode => 200,
Add | Sub => 95,
Neg => 110,
Mul | Div | Mod => 100,
Exp => 120,
Eq | Neq | Gt | Lt | Geq | Leq => 80,
And => 75,
Or => 70,
Not => 110,
Assign | AddAssign | SubAssign | MulAssign | DivAssign | ModAssign | ExpAssign
| AndAssign | OrAssign => 50,
Tuple => 40,
Chain => 0,
Const { .. } => 200,
VariableIdentifierWrite { .. } | VariableIdentifierRead { .. } => 200,
FunctionIdentifier { .. } => 190,
}
}
pub(crate) const fn is_left_to_right(&self) -> bool {
use crate::operator::Operator::*;
!matches!(self, Assign | FunctionIdentifier { .. })
}
pub(crate) const fn is_sequence(&self) -> bool {
use crate::operator::Operator::*;
matches!(self, Tuple | Chain)
}
pub(crate) fn is_leaf(&self) -> bool {
self.max_argument_amount() == Some(0)
}
pub(crate) const fn max_argument_amount(&self) -> Option<usize> {
use crate::operator::Operator::*;
match self {
Add | Sub | Mul | Div | Mod | Exp | Eq | Neq | Gt | Lt | Geq | Leq | And | Or
| Assign | AddAssign | SubAssign | MulAssign | DivAssign | ModAssign | ExpAssign
| AndAssign | OrAssign => Some(2),
Tuple | Chain => None,
Not | Neg | RootNode => Some(1),
Const { .. } => Some(0),
VariableIdentifierWrite { .. } | VariableIdentifierRead { .. } => Some(0),
FunctionIdentifier { .. } => Some(1),
}
}
pub(crate) fn is_unary(&self) -> bool {
self.max_argument_amount() == Some(1) && *self != Operator::RootNode
}
pub(crate) fn eval<C: Context<NumericTypes = NumericTypes>>(
&self,
arguments: &[Value<NumericTypes>],
context: &C,
) -> EvalexprResultValue<NumericTypes> {
use crate::operator::Operator::*;
match self {
RootNode => {
if let Some(first) = arguments.first() {
Ok(first.clone())
} else {
Ok(Value::Empty)
}
},
Add => {
expect_operator_argument_amount(arguments.len(), 2)?;
expect_number_or_string(&arguments[0])?;
expect_number_or_string(&arguments[1])?;
if let (Ok(a), Ok(b)) = (arguments[0].as_string(), arguments[1].as_string()) {
let mut result = String::with_capacity(a.len() + b.len());
result.push_str(&a);
result.push_str(&b);
Ok(Value::String(result))
} else if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) {
a.checked_add(&b).map(Value::Int)
} else if let (Ok(a), Ok(b)) = (arguments[0].as_number(), arguments[1].as_number())
{
Ok(Value::Float(a + b))
} else {
Err(EvalexprError::wrong_type_combination(
self.clone(),
vec![
arguments.get(0).unwrap().into(),
arguments.get(1).unwrap().into(),
],
))
}
},
Sub => {
expect_operator_argument_amount(arguments.len(), 2)?;
arguments[0].as_number()?;
arguments[1].as_number()?;
if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) {
a.checked_sub(&b).map(Value::Int)
} else {
Ok(Value::Float(
arguments[0].as_number()? - arguments[1].as_number()?,
))
}
},
Neg => {
expect_operator_argument_amount(arguments.len(), 1)?;
arguments[0].as_number()?;
if let Ok(a) = arguments[0].as_int() {
a.checked_neg().map(Value::Int)
} else {
Ok(Value::Float(-arguments[0].as_number()?))
}
},
Mul => {
expect_operator_argument_amount(arguments.len(), 2)?;
arguments[0].as_number()?;
arguments[1].as_number()?;
if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) {
a.checked_mul(&b).map(Value::Int)
} else {
Ok(Value::Float(
arguments[0].as_number()? * arguments[1].as_number()?,
))
}
},
Div => {
expect_operator_argument_amount(arguments.len(), 2)?;
arguments[0].as_number()?;
arguments[1].as_number()?;
if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) {
a.checked_div(&b).map(Value::Int)
} else {
Ok(Value::Float(
arguments[0].as_number()? / arguments[1].as_number()?,
))
}
},
Mod => {
expect_operator_argument_amount(arguments.len(), 2)?;
arguments[0].as_number()?;
arguments[1].as_number()?;
if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) {
a.checked_rem(&b).map(Value::Int)
} else {
Ok(Value::Float(
arguments[0].as_number()? % arguments[1].as_number()?,
))
}
},
Exp => {
expect_operator_argument_amount(arguments.len(), 2)?;
arguments[0].as_number()?;
arguments[1].as_number()?;
Ok(Value::Float(
arguments[0].as_number()?.pow(&arguments[1].as_number()?),
))
},
Eq => {
expect_operator_argument_amount(arguments.len(), 2)?;
Ok(Value::Boolean(arguments[0] == arguments[1]))
},
Neq => {
expect_operator_argument_amount(arguments.len(), 2)?;
Ok(Value::Boolean(arguments[0] != arguments[1]))
},
Gt => {
expect_operator_argument_amount(arguments.len(), 2)?;
expect_number_or_string(&arguments[0])?;
expect_number_or_string(&arguments[1])?;
if let (Ok(a), Ok(b)) = (arguments[0].as_string(), arguments[1].as_string()) {
Ok(Value::Boolean(a > b))
} else if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) {
Ok(Value::Boolean(a > b))
} else {
Ok(Value::Boolean(
arguments[0].as_number()? > arguments[1].as_number()?,
))
}
},
Lt => {
expect_operator_argument_amount(arguments.len(), 2)?;
expect_number_or_string(&arguments[0])?;
expect_number_or_string(&arguments[1])?;
if let (Ok(a), Ok(b)) = (arguments[0].as_string(), arguments[1].as_string()) {
Ok(Value::Boolean(a < b))
} else if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) {
Ok(Value::Boolean(a < b))
} else {
Ok(Value::Boolean(
arguments[0].as_number()? < arguments[1].as_number()?,
))
}
},
Geq => {
expect_operator_argument_amount(arguments.len(), 2)?;
expect_number_or_string(&arguments[0])?;
expect_number_or_string(&arguments[1])?;
if let (Ok(a), Ok(b)) = (arguments[0].as_string(), arguments[1].as_string()) {
Ok(Value::Boolean(a >= b))
} else if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) {
Ok(Value::Boolean(a >= b))
} else {
Ok(Value::Boolean(
arguments[0].as_number()? >= arguments[1].as_number()?,
))
}
},
Leq => {
expect_operator_argument_amount(arguments.len(), 2)?;
expect_number_or_string(&arguments[0])?;
expect_number_or_string(&arguments[1])?;
if let (Ok(a), Ok(b)) = (arguments[0].as_string(), arguments[1].as_string()) {
Ok(Value::Boolean(a <= b))
} else if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) {
Ok(Value::Boolean(a <= b))
} else {
Ok(Value::Boolean(
arguments[0].as_number()? <= arguments[1].as_number()?,
))
}
},
And => {
expect_operator_argument_amount(arguments.len(), 2)?;
let a = arguments[0].as_boolean()?;
let b = arguments[1].as_boolean()?;
Ok(Value::Boolean(a && b))
},
Or => {
expect_operator_argument_amount(arguments.len(), 2)?;
let a = arguments[0].as_boolean()?;
let b = arguments[1].as_boolean()?;
Ok(Value::Boolean(a || b))
},
Not => {
expect_operator_argument_amount(arguments.len(), 1)?;
let a = arguments[0].as_boolean()?;
Ok(Value::Boolean(!a))
},
Assign | AddAssign | SubAssign | MulAssign | DivAssign | ModAssign | ExpAssign
| AndAssign | OrAssign => Err(EvalexprError::ContextNotMutable),
Tuple => Ok(Value::Tuple(arguments.into())),
Chain => {
if arguments.is_empty() {
return Err(EvalexprError::wrong_operator_argument_amount(0, 1));
}
Ok(arguments.last().cloned().unwrap_or(Value::Empty))
},
Const { value } => {
expect_operator_argument_amount(arguments.len(), 0)?;
Ok(value.clone())
},
VariableIdentifierWrite { identifier } => {
expect_operator_argument_amount(arguments.len(), 0)?;
Ok(identifier.clone().into())
},
VariableIdentifierRead { identifier } => {
expect_operator_argument_amount(arguments.len(), 0)?;
if let Some(value) = context.get_value(identifier).cloned() {
Ok(value)
} else {
Err(EvalexprError::VariableIdentifierNotFound(
identifier.clone(),
))
}
},
FunctionIdentifier { identifier } => {
expect_operator_argument_amount(arguments.len(), 1)?;
let arguments = &arguments[0];
match context.call_function(identifier, arguments) {
Err(EvalexprError::FunctionIdentifierNotFound(_))
if !context.are_builtin_functions_disabled() =>
{
if let Some(builtin_function) = builtin_function(identifier) {
builtin_function.call(arguments)
} else {
Err(EvalexprError::FunctionIdentifierNotFound(
identifier.clone(),
))
}
},
result => result,
}
},
}
}
pub(crate) fn eval_mut<
C: ContextWithMutableVariables + Context<NumericTypes = NumericTypes>,
>(
&self,
arguments: &[Value<NumericTypes>],
context: &mut C,
) -> EvalexprResultValue<C::NumericTypes> {
use crate::operator::Operator::*;
match self {
Assign => {
expect_operator_argument_amount(arguments.len(), 2)?;
let target = arguments[0].as_string()?;
context.set_value(target, arguments[1].clone())?;
Ok(Value::Empty)
},
AddAssign | SubAssign | MulAssign | DivAssign | ModAssign | ExpAssign | AndAssign
| OrAssign => {
expect_operator_argument_amount(arguments.len(), 2)?;
let target = arguments[0].as_string()?;
let left_value = Operator::VariableIdentifierRead {
identifier: target.clone(),
}
.eval(&Vec::new(), context)?;
let arguments = vec![left_value, arguments[1].clone()];
let result = match self {
AddAssign => Operator::Add.eval(&arguments, context),
SubAssign => Operator::Sub.eval(&arguments, context),
MulAssign => Operator::Mul.eval(&arguments, context),
DivAssign => Operator::Div.eval(&arguments, context),
ModAssign => Operator::Mod.eval(&arguments, context),
ExpAssign => Operator::Exp.eval(&arguments, context),
AndAssign => Operator::And.eval(&arguments, context),
OrAssign => Operator::Or.eval(&arguments, context),
_ => unreachable!(
"Forgot to add a match arm for an assign operation: {}",
self
),
}?;
context.set_value(target, result)?;
Ok(Value::Empty)
},
_ => self.eval(arguments, context),
}
}
}