From 0ee4946eaf1ccc700e027b6fe879bc1c690aeeed Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Fri, 15 Mar 2019 17:40:38 +0200 Subject: [PATCH] Implemented separate int and float types --- src/error/mod.rs | 7 +++++-- src/lib.rs | 26 +++++++++++++------------- src/operator/mod.rs | 40 ++++++++++++++++++++++++++++------------ src/token/mod.rs | 11 ++++++++--- src/tree/mod.rs | 3 ++- src/value/mod.rs | 45 ++++++++++++++++++++++++++++++++++++++++++++- 6 files changed, 100 insertions(+), 32 deletions(-) diff --git a/src/error/mod.rs b/src/error/mod.rs index 320add2..7f3e133 100644 --- a/src/error/mod.rs +++ b/src/error/mod.rs @@ -26,6 +26,9 @@ pub enum Error { /// An identifier operation did not find its value in the configuration. IdentifierNotFound, + + /// A value has the wrong type. + TypeError, } impl Error { @@ -46,9 +49,9 @@ pub fn expect_argument_amount(actual: usize, expected: usize) -> Result<(), Erro } } -pub fn expect_number(actual: &Value) -> Result { +pub fn expect_number(actual: &Value) -> Result<(), Error> { match actual { - Value::Number(number) => Ok(*number), + Value::Float(_) | Value::Int(_) => Ok(()), _ => Err(Error::expected_number(actual.clone())), } } diff --git a/src/lib.rs b/src/lib.rs index 41592da..c64cbf4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,7 +20,7 @@ mod test { #[test] fn test_unary_examples() { - assert_eq!(eval("3"), Ok(Value::Number(3.0))); + assert_eq!(eval("3"), Ok(Value::Int(3))); assert_eq!(eval("true"), Ok(Value::Boolean(true))); assert_eq!(eval("false"), Ok(Value::Boolean(false))); assert_eq!(eval("blub"), Err(Error::IdentifierNotFound)); @@ -28,21 +28,21 @@ mod test { #[test] fn test_binary_examples() { - assert_eq!(eval("1+3"), Ok(Value::Number(4.0))); - assert_eq!(eval("3+1"), Ok(Value::Number(4.0))); - assert_eq!(eval("3-5"), Ok(Value::Number(-2.0))); - assert_eq!(eval("5-3"), Ok(Value::Number(2.0))); - assert_eq!(eval("5 / 4"), Ok(Value::Number(1.25))); - assert_eq!(eval("5 *3"), Ok(Value::Number(15.0))); + assert_eq!(eval("1+3"), Ok(Value::Int(4))); + assert_eq!(eval("3+1"), Ok(Value::Int(4))); + assert_eq!(eval("3-5"), Ok(Value::Int(-2))); + assert_eq!(eval("5-3"), Ok(Value::Int(2))); + assert_eq!(eval("5 / 4"), Ok(Value::Int(1))); + assert_eq!(eval("5 *3"), Ok(Value::Int(15))); } #[test] fn test_arithmetic_precedence_examples() { - assert_eq!(eval("1+3-2"), Ok(Value::Number(2.0))); - assert_eq!(eval("3+1*5"), Ok(Value::Number(8.0))); - assert_eq!(eval("2*3-5"), Ok(Value::Number(1.0))); - assert_eq!(eval("5-3/3"), Ok(Value::Number(4.0))); - assert_eq!(eval("5 / 4*2"), Ok(Value::Number(2.5))); - assert_eq!(eval("1-5 *3/15"), Ok(Value::Number(0.0))); + assert_eq!(eval("1+3-2"), Ok(Value::Int(2))); + assert_eq!(eval("3+1*5"), Ok(Value::Int(8))); + assert_eq!(eval("2*3-5"), Ok(Value::Int(1))); + assert_eq!(eval("5-3/3"), Ok(Value::Int(4))); + assert_eq!(eval("5 / 4*2"), Ok(Value::Int(2))); + assert_eq!(eval("1-5 *3/15"), Ok(Value::Int(0))); } } diff --git a/src/operator/mod.rs b/src/operator/mod.rs index 57fbfd3..2f60237 100644 --- a/src/operator/mod.rs +++ b/src/operator/mod.rs @@ -71,10 +71,14 @@ impl Operator for Add { fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result { expect_argument_amount(arguments.len(), 2)?; - let a = expect_number(&arguments[0])?; - let b = expect_number(&arguments[1])?; + expect_number(&arguments[0])?; + expect_number(&arguments[1])?; - Ok(Value::Number(a + b)) + if arguments[0].is_int() && arguments[1].is_int() { + Ok(Value::Int(arguments[0].as_int().unwrap() + arguments[1].as_int().unwrap())) + } else { + Ok(Value::Float(arguments[0].as_float().unwrap() + arguments[1].as_float().unwrap())) + } } } @@ -89,10 +93,14 @@ impl Operator for Sub { fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result { expect_argument_amount(arguments.len(), 2)?; - let a = expect_number(&arguments[0])?; - let b = expect_number(&arguments[1])?; + expect_number(&arguments[0])?; + expect_number(&arguments[1])?; - Ok(Value::Number(a - b)) + if arguments[0].is_int() && arguments[1].is_int() { + Ok(Value::Int(arguments[0].as_int().unwrap() - arguments[1].as_int().unwrap())) + } else { + Ok(Value::Float(arguments[0].as_float().unwrap() - arguments[1].as_float().unwrap())) + } } } @@ -107,10 +115,14 @@ impl Operator for Mul { fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result { expect_argument_amount(arguments.len(), 2)?; - let a = expect_number(&arguments[0])?; - let b = expect_number(&arguments[1])?; + expect_number(&arguments[0])?; + expect_number(&arguments[1])?; - Ok(Value::Number(a * b)) + if arguments[0].is_int() && arguments[1].is_int() { + Ok(Value::Int(arguments[0].as_int().unwrap() * arguments[1].as_int().unwrap())) + } else { + Ok(Value::Float(arguments[0].as_float().unwrap() * arguments[1].as_float().unwrap())) + } } } @@ -125,10 +137,14 @@ impl Operator for Div { fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result { expect_argument_amount(arguments.len(), 2)?; - let a = expect_number(&arguments[0])?; - let b = expect_number(&arguments[1])?; + expect_number(&arguments[0])?; + expect_number(&arguments[1])?; - Ok(Value::Number(a / b)) + if arguments[0].is_int() && arguments[1].is_int() { + Ok(Value::Int(arguments[0].as_int().unwrap() / arguments[1].as_int().unwrap())) + } else { + Ok(Value::Float(arguments[0].as_float().unwrap() / arguments[1].as_float().unwrap())) + } } } diff --git a/src/token/mod.rs b/src/token/mod.rs index 7dacd90..7b85819 100644 --- a/src/token/mod.rs +++ b/src/token/mod.rs @@ -1,3 +1,5 @@ +use value::{IntType, FloatType}; + #[derive(Clone, PartialEq)] pub enum Token { // Single character tokens @@ -9,7 +11,8 @@ pub enum Token { // Complex tokens Identifier(String), - Number(f64), + Float(FloatType), + Int(IntType), Boolean(bool), } @@ -65,8 +68,10 @@ fn resolve_literals(tokens: &Vec) -> Vec { .map(|token| match token { PartialToken::Token(token) => token.clone(), PartialToken::Literal(literal) => { - if let Ok(number) = literal.parse::() { - Token::Number(number) + if let Ok(number) = literal.parse::() { + Token::Int(number) + } else if let Ok(number) = literal.parse::() { + Token::Float(number) } else if let Ok(boolean) = literal.parse::() { Token::Boolean(boolean) } else { diff --git a/src/tree/mod.rs b/src/tree/mod.rs index b379f30..67d4c8f 100644 --- a/src/tree/mod.rs +++ b/src/tree/mod.rs @@ -86,7 +86,8 @@ pub fn tokens_to_operator_tree(tokens: Vec) -> Result { Token::Slash => Some(Box::new(Div)), Token::Whitespace => None, Token::Identifier(identifier) => Some(Box::new(Identifier::new(identifier))), - Token::Number(number) => Some(Box::new(Const::new(Value::Number(number)))), + Token::Float(number) => Some(Box::new(Const::new(Value::Float(number)))), + Token::Int(number) => Some(Box::new(Const::new(Value::Int(number)))), Token::Boolean(boolean) => Some(Box::new(Const::new(Value::Boolean(boolean)))), }; diff --git a/src/value/mod.rs b/src/value/mod.rs index 35525dc..482b18f 100644 --- a/src/value/mod.rs +++ b/src/value/mod.rs @@ -1,6 +1,49 @@ +use error::Error; + +pub type IntType = i64; +pub type FloatType = f64; + #[derive(Clone, Debug, PartialEq)] pub enum Value { String(String), - Number(f64), + Float(FloatType), + Int(IntType), Boolean(bool), } + +impl Value { + pub fn is_int(&self) -> bool { + match self { + Value::Int(_) => true, + _ => false, + } + } + + pub fn is_float(&self) -> bool { + match self { + Value::Float(_) => true, + _ => false, + } + } + + pub fn as_int(&self) -> Result { + match self { + Value::Int(i) => Ok(*i), + _ => Err(Error::TypeError), + } + } + + pub fn as_float(&self) -> Result { + match self { + Value::Float(f) => Ok(*f), + Value::Int(i) => Ok(*i as FloatType), + _ => Err(Error::TypeError), + } + } +} + +#[derive(Clone, Debug, PartialEq)] +pub enum Number { + Float(FloatType), + Int(IntType), +} \ No newline at end of file