mirror of
https://github.com/PaddiM8/kalker.git
synced 2025-01-05 21:18:59 +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::{
|
||||
ast::{ConditionalPiece, Expr, Identifier, RangedVar, Stmt},
|
||||
errors::KalkError,
|
||||
inverter,
|
||||
lexer::TokenKind,
|
||||
parser::{self, KalkError},
|
||||
prelude,
|
||||
parser, prelude,
|
||||
symbol_table::SymbolTable,
|
||||
};
|
||||
|
||||
|
@ -3,11 +3,11 @@ use crate::ast;
|
||||
use crate::ast::Expr;
|
||||
use crate::ast::Identifier;
|
||||
use crate::ast::Stmt;
|
||||
use crate::errors::KalkError;
|
||||
use crate::float;
|
||||
use crate::interpreter;
|
||||
use crate::kalk_value::KalkValue;
|
||||
use crate::lexer::TokenKind;
|
||||
use crate::parser::KalkError;
|
||||
|
||||
pub fn derive_func(
|
||||
context: &mut interpreter::Context,
|
||||
@ -17,8 +17,8 @@ pub fn derive_func(
|
||||
const H: f64 = 0.000001;
|
||||
|
||||
let unit = argument.get_unit().cloned();
|
||||
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_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 new_identifier = Identifier::from_name_and_primes(&name.pure_name, name.prime_count - 1);
|
||||
|
||||
let f_x_h = interpreter::eval_fn_call_expr(
|
||||
@ -35,8 +35,8 @@ pub fn derive_func(
|
||||
)?;
|
||||
|
||||
Ok(f_x_h
|
||||
.sub_without_unit(&f_x)
|
||||
.div_without_unit(&(2f64 * H).into())
|
||||
.sub_without_unit(&f_x)?
|
||||
.div_without_unit(&(2f64 * H).into())?
|
||||
.round_if_needed())
|
||||
}
|
||||
|
||||
@ -98,11 +98,11 @@ fn simpsons_rule(
|
||||
const N: i32 = 900;
|
||||
let a = interpreter::eval_expr(context, a_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 {
|
||||
let variable_value = a
|
||||
.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(
|
||||
Identifier::from_full_name(integration_variable),
|
||||
Box::new(crate::ast::build_literal_ast(&variable_value)),
|
||||
@ -116,7 +116,7 @@ fn simpsons_rule(
|
||||
|
||||
// factor * f(x_n)
|
||||
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_imaginary += mul_imaginary;
|
||||
@ -133,11 +133,11 @@ fn simpsons_rule(
|
||||
let result = KalkValue::Number(result_real, result_imaginary, None);
|
||||
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_imaginary,
|
||||
h_unit,
|
||||
)))
|
||||
))
|
||||
}
|
||||
|
||||
#[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::{Identifier, RangedVar};
|
||||
use crate::calculation_result::CalculationResult;
|
||||
use crate::errors::KalkError;
|
||||
use crate::kalk_value::KalkValue;
|
||||
use crate::lexer::TokenKind;
|
||||
use crate::parser::KalkError;
|
||||
use crate::parser::DECL_UNIT;
|
||||
use crate::symbol_table::SymbolTable;
|
||||
use crate::{as_number_or_zero, calculus};
|
||||
@ -163,7 +163,7 @@ fn eval_binary_expr(
|
||||
let left = eval_expr(context, left_expr, None)?;
|
||||
let mut right = eval_expr(context, right_expr, None)?;
|
||||
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 {
|
||||
return Ok(right);
|
||||
}
|
||||
@ -184,8 +184,8 @@ fn eval_binary_expr(
|
||||
TokenKind::LessOrEquals => left.less_or_equals(context, right),
|
||||
TokenKind::And => left.and(&right),
|
||||
TokenKind::Or => left.or(&right),
|
||||
_ => KalkValue::from(1f64),
|
||||
};
|
||||
_ => Ok(KalkValue::from(1f64)),
|
||||
}?;
|
||||
|
||||
if unit.is_some() {
|
||||
if let KalkValue::Number(real, imaginary, _) = result {
|
||||
@ -205,9 +205,9 @@ fn eval_unary_expr(
|
||||
let num = eval_expr(context, expr, unit)?;
|
||||
|
||||
match op {
|
||||
TokenKind::Minus => Ok(num.mul(context, KalkValue::from(-1f64))),
|
||||
TokenKind::Percent => Ok(num.mul(context, KalkValue::from(0.01f64))),
|
||||
TokenKind::Exclamation => Ok(prelude::special_funcs::factorial(num)),
|
||||
TokenKind::Minus => num.mul(context, KalkValue::from(-1f64)),
|
||||
TokenKind::Percent => num.mul(context, KalkValue::from(0.01f64)),
|
||||
TokenKind::Exclamation => prelude::special_funcs::factorial(num),
|
||||
_ => Err(KalkError::InvalidOperator),
|
||||
}
|
||||
}
|
||||
@ -397,10 +397,8 @@ pub(crate) fn eval_fn_call_expr(
|
||||
values.push(value);
|
||||
}
|
||||
|
||||
return Ok(
|
||||
prelude::call_vector_func(&identifier.full_name, KalkValue::Vector(values))
|
||||
.unwrap_or_else(KalkValue::nan),
|
||||
);
|
||||
return prelude::call_vector_func(&identifier.full_name, KalkValue::Vector(values))
|
||||
.unwrap_or_else(|| Ok(KalkValue::nan()));
|
||||
}
|
||||
|
||||
// Prelude
|
||||
@ -433,9 +431,7 @@ pub(crate) fn eval_fn_call_expr(
|
||||
};
|
||||
|
||||
if let Some((result, _)) = prelude_func {
|
||||
// If the result is nan and only one argument was given,
|
||||
// it may be due to incompatible types.
|
||||
if result.is_nan() && expressions.len() == 1 {
|
||||
if result.is_err() && expressions.len() == 1 {
|
||||
let x = eval_expr(context, &expressions[0], None)?;
|
||||
|
||||
// If a vector/matrix was given, call the function on every item
|
||||
@ -450,7 +446,7 @@ pub(crate) fn eval_fn_call_expr(
|
||||
value,
|
||||
&context.angle_unit.clone(),
|
||||
) {
|
||||
new_values.push(result.0);
|
||||
new_values.push(result.0?);
|
||||
} else {
|
||||
success = false;
|
||||
break;
|
||||
@ -472,7 +468,7 @@ pub(crate) fn eval_fn_call_expr(
|
||||
value,
|
||||
&context.angle_unit.clone(),
|
||||
) {
|
||||
new_row.push(result.0);
|
||||
new_row.push(result.0?);
|
||||
} else {
|
||||
success = false;
|
||||
break;
|
||||
@ -488,8 +484,9 @@ pub(crate) fn eval_fn_call_expr(
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Symbol Table
|
||||
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)?;
|
||||
if sum_else_prod {
|
||||
sum = sum.add(context, eval);
|
||||
sum = sum.add(context, eval)?;
|
||||
} else {
|
||||
sum = sum.mul(context, eval);
|
||||
sum = sum.mul(context, eval)?;
|
||||
}
|
||||
}
|
||||
|
||||
@ -829,7 +826,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[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)
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::ast::Identifier;
|
||||
use crate::ast::{Expr, Stmt};
|
||||
use crate::errors::KalkError;
|
||||
use crate::lexer::TokenKind;
|
||||
use crate::parser::KalkError;
|
||||
use crate::prelude;
|
||||
use crate::symbol_table::SymbolTable;
|
||||
use lazy_static::lazy_static;
|
||||
|
@ -14,6 +14,7 @@ pub use regular::*;
|
||||
mod rounding;
|
||||
|
||||
use crate::ast::Expr;
|
||||
use crate::errors::KalkError;
|
||||
use crate::radix;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
@ -66,7 +67,10 @@ macro_rules! as_number_or_return {
|
||||
unit,
|
||||
)
|
||||
} 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) => {{
|
||||
if let KalkValue::Vector(values) = $x {
|
||||
if values.len() == 0 {
|
||||
return KalkValue::nan();
|
||||
return Err(KalkError::Expected(String::from("a non-empty vector")));
|
||||
}
|
||||
|
||||
values
|
||||
} 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)
|
||||
}
|
||||
|
||||
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 {
|
||||
if let KalkValue::Number(real, imaginary, _) = self {
|
||||
if !self.has_imaginary() {
|
||||
@ -532,7 +548,7 @@ impl KalkValue {
|
||||
self,
|
||||
context: &mut crate::interpreter::Context,
|
||||
rhs: KalkValue,
|
||||
) -> KalkValue {
|
||||
) -> Result<KalkValue, KalkError> {
|
||||
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
||||
self.add_without_unit(&right)
|
||||
}
|
||||
@ -541,7 +557,7 @@ impl KalkValue {
|
||||
self,
|
||||
context: &mut crate::interpreter::Context,
|
||||
rhs: KalkValue,
|
||||
) -> KalkValue {
|
||||
) -> Result<KalkValue, KalkError> {
|
||||
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
||||
self.sub_without_unit(&right)
|
||||
}
|
||||
@ -550,7 +566,7 @@ impl KalkValue {
|
||||
self,
|
||||
context: &mut crate::interpreter::Context,
|
||||
rhs: KalkValue,
|
||||
) -> KalkValue {
|
||||
) -> Result<KalkValue, KalkError> {
|
||||
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
||||
self.mul_without_unit(&right)
|
||||
}
|
||||
@ -559,7 +575,7 @@ impl KalkValue {
|
||||
self,
|
||||
context: &mut crate::interpreter::Context,
|
||||
rhs: KalkValue,
|
||||
) -> KalkValue {
|
||||
) -> Result<KalkValue, KalkError> {
|
||||
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
||||
self.div_without_unit(&right)
|
||||
}
|
||||
@ -568,7 +584,7 @@ impl KalkValue {
|
||||
self,
|
||||
context: &mut crate::interpreter::Context,
|
||||
rhs: KalkValue,
|
||||
) -> KalkValue {
|
||||
) -> Result<KalkValue, KalkError> {
|
||||
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
||||
self.pow_without_unit(&right)
|
||||
}
|
||||
@ -577,8 +593,8 @@ impl KalkValue {
|
||||
self,
|
||||
context: &mut crate::interpreter::Context,
|
||||
rhs: KalkValue,
|
||||
) -> KalkValue {
|
||||
if let KalkValue::Number(real, _, _) = &self {
|
||||
) -> Result<KalkValue, KalkError> {
|
||||
Ok(if let KalkValue::Number(real, _, _) = &self {
|
||||
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
||||
if let KalkValue::Number(right_real, _, right_unit) = right {
|
||||
KalkValue::Number(real % right_real, float!(0f64), right_unit)
|
||||
@ -587,10 +603,14 @@ impl KalkValue {
|
||||
}
|
||||
} else {
|
||||
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);
|
||||
self.eq_without_unit(&right)
|
||||
}
|
||||
@ -599,7 +619,7 @@ impl KalkValue {
|
||||
self,
|
||||
context: &mut crate::interpreter::Context,
|
||||
rhs: KalkValue,
|
||||
) -> KalkValue {
|
||||
) -> Result<KalkValue, KalkError> {
|
||||
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
||||
self.not_eq_without_unit(&right)
|
||||
}
|
||||
@ -608,7 +628,7 @@ impl KalkValue {
|
||||
self,
|
||||
context: &mut crate::interpreter::Context,
|
||||
rhs: KalkValue,
|
||||
) -> KalkValue {
|
||||
) -> Result<KalkValue, KalkError> {
|
||||
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
||||
self.greater_than_without_unit(&right)
|
||||
}
|
||||
@ -617,7 +637,7 @@ impl KalkValue {
|
||||
self,
|
||||
context: &mut crate::interpreter::Context,
|
||||
rhs: KalkValue,
|
||||
) -> KalkValue {
|
||||
) -> Result<KalkValue, KalkError> {
|
||||
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
||||
self.less_than_without_unit(&right)
|
||||
}
|
||||
@ -626,13 +646,13 @@ impl KalkValue {
|
||||
self,
|
||||
context: &mut crate::interpreter::Context,
|
||||
rhs: KalkValue,
|
||||
) -> KalkValue {
|
||||
) -> Result<KalkValue, KalkError> {
|
||||
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
||||
if let (KalkValue::Boolean(greater), KalkValue::Boolean(equal)) = (
|
||||
self.greater_than_without_unit(&right),
|
||||
self.eq_without_unit(&right),
|
||||
self.greater_than_without_unit(&right)?,
|
||||
self.eq_without_unit(&right)?,
|
||||
) {
|
||||
KalkValue::Boolean(greater || equal)
|
||||
Ok(KalkValue::Boolean(greater || equal))
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
@ -642,69 +662,93 @@ impl KalkValue {
|
||||
self,
|
||||
context: &mut crate::interpreter::Context,
|
||||
rhs: KalkValue,
|
||||
) -> KalkValue {
|
||||
) -> Result<KalkValue, KalkError> {
|
||||
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
||||
if let (KalkValue::Boolean(less), KalkValue::Boolean(equal)) = (
|
||||
self.less_than_without_unit(&right),
|
||||
self.eq_without_unit(&right),
|
||||
self.less_than_without_unit(&right)?,
|
||||
self.eq_without_unit(&right)?,
|
||||
) {
|
||||
KalkValue::Boolean(less || equal)
|
||||
Ok(KalkValue::Boolean(less || equal))
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn and(self, rhs: &KalkValue) -> KalkValue {
|
||||
pub(crate) fn and(self, rhs: &KalkValue) -> Result<KalkValue, KalkError> {
|
||||
match (self, 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) {
|
||||
(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) {
|
||||
(
|
||||
KalkValue::Number(real, imaginary, _),
|
||||
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(_)) => {
|
||||
calculate_matrix(self, rhs, &KalkValue::add_without_unit)
|
||||
}
|
||||
(KalkValue::Vector(_), _) | (_, KalkValue::Vector(_)) => {
|
||||
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) {
|
||||
(
|
||||
KalkValue::Number(real, imaginary, _),
|
||||
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(_)) => {
|
||||
calculate_matrix(self, rhs, &KalkValue::sub_without_unit)
|
||||
}
|
||||
(KalkValue::Vector(_), _) | (_, KalkValue::Vector(_)) => {
|
||||
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
|
||||
// different orders in the next match expression.
|
||||
let (lhs, rhs) = match (&self, rhs) {
|
||||
@ -717,42 +761,38 @@ impl KalkValue {
|
||||
(
|
||||
KalkValue::Number(real, imaginary, _),
|
||||
KalkValue::Number(real_rhs, imaginary_rhs, unit),
|
||||
) => KalkValue::Number(
|
||||
) => Ok(KalkValue::Number(
|
||||
// (a + bi)(c + di) = ac + adi + bci + bdi²
|
||||
real.clone() * real_rhs - imaginary.clone() * imaginary_rhs,
|
||||
real.clone() * imaginary_rhs + imaginary * real_rhs,
|
||||
unit.clone(),
|
||||
),
|
||||
(KalkValue::Matrix(rows), KalkValue::Number(_, _, _)) => KalkValue::Matrix(
|
||||
rows.iter()
|
||||
.map(|row| {
|
||||
row.iter()
|
||||
.map(|x| x.clone().mul_without_unit(rhs))
|
||||
.collect()
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
)),
|
||||
(KalkValue::Matrix(_), KalkValue::Number(_, _, _)) => {
|
||||
calculate_matrix(lhs.clone(), rhs, &KalkValue::mul_without_unit)
|
||||
}
|
||||
(KalkValue::Matrix(rows), KalkValue::Vector(values_rhs)) => {
|
||||
if rows.first().unwrap().len() != values_rhs.len() {
|
||||
return KalkValue::nan();
|
||||
return Err(KalkError::IncompatibleVectorsMatrixes);
|
||||
}
|
||||
|
||||
let mut new_values: Vec<KalkValue> = Vec::new();
|
||||
for row in rows {
|
||||
new_values.push(
|
||||
row.iter()
|
||||
.zip(values_rhs)
|
||||
.map(|(x, y)| x.clone().mul_without_unit(y))
|
||||
.sum(),
|
||||
)
|
||||
let mut sum = KalkValue::from(0);
|
||||
for (x, y) in row.iter().zip(values_rhs) {
|
||||
sum = sum
|
||||
.clone()
|
||||
.add_without_unit(&x.clone().mul_without_unit(y)?)?;
|
||||
}
|
||||
|
||||
new_values.push(sum);
|
||||
}
|
||||
|
||||
KalkValue::Vector(new_values)
|
||||
Ok(KalkValue::Vector(new_values))
|
||||
}
|
||||
(KalkValue::Matrix(rows), KalkValue::Matrix(rows_rhs)) => {
|
||||
let lhs_columns = rows.first().unwrap();
|
||||
if lhs_columns.len() != rows_rhs.len() {
|
||||
return KalkValue::nan();
|
||||
return Err(KalkError::IncompatibleVectorsMatrixes);
|
||||
}
|
||||
|
||||
let rhs_columns = rows_rhs.first().unwrap();
|
||||
@ -767,55 +807,62 @@ impl KalkValue {
|
||||
// For every value in the current lhs row
|
||||
for (k, value) in rows[i].iter().enumerate() {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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)) => {
|
||||
if values.len() != values_rhs.len() {
|
||||
return KalkValue::nan();
|
||||
return Err(KalkError::IncompatibleVectorsMatrixes);
|
||||
}
|
||||
|
||||
let mut sum = KalkValue::from(0f64);
|
||||
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()) {
|
||||
(KalkValue::Number(real, _, _), KalkValue::Number(real_rhs, _, unit)) => {
|
||||
// Avoid unecessary calculations
|
||||
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 {
|
||||
// Multiply both the numerator and denominator
|
||||
// with the conjugate of the denominator, and divide.
|
||||
let conjugate = rhs.get_conjugate();
|
||||
let conjugate = rhs.get_conjugate()?;
|
||||
let (numerator, numerator_imaginary) =
|
||||
self.mul_without_unit(&conjugate).values();
|
||||
let (denominator, _) = rhs.clone().mul_without_unit(&conjugate).values();
|
||||
KalkValue::Number(
|
||||
self.mul_without_unit(&conjugate)?.values();
|
||||
let (denominator, _) = rhs.clone().mul_without_unit(&conjugate)?.values();
|
||||
Ok(KalkValue::Number(
|
||||
numerator / denominator.clone(),
|
||||
numerator_imaginary / denominator,
|
||||
unit,
|
||||
)
|
||||
))
|
||||
}
|
||||
}
|
||||
(KalkValue::Matrix(_), _) | (_, KalkValue::Matrix(_)) => {
|
||||
@ -824,11 +871,15 @@ impl KalkValue {
|
||||
(KalkValue::Vector(_), _) | (_, KalkValue::Vector(_)) => {
|
||||
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) {
|
||||
(
|
||||
KalkValue::Number(real, imaginary, _),
|
||||
@ -842,75 +893,92 @@ impl KalkValue {
|
||||
let b = imaginary;
|
||||
let c = real_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 exp =
|
||||
pow(raised.clone(), c.clone() / 2f64) * (-d.clone() * arg.clone()).exp();
|
||||
let polar = c * arg + d.clone() / 2f64 * raised.ln();
|
||||
|
||||
KalkValue::Number(
|
||||
Ok(KalkValue::Number(
|
||||
polar.clone().cos() * exp.clone(),
|
||||
polar.sin() * exp,
|
||||
unit.clone(),
|
||||
)
|
||||
))
|
||||
} 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, _)) => {
|
||||
if real < &0f64
|
||||
|| real.clone().fract() > 0.000001f64
|
||||
|| !(imaginary == &0f64 || imaginary == &-0f64)
|
||||
|| rows.len() != rows.first().unwrap().len()
|
||||
{
|
||||
return KalkValue::nan();
|
||||
(KalkValue::Matrix(rows), KalkValue::Number(real, _, _)) => {
|
||||
if real < &0f64 || real.clone().fract() > 0.000001f64 {
|
||||
return Err(KalkError::Expected(String::from("a positive integer")));
|
||||
}
|
||||
|
||||
if rhs.has_imaginary() {
|
||||
return Err(KalkError::ExpectedReal);
|
||||
}
|
||||
|
||||
if rows.len() != rows.first().unwrap().len() {
|
||||
return Err(KalkError::Expected(String::from("a square matrix")));
|
||||
}
|
||||
|
||||
if real == &0f64 {
|
||||
return KalkValue::from(1f64);
|
||||
return Ok(KalkValue::from(1f64));
|
||||
}
|
||||
|
||||
let mut result = KalkValue::from(1f64);
|
||||
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(_)) => {
|
||||
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) {
|
||||
(
|
||||
KalkValue::Number(real, imaginary, _),
|
||||
KalkValue::Number(real_rhs, imaginary_rhs, _),
|
||||
) => KalkValue::Boolean(
|
||||
) => Ok(KalkValue::Boolean(
|
||||
(real.clone() - real_rhs.clone()).abs() < ACCEPTABLE_COMPARISON_MARGIN
|
||||
&& (imaginary.clone() - imaginary_rhs.clone()).abs()
|
||||
< ACCEPTABLE_COMPARISON_MARGIN,
|
||||
),
|
||||
)),
|
||||
(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)) => {
|
||||
let mut matrices_are_equal = true;
|
||||
for (row, row_rhs) in rows.iter().zip(rows_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 {
|
||||
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)) => {
|
||||
let mut vecs_are_equal = true;
|
||||
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 {
|
||||
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) {
|
||||
(
|
||||
KalkValue::Number(real, imaginary, _),
|
||||
KalkValue::Number(real_rhs, imaginary_rhs, _),
|
||||
) => KalkValue::Boolean(
|
||||
) => Ok(KalkValue::Boolean(
|
||||
(real.clone() - real_rhs.clone()).abs() > ACCEPTABLE_COMPARISON_MARGIN
|
||||
|| (imaginary.clone() - imaginary_rhs.clone()).abs()
|
||||
> ACCEPTABLE_COMPARISON_MARGIN,
|
||||
),
|
||||
)),
|
||||
(KalkValue::Boolean(boolean), KalkValue::Boolean(boolean_rhs)) => {
|
||||
KalkValue::Boolean(boolean != boolean_rhs)
|
||||
Ok(KalkValue::Boolean(boolean != boolean_rhs))
|
||||
}
|
||||
(KalkValue::Vector(_), KalkValue::Vector(_))
|
||||
| (KalkValue::Matrix(_), KalkValue::Matrix(_)) => {
|
||||
if let KalkValue::Boolean(boolean) = self.eq_without_unit(rhs) {
|
||||
KalkValue::Boolean(!boolean)
|
||||
if let KalkValue::Boolean(boolean) = self.eq_without_unit(rhs)? {
|
||||
Ok(KalkValue::Boolean(!boolean))
|
||||
} 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() {
|
||||
return KalkValue::nan();
|
||||
return Err(KalkError::ExpectedReal);
|
||||
}
|
||||
|
||||
match (self, rhs) {
|
||||
(KalkValue::Number(real, _, _), KalkValue::Number(real_rhs, _, _)) => {
|
||||
KalkValue::Boolean(real.clone() - real_rhs.clone() > ACCEPTABLE_COMPARISON_MARGIN)
|
||||
}
|
||||
_ => KalkValue::nan(),
|
||||
(KalkValue::Number(real, _, _), KalkValue::Number(real_rhs, _, _)) => Ok(
|
||||
KalkValue::Boolean(real.clone() - real_rhs.clone() > ACCEPTABLE_COMPARISON_MARGIN),
|
||||
),
|
||||
_ => 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() {
|
||||
return KalkValue::nan();
|
||||
return Err(KalkError::ExpectedReal);
|
||||
}
|
||||
|
||||
match (self, rhs) {
|
||||
(KalkValue::Number(real, _, _), KalkValue::Number(real_rhs, _, _)) => {
|
||||
KalkValue::Boolean(real.clone() - real_rhs.clone() < -ACCEPTABLE_COMPARISON_MARGIN)
|
||||
}
|
||||
_ => KalkValue::nan(),
|
||||
(KalkValue::Number(real, _, _), KalkValue::Number(real_rhs, _, _)) => Ok(
|
||||
KalkValue::Boolean(real.clone() - real_rhs.clone() < -ACCEPTABLE_COMPARISON_MARGIN),
|
||||
),
|
||||
_ => 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 {
|
||||
KalkValue::Number(real, imaginary, unit) => {
|
||||
KalkValue::Number(real.clone(), imaginary.clone() * (-1f64), unit.clone())
|
||||
}
|
||||
_ => KalkValue::nan(),
|
||||
KalkValue::Number(real, imaginary, unit) => Ok(KalkValue::Number(
|
||||
real.clone(),
|
||||
imaginary.clone() * (-1f64),
|
||||
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(
|
||||
x: KalkValue,
|
||||
y: &KalkValue,
|
||||
action: &dyn Fn(KalkValue, &KalkValue) -> KalkValue,
|
||||
) -> KalkValue {
|
||||
action: &dyn Fn(KalkValue, &KalkValue) -> Result<KalkValue, KalkError>,
|
||||
) -> Result<KalkValue, KalkError> {
|
||||
match (x, y) {
|
||||
(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::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)) => {
|
||||
if values.len() == values_rhs.len() {
|
||||
KalkValue::Vector(
|
||||
values
|
||||
.iter()
|
||||
.zip(values_rhs)
|
||||
.map(|(x, y)| action(x.clone(), y))
|
||||
.collect(),
|
||||
)
|
||||
} else {
|
||||
KalkValue::nan()
|
||||
if values.len() != values_rhs.len() {
|
||||
return Err(KalkError::IncompatibleVectorsMatrixes);
|
||||
}
|
||||
|
||||
let mut new_values = Vec::new();
|
||||
for (value, value_rhs) in values.iter().zip(values_rhs) {
|
||||
new_values.push(action(value.clone(), value_rhs)?);
|
||||
}
|
||||
|
||||
Ok(KalkValue::Vector(new_values))
|
||||
}
|
||||
_ => KalkValue::nan(),
|
||||
(x, y) => Err(KalkError::IncompatibleTypesForOperation(
|
||||
String::from("vector operation"),
|
||||
x.get_type_name(),
|
||||
y.get_type_name(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn calculate_matrix(
|
||||
x: KalkValue,
|
||||
y: &KalkValue,
|
||||
action: &dyn Fn(KalkValue, &KalkValue) -> KalkValue,
|
||||
) -> KalkValue {
|
||||
action: &dyn Fn(KalkValue, &KalkValue) -> Result<KalkValue, KalkError>,
|
||||
) -> Result<KalkValue, KalkError> {
|
||||
// Make sure matrix is always first to avoid having to match
|
||||
// different orders in the next match expression.
|
||||
let (x, y) = match (&x, y) {
|
||||
@ -1053,14 +1158,20 @@ fn calculate_matrix(
|
||||
};
|
||||
|
||||
match (x, y) {
|
||||
(KalkValue::Matrix(rows), KalkValue::Number(_, _, _)) => KalkValue::Matrix(
|
||||
rows.iter()
|
||||
.map(|row| row.iter().map(|x| action(x.clone(), y)).collect())
|
||||
.collect(),
|
||||
),
|
||||
(KalkValue::Matrix(rows), KalkValue::Number(_, _, _)) => {
|
||||
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(action(item.clone(), y)?);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(KalkValue::Matrix(new_rows))
|
||||
}
|
||||
(KalkValue::Matrix(rows), KalkValue::Vector(values_rhs)) => {
|
||||
if rows.len() != values_rhs.len() {
|
||||
return KalkValue::nan();
|
||||
return Err(KalkError::IncompatibleVectorsMatrixes);
|
||||
}
|
||||
|
||||
let mut new_rows = Vec::new();
|
||||
@ -1070,17 +1181,17 @@ fn calculate_matrix(
|
||||
new_rows
|
||||
.last_mut()
|
||||
.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)) => {
|
||||
if rows.len() != rows_rhs.len()
|
||||
|| rows.first().unwrap().len() != rows_rhs.first().unwrap().len()
|
||||
{
|
||||
return KalkValue::nan();
|
||||
return Err(KalkError::IncompatibleVectorsMatrixes);
|
||||
}
|
||||
|
||||
let mut new_rows = Vec::new();
|
||||
@ -1090,13 +1201,17 @@ fn calculate_matrix(
|
||||
new_rows
|
||||
.last_mut()
|
||||
.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
|
||||
where
|
||||
I: std::iter::Iterator<Item = KalkValue>,
|
||||
@ -1151,7 +1266,7 @@ impl std::iter::Sum<KalkValue> for KalkValue {
|
||||
|
||||
sum
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
impl From<KalkValue> for String {
|
||||
fn from(val: KalkValue) -> Self {
|
||||
@ -1211,7 +1326,8 @@ mod tests {
|
||||
|
||||
for (a, b, expected_result) in in_out {
|
||||
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.imaginary_to_f64(), expected_result.1);
|
||||
}
|
||||
@ -1228,7 +1344,8 @@ mod tests {
|
||||
|
||||
for (a, b, expected_result) in in_out {
|
||||
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.imaginary_to_f64(), expected_result.1);
|
||||
}
|
||||
@ -1245,7 +1362,8 @@ mod tests {
|
||||
|
||||
for (a, b, expected_result) in in_out {
|
||||
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.imaginary_to_f64(), expected_result.1);
|
||||
}
|
||||
@ -1261,7 +1379,8 @@ mod tests {
|
||||
|
||||
for (a, b, expected_result) in in_out {
|
||||
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.imaginary_to_f64(), expected_result.1);
|
||||
}
|
||||
@ -1289,7 +1408,8 @@ mod tests {
|
||||
|
||||
for (a, b, expected_result) in in_out {
|
||||
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.imaginary_to_f64(), expected_result.1));
|
||||
}
|
||||
|
@ -1,9 +1,11 @@
|
||||
#![allow(clippy::unused_unit)]
|
||||
#![allow(clippy::float_cmp)]
|
||||
#![allow(clippy::clone_on_copy)] // the float type needs explicit cloning if the rug feature is enabled
|
||||
mod analysis;
|
||||
pub mod ast;
|
||||
pub mod calculation_result;
|
||||
mod calculus;
|
||||
mod errors;
|
||||
mod integration_testing;
|
||||
mod interpreter;
|
||||
mod inverter;
|
||||
|
@ -3,6 +3,7 @@ use std::cell::Cell;
|
||||
use crate::analysis;
|
||||
use crate::ast::Identifier;
|
||||
use crate::calculation_result::CalculationResult;
|
||||
use crate::errors::KalkError;
|
||||
use crate::{
|
||||
ast::{Expr, Stmt},
|
||||
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.
|
||||
///
|
||||
/// `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 {
|
||||
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);
|
||||
|
||||
// Round it a bit, to prevent floating point errors.
|
||||
KalkValue::Number(
|
||||
Ok(KalkValue::Number(
|
||||
(super::funcs::precise_gamma(real + 1f64) * 10e6f64).round() / 10e6f64,
|
||||
float!(0),
|
||||
unit,
|
||||
)
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) mod funcs {
|
||||
use crate::errors::KalkError;
|
||||
use crate::kalk_value::KalkValue;
|
||||
use crate::prelude::funcs::abs;
|
||||
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);
|
||||
|
||||
// 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);
|
||||
|
||||
// Round it a bit, to prevent floating point errors.
|
||||
KalkValue::Number(
|
||||
Ok(KalkValue::Number(
|
||||
(precise_gamma(real) * 10e6f64).round() / 10e6f64,
|
||||
float!(0),
|
||||
unit,
|
||||
)
|
||||
))
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
pub fn bitcmp(x: KalkValue) -> KalkValue {
|
||||
pub fn bitcmp(x: KalkValue) -> Result<KalkValue, KalkError> {
|
||||
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_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_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_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_rhs, _, _) = as_number_or_return!(y);
|
||||
let x = real.round() as i32;
|
||||
let y = real_rhs.round() as i32;
|
||||
if y < 0 {
|
||||
KalkValue::from(x >> y.abs())
|
||||
Ok(KalkValue::from(x >> y.abs()))
|
||||
} else {
|
||||
KalkValue::from(x << y)
|
||||
Ok(KalkValue::from(x << y))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hypot(x: KalkValue, y: KalkValue) -> KalkValue {
|
||||
let (real, imaginary, unit) = as_number_or_return!(x.clone());
|
||||
let (real_rhs, imaginary_rhs, _) = as_number_or_return!(y.clone());
|
||||
pub fn hypot(x: KalkValue, y: KalkValue) -> Result<KalkValue, KalkError> {
|
||||
let (real, _, unit) = as_number_or_return!(x.clone());
|
||||
let (real_rhs, _, _) = as_number_or_return!(y.clone());
|
||||
if x.has_imaginary() || y.has_imaginary() {
|
||||
let abs_x = abs(x);
|
||||
let abs_y = abs(y);
|
||||
let abs_x = abs(x)?;
|
||||
let abs_y = abs(y)?;
|
||||
crate::prelude::funcs::sqrt(
|
||||
abs_x
|
||||
.clone()
|
||||
.mul_without_unit(&abs_x)
|
||||
.add_without_unit(&abs_y.clone().mul_without_unit(&abs_y)),
|
||||
.mul_without_unit(&abs_x)?
|
||||
.add_without_unit(&abs_y.clone().mul_without_unit(&abs_y)?)?,
|
||||
)
|
||||
} 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 {
|
||||
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);
|
||||
|
||||
KalkValue::Number((real + 1f64).gamma(), float!(0), unit)
|
||||
Ok(KalkValue::Number((real + 1f64).gamma(), float!(0), unit))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) mod funcs {
|
||||
use crate::errors::KalkError;
|
||||
use crate::kalk_value::KalkValue;
|
||||
use crate::prelude::funcs::abs;
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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_rhs, _, _) = as_number_or_return!(y);
|
||||
|
||||
KalkValue::from(
|
||||
Ok(KalkValue::from(
|
||||
real.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_rhs, _, _) = as_number_or_return!(y);
|
||||
|
||||
KalkValue::from(
|
||||
Ok(KalkValue::from(
|
||||
real.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_rhs, _, _) = as_number_or_return!(y);
|
||||
|
||||
KalkValue::from(
|
||||
Ok(KalkValue::from(
|
||||
real.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_rhs, _, _) = as_number_or_return!(y);
|
||||
|
||||
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;
|
||||
if y < 0 {
|
||||
KalkValue::from(x >> y.abs())
|
||||
Ok(KalkValue::from(x >> y.abs()))
|
||||
} else {
|
||||
KalkValue::from(x << y)
|
||||
Ok(KalkValue::from(x << y))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hypot(x: KalkValue, y: KalkValue) -> KalkValue {
|
||||
let (real, _, unit) = as_number_or_return!(x.clone());
|
||||
let (real_rhs, _, _) = as_number_or_return!(y.clone());
|
||||
if x.has_imaginary() || y.has_imaginary() {
|
||||
let abs_x = abs(x);
|
||||
let abs_y = abs(y);
|
||||
pub fn hypot(x: KalkValue, y: KalkValue) -> Result<KalkValue, KalkError> {
|
||||
let is_complex = x.has_imaginary() || y.has_imaginary();
|
||||
let (real, imaginary, unit) = as_number_or_return!(x);
|
||||
let (real_rhs, imaginary_rhs, unit_rhs) = as_number_or_return!(y);
|
||||
if is_complex {
|
||||
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(
|
||||
abs_x
|
||||
.clone()
|
||||
.mul_without_unit(&abs_x)
|
||||
.add_without_unit(&abs_y.clone().mul_without_unit(&abs_y)),
|
||||
.mul_without_unit(&abs_x)?
|
||||
.add_without_unit(&abs_y.clone().mul_without_unit(&abs_y)?)?,
|
||||
)
|
||||
} 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