Implemented separate int and float types
This commit is contained in:
parent
22490f5036
commit
0ee4946eaf
@ -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())),
|
||||
}
|
||||
}
|
||||
|
26
src/lib.rs
26
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)));
|
||||
}
|
||||
}
|
||||
|
@ -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()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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)))),
|
||||
};
|
||||
|
||||
|
@ -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),
|
||||
}
|
Loading…
Reference in New Issue
Block a user