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.
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<f64, Error> {
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())),
}
}

View File

@ -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)));
}
}

View File

@ -71,10 +71,14 @@ impl Operator for Add {
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, Error> {
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<Value, Error> {
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<Value, Error> {
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<Value, Error> {
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()))
}
}
}

View File

@ -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<PartialToken>) -> Vec<Token> {
.map(|token| match token {
PartialToken::Token(token) => token.clone(),
PartialToken::Literal(literal) => {
if let Ok(number) = literal.parse::<f64>() {
Token::Number(number)
if let Ok(number) = literal.parse::<IntType>() {
Token::Int(number)
} else if let Ok(number) = literal.parse::<FloatType>() {
Token::Float(number)
} else if let Ok(boolean) = literal.parse::<bool>() {
Token::Boolean(boolean)
} 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::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)))),
};

View File

@ -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<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),
}