2024-03-07 11:33:54 +00:00
|
|
|
use crate::{
|
|
|
|
context::Context,
|
|
|
|
error::{RuntimeError, ValidationError},
|
|
|
|
value::ValueInner,
|
|
|
|
Value,
|
|
|
|
};
|
|
|
|
|
2024-03-08 17:24:11 +00:00
|
|
|
use super::{AbstractTree, Action, Expression, Type};
|
2024-03-07 11:33:54 +00:00
|
|
|
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
|
|
|
pub enum Math<'src> {
|
|
|
|
Add(Expression<'src>, Expression<'src>),
|
|
|
|
Subtract(Expression<'src>, Expression<'src>),
|
|
|
|
Multiply(Expression<'src>, Expression<'src>),
|
|
|
|
Divide(Expression<'src>, Expression<'src>),
|
|
|
|
Modulo(Expression<'src>, Expression<'src>),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'src> AbstractTree for Math<'src> {
|
|
|
|
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
|
|
|
|
match self {
|
|
|
|
Math::Add(left, _)
|
|
|
|
| Math::Subtract(left, _)
|
|
|
|
| Math::Multiply(left, _)
|
|
|
|
| Math::Divide(left, _)
|
|
|
|
| Math::Modulo(left, _) => left.expected_type(_context),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn validate(&self, context: &Context) -> Result<(), ValidationError> {
|
|
|
|
match self {
|
|
|
|
Math::Add(left, right)
|
|
|
|
| Math::Subtract(left, right)
|
|
|
|
| Math::Multiply(left, right)
|
|
|
|
| Math::Divide(left, right)
|
|
|
|
| Math::Modulo(left, right) => {
|
|
|
|
let left_type = left.expected_type(context)?;
|
|
|
|
let right_type = right.expected_type(context)?;
|
|
|
|
|
|
|
|
match (left_type, right_type) {
|
|
|
|
(Type::Integer, Type::Integer)
|
|
|
|
| (Type::Float, Type::Float)
|
|
|
|
| (Type::Integer, Type::Float)
|
|
|
|
| (Type::Float, Type::Integer) => Ok(()),
|
|
|
|
_ => Err(ValidationError::ExpectedIntegerOrFloat),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-08 17:24:11 +00:00
|
|
|
fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
|
|
|
|
let value = match self {
|
2024-03-07 11:33:54 +00:00
|
|
|
Math::Add(left, right) => {
|
2024-03-08 17:24:11 +00:00
|
|
|
let left_value = left.run(_context)?.as_return_value()?;
|
|
|
|
let right_value = right.run(_context)?.as_return_value()?;
|
2024-03-07 11:33:54 +00:00
|
|
|
|
2024-03-08 18:26:55 +00:00
|
|
|
left_value.add(&right_value)?
|
2024-03-07 11:33:54 +00:00
|
|
|
}
|
2024-03-07 17:33:30 +00:00
|
|
|
Math::Subtract(left, right) => {
|
2024-03-08 17:24:11 +00:00
|
|
|
let left_value = left.run(_context)?.as_return_value()?;
|
|
|
|
let right_value = right.run(_context)?.as_return_value()?;
|
2024-03-07 17:33:30 +00:00
|
|
|
|
2024-03-08 18:26:55 +00:00
|
|
|
left_value.subtract(&right_value)?
|
2024-03-07 17:33:30 +00:00
|
|
|
}
|
2024-03-07 11:33:54 +00:00
|
|
|
Math::Multiply(left, right) => {
|
2024-03-08 17:24:11 +00:00
|
|
|
let left_value = left.run(_context)?.as_return_value()?;
|
|
|
|
let right_value = right.run(_context)?.as_return_value()?;
|
2024-03-07 11:33:54 +00:00
|
|
|
|
|
|
|
if let (ValueInner::Integer(left), ValueInner::Integer(right)) =
|
|
|
|
(left_value.inner().as_ref(), right_value.inner().as_ref())
|
|
|
|
{
|
2024-03-08 17:24:11 +00:00
|
|
|
Value::integer(left * right)
|
2024-03-07 11:33:54 +00:00
|
|
|
} else {
|
2024-03-08 17:24:11 +00:00
|
|
|
return Err(RuntimeError::ValidationFailure(
|
2024-03-07 11:33:54 +00:00
|
|
|
ValidationError::ExpectedIntegerOrFloat,
|
2024-03-08 17:24:11 +00:00
|
|
|
));
|
2024-03-07 11:33:54 +00:00
|
|
|
}
|
|
|
|
}
|
2024-03-07 17:33:30 +00:00
|
|
|
Math::Divide(left, right) => {
|
2024-03-08 17:24:11 +00:00
|
|
|
let left_value = left.run(_context)?.as_return_value()?;
|
|
|
|
let right_value = right.run(_context)?.as_return_value()?;
|
2024-03-07 17:33:30 +00:00
|
|
|
|
|
|
|
if let (ValueInner::Integer(left), ValueInner::Integer(right)) =
|
|
|
|
(left_value.inner().as_ref(), right_value.inner().as_ref())
|
|
|
|
{
|
2024-03-08 17:24:11 +00:00
|
|
|
Value::integer(left / right)
|
2024-03-07 17:33:30 +00:00
|
|
|
} else {
|
2024-03-08 17:24:11 +00:00
|
|
|
return Err(RuntimeError::ValidationFailure(
|
2024-03-07 17:33:30 +00:00
|
|
|
ValidationError::ExpectedIntegerOrFloat,
|
2024-03-08 17:24:11 +00:00
|
|
|
));
|
2024-03-07 17:33:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Math::Modulo(left, right) => {
|
2024-03-08 17:24:11 +00:00
|
|
|
let left_value = left.run(_context)?.as_return_value()?;
|
|
|
|
let right_value = right.run(_context)?.as_return_value()?;
|
2024-03-07 17:33:30 +00:00
|
|
|
|
|
|
|
if let (ValueInner::Integer(left), ValueInner::Integer(right)) =
|
|
|
|
(left_value.inner().as_ref(), right_value.inner().as_ref())
|
|
|
|
{
|
2024-03-08 17:24:11 +00:00
|
|
|
Value::integer(left % right)
|
2024-03-07 17:33:30 +00:00
|
|
|
} else {
|
2024-03-08 17:24:11 +00:00
|
|
|
return Err(RuntimeError::ValidationFailure(
|
2024-03-07 17:33:30 +00:00
|
|
|
ValidationError::ExpectedIntegerOrFloat,
|
2024-03-08 17:24:11 +00:00
|
|
|
));
|
2024-03-07 17:33:30 +00:00
|
|
|
}
|
|
|
|
}
|
2024-03-08 17:24:11 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
Ok(Action::Return(value))
|
2024-03-07 11:33:54 +00:00
|
|
|
}
|
|
|
|
}
|