use crate::function::builtin::builtin_function;
use crate::{context::Context, error::*, value::Value};
use std::borrow::Borrow;
mod display;
#[derive(Debug, PartialEq, Clone)]
pub enum Operator {
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,
},
VariableIdentifier {
identifier: String,
},
FunctionIdentifier {
identifier: String,
},
}
impl Operator {
pub(crate) fn value(value: Value) -> Self {
Operator::Const { value }
}
pub(crate) fn variable_identifier(identifier: String) -> Self {
Operator::VariableIdentifier { identifier }
}
pub(crate) fn function_identifier(identifier: String) -> Self {
Operator::FunctionIdentifier { identifier }
}
pub(crate) 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 { value: _ } => 200,
VariableIdentifier { identifier: _ } => 200,
FunctionIdentifier { identifier: _ } => 190,
}
}
pub(crate) fn is_left_to_right(&self) -> bool {
use crate::operator::Operator::*;
match self {
Assign => false,
FunctionIdentifier { identifier: _ } => false,
_ => true,
}
}
pub(crate) fn is_sequence(&self) -> bool {
use crate::operator::Operator::*;
match self {
Tuple | Chain => true,
_ => false,
}
}
pub(crate) fn is_leaf(&self) -> bool {
self.max_argument_amount() == Some(0)
}
pub(crate) 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 { value: _ } => Some(0),
VariableIdentifier { identifier: _ } => Some(0),
FunctionIdentifier { identifier: _ } => Some(1),
}
}
pub(crate) fn eval(&self, arguments: &[Value], context: &dyn Context) -> EvalexprResult<Value> {
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()) {
let result = a.checked_add(b);
if let Some(result) = result {
Ok(Value::Int(result))
} else {
Err(EvalexprError::addition_error(
arguments[0].clone(),
arguments[1].clone(),
))
}
} 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[0].borrow().into(), arguments[1].borrow().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()) {
let result = a.checked_sub(b);
if let Some(result) = result {
Ok(Value::Int(result))
} else {
Err(EvalexprError::subtraction_error(
arguments[0].clone(),
arguments[1].clone(),
))
}
} 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() {
let result = a.checked_neg();
if let Some(result) = result {
Ok(Value::Int(result))
} else {
Err(EvalexprError::negation_error(arguments[0].clone()))
}
} 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()) {
let result = a.checked_mul(b);
if let Some(result) = result {
Ok(Value::Int(result))
} else {
Err(EvalexprError::multiplication_error(
arguments[0].clone(),
arguments[1].clone(),
))
}
} 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()) {
let result = a.checked_div(b);
if let Some(result) = result {
Ok(Value::Int(result))
} else {
Err(EvalexprError::division_error(
arguments[0].clone(),
arguments[1].clone(),
))
}
} 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()) {
let result = a.checked_rem(b);
if let Some(result) = result {
Ok(Value::Int(result))
} else {
Err(EvalexprError::modulation_error(
arguments[0].clone(),
arguments[1].clone(),
))
}
} 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()?.powf(arguments[1].as_number()?),
))
},
Eq => {
expect_operator_argument_amount(arguments.len(), 2)?;
if arguments[0] == arguments[1] {
Ok(Value::Boolean(true))
} else {
Ok(Value::Boolean(false))
}
},
Neq => {
expect_operator_argument_amount(arguments.len(), 2)?;
if arguments[0] != arguments[1] {
Ok(Value::Boolean(true))
} else {
Ok(Value::Boolean(false))
}
},
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()) {
if a > b {
Ok(Value::Boolean(true))
} else {
Ok(Value::Boolean(false))
}
} else if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) {
if a > b {
Ok(Value::Boolean(true))
} else {
Ok(Value::Boolean(false))
}
} else {
if arguments[0].as_number()? > arguments[1].as_number()? {
Ok(Value::Boolean(true))
} else {
Ok(Value::Boolean(false))
}
}
},
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()) {
if a < b {
Ok(Value::Boolean(true))
} else {
Ok(Value::Boolean(false))
}
} else if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) {
if a < b {
Ok(Value::Boolean(true))
} else {
Ok(Value::Boolean(false))
}
} else {
if arguments[0].as_number()? < arguments[1].as_number()? {
Ok(Value::Boolean(true))
} else {
Ok(Value::Boolean(false))
}
}
},
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()) {
if a >= b {
Ok(Value::Boolean(true))
} else {
Ok(Value::Boolean(false))
}
} else if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) {
if a >= b {
Ok(Value::Boolean(true))
} else {
Ok(Value::Boolean(false))
}
} else {
if arguments[0].as_number()? >= arguments[1].as_number()? {
Ok(Value::Boolean(true))
} else {
Ok(Value::Boolean(false))
}
}
},
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()) {
if a <= b {
Ok(Value::Boolean(true))
} else {
Ok(Value::Boolean(false))
}
} else if let (Ok(a), Ok(b)) = (arguments[0].as_int(), arguments[1].as_int()) {
if a <= b {
Ok(Value::Boolean(true))
} else {
Ok(Value::Boolean(false))
}
} else {
if arguments[0].as_number()? <= arguments[1].as_number()? {
Ok(Value::Boolean(true))
} else {
Ok(Value::Boolean(false))
}
}
},
And => {
expect_operator_argument_amount(arguments.len(), 2)?;
let a = arguments[0].as_boolean()?;
let b = arguments[1].as_boolean()?;
if a && b {
Ok(Value::Boolean(true))
} else {
Ok(Value::Boolean(false))
}
},
Or => {
expect_operator_argument_amount(arguments.len(), 2)?;
let a = arguments[0].as_boolean()?;
let b = arguments[1].as_boolean()?;
if a || b {
Ok(Value::Boolean(true))
} else {
Ok(Value::Boolean(false))
}
},
Not => {
expect_operator_argument_amount(arguments.len(), 1)?;
let a = arguments[0].as_boolean()?;
if !a {
Ok(Value::Boolean(true))
} else {
Ok(Value::Boolean(false))
}
},
Assign | AddAssign | SubAssign | MulAssign | DivAssign | ModAssign | ExpAssign
| AndAssign | OrAssign => Err(EvalexprError::ContextNotManipulable),
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())
},
VariableIdentifier { 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];
if let Some(function) = context.get_function(&identifier) {
function.call(arguments)
} else if let Some(builtin_function) = builtin_function(&identifier) {
builtin_function.call(arguments)
} else {
Err(EvalexprError::FunctionIdentifierNotFound(
identifier.clone(),
))
}
},
}
}
pub(crate) fn eval_mut(
&self,
arguments: &[Value],
context: &mut dyn Context,
) -> EvalexprResult<Value> {
use crate::operator::Operator::*;
match self {
Assign => {
expect_operator_argument_amount(arguments.len(), 2)?;
let target = arguments[0].as_string()?;
context.set_value(target.into(), 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::VariableIdentifier {
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.into(), result)?;
Ok(Value::Empty)
},
_ => self.eval(arguments, context),
}
}
}