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 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::Operator::{Caret, Divide, Minus, Modulo, Multiply, Plus};
use crate::Constant::{Pi, E};
@ -245,51 +245,20 @@ fn evaluate_node(ast_node: &AstNode) -> Result<Number, String> {
Ok(subtract(left, right)?)
},
Multiply => {
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 {
// 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))
}
Ok(multiply(left, right)?)
// }
},
Divide => {
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 divide {:?} by {:?}", left.unit, right.unit))
}
Ok(divide(left, right)?)
// }
},
Modulo => {
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))
}
Ok(modulo(left, right)?)
// }
},
Caret => {
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))
}
Ok(pow(left, right)?)
// }
},
_ => {
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> {
if left.unit == right.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() {
pub fn convert_to_lowest(left: Number, right: Number) -> Result<(Number, Number), String> {
if left.unit.weight() == right.unit.weight() {
Ok((left, right))
} else if left.unit.weight() > right.unit.weight() {
let left_converted = convert(left, right.unit)?;
Ok(Number::new(left_converted.value + right.value, right.unit))
Ok((left_converted, right))
} else {
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 {
return Err(format!("Cannot add {:?} and {:?}", left.unit, right.unit))
}
}
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))
} 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 {
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)]
mod tests {
use super::*;