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.
|
/// 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())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
26
src/lib.rs
26
src/lib.rs
@ -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)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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)))),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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),
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user