diff --git a/src/evaluate/function.rs b/src/evaluate/function.rs index ac95a3b..579032e 100644 --- a/src/evaluate/function.rs +++ b/src/evaluate/function.rs @@ -39,7 +39,35 @@ pub fn eval_function(g: &Expression) -> Result { return Ok(Expression::Quantity(*loc + *l, q.without_unit())); } Function::ToBase => { return Ok(Expression::Quantity(*loc + *l, q.convert_to_base())); } - // Trigonometry + + + Function::Abs => { + if !q.unitless() { return Err((*loc + *l, EvalError::IncompatibleUnit));} + return Ok(Expression::Quantity(*loc + *l, q.abs())); + }, + Function::Floor => { + if !q.unitless() { return Err((*loc + *l, EvalError::IncompatibleUnit));} + return Ok(Expression::Quantity(*loc + *l, q.floor())); + }, + Function::Ceil => { + if !q.unitless() { return Err((*loc + *l, EvalError::IncompatibleUnit));} + return Ok(Expression::Quantity(*loc + *l, q.ceil())); + }, + Function::Round => { + if !q.unitless() { return Err((*loc + *l, EvalError::IncompatibleUnit));} + return Ok(Expression::Quantity(*loc + *l, q.round())); + }, + Function::NaturalLog => { + if !q.unitless() { return Err((*loc + *l, EvalError::IncompatibleUnit));} + return Ok(Expression::Quantity(*loc + *l, q.ln())); + }, + Function::TenLog => { + if !q.unitless() { return Err((*loc + *l, EvalError::IncompatibleUnit));} + return Ok(Expression::Quantity(*loc + *l, q.log10())); + }, + + + Function::Sin => { let Ok(q) = to_radians(q.clone()) else { return Err((*loc + *l, EvalError::IncompatibleUnit)); }; return Ok(Expression::Quantity(*loc + *l, q.sin())); @@ -88,44 +116,73 @@ pub fn eval_function(g: &Expression) -> Result {} - } + Function::Asin => { + if !q.unitless() { return Err((*loc + *l, EvalError::IncompatibleUnit));} + return Ok(Expression::Quantity(*loc + *l, q.asin())); + }, + Function::Acos => { + if !q.unitless() { return Err((*loc + *l, EvalError::IncompatibleUnit));} + return Ok(Expression::Quantity(*loc + *l, q.acos())); + }, + Function::Atan => { + if !q.unitless() { return Err((*loc + *l, EvalError::IncompatibleUnit));} + return Ok(Expression::Quantity(*loc + *l, q.atan())); + }, + Function::Asinh => { + if !q.unitless() { return Err((*loc + *l, EvalError::IncompatibleUnit));} + return Ok(Expression::Quantity(*loc + *l, q.asinh())); + }, + Function::Acosh => { + if !q.unitless() { return Err((*loc + *l, EvalError::IncompatibleUnit));} + return Ok(Expression::Quantity(*loc + *l, q.acosh())); + }, + Function::Atanh => { + if !q.unitless() { return Err((*loc + *l, EvalError::IncompatibleUnit));} + return Ok(Expression::Quantity(*loc + *l, q.atanh())); + }, - if !q.unitless() { - return Err((*loc + *l, EvalError::IncompatibleUnit)); - } - match f { - Function::Abs => { return Ok(Expression::Quantity(*loc + *l, q.abs())); }, - Function::Floor => { return Ok(Expression::Quantity(*loc + *l, q.floor())); }, - Function::Ceil => { return Ok(Expression::Quantity(*loc + *l, q.ceil())); }, - Function::Round => { return Ok(Expression::Quantity(*loc + *l, q.round())); }, - Function::NaturalLog => { return Ok(Expression::Quantity(*loc + *l, q.ln())); }, - Function::TenLog => { return Ok(Expression::Quantity(*loc + *l, q.log10())); }, + Function::ToCelsius => { + let mut k = Quantity::new_rational(1f64).unwrap(); + k.insert_unit(FreeUnit::from_whole(WholeUnit::Kelvin), Scalar::new_rational(1f64).unwrap()); + let Some(q) = q.convert_to(k) else { return Err((*loc + *l, EvalError::IncompatibleUnit)) }; - Function::Asin => { return Ok(Expression::Quantity(*loc + *l, q.asin())); }, - Function::Acos => { return Ok(Expression::Quantity(*loc + *l, q.acos())); }, - Function::Atan => { return Ok(Expression::Quantity(*loc + *l, q.atan())); }, + let mut r = q.without_unit(); + r += Quantity::new_rational(-273.15f64).unwrap(); - Function::Asinh => { return Ok(Expression::Quantity(*loc + *l, q.asinh())); }, - Function::Acosh => { return Ok(Expression::Quantity(*loc + *l, q.acosh())); }, - Function::Atanh => { return Ok(Expression::Quantity(*loc + *l, q.atanh())); }, + return Ok(Expression::Quantity(*loc + *l, r)); + }, + Function::ToFahrenheit => { + let mut k = Quantity::new_rational(1f64).unwrap(); + k.insert_unit(FreeUnit::from_whole(WholeUnit::Kelvin), Scalar::new_rational(1f64).unwrap()); + let Some(q) = q.convert_to(k) else { return Err((*loc + *l, EvalError::IncompatibleUnit)) }; - Function::ToBase - | Function::NoUnit - | Function::Sin - | Function::Cos - | Function::Tan - | Function::Csc - | Function::Sec - | Function::Cot - | Function::Sinh - | Function::Cosh - | Function::Tanh - | Function::Csch - | Function::Sech - | Function::Coth - => unreachable!() + let mut r = q.without_unit(); + r *= Quantity::new_rational_from_frac(9i64, 5i64).unwrap(); + r += Quantity::new_rational(-459.67).unwrap(); + + + return Ok(Expression::Quantity(*loc + *l, r)); + }, + Function::FromCelsius => { + if !q.unitless() { return Err((*loc + *l, EvalError::IncompatibleUnit));} + + let mut r = Quantity::new_rational(273.15f64).unwrap(); + r += q.clone(); + r.insert_unit(FreeUnit::from_whole(WholeUnit::Kelvin), Scalar::new_rational(1f64).unwrap()); + + return Ok(Expression::Quantity(*loc + *l, r)); + }, + Function::FromFahrenheit => { + if !q.unitless() { return Err((*loc + *l, EvalError::IncompatibleUnit));} + + let mut r = q.clone(); + r += Quantity::new_rational(459.67).unwrap(); + r *= Quantity::new_rational_from_frac(5i64, 9i64).unwrap(); + r.insert_unit(FreeUnit::from_whole(WholeUnit::Kelvin), Scalar::new_rational(1f64).unwrap()); + + return Ok(Expression::Quantity(*loc + *l, r)); + } } } \ No newline at end of file diff --git a/src/parser/expression/function.rs b/src/parser/expression/function.rs index ba73686..9c71fd5 100644 --- a/src/parser/expression/function.rs +++ b/src/parser/expression/function.rs @@ -33,7 +33,11 @@ pub enum Function { Coth, NoUnit, - ToBase + ToBase, + FromCelsius, + ToCelsius, + FromFahrenheit, + ToFahrenheit } @@ -66,6 +70,10 @@ impl ToString for Function { Function::Coth => { String::from("coth") }, Function::NoUnit => { String::from("nounit") }, Function::ToBase => { String::from("tobase") }, + Function::FromCelsius => { String::from("fromcelsius") }, + Function::ToCelsius => {String::from("tocelsius") }, + Function::FromFahrenheit => { String::from("fromfahrenheit") }, + Function::ToFahrenheit => { String::from("tofahrenheit") }, } } @@ -101,7 +109,20 @@ impl Function { "coth" => {Some(Function::Coth)}, "nounit" => {Some(Function::NoUnit)}, - "tobase" => {Some(Function::ToBase)} + "tobase" => {Some(Function::ToBase)}, + + "toC" => {Some(Function::ToCelsius)}, + "fromC" => {Some(Function::FromCelsius)}, + "toF" => {Some(Function::ToFahrenheit)}, + "fromF" => {Some(Function::FromFahrenheit)}, + "tocelsius" => {Some(Function::ToCelsius)}, + "fromcelsius" => {Some(Function::FromCelsius)}, + "tofahrenheit" => {Some(Function::ToFahrenheit)}, + "fromfahrenheit" => {Some(Function::FromFahrenheit)}, + "toCelsius" => {Some(Function::ToCelsius)}, + "fromCelsius" => {Some(Function::FromCelsius)}, + "toFahrenheit" => {Some(Function::ToFahrenheit)}, + "fromFahrenheit" => {Some(Function::FromFahrenheit)}, _ => None } } diff --git a/src/quantity/quantity.rs b/src/quantity/quantity.rs index d8cd4ab..fd63e5b 100644 --- a/src/quantity/quantity.rs +++ b/src/quantity/quantity.rs @@ -90,6 +90,16 @@ impl Quantity { }); } + pub fn new_rational_from_frac(a: i64, b: i64) -> Option { + let v = Scalar::new_rational_from_frac(a, b); + if v.is_none() { return None; } + + return Some(Quantity{ + scalar: v.unwrap(), + unit: Unit::new() + }); + } + pub fn from_scalar(s: Scalar) -> Quantity { return Quantity{ scalar: s,