Made unit field Optional in KalkValue

This commit is contained in:
bakk 2022-01-23 01:16:34 +01:00
parent 8f7726eab5
commit e10f129706
5 changed files with 147 additions and 119 deletions

View File

@ -15,15 +15,24 @@ pub fn derive_func(
argument: KalkValue, argument: KalkValue,
) -> Result<KalkValue, CalcError> { ) -> Result<KalkValue, CalcError> {
const H: f64 = 0.000001; const H: f64 = 0.000001;
let unit = &argument.get_unit();
let unit = argument.get_unit().cloned();
let argument_with_h = ast::build_literal_ast(&argument.clone().add_without_unit(&H.into())); let argument_with_h = ast::build_literal_ast(&argument.clone().add_without_unit(&H.into()));
let argument_without_h = ast::build_literal_ast(&argument.sub_without_unit(&H.into())); let argument_without_h = ast::build_literal_ast(&argument.sub_without_unit(&H.into()));
let new_identifier = Identifier::from_name_and_primes(&name.pure_name, name.prime_count - 1); let new_identifier = Identifier::from_name_and_primes(&name.pure_name, name.prime_count - 1);
let f_x_h = interpreter::eval_fn_call_expr(context, &new_identifier, &[argument_with_h], unit)?; let f_x_h = interpreter::eval_fn_call_expr(
let f_x = context,
interpreter::eval_fn_call_expr(context, &new_identifier, &[argument_without_h], unit)?; &new_identifier,
&[argument_with_h],
unit.as_ref(),
)?;
let f_x = interpreter::eval_fn_call_expr(
context,
&new_identifier,
&[argument_without_h],
unit.as_ref(),
)?;
Ok(f_x_h Ok(f_x_h
.sub_without_unit(&f_x) .sub_without_unit(&f_x)
@ -87,8 +96,8 @@ fn simpsons_rule(
.get_and_remove_var(integration_variable); .get_and_remove_var(integration_variable);
const N: i32 = 900; const N: i32 = 900;
let a = interpreter::eval_expr(context, a_expr, "")?; let a = interpreter::eval_expr(context, a_expr, None)?;
let b = interpreter::eval_expr(context, b_expr, "")?; let b = interpreter::eval_expr(context, b_expr, None)?;
let h = (b.sub_without_unit(&a)).div_without_unit(&KalkValue::from(N)); let h = (b.sub_without_unit(&a)).div_without_unit(&KalkValue::from(N));
for i in 0..=N { for i in 0..=N {
let variable_value = a let variable_value = a
@ -103,11 +112,11 @@ fn simpsons_rule(
0 | N => 1, 0 | N => 1,
_ if i % 3 == 0 => 2, _ if i % 3 == 0 => 2,
_ => 3, _ => 3,
}); } as f64);
// factor * f(x_n) // factor * f(x_n)
let (mul_real, mul_imaginary, _) = as_number_or_zero!( let (mul_real, mul_imaginary, _) = as_number_or_zero!(
factor.mul_without_unit(&interpreter::eval_expr(context, expr, "")?) factor.mul_without_unit(&interpreter::eval_expr(context, expr, None)?)
); );
result_real += mul_real; result_real += mul_real;
result_imaginary += mul_imaginary; result_imaginary += mul_imaginary;
@ -121,7 +130,7 @@ fn simpsons_rule(
.get_and_remove_var(integration_variable); .get_and_remove_var(integration_variable);
} }
let result = KalkValue::Number(result_real, result_imaginary, String::new()); let result = KalkValue::Number(result_real, result_imaginary, None);
let (h_real, h_imaginary, h_unit) = as_number_or_zero!(h); let (h_real, h_imaginary, h_unit) = as_number_or_zero!(h);
Ok(result.mul_without_unit(&KalkValue::Number( Ok(result.mul_without_unit(&KalkValue::Number(
@ -219,7 +228,7 @@ mod tests {
let result = super::derive_func( let result = super::derive_func(
&mut context, &mut context,
&Identifier::from_full_name("f'"), &Identifier::from_full_name("f'"),
KalkValue::Number(float!(2f64), float!(3f64), String::new()), KalkValue::Number(float!(2f64), float!(3f64), None),
) )
.unwrap(); .unwrap();
assert!(cmp(result.to_f64(), -4.5f64) || cmp(result.to_f64(), -4.499999f64)); assert!(cmp(result.to_f64(), -4.5f64) || cmp(result.to_f64(), -4.499999f64));
@ -264,11 +273,7 @@ mod tests {
let result = super::integrate( let result = super::integrate(
&mut context, &mut context,
&*literal(2f64), &*literal(2f64),
&ast::build_literal_ast(&KalkValue::Number( &ast::build_literal_ast(&KalkValue::Number(float!(3f64), float!(4f64), None)),
float!(3f64),
float!(4f64),
String::new(),
)),
&*binary(var("x"), Star, var("i")), &*binary(var("x"), Star, var("i")),
"x", "x",
) )

View File

@ -53,7 +53,7 @@ impl<'a> Context<'a> {
Stmt::VarDecl( Stmt::VarDecl(
Identifier::from_full_name("ans"), Identifier::from_full_name("ans"),
Box::new(Expr::Unit( Box::new(Expr::Unit(
num.get_unit().clone(), num.get_unit().unwrap().to_string(),
Box::new(crate::ast::build_literal_ast(&num)), Box::new(crate::ast::build_literal_ast(&num)),
)), )),
) )
@ -103,13 +103,13 @@ fn eval_unit_decl_stmt() -> Result<KalkValue, CalcError> {
} }
fn eval_expr_stmt(context: &mut Context, expr: &Expr) -> Result<KalkValue, CalcError> { fn eval_expr_stmt(context: &mut Context, expr: &Expr) -> Result<KalkValue, CalcError> {
eval_expr(context, expr, "") eval_expr(context, expr, None)
} }
pub(crate) fn eval_expr( pub(crate) fn eval_expr(
context: &mut Context, context: &mut Context,
expr: &Expr, expr: &Expr,
unit: &str, unit: Option<&String>,
) -> Result<KalkValue, CalcError> { ) -> Result<KalkValue, CalcError> {
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
if let (Ok(elapsed), Some(timeout)) = (context.start_time.elapsed(), context.timeout) { if let (Ok(elapsed), Some(timeout)) = (context.start_time.elapsed(), context.timeout) {
@ -143,20 +143,25 @@ fn eval_binary_expr(
left_expr: &Expr, left_expr: &Expr,
op: &TokenKind, op: &TokenKind,
right_expr: &Expr, right_expr: &Expr,
unit: &str, unit: Option<&String>,
) -> Result<KalkValue, CalcError> { ) -> Result<KalkValue, CalcError> {
if let TokenKind::ToKeyword = op { if let TokenKind::ToKeyword = op {
// TODO: When the unit conversion function takes a Float instead of Expr, // TODO: When the unit conversion function takes a Float instead of Expr,
// move this to the match statement further down. // move this to the match statement further down.
if let Expr::Var(right_unit) = right_expr { if let Expr::Var(right_unit) = right_expr {
let left_unit = eval_expr(context, left_expr, "")?.get_unit(); let left_unit = eval_expr(context, left_expr, None)?.get_unit().cloned();
return convert_unit(context, left_expr, &left_unit, &right_unit.full_name); return convert_unit(
context,
left_expr,
left_unit.as_ref(),
Some(&right_unit.full_name),
);
// TODO: Avoid evaluating this twice. // TODO: Avoid evaluating this twice.
} }
} }
let left = eval_expr(context, left_expr, "")?; let left = eval_expr(context, left_expr, None)?;
let mut right = eval_expr(context, right_expr, "")?; let mut right = eval_expr(context, right_expr, None)?;
if let Expr::Unary(TokenKind::Percent, _) = right_expr { if let Expr::Unary(TokenKind::Percent, _) = right_expr {
right = right.mul(context, left.clone()); right = right.mul(context, left.clone());
if let TokenKind::Star = op { if let TokenKind::Star = op {
@ -179,12 +184,12 @@ fn eval_binary_expr(
TokenKind::LessOrEquals => left.less_or_equals(context, right), TokenKind::LessOrEquals => left.less_or_equals(context, right),
TokenKind::And => left.and(&right), TokenKind::And => left.and(&right),
TokenKind::Or => left.or(&right), TokenKind::Or => left.or(&right),
_ => KalkValue::from(1), _ => KalkValue::from(1f64),
}; };
if !unit.is_empty() { if unit.is_some() {
if let KalkValue::Number(real, imaginary, _) = result { if let KalkValue::Number(real, imaginary, _) = result {
return Ok(KalkValue::Number(real, imaginary, unit.to_string())); return Ok(KalkValue::Number(real, imaginary, unit.cloned()));
} }
}; };
@ -195,7 +200,7 @@ fn eval_unary_expr(
context: &mut Context, context: &mut Context,
op: &TokenKind, op: &TokenKind,
expr: &Expr, expr: &Expr,
unit: &str, unit: Option<&String>,
) -> Result<KalkValue, CalcError> { ) -> Result<KalkValue, CalcError> {
let num = eval_expr(context, expr, unit)?; let num = eval_expr(context, expr, unit)?;
@ -214,18 +219,29 @@ fn eval_unit_expr(
) -> Result<KalkValue, CalcError> { ) -> Result<KalkValue, CalcError> {
let angle_unit = &context.angle_unit.clone(); let angle_unit = &context.angle_unit.clone();
if (identifier == "rad" || identifier == "deg") && angle_unit != identifier { if (identifier == "rad" || identifier == "deg") && angle_unit != identifier {
return convert_unit(context, expr, identifier, angle_unit); return convert_unit(
context,
expr,
Some(&identifier.to_string()),
Some(angle_unit),
);
} }
eval_expr(context, expr, identifier) eval_expr(context, expr, Some(&identifier.to_string()))
} }
pub fn convert_unit( pub fn convert_unit(
context: &mut Context, context: &mut Context,
expr: &Expr, expr: &Expr,
from_unit: &str, from_unit: Option<&String>,
to_unit: &str, to_unit: Option<&String>,
) -> Result<KalkValue, CalcError> { ) -> Result<KalkValue, CalcError> {
let (from_unit, to_unit) = if let (Some(from_unit), Some(to_unit)) = (from_unit, to_unit) {
(from_unit, to_unit)
} else {
return Err(CalcError::InvalidUnit);
};
if let Some(Stmt::UnitDecl(_, _, unit_def)) = if let Some(Stmt::UnitDecl(_, _, unit_def)) =
context.symbol_table.get_unit(to_unit, from_unit).cloned() context.symbol_table.get_unit(to_unit, from_unit).cloned()
{ {
@ -234,8 +250,8 @@ pub fn convert_unit(
Box::new(expr.clone()), Box::new(expr.clone()),
)); ));
let (real, imaginary, _) = as_number_or_zero!(eval_expr(context, &unit_def, "")?); let (real, imaginary, _) = as_number_or_zero!(eval_expr(context, &unit_def, None)?);
Ok(KalkValue::Number(real, imaginary, to_unit.into())) Ok(KalkValue::Number(real, imaginary, Some(to_unit.clone())))
} else { } else {
Err(CalcError::InvalidUnit) Err(CalcError::InvalidUnit)
} }
@ -244,7 +260,7 @@ pub fn convert_unit(
fn eval_var_expr( fn eval_var_expr(
context: &mut Context, context: &mut Context,
identifier: &Identifier, identifier: &Identifier,
unit: &str, unit: Option<&String>,
) -> Result<KalkValue, CalcError> { ) -> Result<KalkValue, CalcError> {
// If there is a constant with this name, return a literal expression with its value // If there is a constant with this name, return a literal expression with its value
if let Some(value) = prelude::CONSTANTS.get(identifier.full_name.as_ref() as &str) { if let Some(value) = prelude::CONSTANTS.get(identifier.full_name.as_ref() as &str) {
@ -277,12 +293,12 @@ fn eval_var_expr(
fn eval_literal_expr( fn eval_literal_expr(
context: &mut Context, context: &mut Context,
value: f64, value: f64,
unit: &str, unit: Option<&String>,
) -> Result<KalkValue, CalcError> { ) -> Result<KalkValue, CalcError> {
let mut float = float!(value); let mut float = float!(value);
float.set_prec(context.precision); float.set_prec(context.precision);
Ok(KalkValue::Number(float, float!(0), unit.to_string())) Ok(KalkValue::Number(float, float!(0), unit.cloned()))
} }
#[allow(unused_variables)] #[allow(unused_variables)]
@ -290,7 +306,7 @@ fn eval_literal_expr(
fn eval_literal_expr( fn eval_literal_expr(
context: &mut Context, context: &mut Context,
value: f64, value: f64,
unit: &str, unit: Option<&String>,
) -> Result<KalkValue, CalcError> { ) -> Result<KalkValue, CalcError> {
Ok(KalkValue::Number( Ok(KalkValue::Number(
float!(value), float!(value),
@ -299,7 +315,11 @@ fn eval_literal_expr(
)) ))
} }
fn eval_group_expr(context: &mut Context, expr: &Expr, unit: &str) -> Result<KalkValue, CalcError> { fn eval_group_expr(
context: &mut Context,
expr: &Expr,
unit: Option<&String>,
) -> Result<KalkValue, CalcError> {
eval_expr(context, expr, unit) eval_expr(context, expr, unit)
} }
@ -307,13 +327,13 @@ pub(crate) fn eval_fn_call_expr(
context: &mut Context, context: &mut Context,
identifier: &Identifier, identifier: &Identifier,
expressions: &[Expr], expressions: &[Expr],
unit: &str, unit: Option<&String>,
) -> Result<KalkValue, CalcError> { ) -> Result<KalkValue, CalcError> {
// Prelude vector function // Prelude vector function
if prelude::is_vector_func(&identifier.full_name) { if prelude::is_vector_func(&identifier.full_name) {
let mut values = Vec::new(); let mut values = Vec::new();
for expression in expressions { for expression in expressions {
let value = eval_expr(context, expression, "")?; let value = eval_expr(context, expression, None)?;
if expressions.len() == 1 { if expressions.len() == 1 {
if let KalkValue::Vector(internal_values) = value { if let KalkValue::Vector(internal_values) = value {
values = internal_values; values = internal_values;
@ -333,7 +353,7 @@ pub(crate) fn eval_fn_call_expr(
// Prelude // Prelude
let prelude_func = match expressions.len() { let prelude_func = match expressions.len() {
1 => { 1 => {
let x = eval_expr(context, &expressions[0], "")?; let x = eval_expr(context, &expressions[0], None)?;
if identifier.prime_count > 0 { if identifier.prime_count > 0 {
return calculus::derive_func(context, identifier, x); return calculus::derive_func(context, identifier, x);
} else { } else {
@ -346,8 +366,8 @@ pub(crate) fn eval_fn_call_expr(
} }
} }
2 => { 2 => {
let x = eval_expr(context, &expressions[0], "")?; let x = eval_expr(context, &expressions[0], None)?;
let y = eval_expr(context, &expressions[1], "")?; let y = eval_expr(context, &expressions[1], None)?;
prelude::call_binary_func( prelude::call_binary_func(
context, context,
&identifier.full_name, &identifier.full_name,
@ -363,7 +383,7 @@ pub(crate) fn eval_fn_call_expr(
// If the result is nan and only one argument was given, // If the result is nan and only one argument was given,
// it may be due to incompatible types. // it may be due to incompatible types.
if result.is_nan() && expressions.len() == 1 { if result.is_nan() && expressions.len() == 1 {
let x = eval_expr(context, &expressions[0], "")?; let x = eval_expr(context, &expressions[0], None)?;
// If a vector/matrix was given, call the function on every item // If a vector/matrix was given, call the function on every item
// in the vector/matrix. // in the vector/matrix.
@ -453,8 +473,8 @@ pub(crate) fn eval_fn_call_expr(
}); });
} }
let start = eval_expr(context, start_expr, "")?.to_f64() as i128; let start = eval_expr(context, start_expr, None)?.to_f64() as i128;
let end = eval_expr(context, &expressions[1], "")?.to_f64() as i128; let end = eval_expr(context, &expressions[1], None)?.to_f64() as i128;
let sum_else_prod = match identifier.full_name.as_ref() { let sum_else_prod = match identifier.full_name.as_ref() {
"sum" => true, "sum" => true,
"prod" => false, "prod" => false,
@ -470,7 +490,7 @@ pub(crate) fn eval_fn_call_expr(
let sum_variables = context.sum_variables.as_mut().unwrap(); let sum_variables = context.sum_variables.as_mut().unwrap();
sum_variables.last_mut().unwrap().value = n; sum_variables.last_mut().unwrap().value = n;
let eval = eval_expr(context, &expressions[2], "")?; let eval = eval_expr(context, &expressions[2], None)?;
if sum_else_prod { if sum_else_prod {
sum = sum.add(context, eval); sum = sum.add(context, eval);
} else { } else {
@ -484,7 +504,7 @@ pub(crate) fn eval_fn_call_expr(
let (sum_real, sum_imaginary, _) = as_number_or_zero!(sum); let (sum_real, sum_imaginary, _) = as_number_or_zero!(sum);
// Set the unit as well // Set the unit as well
return Ok(KalkValue::Number(sum_real, sum_imaginary, unit.to_string())); return Ok(KalkValue::Number(sum_real, sum_imaginary, unit.cloned()));
} }
"integrate" => { "integrate" => {
return match expressions.len() { return match expressions.len() {
@ -542,7 +562,7 @@ pub(crate) fn eval_fn_call_expr(
Box::new(crate::ast::build_literal_ast(&eval_expr( Box::new(crate::ast::build_literal_ast(&eval_expr(
context, context,
&expressions[i], &expressions[i],
"", None,
)?)), )?)),
); );
@ -581,7 +601,7 @@ pub(crate) fn eval_fn_call_expr(
fn eval_piecewise( fn eval_piecewise(
context: &mut Context, context: &mut Context,
pieces: &[crate::ast::ConditionalPiece], pieces: &[crate::ast::ConditionalPiece],
unit: &str, unit: Option<&String>,
) -> Result<KalkValue, CalcError> { ) -> Result<KalkValue, CalcError> {
for piece in pieces { for piece in pieces {
if let KalkValue::Boolean(condition_is_true) = eval_expr(context, &piece.condition, unit)? { if let KalkValue::Boolean(condition_is_true) = eval_expr(context, &piece.condition, unit)? {
@ -597,7 +617,7 @@ fn eval_piecewise(
fn eval_vector(context: &mut Context, values: &[Expr]) -> Result<KalkValue, CalcError> { fn eval_vector(context: &mut Context, values: &[Expr]) -> Result<KalkValue, CalcError> {
let mut eval_values = Vec::new(); let mut eval_values = Vec::new();
for value in values { for value in values {
eval_values.push(eval_expr(context, value, "")?); eval_values.push(eval_expr(context, value, None)?);
} }
Ok(KalkValue::Vector(eval_values)) Ok(KalkValue::Vector(eval_values))
@ -608,7 +628,7 @@ fn eval_matrix(context: &mut Context, rows: &[Vec<Expr>]) -> Result<KalkValue, C
for row in rows { for row in rows {
let mut eval_row = Vec::new(); let mut eval_row = Vec::new();
for value in row { for value in row {
eval_row.push(eval_expr(context, value, "")?) eval_row.push(eval_expr(context, value, None)?)
} }
eval_rows.push(eval_row); eval_rows.push(eval_row);
@ -621,7 +641,7 @@ fn eval_indexer(
context: &mut Context, context: &mut Context,
var: &Expr, var: &Expr,
index_expressions: &[Expr], index_expressions: &[Expr],
unit: &str, unit: Option<&String>,
) -> Result<KalkValue, CalcError> { ) -> Result<KalkValue, CalcError> {
let var_value = eval_expr(context, var, unit)?; let var_value = eval_expr(context, var, unit)?;
match var_value { match var_value {
@ -682,7 +702,7 @@ fn eval_indexer(
fn as_indices(context: &mut Context, expressions: &[Expr]) -> Result<Vec<usize>, CalcError> { fn as_indices(context: &mut Context, expressions: &[Expr]) -> Result<Vec<usize>, CalcError> {
let mut indices = Vec::new(); let mut indices = Vec::new();
for expr in expressions { for expr in expressions {
let value = eval_expr(context, expr, "")?; let value = eval_expr(context, expr, None)?;
if value.has_imaginary() { if value.has_imaginary() {
return Err(CalcError::CannotIndexByImaginary); return Err(CalcError::CannotIndexByImaginary);
} }
@ -715,8 +735,8 @@ fn eval_comprehension(
Box::new(Expr::Literal(0f64)), Box::new(Expr::Literal(0f64)),
)); ));
let min = eval_expr(context, &var.min, "")?.to_f64() as i32; let min = eval_expr(context, &var.min, None)?.to_f64() as i32;
let max = eval_expr(context, &var.max, "")?.to_f64() as i32; let max = eval_expr(context, &var.max, None)?.to_f64() as i32;
let mut values = Vec::new(); let mut values = Vec::new();
for i in min..max { for i in min..max {
@ -732,10 +752,10 @@ fn eval_comprehension(
} }
} }
let condition = eval_expr(context, condition, "")?; let condition = eval_expr(context, condition, None)?;
if let KalkValue::Boolean(boolean) = condition { if let KalkValue::Boolean(boolean) = condition {
if boolean && vars.len() == 1 { if boolean && vars.len() == 1 {
values.push(eval_expr(context, left, "")?); values.push(eval_expr(context, left, None)?);
} }
} }
} }
@ -800,7 +820,7 @@ mod tests {
} }
#[cfg(not(feature = "rug"))] #[cfg(not(feature = "rug"))]
fn context<'a>(symbol_table: &'a mut SymbolTable, angle_unit: &str) -> Context<'a> { fn context<'a>(symbol_table: &'a mut SymbolTable, angle_unit: Option<&String>) -> Context<'a> {
Context::new(symbol_table, angle_unit, None) Context::new(symbol_table, angle_unit, None)
} }

View File

@ -93,7 +93,7 @@ macro_rules! as_number_or_zero {
if let KalkValue::Number(real, imaginary, unit) = $x { if let KalkValue::Number(real, imaginary, unit) = $x {
(real, imaginary, unit) (real, imaginary, unit)
} else { } else {
(float!(0), float!(0), String::new()) (float!(0), float!(0), None)
} }
}}; }};
} }
@ -145,9 +145,9 @@ impl std::fmt::Display for ScientificNotation {
#[derive(PartialEq, Debug, Clone)] #[derive(PartialEq, Debug, Clone)]
pub enum KalkValue { pub enum KalkValue {
#[cfg(not(feature = "rug"))] #[cfg(not(feature = "rug"))]
Number(f64, f64, String), Number(f64, f64, Option<String>),
#[cfg(feature = "rug")] #[cfg(feature = "rug")]
Number(Float, Float, String), Number(Float, Float, Option<String>),
Boolean(bool), Boolean(bool),
Vector(Vec<KalkValue>), Vector(Vec<KalkValue>),
Matrix(Vec<Vec<KalkValue>>), Matrix(Vec<Vec<KalkValue>>),
@ -227,7 +227,7 @@ impl std::fmt::Display for KalkValue {
impl KalkValue { impl KalkValue {
pub fn nan() -> Self { pub fn nan() -> Self {
KalkValue::Number(float!(f64::NAN), float!(0f64), String::new()) KalkValue::Number(float!(f64::NAN), float!(0f64), None)
} }
pub fn to_string_big(&self) -> String { pub fn to_string_big(&self) -> String {
@ -325,7 +325,7 @@ impl KalkValue {
} }
} }
if !unit.is_empty() { if let Some(unit) = unit {
output.push_str(&format!(" {}", unit)); output.push_str(&format!(" {}", unit));
} }
@ -346,7 +346,9 @@ impl KalkValue {
pub fn to_string_with_unit(&self) -> String { pub fn to_string_with_unit(&self) -> String {
match self { match self {
KalkValue::Number(_, _, unit) => format!("{} {}", self, unit), KalkValue::Number(_, _, unit) => {
format!("{} {}", self, unit.as_ref().unwrap_or(&String::new()))
}
_ => self.to_string(), _ => self.to_string(),
} }
} }
@ -432,7 +434,7 @@ impl KalkValue {
} else { } else {
original_imaginary.clone() original_imaginary.clone()
}, },
unit.to_string(), unit.clone(),
)) ))
} }
@ -489,17 +491,17 @@ impl KalkValue {
pub fn has_unit(&self) -> bool { pub fn has_unit(&self) -> bool {
if let KalkValue::Number(_, _, unit) = self { if let KalkValue::Number(_, _, unit) = self {
!unit.is_empty() unit.is_some()
} else { } else {
false false
} }
} }
pub fn get_unit(&self) -> String { pub fn get_unit(&self) -> Option<&String> {
if let KalkValue::Number(_, _, unit) = self { if let KalkValue::Number(_, _, unit) = self {
unit.to_string() unit.as_ref()
} else { } else {
String::new() None
} }
} }
@ -512,8 +514,8 @@ impl KalkValue {
let result = crate::interpreter::convert_unit( let result = crate::interpreter::convert_unit(
context, context,
&Expr::Literal(primitive!(real)), &Expr::Literal(primitive!(real)),
unit, unit.as_ref(),
to_unit, Some(&to_unit.to_string()),
); );
if let Ok(num) = result { if let Ok(num) = result {
@ -675,7 +677,7 @@ impl KalkValue {
( (
KalkValue::Number(real, imaginary, _), KalkValue::Number(real, imaginary, _),
KalkValue::Number(real_rhs, imaginary_rhs, unit), KalkValue::Number(real_rhs, imaginary_rhs, unit),
) => KalkValue::Number(real + real_rhs, imaginary + imaginary_rhs, unit.to_string()), ) => KalkValue::Number(real + real_rhs, imaginary + imaginary_rhs, unit.clone()),
(KalkValue::Matrix(_), _) | (_, KalkValue::Matrix(_)) => { (KalkValue::Matrix(_), _) | (_, KalkValue::Matrix(_)) => {
calculate_matrix(self, rhs, &KalkValue::add_without_unit) calculate_matrix(self, rhs, &KalkValue::add_without_unit)
} }
@ -691,7 +693,7 @@ impl KalkValue {
( (
KalkValue::Number(real, imaginary, _), KalkValue::Number(real, imaginary, _),
KalkValue::Number(real_rhs, imaginary_rhs, unit), KalkValue::Number(real_rhs, imaginary_rhs, unit),
) => KalkValue::Number(real - real_rhs, imaginary - imaginary_rhs, unit.to_string()), ) => KalkValue::Number(real - real_rhs, imaginary - imaginary_rhs, unit.clone()),
(KalkValue::Matrix(_), _) | (_, KalkValue::Matrix(_)) => { (KalkValue::Matrix(_), _) | (_, KalkValue::Matrix(_)) => {
calculate_matrix(self, rhs, &KalkValue::sub_without_unit) calculate_matrix(self, rhs, &KalkValue::sub_without_unit)
} }
@ -719,7 +721,7 @@ impl KalkValue {
// (a + bi)(c + di) = ac + adi + bci + bdi² // (a + bi)(c + di) = ac + adi + bci + bdi²
real.clone() * real_rhs - imaginary.clone() * imaginary_rhs, real.clone() * real_rhs - imaginary.clone() * imaginary_rhs,
real.clone() * imaginary_rhs + imaginary * real_rhs, real.clone() * imaginary_rhs + imaginary * real_rhs,
unit.to_string(), unit.clone(),
), ),
(KalkValue::Matrix(rows), KalkValue::Number(_, _, _)) => KalkValue::Matrix( (KalkValue::Matrix(rows), KalkValue::Number(_, _, _)) => KalkValue::Matrix(
rows.iter() rows.iter()
@ -849,10 +851,10 @@ impl KalkValue {
KalkValue::Number( KalkValue::Number(
polar.clone().cos() * exp.clone(), polar.clone().cos() * exp.clone(),
polar.sin() * exp, polar.sin() * exp,
unit.to_string(), unit.clone(),
) )
} else { } else {
KalkValue::Number(pow(real, real_rhs.clone()), float!(0), unit.to_string()) KalkValue::Number(pow(real, real_rhs.clone()), float!(0), unit.clone())
} }
} }
(KalkValue::Matrix(rows), KalkValue::Number(real, imaginary, _)) => { (KalkValue::Matrix(rows), KalkValue::Number(real, imaginary, _)) => {
@ -1107,12 +1109,12 @@ fn calculate_unit(
(left, &right) (left, &right)
{ {
if left.has_unit() && right.has_unit() { if left.has_unit() && right.has_unit() {
right.convert_to_unit(context, unit_left) right.convert_to_unit(context, unit_left.as_ref().unwrap())
} else { } else {
Some(KalkValue::Number( Some(KalkValue::Number(
real_right.clone(), real_right.clone(),
imaginary_right.clone(), imaginary_right.clone(),
unit_left.to_string(), unit_left.clone(),
)) ))
} }
} else { } else {
@ -1165,31 +1167,31 @@ impl From<KalkValue> for f64 {
impl From<f64> for KalkValue { impl From<f64> for KalkValue {
fn from(x: f64) -> Self { fn from(x: f64) -> Self {
KalkValue::Number(float!(x), float!(0), String::new()) KalkValue::Number(float!(x), float!(0), None)
} }
} }
impl From<f32> for KalkValue { impl From<f32> for KalkValue {
fn from(x: f32) -> Self { fn from(x: f32) -> Self {
KalkValue::Number(float!(x), float!(0), String::new()) KalkValue::Number(float!(x), float!(0), None)
} }
} }
impl From<i128> for KalkValue { impl From<i128> for KalkValue {
fn from(x: i128) -> Self { fn from(x: i128) -> Self {
KalkValue::Number(float!(x), float!(0), String::new()) KalkValue::Number(float!(x), float!(0), None)
} }
} }
impl From<i64> for KalkValue { impl From<i64> for KalkValue {
fn from(x: i64) -> Self { fn from(x: i64) -> Self {
KalkValue::Number(float!(x), float!(0), String::new()) KalkValue::Number(float!(x), float!(0), None)
} }
} }
impl From<i32> for KalkValue { impl From<i32> for KalkValue {
fn from(x: i32) -> Self { fn from(x: i32) -> Self {
KalkValue::Number(float!(x), float!(0), String::new()) KalkValue::Number(float!(x), float!(0), None)
} }
} }
@ -1208,8 +1210,8 @@ mod tests {
]; ];
for (a, b, expected_result) in in_out { for (a, b, expected_result) in in_out {
let actual_result = KalkValue::Number(float!(a.0), float!(a.1), String::new()) let actual_result = KalkValue::Number(float!(a.0), float!(a.1), None)
.add_without_unit(&KalkValue::Number(float!(b.0), float!(b.1), String::new())); .add_without_unit(&KalkValue::Number(float!(b.0), float!(b.1), None));
assert_eq!(actual_result.to_f64(), expected_result.0); assert_eq!(actual_result.to_f64(), expected_result.0);
assert_eq!(actual_result.imaginary_to_f64(), expected_result.1); assert_eq!(actual_result.imaginary_to_f64(), expected_result.1);
} }
@ -1225,8 +1227,8 @@ mod tests {
]; ];
for (a, b, expected_result) in in_out { for (a, b, expected_result) in in_out {
let actual_result = KalkValue::Number(float!(a.0), float!(a.1), String::new()) let actual_result = KalkValue::Number(float!(a.0), float!(a.1), None)
.sub_without_unit(&KalkValue::Number(float!(b.0), float!(b.1), String::new())); .sub_without_unit(&KalkValue::Number(float!(b.0), float!(b.1), None));
assert_eq!(actual_result.to_f64(), expected_result.0); assert_eq!(actual_result.to_f64(), expected_result.0);
assert_eq!(actual_result.imaginary_to_f64(), expected_result.1); assert_eq!(actual_result.imaginary_to_f64(), expected_result.1);
} }
@ -1242,8 +1244,8 @@ mod tests {
]; ];
for (a, b, expected_result) in in_out { for (a, b, expected_result) in in_out {
let actual_result = KalkValue::Number(float!(a.0), float!(a.1), String::new()) let actual_result = KalkValue::Number(float!(a.0), float!(a.1), None)
.mul_without_unit(&KalkValue::Number(float!(b.0), float!(b.1), String::new())); .mul_without_unit(&KalkValue::Number(float!(b.0), float!(b.1), None));
assert_eq!(actual_result.to_f64(), expected_result.0); assert_eq!(actual_result.to_f64(), expected_result.0);
assert_eq!(actual_result.imaginary_to_f64(), expected_result.1); assert_eq!(actual_result.imaginary_to_f64(), expected_result.1);
} }
@ -1258,8 +1260,8 @@ mod tests {
]; ];
for (a, b, expected_result) in in_out { for (a, b, expected_result) in in_out {
let actual_result = KalkValue::Number(float!(a.0), float!(a.1), String::new()) let actual_result = KalkValue::Number(float!(a.0), float!(a.1), None)
.div_without_unit(&KalkValue::Number(float!(b.0), float!(b.1), String::new())); .div_without_unit(&KalkValue::Number(float!(b.0), float!(b.1), None));
assert_eq!(actual_result.to_f64(), expected_result.0); assert_eq!(actual_result.to_f64(), expected_result.0);
assert_eq!(actual_result.imaginary_to_f64(), expected_result.1); assert_eq!(actual_result.imaginary_to_f64(), expected_result.1);
} }
@ -1286,8 +1288,8 @@ mod tests {
]; ];
for (a, b, expected_result) in in_out { for (a, b, expected_result) in in_out {
let actual_result = KalkValue::Number(float!(a.0), float!(a.1), String::new()) let actual_result = KalkValue::Number(float!(a.0), float!(a.1), None)
.pow_without_unit(&KalkValue::Number(float!(b.0), float!(b.1), String::new())); .pow_without_unit(&KalkValue::Number(float!(b.0), float!(b.1), None));
assert!(cmp(actual_result.to_f64(), expected_result.0)); assert!(cmp(actual_result.to_f64(), expected_result.0));
assert!(cmp(actual_result.imaginary_to_f64(), expected_result.1)); assert!(cmp(actual_result.imaginary_to_f64(), expected_result.1));
} }
@ -1320,8 +1322,8 @@ mod tests {
(3.00000000004, 0.0, "3"), (3.00000000004, 0.0, "3"),
]; ];
for (real, imaginary, output) in in_out { for (real, imaginary, output) in in_out {
let result = KalkValue::Number(float!(real), float!(imaginary), String::new()) let result =
.to_string_pretty(); KalkValue::Number(float!(real), float!(imaginary), None).to_string_pretty();
assert_eq!(output, result); assert_eq!(output, result);
} }
} }

View File

@ -240,7 +240,7 @@ fn equivalent_root(value: f64) -> Option<String> {
return None; return None;
} }
let squared = KalkValue::Number(float!(value * value), float!(0), String::new()) let squared = KalkValue::Number(float!(value * value), float!(0), None)
.round_if_needed() .round_if_needed()
.values() .values()
.0; .0;
@ -282,10 +282,10 @@ pub(super) fn round(
let new_value = integer * sign; let new_value = integer * sign;
let new_num = match complex_number_type { let new_num = match complex_number_type {
ComplexNumberType::Real => { ComplexNumberType::Real => {
KalkValue::Number(new_value, imaginary.clone(), input.get_unit()) KalkValue::Number(new_value, imaginary.clone(), input.get_unit().cloned())
} }
ComplexNumberType::Imaginary => { ComplexNumberType::Imaginary => {
KalkValue::Number(real.clone(), new_value, input.get_unit()) KalkValue::Number(real.clone(), new_value, input.get_unit().cloned())
} }
}; };
@ -296,10 +296,10 @@ pub(super) fn round(
let new_value = value.clone().abs().ceil() * sign; let new_value = value.clone().abs().ceil() * sign;
let new_num = match complex_number_type { let new_num = match complex_number_type {
ComplexNumberType::Real => { ComplexNumberType::Real => {
KalkValue::Number(new_value, imaginary.clone(), input.get_unit()) KalkValue::Number(new_value, imaginary.clone(), input.get_unit().cloned())
} }
ComplexNumberType::Imaginary => { ComplexNumberType::Imaginary => {
KalkValue::Number(real.clone(), new_value, input.get_unit()) KalkValue::Number(real.clone(), new_value, input.get_unit().cloned())
} }
}; };

View File

@ -232,7 +232,12 @@ pub fn call_vector_func(name: &str, x: KalkValue) -> Option<KalkValue> {
fn to_angle_unit(context: &mut interpreter::Context, x: KalkValue, angle_unit: &str) -> KalkValue { fn to_angle_unit(context: &mut interpreter::Context, x: KalkValue, angle_unit: &str) -> KalkValue {
match angle_unit { match angle_unit {
"rad" => x, "rad" => x,
_ => interpreter::convert_unit(context, &Expr::Literal(x.to_f64()), "rad", angle_unit) _ => interpreter::convert_unit(
context,
&Expr::Literal(x.to_f64()),
Some(&String::from("rad")),
Some(&angle_unit.to_string()),
)
.unwrap(), .unwrap(),
} }
} }
@ -244,7 +249,12 @@ fn from_angle_unit(
) -> KalkValue { ) -> KalkValue {
match angle_unit { match angle_unit {
"rad" => x, "rad" => x,
_ => interpreter::convert_unit(context, &Expr::Literal(x.to_f64()), angle_unit, "rad") _ => interpreter::convert_unit(
context,
&Expr::Literal(x.to_f64()),
Some(&angle_unit.to_string()),
Some(&String::from("rad")),
)
.unwrap(), .unwrap(),
} }
} }
@ -478,8 +488,7 @@ pub mod funcs {
sum_imaginary += imaginary; sum_imaginary += imaginary;
} }
KalkValue::Number(sum_real, sum_imaginary, String::new()) KalkValue::Number(sum_real, sum_imaginary, None).div_without_unit(&KalkValue::from(count))
.div_without_unit(&KalkValue::from(count))
} }
pub fn cbrt(x: KalkValue) -> KalkValue { pub fn cbrt(x: KalkValue) -> KalkValue {
@ -1011,11 +1020,7 @@ mod tests {
]; ];
for (i, (func, input, expected_output)) in in_out.iter().enumerate() { for (i, (func, input, expected_output)) in in_out.iter().enumerate() {
let actual_output = func(KalkValue::Number( let actual_output = func(KalkValue::Number(float!(input.0), float!(input.1), None));
float!(input.0),
float!(input.1),
String::new(),
));
println!( println!(
"{} | expected: {}, {}", "{} | expected: {}, {}",
@ -1051,8 +1056,8 @@ mod tests {
for (i, (func, input, expected_output)) in in_out.iter().enumerate() { for (i, (func, input, expected_output)) in in_out.iter().enumerate() {
let actual_output = func( let actual_output = func(
KalkValue::Number(float!(input.0 .0), float!(input.0 .1), String::new()), KalkValue::Number(float!(input.0 .0), float!(input.0 .1), None),
KalkValue::Number(float!(input.1 .0), float!(input.1 .1), String::new()), KalkValue::Number(float!(input.1 .0), float!(input.1 .1), None),
); );
println!( println!(
@ -1360,11 +1365,7 @@ mod tests {
]; ];
for (i, (func, input, expected_output)) in in_out.iter().enumerate() { for (i, (func, input, expected_output)) in in_out.iter().enumerate() {
let actual_output = func(KalkValue::Number( let actual_output = func(KalkValue::Number(float!(input.0), float!(input.1), None));
float!(input.0),
float!(input.1),
String::new(),
));
let expected_has_nan_or_inf = expected_output.0.is_nan() let expected_has_nan_or_inf = expected_output.0.is_nan()
|| expected_output.0.is_infinite() || expected_output.0.is_infinite()