Moved * / % and ^ to units.rs, added support for 1km/1km

This commit is contained in:
Kasper 2020-01-14 14:41:53 +01:00
parent c7141e87ad
commit 1e83f50fbd
2 changed files with 86 additions and 58 deletions

View File

@ -1,6 +1,6 @@
use decimal::d128; use decimal::d128;
use crate::Token; use crate::Token;
use crate::units::{Unit, UnitType, Number, convert, add, subtract}; use crate::units::{Unit, UnitType, Number, convert, add, subtract, multiply, divide, modulo, pow};
use crate::parser::AstNode; use crate::parser::AstNode;
use crate::Operator::{Caret, Divide, Minus, Modulo, Multiply, Plus}; use crate::Operator::{Caret, Divide, Minus, Modulo, Multiply, Plus};
use crate::Constant::{Pi, E}; use crate::Constant::{Pi, E};
@ -245,51 +245,20 @@ fn evaluate_node(ast_node: &AstNode) -> Result<Number, String> {
Ok(subtract(left, right)?) Ok(subtract(left, right)?)
}, },
Multiply => { Multiply => {
if left.unit == Unit::NoUnit && right.unit == Unit::NoUnit { Ok(multiply(left, right)?)
// 3 * 2 // }
return Ok(Number::new(left.value * right.value, left.unit))
} else if left.unit == Unit::NoUnit && right.unit != Unit::NoUnit {
// 3 * 1 km
return Ok(Number::new(left.value * right.value, right.unit))
} else if right.unit == Unit::NoUnit && left.unit != Unit::NoUnit {
// 1 km * 3
return Ok(Number::new(left.value * right.value, left.unit))
} else {
return Err(format!("Cannot multiply {:?} and {:?}", left.unit, right.unit))
}
}, },
Divide => { Divide => {
if left.unit == Unit::NoUnit && right.unit == Unit::NoUnit { Ok(divide(left, right)?)
// 3 / 2 // }
return Ok(Number::new(left.value / right.value, left.unit))
} else if left.unit != Unit::NoUnit && right.unit == Unit::NoUnit {
// 1 km / 2
return Ok(Number::new(left.value / right.value, right.unit))
} else {
return Err(format!("Cannot divide {:?} by {:?}", left.unit, right.unit))
}
}, },
Modulo => { Modulo => {
if left.unit == Unit::NoUnit && right.unit == Unit::NoUnit { Ok(modulo(left, right)?)
// 3 / 2 // }
return Ok(Number::new(left.value % right.value, left.unit))
} else if left.unit != Unit::NoUnit && right.unit == Unit::NoUnit {
// 1 km / 2
return Ok(Number::new(left.value % right.value, right.unit))
} else {
return Err(format!("Cannot modulo {:?} by {:?}", left.unit, right.unit))
}
}, },
Caret => { Caret => {
if left.unit == Unit::NoUnit && right.unit == Unit::NoUnit { Ok(pow(left, right)?)
// 3 ^ 2 // }
return Ok(Number::new(left.value.pow(right.value), left.unit))
} else if right.unit == Unit::NoUnit && left.unit != Unit::NoUnit {
// 1 km ^ 3
return Ok(Number::new(left.value.pow(right.value), left.unit))
} else {
return Err(format!("Cannot multiply {:?} and {:?}", left.unit, right.unit))
}
}, },
_ => { _ => {
Err(format!("Unexpected operator {:?}", operator)) Err(format!("Unexpected operator {:?}", operator))

View File

@ -254,38 +254,97 @@ pub fn convert(number: Number, to_unit: Unit) -> Result<Number, String> {
} }
} }
pub fn add(left: Number, right: Number) -> Result<Number, String> { pub fn convert_to_lowest(left: Number, right: Number) -> Result<(Number, Number), String> {
if left.unit == right.unit { if left.unit.weight() == right.unit.weight() {
Ok(Number::new(left.value + right.value, left.unit)) Ok((left, right))
} else if left.unit.category() == right.unit.category() && left.unit.category() != Temperature { } else if left.unit.weight() > right.unit.weight() {
if left.unit.weight() > right.unit.weight() {
let left_converted = convert(left, right.unit)?; let left_converted = convert(left, right.unit)?;
Ok(Number::new(left_converted.value + right.value, right.unit)) Ok((left_converted, right))
} else { } else {
let right_converted = convert(right, left.unit)?; let right_converted = convert(right, left.unit)?;
Ok(Number::new(right_converted.value + left.value, left.unit)) Ok((left, right_converted))
} }
}
pub fn add(left: Number, right: Number) -> Result<Number, String> {
if left.unit.category() == right.unit.category() && left.unit.category() != Temperature {
let (left, right) = convert_to_lowest(left, right)?;
Ok(Number::new(left.value + right.value, left.unit))
} else { } else {
return Err(format!("Cannot add {:?} and {:?}", left.unit, right.unit)) return Err(format!("Cannot add {:?} and {:?}", left.unit, right.unit))
} }
} }
pub fn subtract(left: Number, right: Number) -> Result<Number, String> { pub fn subtract(left: Number, right: Number) -> Result<Number, String> {
if left.unit == right.unit { if left.unit.category() == right.unit.category() && left.unit.category() != Temperature {
let (left, right) = convert_to_lowest(left, right)?;
Ok(Number::new(left.value - right.value, left.unit)) Ok(Number::new(left.value - right.value, left.unit))
} else if left.unit.category() == right.unit.category() && left.unit.category() != Temperature {
if left.unit.weight() > right.unit.weight() {
let left_converted = convert(left, right.unit)?;
Ok(Number::new(left_converted.value - right.value, right.unit))
} else {
let right_converted = convert(right, left.unit)?;
Ok(Number::new(right_converted.value - left.value, left.unit))
}
} else { } else {
return Err(format!("Cannot subtract {:?} by {:?}", left.unit, right.unit)) return Err(format!("Cannot subtract {:?} by {:?}", left.unit, right.unit))
} }
} }
pub fn multiply(left: Number, right: Number) -> Result<Number, String> {
if left.unit == Unit::NoUnit && right.unit == Unit::NoUnit {
// 3 * 2
return Ok(Number::new(left.value * right.value, left.unit))
} else if left.unit.category() == Temperature || right.unit.category() == Temperature {
// if temperature
return Err(format!("Cannot multiply {:?} and {:?}", left.unit, right.unit))
} else if left.unit == Unit::NoUnit && right.unit != Unit::NoUnit {
// 3 * 1 km
return Ok(Number::new(left.value * right.value, right.unit))
} else if right.unit == Unit::NoUnit && left.unit != Unit::NoUnit {
// 1 km * 3
return Ok(Number::new(left.value * right.value, left.unit))
} else {
return Err(format!("Cannot multiply {:?} and {:?}", left.unit, right.unit))
}
}
pub fn divide(left: Number, right: Number) -> Result<Number, String> {
if left.unit == Unit::NoUnit && right.unit == Unit::NoUnit {
// 3 / 2
Ok(Number::new(left.value / right.value, left.unit))
} else if left.unit.category() == Temperature || right.unit.category() == Temperature {
// if temperature
return Err(format!("Cannot divide {:?} by {:?}", left.unit, right.unit))
} else if left.unit != Unit::NoUnit && right.unit == Unit::NoUnit {
// 1 km / 2
Ok(Number::new(left.value / right.value, right.unit))
} else if left.unit.category() == right.unit.category() {
// 1 km / 1 km
let (left, right) = convert_to_lowest(left, right)?;
Ok(Number::new(left.value * right.value, Unit::NoUnit))
} else {
Err(format!("Cannot divide {:?} by {:?}", left.unit, right.unit))
}
}
pub fn modulo(left: Number, right: Number) -> Result<Number, String> {
if left.unit == Unit::NoUnit && right.unit == Unit::NoUnit {
// 3 / 2
return Ok(Number::new(left.value % right.value, left.unit))
} else if left.unit != Unit::NoUnit && right.unit == Unit::NoUnit {
// 1 km / 2
return Ok(Number::new(left.value % right.value, right.unit))
} else {
return Err(format!("Cannot modulo {:?} by {:?}", left.unit, right.unit))
}
}
pub fn pow(left: Number, right: Number) -> Result<Number, String> {
if left.unit == Unit::NoUnit && right.unit == Unit::NoUnit {
// 3 ^ 2
return Ok(Number::new(left.value.pow(right.value), left.unit))
} else if right.unit == Unit::NoUnit && left.unit != Unit::NoUnit {
// 1 km ^ 3
return Ok(Number::new(left.value.pow(right.value), left.unit))
} else {
return Err(format!("Cannot multiply {:?} and {:?}", left.unit, right.unit))
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;