Implement new math interface for Value
This commit is contained in:
parent
c82f631524
commit
4b0910a545
@ -1,5 +1,3 @@
|
||||
use std::ops::AddAssign;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
@ -136,19 +134,19 @@ impl AbstractTree for Assignment {
|
||||
let new_value = match self.operator {
|
||||
AssignmentOperator::PlusEqual => {
|
||||
if let Some(left) = context.get_value(&self.identifier)? {
|
||||
left.add_assign(right)?
|
||||
left.add(right)?
|
||||
} else {
|
||||
return Err(RuntimeError::VariableIdentifierNotFound(
|
||||
self.identifier.clone(),
|
||||
return Err(RuntimeError::ValidationFailure(
|
||||
ValidationError::VariableIdentifierNotFound(self.identifier.clone()),
|
||||
));
|
||||
}
|
||||
}
|
||||
AssignmentOperator::MinusEqual => {
|
||||
if let Some(mut left) = context.get_value(&self.identifier)? {
|
||||
left.sub_assign(right)?
|
||||
if let Some(left) = context.get_value(&self.identifier)? {
|
||||
left.subtract(right)?
|
||||
} else {
|
||||
return Err(RuntimeError::VariableIdentifierNotFound(
|
||||
self.identifier.clone(),
|
||||
return Err(RuntimeError::ValidationFailure(
|
||||
ValidationError::VariableIdentifierNotFound(self.identifier.clone()),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -139,7 +139,9 @@ impl AbstractTree for FunctionCall {
|
||||
if let Some(value) = context.get_value(identifier)? {
|
||||
value.clone()
|
||||
} else {
|
||||
return Err(RuntimeError::VariableIdentifierNotFound(identifier.clone()));
|
||||
return Err(RuntimeError::ValidationFailure(
|
||||
ValidationError::VariableIdentifierNotFound(identifier.clone()),
|
||||
));
|
||||
}
|
||||
}
|
||||
FunctionExpression::FunctionCall(function_call) => {
|
||||
|
@ -79,7 +79,9 @@ impl AbstractTree for Identifier {
|
||||
if let Some(value) = context.get_value(self)? {
|
||||
Ok(value.clone())
|
||||
} else {
|
||||
Err(RuntimeError::VariableIdentifierNotFound(self.clone()))
|
||||
return Err(RuntimeError::ValidationFailure(
|
||||
ValidationError::VariableIdentifierNotFound(self.clone()),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -66,7 +66,9 @@ impl AbstractTree for Index {
|
||||
if let Some(value) = map.get(identifier) {
|
||||
value
|
||||
} else {
|
||||
return Err(RuntimeError::VariableIdentifierNotFound(identifier.clone()));
|
||||
return Err(RuntimeError::ValidationFailure(
|
||||
ValidationError::VariableIdentifierNotFound(identifier.clone()),
|
||||
));
|
||||
}
|
||||
} else {
|
||||
let index_value = self.index.run(source, context)?;
|
||||
@ -75,7 +77,9 @@ impl AbstractTree for Index {
|
||||
if let Some(value) = map.get(&identifier) {
|
||||
value
|
||||
} else {
|
||||
return Err(RuntimeError::VariableIdentifierNotFound(identifier.clone()));
|
||||
return Err(RuntimeError::ValidationFailure(
|
||||
ValidationError::VariableIdentifierNotFound(identifier.clone()),
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -50,8 +50,8 @@ impl AbstractTree for IndexAssignment {
|
||||
let index_run = self.index.index.run(source, context)?;
|
||||
let expected_identifier = Identifier::new(index_run.as_string()?);
|
||||
|
||||
return Err(RuntimeError::VariableIdentifierNotFound(
|
||||
expected_identifier,
|
||||
return Err(RuntimeError::ValidationFailure(
|
||||
ValidationError::VariableIdentifierNotFound(expected_identifier),
|
||||
));
|
||||
};
|
||||
|
||||
@ -59,17 +59,17 @@ impl AbstractTree for IndexAssignment {
|
||||
|
||||
let new_value = match self.operator {
|
||||
AssignmentOperator::PlusEqual => {
|
||||
if let Some(mut previous_value) = context.get_value(index_identifier)? {
|
||||
previous_value += value;
|
||||
previous_value
|
||||
if let Some(previous_value) = context.get_value(index_identifier)? {
|
||||
previous_value.add(value)?
|
||||
} else {
|
||||
Value::none()
|
||||
return Err(RuntimeError::ValidationFailure(
|
||||
ValidationError::VariableIdentifierNotFound(index_identifier.clone()),
|
||||
));
|
||||
}
|
||||
}
|
||||
AssignmentOperator::MinusEqual => {
|
||||
if let Some(mut previous_value) = context.get_value(index_identifier)? {
|
||||
previous_value -= value;
|
||||
previous_value
|
||||
if let Some(previous_value) = context.get_value(index_identifier)? {
|
||||
previous_value.subtract(value)?
|
||||
} else {
|
||||
Value::none()
|
||||
}
|
||||
|
@ -49,11 +49,11 @@ impl AbstractTree for Math {
|
||||
let left = self.left.run(source, context)?;
|
||||
let right = self.right.run(source, context)?;
|
||||
let value = match self.operator {
|
||||
MathOperator::Add => left.add_assign(right)?,
|
||||
MathOperator::Subtract => todo!(),
|
||||
MathOperator::Multiply => todo!(),
|
||||
MathOperator::Divide => todo!(),
|
||||
MathOperator::Modulo => todo!(),
|
||||
MathOperator::Add => left.add(right)?,
|
||||
MathOperator::Subtract => left.subtract(right)?,
|
||||
MathOperator::Multiply => left.multiply(right)?,
|
||||
MathOperator::Divide => left.divide(right)?,
|
||||
MathOperator::Modulo => left.modulo(right)?,
|
||||
};
|
||||
|
||||
Ok(value)
|
||||
|
@ -7,7 +7,7 @@ use std::{
|
||||
time,
|
||||
};
|
||||
|
||||
use crate::{Identifier, Type, Value};
|
||||
use crate::{Type, Value};
|
||||
|
||||
use super::{rw_lock_error::RwLockError, ValidationError};
|
||||
|
||||
@ -105,9 +105,6 @@ pub enum RuntimeError {
|
||||
|
||||
Utf8(FromUtf8Error),
|
||||
|
||||
/// Failed to find a variable with a value for this key.
|
||||
VariableIdentifierNotFound(Identifier),
|
||||
|
||||
/// A built-in function was called with the wrong amount of arguments.
|
||||
ExpectedBuiltInFunctionArgumentAmount {
|
||||
function_name: String,
|
||||
|
184
src/value/mod.rs
184
src/value/mod.rs
@ -16,7 +16,7 @@ use std::{
|
||||
convert::TryFrom,
|
||||
fmt::{self, Display, Formatter},
|
||||
marker::PhantomData,
|
||||
ops::{Add, AddAssign, Div, Mul, RangeInclusive, Rem, Sub, SubAssign},
|
||||
ops::RangeInclusive,
|
||||
};
|
||||
|
||||
pub use self::{
|
||||
@ -257,10 +257,11 @@ impl Value {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_assign(self, other: Self) -> Result<Value, ValidationError> {
|
||||
/// Return the sum of `self` and `other`.
|
||||
pub fn add(self, other: Self) -> Result<Value, ValidationError> {
|
||||
match (self, other) {
|
||||
(Value::Float(_), Value::Float(_)) => todo!(),
|
||||
(Value::Float(_), Value::Integer(_)) => todo!(),
|
||||
(Value::Float(left), Value::Float(right)) => Ok(Value::Float(left + right)),
|
||||
(Value::Float(left), Value::Integer(right)) => Ok(Value::Float(left + right as f64)),
|
||||
(Value::Integer(left), Value::Float(right)) => Ok(Value::Float((left as f64) + right)),
|
||||
(Value::Integer(left), Value::Integer(right)) => Ok(Value::Integer(left + right)),
|
||||
(Value::List(list), value) | (value, Value::List(list)) => {
|
||||
@ -268,23 +269,54 @@ impl Value {
|
||||
|
||||
Ok(Value::List(list))
|
||||
}
|
||||
(Value::Map(_), _) | (_, Value::Map(_)) => todo!(),
|
||||
(Value::String(_), Value::String(_)) => todo!(),
|
||||
(Value::String(left), Value::String(right)) => Ok(Value::String(left + &right)),
|
||||
(left, right) => Err(ValidationError::CannotAdd { left, right }),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sub_assign(self, other: Self) -> Result<Value, ValidationError> {
|
||||
/// Return the difference of `self` and `other`.
|
||||
pub fn subtract(self, other: Self) -> Result<Value, ValidationError> {
|
||||
match (self, other) {
|
||||
(Value::Float(_), Value::Float(_)) => todo!(),
|
||||
(Value::Float(_), Value::Integer(_)) => todo!(),
|
||||
(Value::Integer(left), Value::Float(right)) => Ok(Value::Float((left as f64) + right)),
|
||||
(Value::Integer(left), Value::Integer(right)) => Ok(Value::Integer(left + right)),
|
||||
(Value::Map(_), _) | (_, Value::Map(_)) => todo!(),
|
||||
(Value::String(_), Value::String(_)) => todo!(),
|
||||
(Value::Float(left), Value::Float(right)) => Ok(Value::Float(left - right)),
|
||||
(Value::Float(left), Value::Integer(right)) => Ok(Value::Float(left - right as f64)),
|
||||
(Value::Integer(left), Value::Float(right)) => Ok(Value::Float(left as f64 - right)),
|
||||
(Value::Integer(left), Value::Integer(right)) => Ok(Value::Integer(left - right)),
|
||||
(left, right) => Err(ValidationError::CannotSubtract { left, right }),
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the product of `self` and `other`.
|
||||
pub fn multiply(self, other: Self) -> Result<Value, ValidationError> {
|
||||
match (self, other) {
|
||||
(Value::Float(left), Value::Float(right)) => Ok(Value::Float(left * right)),
|
||||
(Value::Float(left), Value::Integer(right)) => Ok(Value::Float(left * right as f64)),
|
||||
(Value::Integer(left), Value::Float(right)) => Ok(Value::Float(left as f64 * right)),
|
||||
(Value::Integer(left), Value::Integer(right)) => Ok(Value::Integer(left * right)),
|
||||
(left, right) => Err(ValidationError::CannotMultiply { left, right }),
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the quotient of `self` and `other`.
|
||||
pub fn divide(self, other: Self) -> Result<Value, ValidationError> {
|
||||
match (self, other) {
|
||||
(Value::Float(left), Value::Float(right)) => Ok(Value::Float(left / right)),
|
||||
(Value::Float(left), Value::Integer(right)) => Ok(Value::Float(left / right as f64)),
|
||||
(Value::Integer(left), Value::Float(right)) => Ok(Value::Float(left as f64 / right)),
|
||||
(Value::Integer(left), Value::Integer(right)) => Ok(Value::Integer(left / right)),
|
||||
(left, right) => Err(ValidationError::CannotDivide { left, right }),
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the remainder after diving `self` and `other`.
|
||||
pub fn modulo(self, other: Self) -> Result<Value, ValidationError> {
|
||||
match (self, other) {
|
||||
(Value::Float(left), Value::Float(right)) => Ok(Value::Float(left % right)),
|
||||
(Value::Float(left), Value::Integer(right)) => Ok(Value::Float(left % right as f64)),
|
||||
(Value::Integer(left), Value::Float(right)) => Ok(Value::Float(left as f64 % right)),
|
||||
(Value::Integer(left), Value::Integer(right)) => Ok(Value::Integer(left % right)),
|
||||
(left, right) => Err(ValidationError::CannotDivide { left, right }),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Value {
|
||||
@ -293,132 +325,6 @@ impl Default for Value {
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for Value {
|
||||
type Output = Result<Value, RuntimeError>;
|
||||
|
||||
fn add(self, other: Self) -> Self::Output {
|
||||
if let (Ok(left), Ok(right)) = (self.as_integer(), other.as_integer()) {
|
||||
let (sum, _) = left.overflowing_add(right);
|
||||
|
||||
return Ok(Value::Integer(sum));
|
||||
}
|
||||
|
||||
if let (Ok(left), Ok(right)) = (self.as_number(), other.as_number()) {
|
||||
return Ok(Value::Float(left + right));
|
||||
}
|
||||
|
||||
if let (Ok(left), Ok(right)) = (self.as_string(), other.as_string()) {
|
||||
return Ok(Value::string(left.to_string() + right.as_str()));
|
||||
}
|
||||
|
||||
if self.is_string() || other.is_string() {
|
||||
return Ok(Value::string(self.to_string() + &other.to_string()));
|
||||
}
|
||||
|
||||
let non_number_or_string = if !self.is_number() == !self.is_string() {
|
||||
self
|
||||
} else {
|
||||
other
|
||||
};
|
||||
|
||||
Err(RuntimeError::ExpectedNumberOrString {
|
||||
actual: non_number_or_string,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for Value {
|
||||
type Output = Result<Self, RuntimeError>;
|
||||
|
||||
fn sub(self, other: Self) -> Self::Output {
|
||||
if let (Ok(left), Ok(right)) = (self.as_integer(), other.as_integer()) {
|
||||
let (difference, _) = left.overflowing_sub(right);
|
||||
|
||||
return Ok(Value::Integer(difference));
|
||||
}
|
||||
|
||||
if let (Ok(left), Ok(right)) = (self.as_number(), other.as_number()) {
|
||||
return Ok(Value::Float(left - right));
|
||||
}
|
||||
|
||||
let non_number = if !self.is_number() { self } else { other };
|
||||
|
||||
Err(RuntimeError::ExpectedNumber { actual: non_number })
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul for Value {
|
||||
type Output = Result<Self, RuntimeError>;
|
||||
|
||||
fn mul(self, other: Self) -> Self::Output {
|
||||
if let (Ok(left), Ok(right)) = (self.as_integer(), other.as_integer()) {
|
||||
Ok(Value::Integer(left.saturating_mul(right)))
|
||||
} else if let (Ok(left), Ok(right)) = (self.as_number(), other.as_number()) {
|
||||
Ok(Value::Float(left * right))
|
||||
} else {
|
||||
let non_number = if !self.is_number() { self } else { other };
|
||||
|
||||
Err(RuntimeError::ExpectedNumber { actual: non_number })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Div for Value {
|
||||
type Output = Result<Self, RuntimeError>;
|
||||
|
||||
fn div(self, other: Self) -> Self::Output {
|
||||
if let (Ok(left), Ok(right)) = (self.as_number(), other.as_number()) {
|
||||
let divided = left / right;
|
||||
let is_even = divided % 2.0 == 0.0;
|
||||
|
||||
if self.is_integer() && other.is_integer() && is_even {
|
||||
Ok(Value::Integer(divided as i64))
|
||||
} else {
|
||||
Ok(Value::Float(divided))
|
||||
}
|
||||
} else {
|
||||
let non_number = if !self.is_number() { self } else { other };
|
||||
|
||||
Err(RuntimeError::ExpectedNumber { actual: non_number })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Rem for Value {
|
||||
type Output = Result<Self, RuntimeError>;
|
||||
|
||||
fn rem(self, other: Self) -> Self::Output {
|
||||
let left = self.as_integer()?;
|
||||
let right = other.as_integer()?;
|
||||
let result = left % right;
|
||||
|
||||
Ok(Value::Integer(result))
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign for Value {
|
||||
fn add_assign(&mut self, other: Self) {
|
||||
match (self, other) {
|
||||
(Value::Integer(left), Value::Integer(right)) => *left += right,
|
||||
(Value::Float(left), Value::Float(right)) => *left += right,
|
||||
(Value::Float(left), Value::Integer(right)) => *left += right as f64,
|
||||
(Value::String(left), Value::String(right)) => *left += &right,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SubAssign for Value {
|
||||
fn sub_assign(&mut self, other: Self) {
|
||||
match (self, other) {
|
||||
(Value::Integer(left), Value::Integer(right)) => *left -= right,
|
||||
(Value::Float(left), Value::Float(right)) => *left -= right,
|
||||
(Value::Float(left), Value::Integer(right)) => *left -= right as f64,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Value {}
|
||||
|
||||
impl PartialEq for Value {
|
||||
|
Loading…
Reference in New Issue
Block a user