Implemented separate int and float types

This commit is contained in:
Sebastian Schmidt 2019-03-15 17:40:38 +02:00
parent 22490f5036
commit 0ee4946eaf
6 changed files with 100 additions and 32 deletions

View File

@ -26,6 +26,9 @@ pub enum Error {
/// An identifier operation did not find its value in the configuration. /// An identifier operation did not find its value in the configuration.
IdentifierNotFound, IdentifierNotFound,
/// A value has the wrong type.
TypeError,
} }
impl Error { impl Error {
@ -46,9 +49,9 @@ pub fn expect_argument_amount(actual: usize, expected: usize) -> Result<(), Erro
} }
} }
pub fn expect_number(actual: &Value) -> Result<f64, Error> { pub fn expect_number(actual: &Value) -> Result<(), Error> {
match actual { match actual {
Value::Number(number) => Ok(*number), Value::Float(_) | Value::Int(_) => Ok(()),
_ => Err(Error::expected_number(actual.clone())), _ => Err(Error::expected_number(actual.clone())),
} }
} }

View File

@ -20,7 +20,7 @@ mod test {
#[test] #[test]
fn test_unary_examples() { 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("true"), Ok(Value::Boolean(true)));
assert_eq!(eval("false"), Ok(Value::Boolean(false))); assert_eq!(eval("false"), Ok(Value::Boolean(false)));
assert_eq!(eval("blub"), Err(Error::IdentifierNotFound)); assert_eq!(eval("blub"), Err(Error::IdentifierNotFound));
@ -28,21 +28,21 @@ mod test {
#[test] #[test]
fn test_binary_examples() { fn test_binary_examples() {
assert_eq!(eval("1+3"), Ok(Value::Number(4.0))); assert_eq!(eval("1+3"), Ok(Value::Int(4)));
assert_eq!(eval("3+1"), Ok(Value::Number(4.0))); assert_eq!(eval("3+1"), Ok(Value::Int(4)));
assert_eq!(eval("3-5"), Ok(Value::Number(-2.0))); assert_eq!(eval("3-5"), Ok(Value::Int(-2)));
assert_eq!(eval("5-3"), Ok(Value::Number(2.0))); assert_eq!(eval("5-3"), Ok(Value::Int(2)));
assert_eq!(eval("5 / 4"), Ok(Value::Number(1.25))); assert_eq!(eval("5 / 4"), Ok(Value::Int(1)));
assert_eq!(eval("5 *3"), Ok(Value::Number(15.0))); assert_eq!(eval("5 *3"), Ok(Value::Int(15)));
} }
#[test] #[test]
fn test_arithmetic_precedence_examples() { fn test_arithmetic_precedence_examples() {
assert_eq!(eval("1+3-2"), Ok(Value::Number(2.0))); assert_eq!(eval("1+3-2"), Ok(Value::Int(2)));
assert_eq!(eval("3+1*5"), Ok(Value::Number(8.0))); assert_eq!(eval("3+1*5"), Ok(Value::Int(8)));
assert_eq!(eval("2*3-5"), Ok(Value::Number(1.0))); assert_eq!(eval("2*3-5"), Ok(Value::Int(1)));
assert_eq!(eval("5-3/3"), Ok(Value::Number(4.0))); assert_eq!(eval("5-3/3"), Ok(Value::Int(4)));
assert_eq!(eval("5 / 4*2"), Ok(Value::Number(2.5))); assert_eq!(eval("5 / 4*2"), Ok(Value::Int(2)));
assert_eq!(eval("1-5 *3/15"), Ok(Value::Number(0.0))); assert_eq!(eval("1-5 *3/15"), Ok(Value::Int(0)));
} }
} }

View File

@ -71,10 +71,14 @@ impl Operator for Add {
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> { fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
expect_argument_amount(arguments.len(), 2)?; expect_argument_amount(arguments.len(), 2)?;
let a = expect_number(&arguments[0])?; expect_number(&arguments[0])?;
let b = expect_number(&arguments[1])?; 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<Value, Error> { fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
expect_argument_amount(arguments.len(), 2)?; expect_argument_amount(arguments.len(), 2)?;
let a = expect_number(&arguments[0])?; expect_number(&arguments[0])?;
let b = expect_number(&arguments[1])?; 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<Value, Error> { fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
expect_argument_amount(arguments.len(), 2)?; expect_argument_amount(arguments.len(), 2)?;
let a = expect_number(&arguments[0])?; expect_number(&arguments[0])?;
let b = expect_number(&arguments[1])?; 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<Value, Error> { fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
expect_argument_amount(arguments.len(), 2)?; expect_argument_amount(arguments.len(), 2)?;
let a = expect_number(&arguments[0])?; expect_number(&arguments[0])?;
let b = expect_number(&arguments[1])?; 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()))
}
} }
} }

View File

@ -1,3 +1,5 @@
use value::{IntType, FloatType};
#[derive(Clone, PartialEq)] #[derive(Clone, PartialEq)]
pub enum Token { pub enum Token {
// Single character tokens // Single character tokens
@ -9,7 +11,8 @@ pub enum Token {
// Complex tokens // Complex tokens
Identifier(String), Identifier(String),
Number(f64), Float(FloatType),
Int(IntType),
Boolean(bool), Boolean(bool),
} }
@ -65,8 +68,10 @@ fn resolve_literals(tokens: &Vec<PartialToken>) -> Vec<Token> {
.map(|token| match token { .map(|token| match token {
PartialToken::Token(token) => token.clone(), PartialToken::Token(token) => token.clone(),
PartialToken::Literal(literal) => { PartialToken::Literal(literal) => {
if let Ok(number) = literal.parse::<f64>() { if let Ok(number) = literal.parse::<IntType>() {
Token::Number(number) Token::Int(number)
} else if let Ok(number) = literal.parse::<FloatType>() {
Token::Float(number)
} else if let Ok(boolean) = literal.parse::<bool>() { } else if let Ok(boolean) = literal.parse::<bool>() {
Token::Boolean(boolean) Token::Boolean(boolean)
} else { } else {

View File

@ -86,7 +86,8 @@ pub fn tokens_to_operator_tree(tokens: Vec<Token>) -> Result<Node, Error> {
Token::Slash => Some(Box::new(Div)), Token::Slash => Some(Box::new(Div)),
Token::Whitespace => None, Token::Whitespace => None,
Token::Identifier(identifier) => Some(Box::new(Identifier::new(identifier))), 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)))), Token::Boolean(boolean) => Some(Box::new(Const::new(Value::Boolean(boolean)))),
}; };

View File

@ -1,6 +1,49 @@
use error::Error;
pub type IntType = i64;
pub type FloatType = f64;
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum Value { pub enum Value {
String(String), String(String),
Number(f64), Float(FloatType),
Int(IntType),
Boolean(bool), 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<IntType, Error> {
match self {
Value::Int(i) => Ok(*i),
_ => Err(Error::TypeError),
}
}
pub fn as_float(&self) -> Result<FloatType, Error> {
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),
}