diff --git a/src/expression.rs b/src/expression.rs index d99e007..866e28f 100644 --- a/src/expression.rs +++ b/src/expression.rs @@ -1,3 +1,4 @@ +use crate::compare_values; use crate::environment::Environment; use crate::expression_literal_value::LiteralValue::{self, *}; use crate::token::{Token, TokenType::*}; @@ -9,43 +10,6 @@ use std::string::String; #[path = "./tests/expression_tests.rs"] mod tests; -macro_rules! compare_values { - ($self:ident, $op_symbol:tt, $left:expr, $right:expr) => { - match (&$left, &$right) { - (IntValue(x), IntValue(y)) => Ok(LiteralValue::from(x $op_symbol y)), - (FValue(x), FValue(y)) => Ok(LiteralValue::from(x $op_symbol y)), - (IntValue(x), FValue(y)) => Ok(LiteralValue::from((*x as f64) $op_symbol *y)), - (FValue(x), IntValue(y)) => Ok(LiteralValue::from(*x $op_symbol (*y as f64))), - (StringValue(x), StringValue(y)) => Ok(LiteralValue::from(x $op_symbol y)), - _ => LiteralValue::not_implemented_error(&stringify!($op_symbol), &$left, &$right), - } - }; -} - -macro_rules! arithmetic_operation { - ($self:ident, $op_symbol:tt, $left: expr, $right: expr) => { - { - if stringify!($op_symbol) == "/" && matches!($right, IntValue(0) | FValue(0.0)) { - return Err(String::from("Division by 0")); - } - - match (&$left, &$right) { - (IntValue(x), IntValue(y)) => Ok(IntValue(x $op_symbol y)), - (FValue(x), FValue(y)) => Ok(FValue(x $op_symbol y)), - (IntValue(x), FValue(y)) => Ok(FValue((*x as f64) $op_symbol y)), - (FValue(x), IntValue(y)) => Ok(FValue(x $op_symbol (*y as f64))), - (StringValue(string), any) if stringify!($op_symbol) == "+" => { - Ok(StringValue(format!("{0}{1}", string, any))) - } - (any, StringValue(string)) if stringify!($op_symbol) == "+" => { - Ok(StringValue(format!("{0}{1}", any, string))) - } - _ => LiteralValue::not_implemented_error(&stringify!($op_symbol), &$left, &$right), - } - } - }; -} - #[derive(Clone, Debug, PartialEq)] pub enum Expression { Binary { @@ -157,14 +121,14 @@ impl Expression { let right = (*right).evaluate(environment)?; match &operator.token_type { - Plus => arithmetic_operation!(self, +, left, right), - Minus => arithmetic_operation!(self, -, left, right), - Star => arithmetic_operation!(self, *, left, right), - Slash => arithmetic_operation!(self, /, left, right), - Greater => compare_values!(self, >, left, right), - GreaterEqual => compare_values!(self, >=, left, right), - Less => compare_values!(self, <, left, right), - LessEqual => compare_values!(self, <=, left, right), + Plus => left + right, + Minus => left - right, + Star => left * right, + Slash => left / right, + Greater => compare_values!(>, left, right), + GreaterEqual => compare_values!(>=, left, right), + Less => compare_values!(<, left, right), + LessEqual => compare_values!(<=, left, right), BangEqual => Ok(LiteralValue::from(left != right)), EqualEqual => Ok(LiteralValue::from(left == right)), _ => LiteralValue::not_implemented_error( diff --git a/src/expression_literal_value.rs b/src/expression_literal_value.rs index f41b025..b5a1c71 100644 --- a/src/expression_literal_value.rs +++ b/src/expression_literal_value.rs @@ -1,7 +1,8 @@ use crate::expression_literal_value::LiteralValue::*; -use crate::token::{Token, TokenType, LiteralValue as TokenLiteralValue}; +use crate::token::{LiteralValue as TokenLiteralValue, Token, TokenType}; use std::fmt::{Display, Formatter}; +use std::ops; use std::string::String; #[cfg(test)] @@ -27,9 +28,7 @@ impl From for LiteralValue { _ => panic!("Could not unwrap as number"), }, TokenType::String => match token.literal { - Some(TokenLiteralValue::StringValue(string_value)) => { - StringValue(string_value) - } + Some(TokenLiteralValue::StringValue(string_value)) => StringValue(string_value), _ => panic!("Could not unwrap as String"), }, TokenType::False => Self::False, @@ -107,3 +106,73 @@ impl LiteralValue { )) } } + +#[macro_export] +macro_rules! compare_values { + ($op_symbol:tt, $left:expr, $right:expr) => { + match (&$left, &$right) { + (IntValue(x), IntValue(y)) => Ok(LiteralValue::from(x $op_symbol y)), + (FValue(x), FValue(y)) => Ok(LiteralValue::from(x $op_symbol y)), + (IntValue(x), FValue(y)) => Ok(LiteralValue::from((*x as f64) $op_symbol *y)), + (FValue(x), IntValue(y)) => Ok(LiteralValue::from(*x $op_symbol (*y as f64))), + (StringValue(x), StringValue(y)) => Ok(LiteralValue::from(x $op_symbol y)), + _ => LiteralValue::not_implemented_error(&stringify!($op_symbol), &$left, &$right), + } + }; +} + +macro_rules! arithmetic_operation { + ($left: expr, $op_symbol:tt, $right: expr) => { + { + if stringify!($op_symbol) == "/" && matches!($right, IntValue(0) | FValue(0.0)) { + return Err(String::from("Division by 0")); + } + + match (&$left, &$right) { + (IntValue(x), IntValue(y)) => Ok(IntValue(x $op_symbol y)), + (FValue(x), FValue(y)) => Ok(FValue(x $op_symbol y)), + (IntValue(x), FValue(y)) => Ok(FValue((*x as f64) $op_symbol y)), + (FValue(x), IntValue(y)) => Ok(FValue(x $op_symbol (*y as f64))), + (StringValue(string), any) if stringify!($op_symbol) == "+" => { + Ok(StringValue(format!("{0}{1}", string, any))) + } + (any, StringValue(string)) if stringify!($op_symbol) == "+" => { + Ok(StringValue(format!("{0}{1}", any, string))) + } + _ => LiteralValue::not_implemented_error(&stringify!($op_symbol), &$left, &$right), + } + } + }; +} + +impl ops::Add for LiteralValue { + type Output = Result; + + fn add(self, _rhs: Self) -> Self::Output { + arithmetic_operation!(&self, +, &_rhs) + } +} + +impl ops::Sub for LiteralValue { + type Output = Result; + + fn sub(self, _rhs: Self) -> Self::Output { + arithmetic_operation!(&self, -, &_rhs) + } +} + +impl ops::Mul for LiteralValue { + type Output = Result; + + fn mul(self, _rhs: Self) -> Self::Output { + arithmetic_operation!(&self, *, &_rhs) + } +} + +impl ops::Div for LiteralValue { + type Output = Result; + + fn div(self, _rhs: Self) -> Self::Output { + arithmetic_operation!(&self, /, &_rhs) + } +} \ No newline at end of file