mirror of
https://github.com/PaddiM8/kalker.git
synced 2025-01-23 05:28:34 +01:00
Added error handling to prelude functions and operations
This commit is contained in:
parent
136036f3f0
commit
5ac3a12251
@ -1,9 +1,9 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
ast::{ConditionalPiece, Expr, Identifier, RangedVar, Stmt},
|
ast::{ConditionalPiece, Expr, Identifier, RangedVar, Stmt},
|
||||||
|
errors::KalkError,
|
||||||
inverter,
|
inverter,
|
||||||
lexer::TokenKind,
|
lexer::TokenKind,
|
||||||
parser::{self, KalkError},
|
parser, prelude,
|
||||||
prelude,
|
|
||||||
symbol_table::SymbolTable,
|
symbol_table::SymbolTable,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3,11 +3,11 @@ use crate::ast;
|
|||||||
use crate::ast::Expr;
|
use crate::ast::Expr;
|
||||||
use crate::ast::Identifier;
|
use crate::ast::Identifier;
|
||||||
use crate::ast::Stmt;
|
use crate::ast::Stmt;
|
||||||
|
use crate::errors::KalkError;
|
||||||
use crate::float;
|
use crate::float;
|
||||||
use crate::interpreter;
|
use crate::interpreter;
|
||||||
use crate::kalk_value::KalkValue;
|
use crate::kalk_value::KalkValue;
|
||||||
use crate::lexer::TokenKind;
|
use crate::lexer::TokenKind;
|
||||||
use crate::parser::KalkError;
|
|
||||||
|
|
||||||
pub fn derive_func(
|
pub fn derive_func(
|
||||||
context: &mut interpreter::Context,
|
context: &mut interpreter::Context,
|
||||||
@ -17,8 +17,8 @@ pub fn derive_func(
|
|||||||
const H: f64 = 0.000001;
|
const H: f64 = 0.000001;
|
||||||
|
|
||||||
let unit = argument.get_unit().cloned();
|
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(
|
let f_x_h = interpreter::eval_fn_call_expr(
|
||||||
@ -35,8 +35,8 @@ pub fn derive_func(
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(f_x_h
|
Ok(f_x_h
|
||||||
.sub_without_unit(&f_x)
|
.sub_without_unit(&f_x)?
|
||||||
.div_without_unit(&(2f64 * H).into())
|
.div_without_unit(&(2f64 * H).into())?
|
||||||
.round_if_needed())
|
.round_if_needed())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,11 +98,11 @@ fn simpsons_rule(
|
|||||||
const N: i32 = 900;
|
const N: i32 = 900;
|
||||||
let a = interpreter::eval_expr(context, a_expr, None)?;
|
let a = interpreter::eval_expr(context, a_expr, None)?;
|
||||||
let b = interpreter::eval_expr(context, b_expr, None)?;
|
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
|
||||||
.clone()
|
.clone()
|
||||||
.add_without_unit(&KalkValue::from(i).mul_without_unit(&h.clone()));
|
.add_without_unit(&KalkValue::from(i).mul_without_unit(&h.clone())?)?;
|
||||||
context.symbol_table.set(Stmt::VarDecl(
|
context.symbol_table.set(Stmt::VarDecl(
|
||||||
Identifier::from_full_name(integration_variable),
|
Identifier::from_full_name(integration_variable),
|
||||||
Box::new(crate::ast::build_literal_ast(&variable_value)),
|
Box::new(crate::ast::build_literal_ast(&variable_value)),
|
||||||
@ -116,7 +116,7 @@ fn simpsons_rule(
|
|||||||
|
|
||||||
// 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, None)?)
|
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;
|
||||||
@ -133,11 +133,11 @@ fn simpsons_rule(
|
|||||||
let result = KalkValue::Number(result_real, result_imaginary, None);
|
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(
|
result.mul_without_unit(&KalkValue::Number(
|
||||||
3f64 / 8f64 * h_real,
|
3f64 / 8f64 * h_real,
|
||||||
3f64 / 8f64 * h_imaginary,
|
3f64 / 8f64 * h_imaginary,
|
||||||
h_unit,
|
h_unit,
|
||||||
)))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
83
kalk/src/errors.rs
Normal file
83
kalk/src/errors.rs
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
use crate::lexer::TokenKind;
|
||||||
|
|
||||||
|
/// Error that occured during parsing or evaluation.
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum KalkError {
|
||||||
|
CannotIndexByImaginary,
|
||||||
|
CanOnlyIndexX,
|
||||||
|
Expected(String),
|
||||||
|
ExpectedDx,
|
||||||
|
ExpectedIf,
|
||||||
|
ExpectedReal,
|
||||||
|
IncompatibleTypesForOperation(String, String, String),
|
||||||
|
IncompatibleVectorsMatrixes,
|
||||||
|
IncorrectAmountOfArguments(usize, String, usize),
|
||||||
|
IncorrectAmountOfIndexes(usize, usize),
|
||||||
|
ItemOfIndexDoesNotExist(Vec<usize>),
|
||||||
|
InconsistentColumnWidths,
|
||||||
|
InvalidComprehension(String),
|
||||||
|
InvalidNumberLiteral(String),
|
||||||
|
InvalidOperator,
|
||||||
|
InvalidUnit,
|
||||||
|
TimedOut,
|
||||||
|
VariableReferencesItself,
|
||||||
|
PiecewiseConditionsAreFalse,
|
||||||
|
EvaluationError(String),
|
||||||
|
UnexpectedToken(TokenKind, TokenKind),
|
||||||
|
UnexpectedType(String, Vec<String>),
|
||||||
|
UndefinedFn(String),
|
||||||
|
UndefinedVar(String),
|
||||||
|
UnableToInvert(String),
|
||||||
|
UnableToSolveEquation,
|
||||||
|
UnableToOverrideConstant(String),
|
||||||
|
UnableToParseExpression,
|
||||||
|
UnrecognizedBase,
|
||||||
|
Unknown,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToString for KalkError {
|
||||||
|
fn to_string(&self) -> String {
|
||||||
|
match self {
|
||||||
|
KalkError::CannotIndexByImaginary => String::from("Cannot index by imaginary numbers."),
|
||||||
|
KalkError::CanOnlyIndexX => String::from("Indexing (getting an item with a specific index) is only possible on vectors and matrices."),
|
||||||
|
KalkError::Expected(description) => format!("Expected: {}", description),
|
||||||
|
KalkError::ExpectedDx => String::from("Expected eg. dx, to specify for which variable the operation is being done to. Example with integration: ∫(0, 1, x dx) or ∫(0, 1, x, dx). You may need to put parenthesis around the expression before dx/dy/du/etc."),
|
||||||
|
KalkError::ExpectedIf => String::from("Expected 'if', with a condition after it."),
|
||||||
|
KalkError::ExpectedReal => String::from("Expected a real value but got imaginary."),
|
||||||
|
KalkError::IncompatibleTypesForOperation(operation, got1, got2) => format!("Incompatible types for operation '{}': {} and {}.", operation, got1, got2),
|
||||||
|
KalkError::IncompatibleVectorsMatrixes => String::from("Incompatible vectors/matrixes."),
|
||||||
|
KalkError::IncorrectAmountOfArguments(expected, func, got) => format!(
|
||||||
|
"Expected {} arguments for function {}, but got {}.",
|
||||||
|
expected, func, got
|
||||||
|
),
|
||||||
|
KalkError::IncorrectAmountOfIndexes(expected, got) => format!(
|
||||||
|
"Expected {} indexes but got {}.",
|
||||||
|
expected, got
|
||||||
|
),
|
||||||
|
KalkError::ItemOfIndexDoesNotExist(indices) => format!("Item of index ⟦{}⟧ does not exist.", indices.iter().map(|x| x.to_string()).collect::<Vec<String>>().join(", ")),
|
||||||
|
KalkError::InconsistentColumnWidths => String::from("Inconsistent column widths. Matrix columns must be the same size."),
|
||||||
|
KalkError::InvalidComprehension(x) => format!("Invalid comprehension: {}", x),
|
||||||
|
KalkError::InvalidNumberLiteral(x) => format!("Invalid number literal: '{}'.", x),
|
||||||
|
KalkError::InvalidOperator => String::from("Invalid operator."),
|
||||||
|
KalkError::InvalidUnit => String::from("Invalid unit."),
|
||||||
|
KalkError::TimedOut => String::from("Operation took too long."),
|
||||||
|
KalkError::VariableReferencesItself => String::from("Variable references itself."),
|
||||||
|
KalkError::PiecewiseConditionsAreFalse => String::from("All the conditions in the piecewise are false."),
|
||||||
|
KalkError::EvaluationError(msg) => format!("Evaluation error: {}", msg),
|
||||||
|
KalkError::UnexpectedToken(got, expected) => {
|
||||||
|
format!("Unexpected token: '{:?}', expected '{:?}'.", got, expected)
|
||||||
|
}
|
||||||
|
KalkError::UnexpectedType(got, expected) => {
|
||||||
|
format!("Unexpected type. Got {:?} but expected: {:?}.", got, expected.join(", "))
|
||||||
|
}
|
||||||
|
KalkError::UnableToInvert(msg) => format!("Unable to invert: {}", msg),
|
||||||
|
KalkError::UndefinedFn(name) => format!("Undefined function: '{}'.", name),
|
||||||
|
KalkError::UndefinedVar(name) => format!("Undefined variable: '{}'.", name),
|
||||||
|
KalkError::UnableToParseExpression => String::from("Unable to parse expression."),
|
||||||
|
KalkError::UnableToSolveEquation => String::from("Unable to solve equation."),
|
||||||
|
KalkError::UnableToOverrideConstant(name) => format!("Unable to override constant: '{}'.", name),
|
||||||
|
KalkError::UnrecognizedBase => String::from("Unrecognized base."),
|
||||||
|
KalkError::Unknown => String::from("Unknown error."),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +1,9 @@
|
|||||||
use crate::ast::{Expr, Stmt};
|
use crate::ast::{Expr, Stmt};
|
||||||
use crate::ast::{Identifier, RangedVar};
|
use crate::ast::{Identifier, RangedVar};
|
||||||
use crate::calculation_result::CalculationResult;
|
use crate::calculation_result::CalculationResult;
|
||||||
|
use crate::errors::KalkError;
|
||||||
use crate::kalk_value::KalkValue;
|
use crate::kalk_value::KalkValue;
|
||||||
use crate::lexer::TokenKind;
|
use crate::lexer::TokenKind;
|
||||||
use crate::parser::KalkError;
|
|
||||||
use crate::parser::DECL_UNIT;
|
use crate::parser::DECL_UNIT;
|
||||||
use crate::symbol_table::SymbolTable;
|
use crate::symbol_table::SymbolTable;
|
||||||
use crate::{as_number_or_zero, calculus};
|
use crate::{as_number_or_zero, calculus};
|
||||||
@ -163,7 +163,7 @@ fn eval_binary_expr(
|
|||||||
let left = eval_expr(context, left_expr, None)?;
|
let left = eval_expr(context, left_expr, None)?;
|
||||||
let mut right = eval_expr(context, right_expr, None)?;
|
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 {
|
||||||
return Ok(right);
|
return Ok(right);
|
||||||
}
|
}
|
||||||
@ -184,8 +184,8 @@ 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(1f64),
|
_ => Ok(KalkValue::from(1f64)),
|
||||||
};
|
}?;
|
||||||
|
|
||||||
if unit.is_some() {
|
if unit.is_some() {
|
||||||
if let KalkValue::Number(real, imaginary, _) = result {
|
if let KalkValue::Number(real, imaginary, _) = result {
|
||||||
@ -205,9 +205,9 @@ fn eval_unary_expr(
|
|||||||
let num = eval_expr(context, expr, unit)?;
|
let num = eval_expr(context, expr, unit)?;
|
||||||
|
|
||||||
match op {
|
match op {
|
||||||
TokenKind::Minus => Ok(num.mul(context, KalkValue::from(-1f64))),
|
TokenKind::Minus => num.mul(context, KalkValue::from(-1f64)),
|
||||||
TokenKind::Percent => Ok(num.mul(context, KalkValue::from(0.01f64))),
|
TokenKind::Percent => num.mul(context, KalkValue::from(0.01f64)),
|
||||||
TokenKind::Exclamation => Ok(prelude::special_funcs::factorial(num)),
|
TokenKind::Exclamation => prelude::special_funcs::factorial(num),
|
||||||
_ => Err(KalkError::InvalidOperator),
|
_ => Err(KalkError::InvalidOperator),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -397,10 +397,8 @@ pub(crate) fn eval_fn_call_expr(
|
|||||||
values.push(value);
|
values.push(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(
|
return prelude::call_vector_func(&identifier.full_name, KalkValue::Vector(values))
|
||||||
prelude::call_vector_func(&identifier.full_name, KalkValue::Vector(values))
|
.unwrap_or_else(|| Ok(KalkValue::nan()));
|
||||||
.unwrap_or_else(KalkValue::nan),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prelude
|
// Prelude
|
||||||
@ -433,9 +431,7 @@ pub(crate) fn eval_fn_call_expr(
|
|||||||
};
|
};
|
||||||
|
|
||||||
if let Some((result, _)) = prelude_func {
|
if let Some((result, _)) = prelude_func {
|
||||||
// If the result is nan and only one argument was given,
|
if result.is_err() && expressions.len() == 1 {
|
||||||
// it may be due to incompatible types.
|
|
||||||
if result.is_nan() && expressions.len() == 1 {
|
|
||||||
let x = eval_expr(context, &expressions[0], None)?;
|
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
|
||||||
@ -450,7 +446,7 @@ pub(crate) fn eval_fn_call_expr(
|
|||||||
value,
|
value,
|
||||||
&context.angle_unit.clone(),
|
&context.angle_unit.clone(),
|
||||||
) {
|
) {
|
||||||
new_values.push(result.0);
|
new_values.push(result.0?);
|
||||||
} else {
|
} else {
|
||||||
success = false;
|
success = false;
|
||||||
break;
|
break;
|
||||||
@ -472,7 +468,7 @@ pub(crate) fn eval_fn_call_expr(
|
|||||||
value,
|
value,
|
||||||
&context.angle_unit.clone(),
|
&context.angle_unit.clone(),
|
||||||
) {
|
) {
|
||||||
new_row.push(result.0);
|
new_row.push(result.0?);
|
||||||
} else {
|
} else {
|
||||||
success = false;
|
success = false;
|
||||||
break;
|
break;
|
||||||
@ -488,8 +484,9 @@ pub(crate) fn eval_fn_call_expr(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(result);
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Symbol Table
|
// Symbol Table
|
||||||
let stmt_definition = context.symbol_table.get_fn(&identifier.full_name).cloned();
|
let stmt_definition = context.symbol_table.get_fn(&identifier.full_name).cloned();
|
||||||
|
|
||||||
@ -593,9 +590,9 @@ fn eval_loop(
|
|||||||
|
|
||||||
let eval = eval_expr(context, expression, None)?;
|
let eval = eval_expr(context, expression, None)?;
|
||||||
if sum_else_prod {
|
if sum_else_prod {
|
||||||
sum = sum.add(context, eval);
|
sum = sum.add(context, eval)?;
|
||||||
} else {
|
} else {
|
||||||
sum = sum.mul(context, eval);
|
sum = sum.mul(context, eval)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -829,7 +826,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "rug"))]
|
#[cfg(not(feature = "rug"))]
|
||||||
fn context<'a>(symbol_table: &'a mut SymbolTable, angle_unit: Option<&String>) -> Context<'a> {
|
fn context<'a>(symbol_table: &'a mut SymbolTable, angle_unit: &str) -> Context<'a> {
|
||||||
Context::new(symbol_table, angle_unit, None)
|
Context::new(symbol_table, angle_unit, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::ast::Identifier;
|
use crate::ast::Identifier;
|
||||||
use crate::ast::{Expr, Stmt};
|
use crate::ast::{Expr, Stmt};
|
||||||
|
use crate::errors::KalkError;
|
||||||
use crate::lexer::TokenKind;
|
use crate::lexer::TokenKind;
|
||||||
use crate::parser::KalkError;
|
|
||||||
use crate::prelude;
|
use crate::prelude;
|
||||||
use crate::symbol_table::SymbolTable;
|
use crate::symbol_table::SymbolTable;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
|
@ -14,6 +14,7 @@ pub use regular::*;
|
|||||||
mod rounding;
|
mod rounding;
|
||||||
|
|
||||||
use crate::ast::Expr;
|
use crate::ast::Expr;
|
||||||
|
use crate::errors::KalkError;
|
||||||
use crate::radix;
|
use crate::radix;
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
@ -66,7 +67,10 @@ macro_rules! as_number_or_return {
|
|||||||
unit,
|
unit,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
return KalkValue::nan();
|
return Err(KalkError::UnexpectedType(
|
||||||
|
$x.get_type_name(),
|
||||||
|
vec![String::from("number")],
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
@ -76,12 +80,15 @@ macro_rules! as_vector_or_return {
|
|||||||
($x:expr) => {{
|
($x:expr) => {{
|
||||||
if let KalkValue::Vector(values) = $x {
|
if let KalkValue::Vector(values) = $x {
|
||||||
if values.len() == 0 {
|
if values.len() == 0 {
|
||||||
return KalkValue::nan();
|
return Err(KalkError::Expected(String::from("a non-empty vector")));
|
||||||
}
|
}
|
||||||
|
|
||||||
values
|
values
|
||||||
} else {
|
} else {
|
||||||
return KalkValue::nan();
|
return Err(KalkError::UnexpectedType(
|
||||||
|
$x.get_type_name(),
|
||||||
|
vec![String::from("vector")],
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
@ -230,6 +237,15 @@ impl KalkValue {
|
|||||||
KalkValue::Number(float!(f64::NAN), float!(0f64), None)
|
KalkValue::Number(float!(f64::NAN), float!(0f64), None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_type_name(&self) -> String {
|
||||||
|
match self {
|
||||||
|
KalkValue::Number(_, _, _) => String::from("number"),
|
||||||
|
KalkValue::Boolean(_) => String::from("boolean"),
|
||||||
|
KalkValue::Vector(_) => String::from("vector"),
|
||||||
|
KalkValue::Matrix(_) => String::from("matrix"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn to_string_big(&self) -> String {
|
pub fn to_string_big(&self) -> String {
|
||||||
if let KalkValue::Number(real, imaginary, _) = self {
|
if let KalkValue::Number(real, imaginary, _) = self {
|
||||||
if !self.has_imaginary() {
|
if !self.has_imaginary() {
|
||||||
@ -532,7 +548,7 @@ impl KalkValue {
|
|||||||
self,
|
self,
|
||||||
context: &mut crate::interpreter::Context,
|
context: &mut crate::interpreter::Context,
|
||||||
rhs: KalkValue,
|
rhs: KalkValue,
|
||||||
) -> KalkValue {
|
) -> Result<KalkValue, KalkError> {
|
||||||
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
||||||
self.add_without_unit(&right)
|
self.add_without_unit(&right)
|
||||||
}
|
}
|
||||||
@ -541,7 +557,7 @@ impl KalkValue {
|
|||||||
self,
|
self,
|
||||||
context: &mut crate::interpreter::Context,
|
context: &mut crate::interpreter::Context,
|
||||||
rhs: KalkValue,
|
rhs: KalkValue,
|
||||||
) -> KalkValue {
|
) -> Result<KalkValue, KalkError> {
|
||||||
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
||||||
self.sub_without_unit(&right)
|
self.sub_without_unit(&right)
|
||||||
}
|
}
|
||||||
@ -550,7 +566,7 @@ impl KalkValue {
|
|||||||
self,
|
self,
|
||||||
context: &mut crate::interpreter::Context,
|
context: &mut crate::interpreter::Context,
|
||||||
rhs: KalkValue,
|
rhs: KalkValue,
|
||||||
) -> KalkValue {
|
) -> Result<KalkValue, KalkError> {
|
||||||
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
||||||
self.mul_without_unit(&right)
|
self.mul_without_unit(&right)
|
||||||
}
|
}
|
||||||
@ -559,7 +575,7 @@ impl KalkValue {
|
|||||||
self,
|
self,
|
||||||
context: &mut crate::interpreter::Context,
|
context: &mut crate::interpreter::Context,
|
||||||
rhs: KalkValue,
|
rhs: KalkValue,
|
||||||
) -> KalkValue {
|
) -> Result<KalkValue, KalkError> {
|
||||||
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
||||||
self.div_without_unit(&right)
|
self.div_without_unit(&right)
|
||||||
}
|
}
|
||||||
@ -568,7 +584,7 @@ impl KalkValue {
|
|||||||
self,
|
self,
|
||||||
context: &mut crate::interpreter::Context,
|
context: &mut crate::interpreter::Context,
|
||||||
rhs: KalkValue,
|
rhs: KalkValue,
|
||||||
) -> KalkValue {
|
) -> Result<KalkValue, KalkError> {
|
||||||
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
||||||
self.pow_without_unit(&right)
|
self.pow_without_unit(&right)
|
||||||
}
|
}
|
||||||
@ -577,8 +593,8 @@ impl KalkValue {
|
|||||||
self,
|
self,
|
||||||
context: &mut crate::interpreter::Context,
|
context: &mut crate::interpreter::Context,
|
||||||
rhs: KalkValue,
|
rhs: KalkValue,
|
||||||
) -> KalkValue {
|
) -> Result<KalkValue, KalkError> {
|
||||||
if let KalkValue::Number(real, _, _) = &self {
|
Ok(if let KalkValue::Number(real, _, _) = &self {
|
||||||
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
||||||
if let KalkValue::Number(right_real, _, right_unit) = right {
|
if let KalkValue::Number(right_real, _, right_unit) = right {
|
||||||
KalkValue::Number(real % right_real, float!(0f64), right_unit)
|
KalkValue::Number(real % right_real, float!(0f64), right_unit)
|
||||||
@ -587,10 +603,14 @@ impl KalkValue {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self
|
self
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn eq(self, context: &mut crate::interpreter::Context, rhs: KalkValue) -> KalkValue {
|
pub(crate) fn eq(
|
||||||
|
self,
|
||||||
|
context: &mut crate::interpreter::Context,
|
||||||
|
rhs: KalkValue,
|
||||||
|
) -> Result<KalkValue, KalkError> {
|
||||||
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
||||||
self.eq_without_unit(&right)
|
self.eq_without_unit(&right)
|
||||||
}
|
}
|
||||||
@ -599,7 +619,7 @@ impl KalkValue {
|
|||||||
self,
|
self,
|
||||||
context: &mut crate::interpreter::Context,
|
context: &mut crate::interpreter::Context,
|
||||||
rhs: KalkValue,
|
rhs: KalkValue,
|
||||||
) -> KalkValue {
|
) -> Result<KalkValue, KalkError> {
|
||||||
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
||||||
self.not_eq_without_unit(&right)
|
self.not_eq_without_unit(&right)
|
||||||
}
|
}
|
||||||
@ -608,7 +628,7 @@ impl KalkValue {
|
|||||||
self,
|
self,
|
||||||
context: &mut crate::interpreter::Context,
|
context: &mut crate::interpreter::Context,
|
||||||
rhs: KalkValue,
|
rhs: KalkValue,
|
||||||
) -> KalkValue {
|
) -> Result<KalkValue, KalkError> {
|
||||||
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
||||||
self.greater_than_without_unit(&right)
|
self.greater_than_without_unit(&right)
|
||||||
}
|
}
|
||||||
@ -617,7 +637,7 @@ impl KalkValue {
|
|||||||
self,
|
self,
|
||||||
context: &mut crate::interpreter::Context,
|
context: &mut crate::interpreter::Context,
|
||||||
rhs: KalkValue,
|
rhs: KalkValue,
|
||||||
) -> KalkValue {
|
) -> Result<KalkValue, KalkError> {
|
||||||
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
||||||
self.less_than_without_unit(&right)
|
self.less_than_without_unit(&right)
|
||||||
}
|
}
|
||||||
@ -626,13 +646,13 @@ impl KalkValue {
|
|||||||
self,
|
self,
|
||||||
context: &mut crate::interpreter::Context,
|
context: &mut crate::interpreter::Context,
|
||||||
rhs: KalkValue,
|
rhs: KalkValue,
|
||||||
) -> KalkValue {
|
) -> Result<KalkValue, KalkError> {
|
||||||
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
||||||
if let (KalkValue::Boolean(greater), KalkValue::Boolean(equal)) = (
|
if let (KalkValue::Boolean(greater), KalkValue::Boolean(equal)) = (
|
||||||
self.greater_than_without_unit(&right),
|
self.greater_than_without_unit(&right)?,
|
||||||
self.eq_without_unit(&right),
|
self.eq_without_unit(&right)?,
|
||||||
) {
|
) {
|
||||||
KalkValue::Boolean(greater || equal)
|
Ok(KalkValue::Boolean(greater || equal))
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
@ -642,69 +662,93 @@ impl KalkValue {
|
|||||||
self,
|
self,
|
||||||
context: &mut crate::interpreter::Context,
|
context: &mut crate::interpreter::Context,
|
||||||
rhs: KalkValue,
|
rhs: KalkValue,
|
||||||
) -> KalkValue {
|
) -> Result<KalkValue, KalkError> {
|
||||||
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
||||||
if let (KalkValue::Boolean(less), KalkValue::Boolean(equal)) = (
|
if let (KalkValue::Boolean(less), KalkValue::Boolean(equal)) = (
|
||||||
self.less_than_without_unit(&right),
|
self.less_than_without_unit(&right)?,
|
||||||
self.eq_without_unit(&right),
|
self.eq_without_unit(&right)?,
|
||||||
) {
|
) {
|
||||||
KalkValue::Boolean(less || equal)
|
Ok(KalkValue::Boolean(less || equal))
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn and(self, rhs: &KalkValue) -> KalkValue {
|
pub(crate) fn and(self, rhs: &KalkValue) -> Result<KalkValue, KalkError> {
|
||||||
match (self, rhs) {
|
match (self, rhs) {
|
||||||
(KalkValue::Boolean(boolean), KalkValue::Boolean(boolean_rhs)) => {
|
(KalkValue::Boolean(boolean), KalkValue::Boolean(boolean_rhs)) => {
|
||||||
KalkValue::Boolean(boolean && *boolean_rhs)
|
Ok(KalkValue::Boolean(boolean && *boolean_rhs))
|
||||||
}
|
}
|
||||||
_ => KalkValue::nan(),
|
(lhs, rhs) => Err(KalkError::IncompatibleTypesForOperation(
|
||||||
|
String::from("and"),
|
||||||
|
lhs.get_type_name(),
|
||||||
|
rhs.get_type_name(),
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn or(self, rhs: &KalkValue) -> KalkValue {
|
pub(crate) fn or(self, rhs: &KalkValue) -> Result<KalkValue, KalkError> {
|
||||||
match (self, rhs) {
|
match (self, rhs) {
|
||||||
(KalkValue::Boolean(boolean), KalkValue::Boolean(boolean_rhs)) => {
|
(KalkValue::Boolean(boolean), KalkValue::Boolean(boolean_rhs)) => {
|
||||||
KalkValue::Boolean(boolean || *boolean_rhs)
|
Ok(KalkValue::Boolean(boolean || *boolean_rhs))
|
||||||
}
|
}
|
||||||
_ => KalkValue::nan(),
|
(lhs, rhs) => Err(KalkError::IncompatibleTypesForOperation(
|
||||||
|
String::from("or"),
|
||||||
|
lhs.get_type_name(),
|
||||||
|
rhs.get_type_name(),
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn add_without_unit(self, rhs: &KalkValue) -> KalkValue {
|
pub(crate) fn add_without_unit(self, rhs: &KalkValue) -> Result<KalkValue, KalkError> {
|
||||||
match (self.clone(), rhs) {
|
match (self.clone(), rhs) {
|
||||||
(
|
(
|
||||||
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.clone()),
|
) => Ok(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)
|
||||||
}
|
}
|
||||||
(KalkValue::Vector(_), _) | (_, KalkValue::Vector(_)) => {
|
(KalkValue::Vector(_), _) | (_, KalkValue::Vector(_)) => {
|
||||||
calculate_vector(self, rhs, &KalkValue::add_without_unit)
|
calculate_vector(self, rhs, &KalkValue::add_without_unit)
|
||||||
}
|
}
|
||||||
_ => KalkValue::nan(),
|
_ => Err(KalkError::IncompatibleTypesForOperation(
|
||||||
|
String::from("addition"),
|
||||||
|
self.get_type_name(),
|
||||||
|
rhs.get_type_name(),
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn sub_without_unit(self, rhs: &KalkValue) -> KalkValue {
|
pub(crate) fn sub_without_unit(self, rhs: &KalkValue) -> Result<KalkValue, KalkError> {
|
||||||
match (self.clone(), rhs) {
|
match (self.clone(), rhs) {
|
||||||
(
|
(
|
||||||
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.clone()),
|
) => Ok(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)
|
||||||
}
|
}
|
||||||
(KalkValue::Vector(_), _) | (_, KalkValue::Vector(_)) => {
|
(KalkValue::Vector(_), _) | (_, KalkValue::Vector(_)) => {
|
||||||
calculate_vector(self, rhs, &KalkValue::sub_without_unit)
|
calculate_vector(self, rhs, &KalkValue::sub_without_unit)
|
||||||
}
|
}
|
||||||
_ => KalkValue::nan(),
|
_ => Err(KalkError::IncompatibleTypesForOperation(
|
||||||
|
String::from("subtraction"),
|
||||||
|
self.get_type_name(),
|
||||||
|
rhs.get_type_name(),
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn mul_without_unit(self, rhs: &KalkValue) -> KalkValue {
|
pub(crate) fn mul_without_unit(self, rhs: &KalkValue) -> Result<KalkValue, KalkError> {
|
||||||
// Make sure matrix is always first to avoid having to match
|
// Make sure matrix is always first to avoid having to match
|
||||||
// different orders in the next match expression.
|
// different orders in the next match expression.
|
||||||
let (lhs, rhs) = match (&self, rhs) {
|
let (lhs, rhs) = match (&self, rhs) {
|
||||||
@ -717,42 +761,38 @@ 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(
|
) => Ok(KalkValue::Number(
|
||||||
// (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.clone(),
|
unit.clone(),
|
||||||
),
|
)),
|
||||||
(KalkValue::Matrix(rows), KalkValue::Number(_, _, _)) => KalkValue::Matrix(
|
(KalkValue::Matrix(_), KalkValue::Number(_, _, _)) => {
|
||||||
rows.iter()
|
calculate_matrix(lhs.clone(), rhs, &KalkValue::mul_without_unit)
|
||||||
.map(|row| {
|
}
|
||||||
row.iter()
|
|
||||||
.map(|x| x.clone().mul_without_unit(rhs))
|
|
||||||
.collect()
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
),
|
|
||||||
(KalkValue::Matrix(rows), KalkValue::Vector(values_rhs)) => {
|
(KalkValue::Matrix(rows), KalkValue::Vector(values_rhs)) => {
|
||||||
if rows.first().unwrap().len() != values_rhs.len() {
|
if rows.first().unwrap().len() != values_rhs.len() {
|
||||||
return KalkValue::nan();
|
return Err(KalkError::IncompatibleVectorsMatrixes);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut new_values: Vec<KalkValue> = Vec::new();
|
let mut new_values: Vec<KalkValue> = Vec::new();
|
||||||
for row in rows {
|
for row in rows {
|
||||||
new_values.push(
|
let mut sum = KalkValue::from(0);
|
||||||
row.iter()
|
for (x, y) in row.iter().zip(values_rhs) {
|
||||||
.zip(values_rhs)
|
sum = sum
|
||||||
.map(|(x, y)| x.clone().mul_without_unit(y))
|
.clone()
|
||||||
.sum(),
|
.add_without_unit(&x.clone().mul_without_unit(y)?)?;
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
KalkValue::Vector(new_values)
|
new_values.push(sum);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(KalkValue::Vector(new_values))
|
||||||
}
|
}
|
||||||
(KalkValue::Matrix(rows), KalkValue::Matrix(rows_rhs)) => {
|
(KalkValue::Matrix(rows), KalkValue::Matrix(rows_rhs)) => {
|
||||||
let lhs_columns = rows.first().unwrap();
|
let lhs_columns = rows.first().unwrap();
|
||||||
if lhs_columns.len() != rows_rhs.len() {
|
if lhs_columns.len() != rows_rhs.len() {
|
||||||
return KalkValue::nan();
|
return Err(KalkError::IncompatibleVectorsMatrixes);
|
||||||
}
|
}
|
||||||
|
|
||||||
let rhs_columns = rows_rhs.first().unwrap();
|
let rhs_columns = rows_rhs.first().unwrap();
|
||||||
@ -767,55 +807,62 @@ impl KalkValue {
|
|||||||
// For every value in the current lhs row
|
// For every value in the current lhs row
|
||||||
for (k, value) in rows[i].iter().enumerate() {
|
for (k, value) in rows[i].iter().enumerate() {
|
||||||
let value_rhs = &rows_rhs[k][j];
|
let value_rhs = &rows_rhs[k][j];
|
||||||
sum = sum.add_without_unit(&value.clone().mul_without_unit(value_rhs));
|
sum =
|
||||||
|
sum.add_without_unit(&value.clone().mul_without_unit(value_rhs)?)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
result[i][j] = sum;
|
result[i][j] = sum;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
KalkValue::Matrix(result)
|
Ok(KalkValue::Matrix(result))
|
||||||
|
}
|
||||||
|
(KalkValue::Vector(values), KalkValue::Number(_, _, _)) => {
|
||||||
|
let mut multiplied_values = Vec::new();
|
||||||
|
for value in values {
|
||||||
|
multiplied_values.push(value.clone().mul_without_unit(rhs)?);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(KalkValue::Vector(multiplied_values))
|
||||||
}
|
}
|
||||||
(KalkValue::Vector(values), KalkValue::Number(_, _, _)) => KalkValue::Vector(
|
|
||||||
values
|
|
||||||
.iter()
|
|
||||||
.map(|x| x.clone().mul_without_unit(rhs))
|
|
||||||
.collect(),
|
|
||||||
),
|
|
||||||
(KalkValue::Vector(values), KalkValue::Vector(values_rhs)) => {
|
(KalkValue::Vector(values), KalkValue::Vector(values_rhs)) => {
|
||||||
if values.len() != values_rhs.len() {
|
if values.len() != values_rhs.len() {
|
||||||
return KalkValue::nan();
|
return Err(KalkError::IncompatibleVectorsMatrixes);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut sum = KalkValue::from(0f64);
|
let mut sum = KalkValue::from(0f64);
|
||||||
for (value, value_rhs) in values.iter().zip(values_rhs) {
|
for (value, value_rhs) in values.iter().zip(values_rhs) {
|
||||||
sum = sum.add_without_unit(&value.clone().mul_without_unit(value_rhs));
|
sum = sum.add_without_unit(&value.clone().mul_without_unit(value_rhs)?)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
sum
|
Ok(sum)
|
||||||
}
|
}
|
||||||
_ => KalkValue::nan(),
|
_ => Err(KalkError::IncompatibleTypesForOperation(
|
||||||
|
String::from("multiplication"),
|
||||||
|
self.get_type_name(),
|
||||||
|
rhs.get_type_name(),
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn div_without_unit(self, rhs: &KalkValue) -> KalkValue {
|
pub(crate) fn div_without_unit(self, rhs: &KalkValue) -> Result<KalkValue, KalkError> {
|
||||||
match (self.clone(), rhs.clone()) {
|
match (self.clone(), rhs.clone()) {
|
||||||
(KalkValue::Number(real, _, _), KalkValue::Number(real_rhs, _, unit)) => {
|
(KalkValue::Number(real, _, _), KalkValue::Number(real_rhs, _, unit)) => {
|
||||||
// Avoid unecessary calculations
|
// Avoid unecessary calculations
|
||||||
if !self.has_imaginary() && !rhs.has_imaginary() {
|
if !self.has_imaginary() && !rhs.has_imaginary() {
|
||||||
KalkValue::Number(real / real_rhs, float!(0f64), unit)
|
Ok(KalkValue::Number(real / real_rhs, float!(0f64), unit))
|
||||||
} else {
|
} else {
|
||||||
// Multiply both the numerator and denominator
|
// Multiply both the numerator and denominator
|
||||||
// with the conjugate of the denominator, and divide.
|
// with the conjugate of the denominator, and divide.
|
||||||
let conjugate = rhs.get_conjugate();
|
let conjugate = rhs.get_conjugate()?;
|
||||||
let (numerator, numerator_imaginary) =
|
let (numerator, numerator_imaginary) =
|
||||||
self.mul_without_unit(&conjugate).values();
|
self.mul_without_unit(&conjugate)?.values();
|
||||||
let (denominator, _) = rhs.clone().mul_without_unit(&conjugate).values();
|
let (denominator, _) = rhs.clone().mul_without_unit(&conjugate)?.values();
|
||||||
KalkValue::Number(
|
Ok(KalkValue::Number(
|
||||||
numerator / denominator.clone(),
|
numerator / denominator.clone(),
|
||||||
numerator_imaginary / denominator,
|
numerator_imaginary / denominator,
|
||||||
unit,
|
unit,
|
||||||
)
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(KalkValue::Matrix(_), _) | (_, KalkValue::Matrix(_)) => {
|
(KalkValue::Matrix(_), _) | (_, KalkValue::Matrix(_)) => {
|
||||||
@ -824,11 +871,15 @@ impl KalkValue {
|
|||||||
(KalkValue::Vector(_), _) | (_, KalkValue::Vector(_)) => {
|
(KalkValue::Vector(_), _) | (_, KalkValue::Vector(_)) => {
|
||||||
calculate_vector(self, rhs, &KalkValue::div_without_unit)
|
calculate_vector(self, rhs, &KalkValue::div_without_unit)
|
||||||
}
|
}
|
||||||
_ => KalkValue::nan(),
|
_ => Err(KalkError::IncompatibleTypesForOperation(
|
||||||
|
String::from("division"),
|
||||||
|
self.get_type_name(),
|
||||||
|
rhs.get_type_name(),
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn pow_without_unit(self, rhs: &KalkValue) -> KalkValue {
|
pub(crate) fn pow_without_unit(self, rhs: &KalkValue) -> Result<KalkValue, KalkError> {
|
||||||
match (self.clone(), rhs) {
|
match (self.clone(), rhs) {
|
||||||
(
|
(
|
||||||
KalkValue::Number(real, imaginary, _),
|
KalkValue::Number(real, imaginary, _),
|
||||||
@ -842,75 +893,92 @@ impl KalkValue {
|
|||||||
let b = imaginary;
|
let b = imaginary;
|
||||||
let c = real_rhs;
|
let c = real_rhs;
|
||||||
let d = imaginary_rhs;
|
let d = imaginary_rhs;
|
||||||
let arg = crate::prelude::funcs::arg(self).values().0;
|
let arg = crate::prelude::funcs::arg(self)?.values().0;
|
||||||
let raised = a.clone() * a + b.clone() * b;
|
let raised = a.clone() * a + b.clone() * b;
|
||||||
let exp =
|
let exp =
|
||||||
pow(raised.clone(), c.clone() / 2f64) * (-d.clone() * arg.clone()).exp();
|
pow(raised.clone(), c.clone() / 2f64) * (-d.clone() * arg.clone()).exp();
|
||||||
let polar = c * arg + d.clone() / 2f64 * raised.ln();
|
let polar = c * arg + d.clone() / 2f64 * raised.ln();
|
||||||
|
|
||||||
KalkValue::Number(
|
Ok(KalkValue::Number(
|
||||||
polar.clone().cos() * exp.clone(),
|
polar.clone().cos() * exp.clone(),
|
||||||
polar.sin() * exp,
|
polar.sin() * exp,
|
||||||
unit.clone(),
|
unit.clone(),
|
||||||
)
|
))
|
||||||
} else {
|
} else {
|
||||||
KalkValue::Number(pow(real, real_rhs.clone()), float!(0), unit.clone())
|
Ok(KalkValue::Number(
|
||||||
|
pow(real, real_rhs.clone()),
|
||||||
|
float!(0),
|
||||||
|
unit.clone(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(KalkValue::Matrix(rows), KalkValue::Number(real, imaginary, _)) => {
|
(KalkValue::Matrix(rows), KalkValue::Number(real, _, _)) => {
|
||||||
if real < &0f64
|
if real < &0f64 || real.clone().fract() > 0.000001f64 {
|
||||||
|| real.clone().fract() > 0.000001f64
|
return Err(KalkError::Expected(String::from("a positive integer")));
|
||||||
|| !(imaginary == &0f64 || imaginary == &-0f64)
|
}
|
||||||
|| rows.len() != rows.first().unwrap().len()
|
|
||||||
{
|
if rhs.has_imaginary() {
|
||||||
return KalkValue::nan();
|
return Err(KalkError::ExpectedReal);
|
||||||
|
}
|
||||||
|
|
||||||
|
if rows.len() != rows.first().unwrap().len() {
|
||||||
|
return Err(KalkError::Expected(String::from("a square matrix")));
|
||||||
}
|
}
|
||||||
|
|
||||||
if real == &0f64 {
|
if real == &0f64 {
|
||||||
return KalkValue::from(1f64);
|
return Ok(KalkValue::from(1f64));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut result = KalkValue::from(1f64);
|
let mut result = KalkValue::from(1f64);
|
||||||
for _ in 0..primitive!(real) as i32 {
|
for _ in 0..primitive!(real) as i32 {
|
||||||
result = result.mul_without_unit(&self);
|
result = result.mul_without_unit(&self)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
result
|
Ok(result)
|
||||||
|
}
|
||||||
|
(KalkValue::Number(_, _, _), KalkValue::Matrix(rows)) => {
|
||||||
|
let mut new_rows = Vec::new();
|
||||||
|
for row in rows {
|
||||||
|
new_rows.push(Vec::new());
|
||||||
|
for item in row {
|
||||||
|
new_rows
|
||||||
|
.last_mut()
|
||||||
|
.unwrap()
|
||||||
|
.push(self.clone().pow_without_unit(item)?);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(KalkValue::Matrix(new_rows))
|
||||||
}
|
}
|
||||||
(KalkValue::Number(_, _, _), KalkValue::Matrix(rows)) => KalkValue::Matrix(
|
|
||||||
rows.iter()
|
|
||||||
.map(|row| {
|
|
||||||
row.iter()
|
|
||||||
.map(|x| self.clone().pow_without_unit(x))
|
|
||||||
.collect()
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
),
|
|
||||||
(KalkValue::Vector(_), _) | (_, KalkValue::Vector(_)) => {
|
(KalkValue::Vector(_), _) | (_, KalkValue::Vector(_)) => {
|
||||||
calculate_vector(self, rhs, &KalkValue::pow_without_unit)
|
calculate_vector(self, rhs, &KalkValue::pow_without_unit)
|
||||||
}
|
}
|
||||||
_ => KalkValue::nan(),
|
_ => Err(KalkError::IncompatibleTypesForOperation(
|
||||||
|
String::from("pow"),
|
||||||
|
self.get_type_name(),
|
||||||
|
rhs.get_type_name(),
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn eq_without_unit(&self, rhs: &KalkValue) -> KalkValue {
|
pub(crate) fn eq_without_unit(&self, rhs: &KalkValue) -> Result<KalkValue, KalkError> {
|
||||||
match (self, rhs) {
|
match (self, rhs) {
|
||||||
(
|
(
|
||||||
KalkValue::Number(real, imaginary, _),
|
KalkValue::Number(real, imaginary, _),
|
||||||
KalkValue::Number(real_rhs, imaginary_rhs, _),
|
KalkValue::Number(real_rhs, imaginary_rhs, _),
|
||||||
) => KalkValue::Boolean(
|
) => Ok(KalkValue::Boolean(
|
||||||
(real.clone() - real_rhs.clone()).abs() < ACCEPTABLE_COMPARISON_MARGIN
|
(real.clone() - real_rhs.clone()).abs() < ACCEPTABLE_COMPARISON_MARGIN
|
||||||
&& (imaginary.clone() - imaginary_rhs.clone()).abs()
|
&& (imaginary.clone() - imaginary_rhs.clone()).abs()
|
||||||
< ACCEPTABLE_COMPARISON_MARGIN,
|
< ACCEPTABLE_COMPARISON_MARGIN,
|
||||||
),
|
)),
|
||||||
(KalkValue::Boolean(boolean), KalkValue::Boolean(boolean_rhs)) => {
|
(KalkValue::Boolean(boolean), KalkValue::Boolean(boolean_rhs)) => {
|
||||||
KalkValue::Boolean(boolean == boolean_rhs)
|
Ok(KalkValue::Boolean(boolean == boolean_rhs))
|
||||||
}
|
}
|
||||||
(KalkValue::Matrix(rows), KalkValue::Matrix(rows_rhs)) => {
|
(KalkValue::Matrix(rows), KalkValue::Matrix(rows_rhs)) => {
|
||||||
let mut matrices_are_equal = true;
|
let mut matrices_are_equal = true;
|
||||||
for (row, row_rhs) in rows.iter().zip(rows_rhs) {
|
for (row, row_rhs) in rows.iter().zip(rows_rhs) {
|
||||||
for (value, value_rhs) in row.iter().zip(row_rhs) {
|
for (value, value_rhs) in row.iter().zip(row_rhs) {
|
||||||
if let KalkValue::Boolean(are_equal) = value.eq_without_unit(value_rhs) {
|
if let KalkValue::Boolean(are_equal) = value.eq_without_unit(value_rhs)? {
|
||||||
if !are_equal {
|
if !are_equal {
|
||||||
matrices_are_equal = false;
|
matrices_are_equal = false;
|
||||||
}
|
}
|
||||||
@ -918,82 +986,106 @@ impl KalkValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
KalkValue::Boolean(matrices_are_equal)
|
Ok(KalkValue::Boolean(matrices_are_equal))
|
||||||
}
|
}
|
||||||
|
|
||||||
(KalkValue::Vector(values), KalkValue::Vector(values_rhs)) => {
|
(KalkValue::Vector(values), KalkValue::Vector(values_rhs)) => {
|
||||||
let mut vecs_are_equal = true;
|
let mut vecs_are_equal = true;
|
||||||
for (value, value_rhs) in values.iter().zip(values_rhs) {
|
for (value, value_rhs) in values.iter().zip(values_rhs) {
|
||||||
if let KalkValue::Boolean(are_equal) = value.eq_without_unit(value_rhs) {
|
if let KalkValue::Boolean(are_equal) = value.eq_without_unit(value_rhs)? {
|
||||||
if !are_equal {
|
if !are_equal {
|
||||||
vecs_are_equal = false;
|
vecs_are_equal = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
KalkValue::Boolean(vecs_are_equal)
|
Ok(KalkValue::Boolean(vecs_are_equal))
|
||||||
}
|
}
|
||||||
_ => KalkValue::nan(),
|
_ => Err(KalkError::IncompatibleTypesForOperation(
|
||||||
|
String::from("equal"),
|
||||||
|
self.get_type_name(),
|
||||||
|
rhs.get_type_name(),
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn not_eq_without_unit(&self, rhs: &KalkValue) -> KalkValue {
|
pub(crate) fn not_eq_without_unit(&self, rhs: &KalkValue) -> Result<KalkValue, KalkError> {
|
||||||
match (self, rhs) {
|
match (self, rhs) {
|
||||||
(
|
(
|
||||||
KalkValue::Number(real, imaginary, _),
|
KalkValue::Number(real, imaginary, _),
|
||||||
KalkValue::Number(real_rhs, imaginary_rhs, _),
|
KalkValue::Number(real_rhs, imaginary_rhs, _),
|
||||||
) => KalkValue::Boolean(
|
) => Ok(KalkValue::Boolean(
|
||||||
(real.clone() - real_rhs.clone()).abs() > ACCEPTABLE_COMPARISON_MARGIN
|
(real.clone() - real_rhs.clone()).abs() > ACCEPTABLE_COMPARISON_MARGIN
|
||||||
|| (imaginary.clone() - imaginary_rhs.clone()).abs()
|
|| (imaginary.clone() - imaginary_rhs.clone()).abs()
|
||||||
> ACCEPTABLE_COMPARISON_MARGIN,
|
> ACCEPTABLE_COMPARISON_MARGIN,
|
||||||
),
|
)),
|
||||||
(KalkValue::Boolean(boolean), KalkValue::Boolean(boolean_rhs)) => {
|
(KalkValue::Boolean(boolean), KalkValue::Boolean(boolean_rhs)) => {
|
||||||
KalkValue::Boolean(boolean != boolean_rhs)
|
Ok(KalkValue::Boolean(boolean != boolean_rhs))
|
||||||
}
|
}
|
||||||
(KalkValue::Vector(_), KalkValue::Vector(_))
|
(KalkValue::Vector(_), KalkValue::Vector(_))
|
||||||
| (KalkValue::Matrix(_), KalkValue::Matrix(_)) => {
|
| (KalkValue::Matrix(_), KalkValue::Matrix(_)) => {
|
||||||
if let KalkValue::Boolean(boolean) = self.eq_without_unit(rhs) {
|
if let KalkValue::Boolean(boolean) = self.eq_without_unit(rhs)? {
|
||||||
KalkValue::Boolean(!boolean)
|
Ok(KalkValue::Boolean(!boolean))
|
||||||
} else {
|
} else {
|
||||||
KalkValue::nan()
|
unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => KalkValue::nan(),
|
_ => Err(KalkError::IncompatibleTypesForOperation(
|
||||||
|
String::from("not equal"),
|
||||||
|
self.get_type_name(),
|
||||||
|
rhs.get_type_name(),
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn greater_than_without_unit(&self, rhs: &KalkValue) -> KalkValue {
|
pub(crate) fn greater_than_without_unit(
|
||||||
|
&self,
|
||||||
|
rhs: &KalkValue,
|
||||||
|
) -> Result<KalkValue, KalkError> {
|
||||||
if self.has_imaginary() || rhs.has_imaginary() {
|
if self.has_imaginary() || rhs.has_imaginary() {
|
||||||
return KalkValue::nan();
|
return Err(KalkError::ExpectedReal);
|
||||||
}
|
}
|
||||||
|
|
||||||
match (self, rhs) {
|
match (self, rhs) {
|
||||||
(KalkValue::Number(real, _, _), KalkValue::Number(real_rhs, _, _)) => {
|
(KalkValue::Number(real, _, _), KalkValue::Number(real_rhs, _, _)) => Ok(
|
||||||
KalkValue::Boolean(real.clone() - real_rhs.clone() > ACCEPTABLE_COMPARISON_MARGIN)
|
KalkValue::Boolean(real.clone() - real_rhs.clone() > ACCEPTABLE_COMPARISON_MARGIN),
|
||||||
}
|
),
|
||||||
_ => KalkValue::nan(),
|
_ => Err(KalkError::IncompatibleTypesForOperation(
|
||||||
|
String::from("greater than"),
|
||||||
|
self.get_type_name(),
|
||||||
|
rhs.get_type_name(),
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn less_than_without_unit(&self, rhs: &KalkValue) -> KalkValue {
|
pub(crate) fn less_than_without_unit(&self, rhs: &KalkValue) -> Result<KalkValue, KalkError> {
|
||||||
if self.has_imaginary() || rhs.has_imaginary() {
|
if self.has_imaginary() || rhs.has_imaginary() {
|
||||||
return KalkValue::nan();
|
return Err(KalkError::ExpectedReal);
|
||||||
}
|
}
|
||||||
|
|
||||||
match (self, rhs) {
|
match (self, rhs) {
|
||||||
(KalkValue::Number(real, _, _), KalkValue::Number(real_rhs, _, _)) => {
|
(KalkValue::Number(real, _, _), KalkValue::Number(real_rhs, _, _)) => Ok(
|
||||||
KalkValue::Boolean(real.clone() - real_rhs.clone() < -ACCEPTABLE_COMPARISON_MARGIN)
|
KalkValue::Boolean(real.clone() - real_rhs.clone() < -ACCEPTABLE_COMPARISON_MARGIN),
|
||||||
}
|
),
|
||||||
_ => KalkValue::nan(),
|
_ => Err(KalkError::IncompatibleTypesForOperation(
|
||||||
|
String::from("less than"),
|
||||||
|
self.get_type_name(),
|
||||||
|
rhs.get_type_name(),
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_conjugate(&self) -> KalkValue {
|
pub fn get_conjugate(&self) -> Result<KalkValue, KalkError> {
|
||||||
match self {
|
match self {
|
||||||
KalkValue::Number(real, imaginary, unit) => {
|
KalkValue::Number(real, imaginary, unit) => Ok(KalkValue::Number(
|
||||||
KalkValue::Number(real.clone(), imaginary.clone() * (-1f64), unit.clone())
|
real.clone(),
|
||||||
}
|
imaginary.clone() * (-1f64),
|
||||||
_ => KalkValue::nan(),
|
unit.clone(),
|
||||||
|
)),
|
||||||
|
_ => Err(KalkError::UnexpectedType(
|
||||||
|
self.get_type_name(),
|
||||||
|
vec![String::from("number")],
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1013,37 +1105,50 @@ pub fn format_number(input: f64) -> String {
|
|||||||
fn calculate_vector(
|
fn calculate_vector(
|
||||||
x: KalkValue,
|
x: KalkValue,
|
||||||
y: &KalkValue,
|
y: &KalkValue,
|
||||||
action: &dyn Fn(KalkValue, &KalkValue) -> KalkValue,
|
action: &dyn Fn(KalkValue, &KalkValue) -> Result<KalkValue, KalkError>,
|
||||||
) -> KalkValue {
|
) -> Result<KalkValue, KalkError> {
|
||||||
match (x, y) {
|
match (x, y) {
|
||||||
(KalkValue::Vector(values), KalkValue::Number(_, _, _)) => {
|
(KalkValue::Vector(values), KalkValue::Number(_, _, _)) => {
|
||||||
KalkValue::Vector(values.iter().map(|x| action(x.clone(), y)).collect())
|
let mut new_values = Vec::new();
|
||||||
|
for value in values {
|
||||||
|
new_values.push(action(value.clone(), y)?);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(KalkValue::Vector(new_values))
|
||||||
}
|
}
|
||||||
(KalkValue::Number(_, _, _), KalkValue::Vector(values_rhs)) => {
|
(KalkValue::Number(_, _, _), KalkValue::Vector(values_rhs)) => {
|
||||||
KalkValue::Vector(values_rhs.iter().map(|x| action(y.clone(), x)).collect())
|
let mut new_values = Vec::new();
|
||||||
|
for value in values_rhs {
|
||||||
|
new_values.push(action(y.clone(), value)?);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(KalkValue::Vector(new_values))
|
||||||
}
|
}
|
||||||
(KalkValue::Vector(values), KalkValue::Vector(values_rhs)) => {
|
(KalkValue::Vector(values), KalkValue::Vector(values_rhs)) => {
|
||||||
if values.len() == values_rhs.len() {
|
if values.len() != values_rhs.len() {
|
||||||
KalkValue::Vector(
|
return Err(KalkError::IncompatibleVectorsMatrixes);
|
||||||
values
|
|
||||||
.iter()
|
|
||||||
.zip(values_rhs)
|
|
||||||
.map(|(x, y)| action(x.clone(), y))
|
|
||||||
.collect(),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
KalkValue::nan()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut new_values = Vec::new();
|
||||||
|
for (value, value_rhs) in values.iter().zip(values_rhs) {
|
||||||
|
new_values.push(action(value.clone(), value_rhs)?);
|
||||||
}
|
}
|
||||||
_ => KalkValue::nan(),
|
|
||||||
|
Ok(KalkValue::Vector(new_values))
|
||||||
|
}
|
||||||
|
(x, y) => Err(KalkError::IncompatibleTypesForOperation(
|
||||||
|
String::from("vector operation"),
|
||||||
|
x.get_type_name(),
|
||||||
|
y.get_type_name(),
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculate_matrix(
|
fn calculate_matrix(
|
||||||
x: KalkValue,
|
x: KalkValue,
|
||||||
y: &KalkValue,
|
y: &KalkValue,
|
||||||
action: &dyn Fn(KalkValue, &KalkValue) -> KalkValue,
|
action: &dyn Fn(KalkValue, &KalkValue) -> Result<KalkValue, KalkError>,
|
||||||
) -> KalkValue {
|
) -> Result<KalkValue, KalkError> {
|
||||||
// Make sure matrix is always first to avoid having to match
|
// Make sure matrix is always first to avoid having to match
|
||||||
// different orders in the next match expression.
|
// different orders in the next match expression.
|
||||||
let (x, y) = match (&x, y) {
|
let (x, y) = match (&x, y) {
|
||||||
@ -1053,14 +1158,20 @@ fn calculate_matrix(
|
|||||||
};
|
};
|
||||||
|
|
||||||
match (x, y) {
|
match (x, y) {
|
||||||
(KalkValue::Matrix(rows), KalkValue::Number(_, _, _)) => KalkValue::Matrix(
|
(KalkValue::Matrix(rows), KalkValue::Number(_, _, _)) => {
|
||||||
rows.iter()
|
let mut new_rows = Vec::new();
|
||||||
.map(|row| row.iter().map(|x| action(x.clone(), y)).collect())
|
for row in rows {
|
||||||
.collect(),
|
new_rows.push(Vec::new());
|
||||||
),
|
for item in row {
|
||||||
|
new_rows.last_mut().unwrap().push(action(item.clone(), y)?);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(KalkValue::Matrix(new_rows))
|
||||||
|
}
|
||||||
(KalkValue::Matrix(rows), KalkValue::Vector(values_rhs)) => {
|
(KalkValue::Matrix(rows), KalkValue::Vector(values_rhs)) => {
|
||||||
if rows.len() != values_rhs.len() {
|
if rows.len() != values_rhs.len() {
|
||||||
return KalkValue::nan();
|
return Err(KalkError::IncompatibleVectorsMatrixes);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut new_rows = Vec::new();
|
let mut new_rows = Vec::new();
|
||||||
@ -1070,17 +1181,17 @@ fn calculate_matrix(
|
|||||||
new_rows
|
new_rows
|
||||||
.last_mut()
|
.last_mut()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.push(action(value.clone(), &values_rhs[i]))
|
.push(action(value.clone(), &values_rhs[i])?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
KalkValue::Matrix(new_rows)
|
Ok(KalkValue::Matrix(new_rows))
|
||||||
}
|
}
|
||||||
(KalkValue::Matrix(rows), KalkValue::Matrix(rows_rhs)) => {
|
(KalkValue::Matrix(rows), KalkValue::Matrix(rows_rhs)) => {
|
||||||
if rows.len() != rows_rhs.len()
|
if rows.len() != rows_rhs.len()
|
||||||
|| rows.first().unwrap().len() != rows_rhs.first().unwrap().len()
|
|| rows.first().unwrap().len() != rows_rhs.first().unwrap().len()
|
||||||
{
|
{
|
||||||
return KalkValue::nan();
|
return Err(KalkError::IncompatibleVectorsMatrixes);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut new_rows = Vec::new();
|
let mut new_rows = Vec::new();
|
||||||
@ -1090,13 +1201,17 @@ fn calculate_matrix(
|
|||||||
new_rows
|
new_rows
|
||||||
.last_mut()
|
.last_mut()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.push(action(value.clone(), &rows_rhs[i][j]))
|
.push(action(value.clone(), &rows_rhs[i][j])?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
KalkValue::Matrix(new_rows)
|
Ok(KalkValue::Matrix(new_rows))
|
||||||
}
|
}
|
||||||
_ => KalkValue::nan(),
|
_ => Err(KalkError::IncompatibleTypesForOperation(
|
||||||
|
String::from("matrix operation"),
|
||||||
|
x.get_type_name(),
|
||||||
|
y.get_type_name(),
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1139,7 +1254,7 @@ impl From<ScientificNotation> for String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::iter::Sum<KalkValue> for KalkValue {
|
/*impl std::iter::Sum<KalkValue> for KalkValue {
|
||||||
fn sum<I>(iter: I) -> KalkValue
|
fn sum<I>(iter: I) -> KalkValue
|
||||||
where
|
where
|
||||||
I: std::iter::Iterator<Item = KalkValue>,
|
I: std::iter::Iterator<Item = KalkValue>,
|
||||||
@ -1151,7 +1266,7 @@ impl std::iter::Sum<KalkValue> for KalkValue {
|
|||||||
|
|
||||||
sum
|
sum
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
|
|
||||||
impl From<KalkValue> for String {
|
impl From<KalkValue> for String {
|
||||||
fn from(val: KalkValue) -> Self {
|
fn from(val: KalkValue) -> Self {
|
||||||
@ -1211,7 +1326,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), None)
|
let actual_result = KalkValue::Number(float!(a.0), float!(a.1), None)
|
||||||
.add_without_unit(&KalkValue::Number(float!(b.0), float!(b.1), None));
|
.add_without_unit(&KalkValue::Number(float!(b.0), float!(b.1), None))
|
||||||
|
.unwrap();
|
||||||
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);
|
||||||
}
|
}
|
||||||
@ -1228,7 +1344,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), None)
|
let actual_result = KalkValue::Number(float!(a.0), float!(a.1), None)
|
||||||
.sub_without_unit(&KalkValue::Number(float!(b.0), float!(b.1), None));
|
.sub_without_unit(&KalkValue::Number(float!(b.0), float!(b.1), None))
|
||||||
|
.unwrap();
|
||||||
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);
|
||||||
}
|
}
|
||||||
@ -1245,7 +1362,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), None)
|
let actual_result = KalkValue::Number(float!(a.0), float!(a.1), None)
|
||||||
.mul_without_unit(&KalkValue::Number(float!(b.0), float!(b.1), None));
|
.mul_without_unit(&KalkValue::Number(float!(b.0), float!(b.1), None))
|
||||||
|
.unwrap();
|
||||||
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);
|
||||||
}
|
}
|
||||||
@ -1261,7 +1379,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), None)
|
let actual_result = KalkValue::Number(float!(a.0), float!(a.1), None)
|
||||||
.div_without_unit(&KalkValue::Number(float!(b.0), float!(b.1), None));
|
.div_without_unit(&KalkValue::Number(float!(b.0), float!(b.1), None))
|
||||||
|
.unwrap();
|
||||||
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);
|
||||||
}
|
}
|
||||||
@ -1289,7 +1408,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), None)
|
let actual_result = KalkValue::Number(float!(a.0), float!(a.1), None)
|
||||||
.pow_without_unit(&KalkValue::Number(float!(b.0), float!(b.1), None));
|
.pow_without_unit(&KalkValue::Number(float!(b.0), float!(b.1), None))
|
||||||
|
.unwrap();
|
||||||
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));
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
#![allow(clippy::unused_unit)]
|
#![allow(clippy::unused_unit)]
|
||||||
#![allow(clippy::float_cmp)]
|
#![allow(clippy::float_cmp)]
|
||||||
|
#![allow(clippy::clone_on_copy)] // the float type needs explicit cloning if the rug feature is enabled
|
||||||
mod analysis;
|
mod analysis;
|
||||||
pub mod ast;
|
pub mod ast;
|
||||||
pub mod calculation_result;
|
pub mod calculation_result;
|
||||||
mod calculus;
|
mod calculus;
|
||||||
|
mod errors;
|
||||||
mod integration_testing;
|
mod integration_testing;
|
||||||
mod interpreter;
|
mod interpreter;
|
||||||
mod inverter;
|
mod inverter;
|
||||||
|
@ -3,6 +3,7 @@ use std::cell::Cell;
|
|||||||
use crate::analysis;
|
use crate::analysis;
|
||||||
use crate::ast::Identifier;
|
use crate::ast::Identifier;
|
||||||
use crate::calculation_result::CalculationResult;
|
use crate::calculation_result::CalculationResult;
|
||||||
|
use crate::errors::KalkError;
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{Expr, Stmt},
|
ast::{Expr, Stmt},
|
||||||
interpreter,
|
interpreter,
|
||||||
@ -86,76 +87,6 @@ impl Default for Context {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Error that occured during parsing or evaluation.
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub enum KalkError {
|
|
||||||
CannotIndexByImaginary,
|
|
||||||
CanOnlyIndexX,
|
|
||||||
Expected(String),
|
|
||||||
ExpectedDx,
|
|
||||||
ExpectedIf,
|
|
||||||
IncorrectAmountOfArguments(usize, String, usize),
|
|
||||||
IncorrectAmountOfIndexes(usize, usize),
|
|
||||||
ItemOfIndexDoesNotExist(Vec<usize>),
|
|
||||||
InconsistentColumnWidths,
|
|
||||||
InvalidComprehension(String),
|
|
||||||
InvalidNumberLiteral(String),
|
|
||||||
InvalidOperator,
|
|
||||||
InvalidUnit,
|
|
||||||
TimedOut,
|
|
||||||
VariableReferencesItself,
|
|
||||||
PiecewiseConditionsAreFalse,
|
|
||||||
UnexpectedToken(TokenKind, TokenKind),
|
|
||||||
UndefinedFn(String),
|
|
||||||
UndefinedVar(String),
|
|
||||||
UnableToInvert(String),
|
|
||||||
UnableToSolveEquation,
|
|
||||||
UnableToOverrideConstant(String),
|
|
||||||
UnableToParseExpression,
|
|
||||||
UnrecognizedBase,
|
|
||||||
Unknown,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToString for KalkError {
|
|
||||||
fn to_string(&self) -> String {
|
|
||||||
match self {
|
|
||||||
KalkError::CannotIndexByImaginary => String::from("Cannot index by imaginary numbers."),
|
|
||||||
KalkError::CanOnlyIndexX => String::from("Indexing (getting an item with a specific index) is only possible on vectors and matrices."),
|
|
||||||
KalkError::Expected(description) => format!("Expected: {}", description),
|
|
||||||
KalkError::ExpectedDx => String::from("Expected eg. dx, to specify for which variable the operation is being done to. Example with integration: ∫(0, 1, x dx) or ∫(0, 1, x, dx). You may need to put parenthesis around the expression before dx/dy/du/etc."),
|
|
||||||
KalkError::ExpectedIf => String::from("Expected 'if', with a condition after it."),
|
|
||||||
KalkError::IncorrectAmountOfArguments(expected, func, got) => format!(
|
|
||||||
"Expected {} arguments for function {}, but got {}.",
|
|
||||||
expected, func, got
|
|
||||||
),
|
|
||||||
KalkError::IncorrectAmountOfIndexes(expected, got) => format!(
|
|
||||||
"Expected {} indexes but got {}.",
|
|
||||||
expected, got
|
|
||||||
),
|
|
||||||
KalkError::ItemOfIndexDoesNotExist(indexes) => format!("Item of index ⟦{}⟧ does not exist.", indexes.iter().map(|x| x.to_string()).collect::<Vec<String>>().join(", ")),
|
|
||||||
KalkError::InconsistentColumnWidths => String::from("Inconsistent column widths. Matrix columns must be the same size."),
|
|
||||||
KalkError::InvalidComprehension(x) => format!("Invalid comprehension: {}", x),
|
|
||||||
KalkError::InvalidNumberLiteral(x) => format!("Invalid number literal: '{}'.", x),
|
|
||||||
KalkError::InvalidOperator => String::from("Invalid operator."),
|
|
||||||
KalkError::InvalidUnit => String::from("Invalid unit."),
|
|
||||||
KalkError::TimedOut => String::from("Operation took too long."),
|
|
||||||
KalkError::VariableReferencesItself => String::from("Variable references itself."),
|
|
||||||
KalkError::PiecewiseConditionsAreFalse => String::from("All the conditions in the piecewise are false."),
|
|
||||||
KalkError::UnexpectedToken(got, expected) => {
|
|
||||||
format!("Unexpected token: '{:?}', expected '{:?}'.", got, expected)
|
|
||||||
}
|
|
||||||
KalkError::UnableToInvert(msg) => format!("Unable to invert: {}", msg),
|
|
||||||
KalkError::UndefinedFn(name) => format!("Undefined function: '{}'.", name),
|
|
||||||
KalkError::UndefinedVar(name) => format!("Undefined variable: '{}'.", name),
|
|
||||||
KalkError::UnableToParseExpression => String::from("Unable to parse expression."),
|
|
||||||
KalkError::UnableToSolveEquation => String::from("Unable to solve equation."),
|
|
||||||
KalkError::UnableToOverrideConstant(name) => format!("Unable to override constant: '{}'.", name),
|
|
||||||
KalkError::UnrecognizedBase => String::from("Unrecognized base."),
|
|
||||||
KalkError::Unknown => String::from("Unknown error."),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Evaluate expressions/declarations and return the answer.
|
/// Evaluate expressions/declarations and return the answer.
|
||||||
///
|
///
|
||||||
/// `None` will be returned if the last statement is a declaration.
|
/// `None` will be returned if the last statement is a declaration.
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,39 +1,40 @@
|
|||||||
pub mod special_funcs {
|
pub mod special_funcs {
|
||||||
use crate::{as_number_or_return, float, kalk_value::KalkValue};
|
use crate::{as_number_or_return, errors::KalkError, float, kalk_value::KalkValue};
|
||||||
|
|
||||||
pub fn factorial(x: KalkValue) -> KalkValue {
|
pub fn factorial(x: KalkValue) -> Result<KalkValue, KalkError> {
|
||||||
let (real, _, unit) = as_number_or_return!(x);
|
let (real, _, unit) = as_number_or_return!(x);
|
||||||
|
|
||||||
// Round it a bit, to prevent floating point errors.
|
// Round it a bit, to prevent floating point errors.
|
||||||
KalkValue::Number(
|
Ok(KalkValue::Number(
|
||||||
(super::funcs::precise_gamma(real + 1f64) * 10e6f64).round() / 10e6f64,
|
(super::funcs::precise_gamma(real + 1f64) * 10e6f64).round() / 10e6f64,
|
||||||
float!(0),
|
float!(0),
|
||||||
unit,
|
unit,
|
||||||
)
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) mod funcs {
|
pub(crate) mod funcs {
|
||||||
|
use crate::errors::KalkError;
|
||||||
use crate::kalk_value::KalkValue;
|
use crate::kalk_value::KalkValue;
|
||||||
use crate::prelude::funcs::abs;
|
use crate::prelude::funcs::abs;
|
||||||
use crate::{as_number_or_return, float};
|
use crate::{as_number_or_return, float};
|
||||||
|
|
||||||
pub fn arg(x: KalkValue) -> KalkValue {
|
pub fn arg(x: KalkValue) -> Result<KalkValue, KalkError> {
|
||||||
let (real, imaginary, unit) = as_number_or_return!(x);
|
let (real, imaginary, unit) = as_number_or_return!(x);
|
||||||
|
|
||||||
// i(ln|x| - ln(x))
|
// i(ln|x| - ln(x))
|
||||||
KalkValue::Number(imaginary.atan2(real), float!(0), unit)
|
Ok(KalkValue::Number(imaginary.atan2(real), float!(0), unit))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gamma(x: KalkValue) -> KalkValue {
|
pub fn gamma(x: KalkValue) -> Result<KalkValue, KalkError> {
|
||||||
let (real, _, unit) = as_number_or_return!(x);
|
let (real, _, unit) = as_number_or_return!(x);
|
||||||
|
|
||||||
// Round it a bit, to prevent floating point errors.
|
// Round it a bit, to prevent floating point errors.
|
||||||
KalkValue::Number(
|
Ok(KalkValue::Number(
|
||||||
(precise_gamma(real) * 10e6f64).round() / 10e6f64,
|
(precise_gamma(real) * 10e6f64).round() / 10e6f64,
|
||||||
float!(0),
|
float!(0),
|
||||||
unit,
|
unit,
|
||||||
)
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Matthias Eiholzer - https://gitlab.com/matthiaseiholzer/mathru/-/tree/master
|
// Matthias Eiholzer - https://gitlab.com/matthiaseiholzer/mathru/-/tree/master
|
||||||
@ -59,59 +60,65 @@ pub(crate) mod funcs {
|
|||||||
2f64.sqrt() * pi.sqrt() * t.powf(x - 0.5f64) * (-t).exp() * a
|
2f64.sqrt() * pi.sqrt() * t.powf(x - 0.5f64) * (-t).exp() * a
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bitcmp(x: KalkValue) -> KalkValue {
|
pub fn bitcmp(x: KalkValue) -> Result<KalkValue, KalkError> {
|
||||||
let (real, _, _) = as_number_or_return!(x);
|
let (real, _, _) = as_number_or_return!(x);
|
||||||
|
|
||||||
KalkValue::from(!(real.round() as i32))
|
Ok(KalkValue::from(!(real.round() as i32)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bitand(x: KalkValue, y: KalkValue) -> KalkValue {
|
pub fn bitand(x: KalkValue, y: KalkValue) -> Result<KalkValue, KalkError> {
|
||||||
let (real, _, _) = as_number_or_return!(x);
|
let (real, _, _) = as_number_or_return!(x);
|
||||||
let (real_rhs, _, _) = as_number_or_return!(y);
|
let (real_rhs, _, _) = as_number_or_return!(y);
|
||||||
|
|
||||||
KalkValue::from(real.round() as i32 & real_rhs.round() as i32)
|
Ok(KalkValue::from(
|
||||||
|
real.round() as i32 & real_rhs.round() as i32,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bitor(x: KalkValue, y: KalkValue) -> KalkValue {
|
pub fn bitor(x: KalkValue, y: KalkValue) -> Result<KalkValue, KalkError> {
|
||||||
let (real, _, _) = as_number_or_return!(x);
|
let (real, _, _) = as_number_or_return!(x);
|
||||||
let (real_rhs, _, _) = as_number_or_return!(y);
|
let (real_rhs, _, _) = as_number_or_return!(y);
|
||||||
|
|
||||||
KalkValue::from(real.round() as i32 | real_rhs.round() as i32)
|
Ok(KalkValue::from(
|
||||||
|
real.round() as i32 | real_rhs.round() as i32,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bitxor(x: KalkValue, y: KalkValue) -> KalkValue {
|
pub fn bitxor(x: KalkValue, y: KalkValue) -> Result<KalkValue, KalkError> {
|
||||||
let (real, _, _) = as_number_or_return!(x);
|
let (real, _, _) = as_number_or_return!(x);
|
||||||
let (real_rhs, _, _) = as_number_or_return!(y);
|
let (real_rhs, _, _) = as_number_or_return!(y);
|
||||||
|
|
||||||
KalkValue::from(real.round() as i32 ^ real_rhs.round() as i32)
|
Ok(KalkValue::from(
|
||||||
|
real.round() as i32 ^ real_rhs.round() as i32,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bitshift(x: KalkValue, y: KalkValue) -> KalkValue {
|
pub fn bitshift(x: KalkValue, y: KalkValue) -> Result<KalkValue, KalkError> {
|
||||||
let (real, _, _) = as_number_or_return!(x);
|
let (real, _, _) = as_number_or_return!(x);
|
||||||
let (real_rhs, _, _) = as_number_or_return!(y);
|
let (real_rhs, _, _) = as_number_or_return!(y);
|
||||||
let x = real.round() as i32;
|
let x = real.round() as i32;
|
||||||
let y = real_rhs.round() as i32;
|
let y = real_rhs.round() as i32;
|
||||||
if y < 0 {
|
if y < 0 {
|
||||||
KalkValue::from(x >> y.abs())
|
Ok(KalkValue::from(x >> y.abs()))
|
||||||
} else {
|
} else {
|
||||||
KalkValue::from(x << y)
|
Ok(KalkValue::from(x << y))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hypot(x: KalkValue, y: KalkValue) -> KalkValue {
|
pub fn hypot(x: KalkValue, y: KalkValue) -> Result<KalkValue, KalkError> {
|
||||||
let (real, imaginary, unit) = as_number_or_return!(x.clone());
|
let (real, _, unit) = as_number_or_return!(x.clone());
|
||||||
let (real_rhs, imaginary_rhs, _) = as_number_or_return!(y.clone());
|
let (real_rhs, _, _) = as_number_or_return!(y.clone());
|
||||||
if x.has_imaginary() || y.has_imaginary() {
|
if x.has_imaginary() || y.has_imaginary() {
|
||||||
let abs_x = abs(x);
|
let abs_x = abs(x)?;
|
||||||
let abs_y = abs(y);
|
let abs_y = abs(y)?;
|
||||||
crate::prelude::funcs::sqrt(
|
crate::prelude::funcs::sqrt(
|
||||||
abs_x
|
abs_x
|
||||||
.clone()
|
.clone()
|
||||||
.mul_without_unit(&abs_x)
|
.mul_without_unit(&abs_x)?
|
||||||
.add_without_unit(&abs_y.clone().mul_without_unit(&abs_y)),
|
.add_without_unit(&abs_y.clone().mul_without_unit(&abs_y)?)?,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
KalkValue::Number(real.hypot(real_rhs), float!(0), unit)
|
Ok(KalkValue::Number(real.hypot(real_rhs), float!(0), unit))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,93 +1,97 @@
|
|||||||
pub mod special_funcs {
|
pub mod special_funcs {
|
||||||
use crate::{as_number_or_return, float, prelude::KalkValue};
|
use crate::{as_number_or_return, errors::KalkError, float, prelude::KalkValue};
|
||||||
|
|
||||||
pub fn factorial(x: KalkValue) -> KalkValue {
|
pub fn factorial(x: KalkValue) -> Result<KalkValue, KalkError> {
|
||||||
let (real, _, unit) = as_number_or_return!(x);
|
let (real, _, unit) = as_number_or_return!(x);
|
||||||
|
|
||||||
KalkValue::Number((real + 1f64).gamma(), float!(0), unit)
|
Ok(KalkValue::Number((real + 1f64).gamma(), float!(0), unit))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) mod funcs {
|
pub(crate) mod funcs {
|
||||||
|
use crate::errors::KalkError;
|
||||||
use crate::kalk_value::KalkValue;
|
use crate::kalk_value::KalkValue;
|
||||||
use crate::prelude::funcs::abs;
|
use crate::prelude::funcs::abs;
|
||||||
use crate::{as_number_or_return, float};
|
use crate::{as_number_or_return, float};
|
||||||
|
|
||||||
pub fn arg(x: KalkValue) -> KalkValue {
|
pub fn arg(x: KalkValue) -> Result<KalkValue, KalkError> {
|
||||||
let (real, imaginary, unit) = as_number_or_return!(x);
|
let (real, imaginary, unit) = as_number_or_return!(x);
|
||||||
|
|
||||||
KalkValue::Number(imaginary.atan2(&real), float!(0), unit)
|
Ok(KalkValue::Number(imaginary.atan2(&real), float!(0), unit))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gamma(x: KalkValue) -> KalkValue {
|
pub fn gamma(x: KalkValue) -> Result<KalkValue, KalkError> {
|
||||||
let (real, _, unit) = as_number_or_return!(x);
|
let (real, _, unit) = as_number_or_return!(x);
|
||||||
|
|
||||||
KalkValue::Number(real.gamma(), float!(0), unit)
|
Ok(KalkValue::Number(real.gamma(), float!(0), unit))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bitcmp(x: KalkValue) -> KalkValue {
|
pub fn bitcmp(x: KalkValue) -> Result<KalkValue, KalkError> {
|
||||||
let (real, _, _) = as_number_or_return!(x);
|
let (real, _, _) = as_number_or_return!(x);
|
||||||
|
|
||||||
KalkValue::from(!real.to_i32_saturating().unwrap_or(i32::MAX))
|
Ok(KalkValue::from(
|
||||||
|
!real.to_i32_saturating().unwrap_or(i32::MAX),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bitand(x: KalkValue, y: KalkValue) -> KalkValue {
|
pub fn bitand(x: KalkValue, y: KalkValue) -> Result<KalkValue, KalkError> {
|
||||||
let (real, _, _) = as_number_or_return!(x);
|
let (real, _, _) = as_number_or_return!(x);
|
||||||
let (real_rhs, _, _) = as_number_or_return!(y);
|
let (real_rhs, _, _) = as_number_or_return!(y);
|
||||||
|
|
||||||
KalkValue::from(
|
Ok(KalkValue::from(
|
||||||
real.to_i32_saturating().unwrap_or(i32::MAX)
|
real.to_i32_saturating().unwrap_or(i32::MAX)
|
||||||
& real_rhs.to_i32_saturating().unwrap_or(i32::MAX),
|
& real_rhs.to_i32_saturating().unwrap_or(i32::MAX),
|
||||||
)
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bitor(x: KalkValue, y: KalkValue) -> KalkValue {
|
pub fn bitor(x: KalkValue, y: KalkValue) -> Result<KalkValue, KalkError> {
|
||||||
let (real, _, _) = as_number_or_return!(x);
|
let (real, _, _) = as_number_or_return!(x);
|
||||||
let (real_rhs, _, _) = as_number_or_return!(y);
|
let (real_rhs, _, _) = as_number_or_return!(y);
|
||||||
|
|
||||||
KalkValue::from(
|
Ok(KalkValue::from(
|
||||||
real.to_i32_saturating().unwrap_or(i32::MAX)
|
real.to_i32_saturating().unwrap_or(i32::MAX)
|
||||||
| real_rhs.to_i32_saturating().unwrap_or(i32::MAX),
|
| real_rhs.to_i32_saturating().unwrap_or(i32::MAX),
|
||||||
)
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bitxor(x: KalkValue, y: KalkValue) -> KalkValue {
|
pub fn bitxor(x: KalkValue, y: KalkValue) -> Result<KalkValue, KalkError> {
|
||||||
let (real, _, _) = as_number_or_return!(x);
|
let (real, _, _) = as_number_or_return!(x);
|
||||||
let (real_rhs, _, _) = as_number_or_return!(y);
|
let (real_rhs, _, _) = as_number_or_return!(y);
|
||||||
|
|
||||||
KalkValue::from(
|
Ok(KalkValue::from(
|
||||||
real.to_i32_saturating().unwrap_or(i32::MAX)
|
real.to_i32_saturating().unwrap_or(i32::MAX)
|
||||||
^ real_rhs.to_i32_saturating().unwrap_or(i32::MAX),
|
^ real_rhs.to_i32_saturating().unwrap_or(i32::MAX),
|
||||||
)
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bitshift(x: KalkValue, y: KalkValue) -> KalkValue {
|
pub fn bitshift(x: KalkValue, y: KalkValue) -> Result<KalkValue, KalkError> {
|
||||||
let (real, _, _) = as_number_or_return!(x);
|
let (real, _, _) = as_number_or_return!(x);
|
||||||
let (real_rhs, _, _) = as_number_or_return!(y);
|
let (real_rhs, _, _) = as_number_or_return!(y);
|
||||||
|
|
||||||
let x = real.to_i32_saturating().unwrap_or(i32::MAX) as i32;
|
let x = real.to_i32_saturating().unwrap_or(i32::MAX) as i32;
|
||||||
let y = real_rhs.to_i32_saturating().unwrap_or(i32::MAX) as i32;
|
let y = real_rhs.to_i32_saturating().unwrap_or(i32::MAX) as i32;
|
||||||
if y < 0 {
|
if y < 0 {
|
||||||
KalkValue::from(x >> y.abs())
|
Ok(KalkValue::from(x >> y.abs()))
|
||||||
} else {
|
} else {
|
||||||
KalkValue::from(x << y)
|
Ok(KalkValue::from(x << y))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hypot(x: KalkValue, y: KalkValue) -> KalkValue {
|
pub fn hypot(x: KalkValue, y: KalkValue) -> Result<KalkValue, KalkError> {
|
||||||
let (real, _, unit) = as_number_or_return!(x.clone());
|
let is_complex = x.has_imaginary() || y.has_imaginary();
|
||||||
let (real_rhs, _, _) = as_number_or_return!(y.clone());
|
let (real, imaginary, unit) = as_number_or_return!(x);
|
||||||
if x.has_imaginary() || y.has_imaginary() {
|
let (real_rhs, imaginary_rhs, unit_rhs) = as_number_or_return!(y);
|
||||||
let abs_x = abs(x);
|
if is_complex {
|
||||||
let abs_y = abs(y);
|
let abs_x = abs(KalkValue::Number(real, imaginary, unit))?;
|
||||||
|
let abs_y = abs(KalkValue::Number(real_rhs, imaginary_rhs, unit_rhs))?;
|
||||||
crate::prelude::funcs::sqrt(
|
crate::prelude::funcs::sqrt(
|
||||||
abs_x
|
abs_x
|
||||||
.clone()
|
.clone()
|
||||||
.mul_without_unit(&abs_x)
|
.mul_without_unit(&abs_x)?
|
||||||
.add_without_unit(&abs_y.clone().mul_without_unit(&abs_y)),
|
.add_without_unit(&abs_y.clone().mul_without_unit(&abs_y)?)?,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
KalkValue::Number(real.hypot(&real_rhs), float!(0), unit)
|
Ok(KalkValue::Number(real.hypot(&real_rhs), float!(0), unit))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user