Fixed clippy lints

This commit is contained in:
bakk 2022-01-16 20:58:00 +01:00 committed by PaddiM8
parent a36d9849d5
commit 4704095cd9
17 changed files with 260 additions and 298 deletions

View File

@ -63,7 +63,7 @@ fn default_action(context: &Context) {
load_input_file(&input_file_path, precision, &mut parser_context); load_input_file(&input_file_path, precision, &mut parser_context);
} }
if context.args.len() == 0 { if context.args.is_empty() {
// REPL // REPL
repl::start(&mut parser_context, precision); repl::start(&mut parser_context, precision);
} else { } else {

View File

@ -20,7 +20,7 @@ use std::collections::HashMap;
use std::fs; use std::fs;
use std::process; use std::process;
pub fn start(mut parser: &mut parser::Context, precision: u32) { pub fn start(parser: &mut parser::Context, precision: u32) {
let mut editor = Editor::<RLHelper>::new(); let mut editor = Editor::<RLHelper>::new();
editor.set_helper(Some(RLHelper { editor.set_helper(Some(RLHelper {
highlighter: LineHighlighter {}, highlighter: LineHighlighter {},
@ -31,9 +31,9 @@ pub fn start(mut parser: &mut parser::Context, precision: u32) {
// Load history // Load history
let mut history_path = None; let mut history_path = None;
if let Some(config_path) = dirs::config_dir() { if let Some(config_path) = dirs::config_dir() {
let mut config_path = config_path.clone(); let mut config_path = config_path;
config_path.push("kalker"); config_path.push("kalker");
if let Ok(_) = fs::create_dir_all(config_path.as_path()) { if fs::create_dir_all(config_path.as_path()).is_ok() {
config_path.push("history.txt"); config_path.push("history.txt");
let history = config_path.into_os_string().into_string().unwrap(); let history = config_path.into_os_string().into_string().unwrap();
editor.load_history(&history).ok(); editor.load_history(&history).ok();
@ -61,7 +61,7 @@ pub fn start(mut parser: &mut parser::Context, precision: u32) {
match readline { match readline {
Ok(input) => { Ok(input) => {
editor.add_history_entry(input.as_str()); editor.add_history_entry(input.as_str());
eval_repl(&mut parser, &input, precision); eval_repl(parser, &input, precision);
} }
Err(ReadlineError::Interrupted) => break, Err(ReadlineError::Interrupted) => break,
_ => break, _ => break,
@ -74,8 +74,7 @@ pub fn start(mut parser: &mut parser::Context, precision: u32) {
} }
fn eval_repl(parser: &mut parser::Context, input: &str, precision: u32) { fn eval_repl(parser: &mut parser::Context, input: &str, precision: u32) {
if input.starts_with("load ") { if let Some(file_name) = input.strip_prefix("load ") {
let file_name = &input[5..];
if let Some(file_path) = crate::get_input_file_by_name(file_name) { if let Some(file_path) = crate::get_input_file_by_name(file_name) {
crate::load_input_file(&file_path, precision, parser); crate::load_input_file(&file_path, precision, parser);
} else { } else {
@ -216,7 +215,7 @@ impl Completer for RLHelper {
fn update(&self, line: &mut rustyline::line_buffer::LineBuffer, start: usize, elected: &str) { fn update(&self, line: &mut rustyline::line_buffer::LineBuffer, start: usize, elected: &str) {
line.backspace(line.pos() - start); line.backspace(line.pos() - start);
line.insert_str(line.pos(), elected); line.insert_str(line.pos(), elected);
line.move_forward(if elected.ends_with(")") || elected.ends_with("") { line.move_forward(if elected.ends_with(')') || elected.ends_with('⟧') {
elected.chars().count() - 1 elected.chars().count() - 1
} else { } else {
elected.chars().count() elected.chars().count()
@ -242,7 +241,7 @@ impl Highlighter for RLHelper {
} }
fn highlight_char(&self, line: &str, _: usize) -> bool { fn highlight_char(&self, line: &str, _: usize) -> bool {
line.len() > 0 !line.is_empty()
} }
} }

View File

@ -83,18 +83,12 @@ fn analyse_stmt_expr(context: &mut Context, value: Expr) -> Result<Stmt, CalcErr
build_fn_decl(context, *identifier_expr, *parameter_expr, *right)? build_fn_decl(context, *identifier_expr, *parameter_expr, *right)?
} }
Expr::Var(identifier) if !context.in_conditional => { Expr::Var(identifier) if !context.in_conditional => {
if inverter::contains_var( if inverter::contains_var(context.symbol_table, &right, &identifier.full_name) {
&mut context.symbol_table,
&right,
&identifier.full_name,
) {
return Err(CalcError::VariableReferencesItself); return Err(CalcError::VariableReferencesItself);
} }
if prelude::is_constant(&identifier.full_name) { if prelude::is_constant(&identifier.full_name) {
return Err(CalcError::UnableToOverrideConstant( return Err(CalcError::UnableToOverrideConstant(identifier.pure_name));
identifier.pure_name.into(),
));
} }
let result = let result =
@ -129,14 +123,10 @@ fn build_fn_decl(
Expr::Vector(exprs) => { Expr::Vector(exprs) => {
exprs exprs
.iter() .iter()
.any(|x| if let Expr::Var(_) = x { true } else { false }) .any(|x| matches!(x, Expr::Var(_)))
} }
Expr::Group(expr) => { Expr::Group(expr) => {
if let Expr::Var(_) = &**expr { matches!(&**expr, Expr::Var(_))
true
} else {
false
}
} }
_ => false, _ => false,
}; };
@ -266,8 +256,8 @@ fn analyse_expr(context: &mut Context, expr: Expr) -> Result<Expr, CalcError> {
}) })
} }
fn analyse_binary<'a>( fn analyse_binary(
context: &'a mut Context, context: &mut Context,
left: Expr, left: Expr,
op: TokenKind, op: TokenKind,
right: Expr, right: Expr,
@ -286,7 +276,7 @@ fn analyse_binary<'a>(
// If it has already been set to false manually somewhere else, // If it has already been set to false manually somewhere else,
// abort and analyse as a comparison instead. // abort and analyse as a comparison instead.
if context.in_equation == false { if !context.in_equation {
context.in_conditional = true; context.in_conditional = true;
let result = analyse_binary(context, left, op, right); let result = analyse_binary(context, left, op, right);
context.in_conditional = previous_in_conditional; context.in_conditional = previous_in_conditional;
@ -306,7 +296,7 @@ fn analyse_binary<'a>(
return result; return result;
}; };
let inverted = if inverter::contains_var(&mut context.symbol_table, &left, var_name) { let inverted = if inverter::contains_var(context.symbol_table, &left, var_name) {
left.invert_to_target(context.symbol_table, right, var_name)? left.invert_to_target(context.symbol_table, right, var_name)?
} else { } else {
right.invert_to_target(context.symbol_table, left, var_name)? right.invert_to_target(context.symbol_table, left, var_name)?
@ -441,20 +431,20 @@ fn analyse_comparison_with_var(
match op { match op {
TokenKind::GreaterThan => { TokenKind::GreaterThan => {
ranged_var.min = Expr::Binary( ranged_var.min = Expr::Binary(
Box::new(right.clone()), Box::new(right),
TokenKind::Plus, TokenKind::Plus,
Box::new(Expr::Literal(1f64)), Box::new(Expr::Literal(1f64)),
); );
} }
TokenKind::LessThan => { TokenKind::LessThan => {
ranged_var.max = right.clone(); ranged_var.max = right;
} }
TokenKind::GreaterOrEquals => { TokenKind::GreaterOrEquals => {
ranged_var.min = right.clone(); ranged_var.min = right;
} }
TokenKind::LessOrEquals => { TokenKind::LessOrEquals => {
ranged_var.max = Expr::Binary( ranged_var.max = Expr::Binary(
Box::new(right.clone()), Box::new(right),
TokenKind::Plus, TokenKind::Plus,
Box::new(Expr::Literal(1f64)), Box::new(Expr::Literal(1f64)),
); );
@ -526,7 +516,7 @@ fn analyse_var(
) )
} else if context } else if context
.symbol_table .symbol_table
.contains_var(&identifier.get_name_without_lowered()) .contains_var(identifier.get_name_without_lowered())
{ {
with_adjacent( with_adjacent(
build_indexed_var(context, identifier)?, build_indexed_var(context, identifier)?,
@ -653,21 +643,22 @@ fn build_fn_call(
context.in_sum_prod = false; context.in_sum_prod = false;
} }
return Ok(Expr::FnCall(identifier, arguments)); Ok(Expr::FnCall(identifier, arguments))
} }
fn build_indexed_var(context: &mut Context, identifier: Identifier) -> Result<Expr, CalcError> { fn build_indexed_var(context: &mut Context, identifier: Identifier) -> Result<Expr, CalcError> {
let underscore_pos = identifier.pure_name.find('_').unwrap(); let underscore_pos = identifier.pure_name.find('_').unwrap();
let var_name = &identifier.pure_name[0..underscore_pos]; let var_name = &identifier.pure_name[0..underscore_pos];
let lowered = &identifier.pure_name[underscore_pos + 1..]; let lowered = &identifier.pure_name[underscore_pos + 1..];
let lowered_expr = if lowered.len() > 0 && lowered.chars().nth(0).unwrap_or('\0').is_digit(10) { let lowered_expr = if !lowered.is_empty() && lowered.chars().next().unwrap_or('\0').is_digit(10)
{
Expr::Literal(lowered.parse::<f64>().unwrap_or(f64::NAN)) Expr::Literal(lowered.parse::<f64>().unwrap_or(f64::NAN))
} else { } else {
build_var(context, lowered) build_var(context, lowered)
}; };
Ok(Expr::Indexer( Ok(Expr::Indexer(
Box::new(build_var(context, &var_name)), Box::new(build_var(context, var_name)),
vec![lowered_expr], vec![lowered_expr],
)) ))
} }
@ -677,10 +668,10 @@ fn build_dx(
name_without_dx: &str, name_without_dx: &str,
char_after_d: char, char_after_d: char,
) -> Result<Expr, CalcError> { ) -> Result<Expr, CalcError> {
if name_without_dx.len() == 0 { if name_without_dx.is_empty() {
Ok(Expr::Var(Identifier::from_full_name(&format!( Ok(Expr::Var(Identifier::from_full_name(&format!(
"d{}", "d{}",
char_after_d.to_string() char_after_d
)))) ))))
} else { } else {
Ok(Expr::Binary( Ok(Expr::Binary(
@ -693,7 +684,7 @@ fn build_dx(
TokenKind::Star, TokenKind::Star,
Box::new(Expr::Var(Identifier::from_full_name(&format!( Box::new(Expr::Var(Identifier::from_full_name(&format!(
"d{}", "d{}",
char_after_d.to_string() char_after_d
)))), )))),
)) ))
} }
@ -754,7 +745,7 @@ fn build_var(context: &mut Context, name: &str) -> Expr {
context.current_function_name.as_ref(), context.current_function_name.as_ref(),
context.current_function_parameters.as_ref(), context.current_function_parameters.as_ref(),
) { ) {
let identifier = Identifier::parameter_from_name(name, &function_name); let identifier = Identifier::parameter_from_name(name, function_name);
if params.contains(&identifier.full_name) { if params.contains(&identifier.full_name) {
return Expr::Var(identifier); return Expr::Var(identifier);
} }

View File

@ -116,7 +116,7 @@ fn separate_identifier_and_prime(identifier: &str) -> (String, u32) {
let mut pure_identifier = identifier.to_string(); let mut pure_identifier = identifier.to_string();
loop { loop {
if pure_identifier.ends_with("'") { if pure_identifier.ends_with('\'') {
pure_identifier.pop(); pure_identifier.pop();
prim_count += 1; prim_count += 1;
} else { } else {

View File

@ -22,8 +22,8 @@ impl CalculationResult {
} }
#[wasm_bindgen(js_name = toString)] #[wasm_bindgen(js_name = toString)]
pub fn to_string(&self) -> String { pub fn to_js_string(&self) -> String {
self.value.to_string() self.to_string()
} }
#[wasm_bindgen(js_name = toStringBig)] #[wasm_bindgen(js_name = toStringBig)]
@ -71,3 +71,9 @@ impl CalculationResult {
self.value.estimate() self.value.estimate()
} }
} }
impl std::fmt::Display for CalculationResult {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.value)
}
}

View File

@ -42,7 +42,7 @@ pub fn integrate_with_unknown_variable(
// integral(a, b, expr dx) // integral(a, b, expr dx)
if let Expr::Binary(_, TokenKind::Star, right) = expr { if let Expr::Binary(_, TokenKind::Star, right) = expr {
if let Expr::Var(right_name) = &**right { if let Expr::Var(right_name) = &**right {
if right_name.full_name.starts_with("d") { if right_name.full_name.starts_with('d') {
// Take the value, but remove the d, so that only eg. x is left from dx // Take the value, but remove the d, so that only eg. x is left from dx
integration_variable = Some(&right_name.full_name[1..]); integration_variable = Some(&right_name.full_name[1..]);
} }
@ -89,7 +89,7 @@ fn simpsons_rule(
const N: i32 = 900; const N: i32 = 900;
let a = interpreter::eval_expr(context, a_expr, "")?; let a = interpreter::eval_expr(context, a_expr, "")?;
let b = interpreter::eval_expr(context, b_expr, "")?; let b = interpreter::eval_expr(context, b_expr, "")?;
let h = (b.sub_without_unit(&a.clone())).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()
@ -143,7 +143,7 @@ mod tests {
use crate::symbol_table::SymbolTable; use crate::symbol_table::SymbolTable;
use crate::test_helpers::*; use crate::test_helpers::*;
fn get_context<'a>(symbol_table: &'a mut SymbolTable) -> interpreter::Context<'a> { fn get_context(symbol_table: &mut SymbolTable) -> interpreter::Context {
interpreter::Context::new( interpreter::Context::new(
symbol_table, symbol_table,
"", "",

View File

@ -35,7 +35,7 @@ impl<'a> Context<'a> {
precision, precision,
sum_n_value: None, sum_n_value: None,
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
timeout: timeout, timeout,
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
start_time: std::time::SystemTime::now(), start_time: std::time::SystemTime::now(),
} }
@ -80,7 +80,7 @@ fn eval_stmt(context: &mut Context, stmt: &Stmt) -> Result<KalkValue, CalcError>
Stmt::VarDecl(_, _) => eval_var_decl_stmt(context, stmt), Stmt::VarDecl(_, _) => eval_var_decl_stmt(context, stmt),
Stmt::FnDecl(_, _, _) => eval_fn_decl_stmt(), Stmt::FnDecl(_, _, _) => eval_fn_decl_stmt(),
Stmt::UnitDecl(_, _, _) => eval_unit_decl_stmt(), Stmt::UnitDecl(_, _, _) => eval_unit_decl_stmt(),
Stmt::Expr(expr) => eval_expr_stmt(context, &expr), Stmt::Expr(expr) => eval_expr_stmt(context, expr),
} }
} }
@ -98,7 +98,7 @@ fn eval_unit_decl_stmt() -> Result<KalkValue, CalcError> {
} }
fn eval_expr_stmt(context: &mut Context, expr: &Expr) -> Result<KalkValue, CalcError> { fn eval_expr_stmt(context: &mut Context, expr: &Expr) -> Result<KalkValue, CalcError> {
eval_expr(context, &expr, "") eval_expr(context, expr, "")
} }
pub(crate) fn eval_expr( pub(crate) fn eval_expr(
@ -114,12 +114,12 @@ pub(crate) fn eval_expr(
} }
match expr { match expr {
Expr::Binary(left, op, right) => eval_binary_expr(context, &left, op, &right, unit), Expr::Binary(left, op, right) => eval_binary_expr(context, left, op, right, unit),
Expr::Unary(op, expr) => eval_unary_expr(context, op, expr, unit), Expr::Unary(op, expr) => eval_unary_expr(context, op, expr, unit),
Expr::Unit(identifier, expr) => eval_unit_expr(context, identifier, expr), Expr::Unit(identifier, expr) => eval_unit_expr(context, identifier, expr),
Expr::Var(identifier) => eval_var_expr(context, identifier, unit), Expr::Var(identifier) => eval_var_expr(context, identifier, unit),
Expr::Literal(value) => eval_literal_expr(context, *value, unit), Expr::Literal(value) => eval_literal_expr(context, *value, unit),
Expr::Group(expr) => eval_group_expr(context, &expr, unit), Expr::Group(expr) => eval_group_expr(context, expr, unit),
Expr::FnCall(identifier, expressions) => { Expr::FnCall(identifier, expressions) => {
eval_fn_call_expr(context, identifier, expressions, unit) eval_fn_call_expr(context, identifier, expressions, unit)
} }
@ -177,7 +177,7 @@ fn eval_binary_expr(
_ => KalkValue::from(1), _ => KalkValue::from(1),
}; };
if unit.len() > 0 { if !unit.is_empty() {
if let KalkValue::Number(real, imaginary, _) = result { if let KalkValue::Number(real, imaginary, _) = result {
return Ok(KalkValue::Number(real, imaginary, unit.to_string())); return Ok(KalkValue::Number(real, imaginary, unit.to_string()));
} }
@ -192,7 +192,7 @@ fn eval_unary_expr(
expr: &Expr, expr: &Expr,
unit: &str, unit: &str,
) -> Result<KalkValue, CalcError> { ) -> Result<KalkValue, CalcError> {
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 => Ok(num.mul(context, KalkValue::from(-1f64))),
@ -318,7 +318,7 @@ pub(crate) fn eval_fn_call_expr(
return Ok( return Ok(
prelude::call_vector_func(&identifier.full_name, KalkValue::Vector(values)) prelude::call_vector_func(&identifier.full_name, KalkValue::Vector(values))
.unwrap_or(KalkValue::nan()), .unwrap_or_else(KalkValue::nan),
); );
} }
@ -327,7 +327,7 @@ pub(crate) fn eval_fn_call_expr(
1 => { 1 => {
let x = eval_expr(context, &expressions[0], "")?; let x = eval_expr(context, &expressions[0], "")?;
if identifier.prime_count > 0 { if identifier.prime_count > 0 {
return calculus::derive_func(context, &identifier, x); return calculus::derive_func(context, identifier, x);
} else { } else {
prelude::call_unary_func( prelude::call_unary_func(
context, context,
@ -496,7 +496,7 @@ pub(crate) fn eval_fn_call_expr(
// Initialise the arguments as their own variables. // Initialise the arguments as their own variables.
let mut new_argument_values = Vec::new(); let mut new_argument_values = Vec::new();
for (i, argument) in arguments.iter().enumerate() { for (i, argument) in arguments.iter().enumerate() {
let argument_identifier = if argument.contains("-") { let argument_identifier = if argument.contains('-') {
let identifier_parts: Vec<&str> = argument.split('-').collect(); let identifier_parts: Vec<&str> = argument.split('-').collect();
Identifier::parameter_from_name(identifier_parts[1], identifier_parts[0]) Identifier::parameter_from_name(identifier_parts[1], identifier_parts[0])
} else { } else {
@ -533,10 +533,8 @@ pub(crate) fn eval_fn_call_expr(
let fn_value = eval_expr(context, &fn_body, unit); let fn_value = eval_expr(context, &fn_body, unit);
// Revert to original argument values // Revert to original argument values
for old_argument_value in old_argument_values { for old_argument_value in old_argument_values.into_iter().flatten() {
if let Some(old_argument_value) = old_argument_value { context.symbol_table.insert(old_argument_value);
context.symbol_table.insert(old_argument_value);
}
} }
fn_value fn_value
@ -547,13 +545,13 @@ pub(crate) fn eval_fn_call_expr(
fn eval_piecewise( fn eval_piecewise(
context: &mut Context, context: &mut Context,
pieces: &Vec<crate::ast::ConditionalPiece>, pieces: &[crate::ast::ConditionalPiece],
unit: &str, unit: &str,
) -> Result<KalkValue, CalcError> { ) -> Result<KalkValue, CalcError> {
for piece in pieces { for piece in pieces {
if let KalkValue::Boolean(condition_is_true) = eval_expr(context, &piece.condition, unit)? { if let KalkValue::Boolean(condition_is_true) = eval_expr(context, &piece.condition, unit)? {
if condition_is_true { if condition_is_true {
return Ok(eval_expr(context, &piece.expr, unit)?); return eval_expr(context, &piece.expr, unit);
} }
} }
} }
@ -561,7 +559,7 @@ fn eval_piecewise(
Err(CalcError::PiecewiseConditionsAreFalse) Err(CalcError::PiecewiseConditionsAreFalse)
} }
fn eval_vector(context: &mut Context, values: &Vec<Expr>) -> Result<KalkValue, CalcError> { fn eval_vector(context: &mut Context, values: &[Expr]) -> Result<KalkValue, CalcError> {
let mut eval_values = Vec::new(); let mut eval_values = Vec::new();
for value in values { for value in values {
eval_values.push(eval_expr(context, value, "")?); eval_values.push(eval_expr(context, value, "")?);
@ -570,7 +568,7 @@ fn eval_vector(context: &mut Context, values: &Vec<Expr>) -> Result<KalkValue, C
Ok(KalkValue::Vector(eval_values)) Ok(KalkValue::Vector(eval_values))
} }
fn eval_matrix(context: &mut Context, rows: &Vec<Vec<Expr>>) -> Result<KalkValue, CalcError> { fn eval_matrix(context: &mut Context, rows: &[Vec<Expr>]) -> Result<KalkValue, CalcError> {
let mut eval_rows = Vec::new(); let mut eval_rows = Vec::new();
for row in rows { for row in rows {
let mut eval_row = Vec::new(); let mut eval_row = Vec::new();
@ -783,27 +781,27 @@ mod tests {
assert_eq!(interpret(pow).unwrap().unwrap().to_f64(), 8f64); assert_eq!(interpret(pow).unwrap().unwrap().to_f64(), 8f64);
let result = interpret(equals).unwrap().unwrap(); let result = interpret(equals).unwrap().unwrap();
assert_eq!(bool(&result), false); assert!(!bool(&result));
assert!(result.to_f64().is_nan()); assert!(result.to_f64().is_nan());
let result = interpret(not_equals).unwrap().unwrap(); let result = interpret(not_equals).unwrap().unwrap();
assert_eq!(bool(&result), true); assert!(bool(&result));
assert!(result.to_f64().is_nan()); assert!(result.to_f64().is_nan());
let result = interpret(greater_than).unwrap().unwrap(); let result = interpret(greater_than).unwrap().unwrap();
assert_eq!(bool(&result), false); assert!(!bool(&result));
assert!(result.to_f64().is_nan()); assert!(result.to_f64().is_nan());
let result = interpret(less_than).unwrap().unwrap(); let result = interpret(less_than).unwrap().unwrap();
assert_eq!(bool(&result), true); assert!(bool(&result));
assert!(result.to_f64().is_nan()); assert!(result.to_f64().is_nan());
let result = interpret(greater_or_equals).unwrap().unwrap(); let result = interpret(greater_or_equals).unwrap().unwrap();
assert_eq!(bool(&result), false); assert!(!bool(&result));
assert!(result.to_f64().is_nan()); assert!(result.to_f64().is_nan());
let result = interpret(less_or_equals).unwrap().unwrap(); let result = interpret(less_or_equals).unwrap().unwrap();
assert_eq!(bool(&result), true); assert!(bool(&result));
assert!(result.to_f64().is_nan()); assert!(result.to_f64().is_nan());
} }

View File

@ -70,11 +70,11 @@ fn invert(
) -> Result<(Expr, Expr), CalcError> { ) -> Result<(Expr, Expr), CalcError> {
match expr { match expr {
Expr::Binary(left, op, right) => { Expr::Binary(left, op, right) => {
invert_binary(target_expr, symbol_table, &left, op, &right, unknown_var) invert_binary(target_expr, symbol_table, left, op, right, unknown_var)
} }
Expr::Unary(op, expr) => invert_unary(target_expr, op, &expr), Expr::Unary(op, expr) => invert_unary(target_expr, op, expr),
Expr::Unit(identifier, expr) => { Expr::Unit(identifier, expr) => {
invert_unit(target_expr, symbol_table, &identifier, &expr, unknown_var) invert_unit(target_expr, symbol_table, identifier, expr, unknown_var)
} }
Expr::Var(identifier) => invert_var(target_expr, symbol_table, identifier, unknown_var), Expr::Var(identifier) => invert_var(target_expr, symbol_table, identifier, unknown_var),
Expr::Group(expr) => Ok((target_expr, *expr.clone())), Expr::Group(expr) => Ok((target_expr, *expr.clone())),
@ -153,7 +153,7 @@ fn invert_binary(
return invert( return invert(
target_expr, target_expr,
symbol_table, symbol_table,
&Expr::Binary(inside_group.clone(), op.clone(), Box::new(right.clone())), &Expr::Binary(inside_group.clone(), *op, Box::new(right.clone())),
unknown_var, unknown_var,
); );
} }
@ -164,7 +164,7 @@ fn invert_binary(
return invert( return invert(
target_expr, target_expr,
symbol_table, symbol_table,
&Expr::Binary(Box::new(left.clone()), op.clone(), inside_group.clone()), &Expr::Binary(Box::new(left.clone()), *op, inside_group.clone()),
unknown_var, unknown_var,
); );
} }
@ -208,17 +208,17 @@ fn invert_binary(
))); )));
} }
return Ok(invert( return invert(
Expr::Binary(Box::new(target_expr), op_inv, Box::new(right.clone())), Expr::Binary(Box::new(target_expr), op_inv, Box::new(right.clone())),
symbol_table, symbol_table,
left, left,
unknown_var, unknown_var,
)?); );
} }
// Otherwise, invert the left side. // Otherwise, invert the left side.
let final_target_expr = Expr::Binary(Box::new(target_expr), op_inv, Box::new(left.clone())); let final_target_expr = Expr::Binary(Box::new(target_expr), op_inv, Box::new(left.clone()));
Ok(invert( invert(
// Eg. 2-a // Eg. 2-a
// If the operator is minus (and the left expression is being inverted), // If the operator is minus (and the left expression is being inverted),
// make the target expression negative to keep balance. // make the target expression negative to keep balance.
@ -230,7 +230,7 @@ fn invert_binary(
symbol_table, symbol_table,
right, // Then invert the right expression. right, // Then invert the right expression.
unknown_var, unknown_var,
)?) )
} }
fn invert_unary(target_expr: Expr, op: &TokenKind, expr: &Expr) -> Result<(Expr, Expr), CalcError> { fn invert_unary(target_expr: Expr, op: &TokenKind, expr: &Expr) -> Result<(Expr, Expr), CalcError> {
@ -240,7 +240,7 @@ fn invert_unary(target_expr: Expr, op: &TokenKind, expr: &Expr) -> Result<(Expr,
Expr::Unary(TokenKind::Minus, Box::new(target_expr)), Expr::Unary(TokenKind::Minus, Box::new(target_expr)),
expr.clone(), // And then continue inverting the inner-expression. expr.clone(), // And then continue inverting the inner-expression.
)), )),
_ => return Err(CalcError::UnableToInvert(String::new())), _ => Err(CalcError::UnableToInvert(String::new())),
} }
} }
@ -280,7 +280,7 @@ fn invert_fn_call(
target_expr: Expr, target_expr: Expr,
symbol_table: &mut SymbolTable, symbol_table: &mut SymbolTable,
identifier: &Identifier, identifier: &Identifier,
arguments: &Vec<Expr>, arguments: &[Expr],
unknown_var: &str, unknown_var: &str,
) -> Result<(Expr, Expr), CalcError> { ) -> Result<(Expr, Expr), CalcError> {
// If prelude function // If prelude function
@ -409,17 +409,17 @@ fn multiply_into(expr: &Expr, base_expr: &Expr) -> Result<Expr, CalcError> {
Expr::Binary(left, op, right) => match op { Expr::Binary(left, op, right) => match op {
// If + or -, multiply the expression with each term. // If + or -, multiply the expression with each term.
TokenKind::Plus | TokenKind::Minus => Ok(Expr::Binary( TokenKind::Plus | TokenKind::Minus => Ok(Expr::Binary(
Box::new(multiply_into(expr, &left)?), Box::new(multiply_into(expr, left)?),
op.clone(), *op,
Box::new(multiply_into(expr, &right)?), Box::new(multiply_into(expr, right)?),
)), )),
// If * or /, only multiply with the first factor. // If * or /, only multiply with the first factor.
TokenKind::Star | TokenKind::Slash => Ok(Expr::Binary( TokenKind::Star | TokenKind::Slash => Ok(Expr::Binary(
Box::new(multiply_into(expr, &left)?), Box::new(multiply_into(expr, left)?),
op.clone(), *op,
right.clone(), right.clone(),
)), )),
_ => return Err(CalcError::UnableToInvert(String::new())), _ => Err(CalcError::UnableToInvert(String::new())),
}, },
// If it's a literal, just multiply them together. // If it's a literal, just multiply them together.
Expr::Literal(_) | Expr::Var(_) => Ok(Expr::Binary( Expr::Literal(_) | Expr::Var(_) => Ok(Expr::Binary(
@ -430,7 +430,7 @@ fn multiply_into(expr: &Expr, base_expr: &Expr) -> Result<Expr, CalcError> {
Expr::Group(_) => Err(CalcError::UnableToInvert(String::from( Expr::Group(_) => Err(CalcError::UnableToInvert(String::from(
"Parenthesis multiplied with parenthesis (this should be possible in the future).", "Parenthesis multiplied with parenthesis (this should be possible in the future).",
))), ))),
_ => return Err(CalcError::UnableToInvert(String::new())), _ => Err(CalcError::UnableToInvert(String::new())),
} }
} }

View File

@ -147,7 +147,13 @@ pub enum ComplexNumberType {
#[wasm_bindgen] #[wasm_bindgen]
impl ScientificNotation { impl ScientificNotation {
#[wasm_bindgen(js_name = toString)] #[wasm_bindgen(js_name = toString)]
pub fn to_string(&self) -> String { pub fn to_js_string(&self) -> String {
self.to_string()
}
}
impl std::fmt::Display for ScientificNotation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let sign = if self.negative { "-" } else { "" }; let sign = if self.negative { "-" } else { "" };
let digits_and_mul = if self.value == 1f64 { let digits_and_mul = if self.value == 1f64 {
String::new() String::new()
@ -155,7 +161,8 @@ impl ScientificNotation {
format!("{}×", format_number(self.value)) format!("{}×", format_number(self.value))
}; };
format!( write!(
f,
"{}{}10^{} {}", "{}{}10^{} {}",
sign, sign,
digits_and_mul, digits_and_mul,
@ -176,12 +183,8 @@ pub enum KalkValue {
Matrix(Vec<Vec<KalkValue>>), Matrix(Vec<Vec<KalkValue>>),
} }
impl KalkValue { impl std::fmt::Display for KalkValue {
pub fn nan() -> Self { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
KalkValue::Number(float!(f64::NAN), float!(0f64), String::new())
}
pub fn to_string(&self) -> String {
match self { match self {
KalkValue::Number(real, imaginary, _) => { KalkValue::Number(real, imaginary, _) => {
let as_str = format_number(primitive!(real)); let as_str = format_number(primitive!(real));
@ -191,23 +194,24 @@ impl KalkValue {
let sign = if imaginary < &0f64 { "-" } else { "+" }; let sign = if imaginary < &0f64 { "-" } else { "+" };
if &as_str == "0" { if &as_str == "0" {
imaginary_as_str write!(f, "{}", imaginary_as_str)
} else { } else {
format!("{} {} {}i", as_str, sign, imaginary_as_str) write!(f, "{} {} {}i", as_str, sign, imaginary_as_str)
} }
} else { } else {
as_str write!(f, "{}", as_str)
} }
} }
KalkValue::Boolean(is_true) => { KalkValue::Boolean(is_true) => {
if *is_true { if *is_true {
String::from("true") write!(f, "true")
} else { } else {
String::from("false") write!(f, "false")
} }
} }
KalkValue::Vector(values) => { KalkValue::Vector(values) => {
format!( write!(
f,
"({})", "({})",
values values
.iter() .iter()
@ -245,10 +249,16 @@ impl KalkValue {
result.pop(); // Trailing comma result.pop(); // Trailing comma
result.push(']'); result.push(']');
result write!(f, "{}", result)
} }
} }
} }
}
impl KalkValue {
pub fn nan() -> Self {
KalkValue::Number(float!(f64::NAN), float!(0f64), String::new())
}
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 {
@ -257,7 +267,7 @@ impl KalkValue {
} }
let sign = if imaginary < &0f64 { "-" } else { "+" }; let sign = if imaginary < &0f64 { "-" } else { "+" };
format!("{} {} {}", real.to_string(), sign, imaginary.to_string()) format!("{} {} {}", real, sign, imaginary)
} else { } else {
self.to_string() self.to_string()
} }
@ -304,12 +314,10 @@ impl KalkValue {
} else if sci_notation_real.exponent <= -14 { } else if sci_notation_real.exponent <= -14 {
new_real = float!(0); new_real = float!(0);
String::from("0") String::from("0")
} else if radix == 10 {
sci_notation_real.to_string().trim().to_string()
} else { } else {
if radix == 10 { return String::new();
sci_notation_real.to_string().trim().to_string()
} else {
return String::new();
}
}; };
let sci_notation_imaginary = self.to_scientific_notation(ComplexNumberType::Imaginary); let sci_notation_imaginary = self.to_scientific_notation(ComplexNumberType::Imaginary);
@ -321,12 +329,10 @@ impl KalkValue {
} else if sci_notation_imaginary.exponent <= -14 { } else if sci_notation_imaginary.exponent <= -14 {
new_imaginary = float!(0); new_imaginary = float!(0);
String::from("0") String::from("0")
} else if radix == 10 {
sci_notation_imaginary.to_string().trim().to_string()
} else { } else {
if radix == 10 { return String::new();
format!("{}", sci_notation_imaginary.to_string().trim())
} else {
return String::new();
}
}; };
let mut output = result_str; let mut output = result_str;
@ -338,18 +344,18 @@ impl KalkValue {
} }
// If there is a real value as well // If there is a real value as well
if output.len() > 0 { if !output.is_empty() {
output.push_str(&format!( output.push_str(&format!(
" {} {}", " {} {}",
if imaginary < &0f64 { "-" } else { "+" }, if imaginary < &0f64 { "-" } else { "+" },
result_str_imaginary.trim_start_matches("-"), result_str_imaginary.trim_start_matches('-'),
)); ));
} else { } else {
output.push_str(&format!("{}", result_str_imaginary)); output.push_str(&result_str_imaginary);
} }
} }
if unit != "" { if !unit.is_empty() {
output.push_str(&format!(" {}", unit)); output.push_str(&format!(" {}", unit));
} }
@ -370,7 +376,7 @@ impl KalkValue {
pub fn to_string_with_unit(&self) -> String { pub fn to_string_with_unit(&self) -> String {
match self { match self {
KalkValue::Number(_, _, unit) => format!("{} {}", self.to_string(), unit), KalkValue::Number(_, _, unit) => format!("{} {}", self, unit),
_ => self.to_string(), _ => self.to_string(),
} }
} }
@ -408,11 +414,11 @@ impl KalkValue {
if value == "0" { if value == "0" {
// If both values ended up being estimated as zero, // If both values ended up being estimated as zero,
// return zero. // return zero.
if output.len() == 0 { if output.is_empty() {
return Some(String::from("0")); return Some(String::from("0"));
} }
} else { } else {
let sign = if value.starts_with("-") { "-" } else { "+" }; let sign = if value.starts_with('-') { "-" } else { "+" };
let value = match value.as_ref() { let value = match value.as_ref() {
"1" => String::from("i"), "1" => String::from("i"),
"-1" => String::from("-i"), "-1" => String::from("-i"),
@ -420,8 +426,8 @@ impl KalkValue {
}; };
// If there is a real value as well // If there is a real value as well
if output.len() > 0 { if !output.is_empty() {
output.push_str(&format!(" {} {}", sign, value.trim_start_matches("-"))); output.push_str(&format!(" {} {}", sign, value.trim_start_matches('-')));
} else { } else {
output.push_str(&value); output.push_str(&value);
} }
@ -500,7 +506,7 @@ impl KalkValue {
ComplexNumberType::Real => self.to_f64(), ComplexNumberType::Real => self.to_f64(),
ComplexNumberType::Imaginary => self.imaginary_to_f64(), ComplexNumberType::Imaginary => self.imaginary_to_f64(),
}; };
let exponent = value.clone().abs().log10().floor() as i32 + 1; let exponent = value.abs().log10().floor() as i32 + 1;
ScientificNotation { ScientificNotation {
negative: value < 0f64, negative: value < 0f64,
@ -513,7 +519,7 @@ impl KalkValue {
pub fn has_unit(&self) -> bool { pub fn has_unit(&self) -> bool {
if let KalkValue::Number(_, _, unit) = self { if let KalkValue::Number(_, _, unit) = self {
unit.len() > 0 !unit.is_empty()
} else { } else {
false false
} }
@ -536,7 +542,7 @@ impl KalkValue {
let result = crate::interpreter::convert_unit( let result = crate::interpreter::convert_unit(
context, context,
&Expr::Literal(primitive!(real)), &Expr::Literal(primitive!(real)),
&unit, unit,
to_unit, to_unit,
); );
@ -582,7 +588,7 @@ impl KalkValue {
context: &mut crate::interpreter::Context, context: &mut crate::interpreter::Context,
rhs: KalkValue, rhs: KalkValue,
) -> KalkValue { ) -> KalkValue {
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs.clone()); let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
self.div_without_unit(&right) self.div_without_unit(&right)
} }
@ -649,7 +655,7 @@ impl KalkValue {
context: &mut crate::interpreter::Context, context: &mut crate::interpreter::Context,
rhs: KalkValue, rhs: KalkValue,
) -> KalkValue { ) -> KalkValue {
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs.clone()); 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),
@ -665,7 +671,7 @@ impl KalkValue {
context: &mut crate::interpreter::Context, context: &mut crate::interpreter::Context,
rhs: KalkValue, rhs: KalkValue,
) -> KalkValue { ) -> KalkValue {
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs.clone()); 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),
@ -824,10 +830,7 @@ impl KalkValue {
pub(crate) fn div_without_unit(self, rhs: &KalkValue) -> KalkValue { pub(crate) fn div_without_unit(self, rhs: &KalkValue) -> KalkValue {
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) KalkValue::Number(real / real_rhs, float!(0f64), unit)
@ -836,7 +839,7 @@ impl KalkValue {
// 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.clone().mul_without_unit(&conjugate.clone()).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( KalkValue::Number(
numerator / denominator.clone(), numerator / denominator.clone(),
@ -861,10 +864,12 @@ impl KalkValue {
KalkValue::Number(real, imaginary, _), KalkValue::Number(real, imaginary, _),
KalkValue::Number(real_rhs, imaginary_rhs, unit), KalkValue::Number(real_rhs, imaginary_rhs, unit),
) => { ) => {
if self.has_imaginary() || imaginary_rhs != &0f64 || (real < 0f64 && real_rhs < &1f64) if self.has_imaginary()
|| imaginary_rhs != &0f64
|| (real < 0f64 && real_rhs < &1f64)
{ {
let a = real.clone(); let a = real;
let b = imaginary.clone(); 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;
@ -935,7 +940,7 @@ impl KalkValue {
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;
} }
@ -949,7 +954,7 @@ impl KalkValue {
(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;
} }
@ -1025,13 +1030,13 @@ impl KalkValue {
pub fn format_number(input: f64) -> String { pub fn format_number(input: f64) -> String {
let rounded = format!("{:.1$}", input, 10); let rounded = format!("{:.1$}", input, 10);
if rounded.contains(".") { if rounded.contains('.') {
rounded rounded
.trim_end_matches('0') .trim_end_matches('0')
.trim_end_matches('.') .trim_end_matches('.')
.to_string() .to_string()
} else { } else {
rounded.into() rounded
} }
} }
@ -1053,7 +1058,7 @@ fn calculate_vector(
values values
.iter() .iter()
.zip(values_rhs) .zip(values_rhs)
.map(|(x, y)| action(x.clone(), &y)) .map(|(x, y)| action(x.clone(), y))
.collect(), .collect(),
) )
} else { } else {
@ -1158,9 +1163,9 @@ fn pow(x: Float, y: Float) -> Float {
x.pow(y) x.pow(y)
} }
impl Into<String> for ScientificNotation { impl From<ScientificNotation> for String {
fn into(self) -> String { fn from(val: ScientificNotation) -> Self {
self.to_string() val.to_string()
} }
} }
@ -1178,15 +1183,15 @@ impl std::iter::Sum<KalkValue> for KalkValue {
} }
} }
impl Into<String> for KalkValue { impl From<KalkValue> for String {
fn into(self) -> String { fn from(val: KalkValue) -> Self {
self.to_string() val.to_string()
} }
} }
impl Into<f64> for KalkValue { impl From<KalkValue> for f64 {
fn into(self) -> f64 { fn from(val: KalkValue) -> Self {
self.to_f64() val.to_f64()
} }
} }

View File

@ -31,19 +31,19 @@ pub(super) fn estimate(
} }
// Eg. 0.5 to 1/2 // Eg. 0.5 to 1/2
let as_abs_string = value_string.trim_start_matches("-").to_string(); let as_abs_string = value_string.trim_start_matches('-').to_string();
let sign = if value < &0f64 { "-" } else { "" }; let sign = if value < &0f64 { "-" } else { "" };
if as_abs_string.starts_with("0.5") { if as_abs_string.starts_with("0.5")
if as_abs_string.len() == 3 || (as_abs_string.len() > 6 && &as_abs_string[3..5] == "00") { && (as_abs_string.len() == 3 || (as_abs_string.len() > 6 && &as_abs_string[3..5] == "00"))
return Some(format!("{}1/2", sign)); {
} return Some(format!("{}1/2", sign));
} }
// Eg. 1.33333333 to 1 + 1/3 // Eg. 1.33333333 to 1 + 1/3
if fract_as_string.len() >= 7 { if fract_as_string.len() >= 7 {
let first_five_decimals = &fract_as_string[2..7]; let first_five_decimals = &fract_as_string[2..7];
if first_five_decimals == "33333" || first_five_decimals == "66666" { if first_five_decimals == "33333" || first_five_decimals == "66666" {
let fraction = match first_five_decimals.as_ref() { let fraction = match first_five_decimals {
"33333" => "1/3", "33333" => "1/3",
"66666" => "2/3", "66666" => "2/3",
_ => "?", _ => "?",
@ -52,7 +52,7 @@ pub(super) fn estimate(
if integer == 0f64 { if integer == 0f64 {
return Some(format!("{}{}", sign, fraction)); return Some(format!("{}{}", sign, fraction));
} else { } else {
let explicit_sign = if sign == "" { "+" } else { "-" }; let explicit_sign = if sign.is_empty() { "+" } else { "-" };
return Some(format!( return Some(format!(
"{} {} {}", "{} {} {}",
trim_zeroes(&integer.to_string()), trim_zeroes(&integer.to_string()),
@ -66,7 +66,7 @@ pub(super) fn estimate(
// Match with common numbers, eg. π, 2π/3, √2 // Match with common numbers, eg. π, 2π/3, √2
if as_abs_string.len() >= 8 { if as_abs_string.len() >= 8 {
if let Some(constant) = CONSTANTS.get(&as_abs_string[0..8]) { if let Some(constant) = CONSTANTS.get(&as_abs_string[0..8]) {
return Some(format!("{}{}", sign, constant.to_string())); return Some(format!("{}{}", sign, constant));
} }
} }
@ -80,7 +80,7 @@ pub(super) fn estimate(
.values() .values()
.0; .0;
if squared.clone().sqrt().fract() != 0f64 && squared.clone().fract() == 0f64 { if squared.clone().sqrt().fract() != 0f64 && squared.clone().fract() == 0f64 {
return Some(format!("{}", squared.to_string())); return Some(format!("{}", squared));
} }
} }
@ -135,7 +135,7 @@ pub(super) fn round(
}; };
Some(new_num) Some(new_num)
} else if (1f64 - fract.clone()).log10() < limit_ceil { } else if (1f64 - fract).log10() < limit_ceil {
// If eg. 0.999 // If eg. 0.999
// .abs() this before ceiling to make sure it rounds correctly. The sign is re-added afterwards. // .abs() this before ceiling to make sure it rounds correctly. The sign is re-added afterwards.
let new_value = value.clone().abs().ceil() * sign; let new_value = value.clone().abs().ceil() * sign;
@ -155,10 +155,10 @@ pub(super) fn round(
} }
pub(super) fn trim_zeroes(input: &str) -> String { pub(super) fn trim_zeroes(input: &str) -> String {
if input.contains(".") { if input.contains('.') {
input input
.trim_end_matches("0") .trim_end_matches('0')
.trim_end_matches(".") .trim_end_matches('.')
.to_string() .to_string()
} else { } else {
input.into() input.into()

View File

@ -49,7 +49,7 @@ pub enum TokenKind {
Semicolon, Semicolon,
Newline, Newline,
EOF, Eof,
} }
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
@ -80,7 +80,7 @@ impl<'a> Lexer<'a> {
loop { loop {
let next = self.next(); let next = self.next();
if let TokenKind::EOF = next.kind { if let TokenKind::Eof = next.kind {
tokens.push(next); tokens.push(next);
break; break;
} else { } else {
@ -96,7 +96,7 @@ impl<'a> Lexer<'a> {
} }
fn next(&mut self) -> Token { fn next(&mut self) -> Token {
let eof = build(TokenKind::EOF, "", (self.index, self.index)); let eof = build(TokenKind::Eof, "", (self.index, self.index));
let mut c = if let Some(c) = self.peek() { let mut c = if let Some(c) = self.peek() {
*c *c
} else { } else {
@ -104,7 +104,7 @@ impl<'a> Lexer<'a> {
}; };
while c == ' ' || c == '\t' || c == '\r' { while c == ' ' || c == '\t' || c == '\r' {
if let None = self.advance() { if self.advance().is_none() {
return eof; return eof;
} }
@ -210,13 +210,7 @@ impl<'a> Lexer<'a> {
let mut leading_zero = self.peek().unwrap_or(&'\0') == &'0'; let mut leading_zero = self.peek().unwrap_or(&'\0') == &'0';
let mut base = 10u8; let mut base = 10u8;
loop { while let Some(c) = self.peek() {
let c = if let Some(c) = self.peek() {
*c
} else {
break;
};
// If at the second character and // If at the second character and
// the first character is a zero, // the first character is a zero,
// allow a letter // allow a letter
@ -239,15 +233,15 @@ impl<'a> Lexer<'a> {
} }
} }
if !c.is_digit(base as u32) && c != '.' && c != '_' && !c.is_whitespace() if !c.is_digit(base as u32) && *c != '.' && *c != '_' && !c.is_whitespace()
|| c == '\n' || *c == '\n'
|| c == '\r' || *c == '\r'
{ {
break; break;
} }
end += 1; end += 1;
value.push(c); value.push(*c);
self.advance(); self.advance();
} }
@ -258,7 +252,7 @@ impl<'a> Lexer<'a> {
self.advance(); self.advance();
} }
if base_str != "" { if !base_str.is_empty() {
base = crate::text_utils::subscript_to_normal(base_str.chars()) base = crate::text_utils::subscript_to_normal(base_str.chars())
.parse::<u8>() .parse::<u8>()
.unwrap_or(10); .unwrap_or(10);
@ -295,7 +289,7 @@ impl<'a> Lexer<'a> {
self.advance(); self.advance();
let num = self.next().value; let num = self.next().value;
value.push('_'); value.push('_');
value.push_str(&num.trim_end()); // Trim, since the number_literal function allows whitespace, which identifiers should not contain. value.push_str(num.trim_end()); // Trim, since the number_literal function allows whitespace, which identifiers should not contain.
break; break;
} }
@ -353,7 +347,7 @@ impl<'a> Lexer<'a> {
_ => value, // things like log_2 are handled in the parser _ => value, // things like log_2 are handled in the parser
}; };
if subscript.len() > 0 { if !subscript.is_empty() {
build( build(
kind, kind,
&format!( &format!(
@ -433,7 +427,7 @@ mod tests {
TokenKind::Equals, TokenKind::Equals,
TokenKind::Exclamation, TokenKind::Exclamation,
TokenKind::Comma, TokenKind::Comma,
TokenKind::EOF, TokenKind::Eof,
]; ];
match_tokens(tokens, expected); match_tokens(tokens, expected);
@ -449,7 +443,7 @@ mod tests {
TokenKind::LessThan, TokenKind::LessThan,
TokenKind::Literal, TokenKind::Literal,
TokenKind::ClosedBracket, TokenKind::ClosedBracket,
TokenKind::EOF, TokenKind::Eof,
]; ];
match_tokens(tokens, expected); match_tokens(tokens, expected);
@ -465,10 +459,10 @@ mod tests {
let tokens = Lexer::new(input).lex(); let tokens = Lexer::new(input).lex();
if regex::Regex::new(r"^\s*$").unwrap().is_match(input) { if regex::Regex::new(r"^\s*$").unwrap().is_match(input) {
let expected = vec![TokenKind::EOF]; let expected = vec![TokenKind::Eof];
match_tokens(tokens, expected); match_tokens(tokens, expected);
} else { } else {
let expected = vec![TokenKind::Identifier, TokenKind::EOF]; let expected = vec![TokenKind::Identifier, TokenKind::Eof];
match_tokens(tokens, expected); match_tokens(tokens, expected);
} }
} }
@ -479,7 +473,7 @@ mod tests {
#[test_case("56.4")] #[test_case("56.4")]
fn test_number_literal(input: &str) { fn test_number_literal(input: &str) {
let tokens = Lexer::new(input).lex(); let tokens = Lexer::new(input).lex();
let expected = vec![TokenKind::Literal, TokenKind::EOF]; let expected = vec![TokenKind::Literal, TokenKind::Eof];
assert_eq!(&tokens[0].value, input); assert_eq!(&tokens[0].value, input);
match_tokens(tokens, expected); match_tokens(tokens, expected);
@ -489,7 +483,7 @@ mod tests {
#[test_case("xy")] #[test_case("xy")]
fn test_identifier(input: &str) { fn test_identifier(input: &str) {
let tokens = Lexer::new(input).lex(); let tokens = Lexer::new(input).lex();
let expected = vec![TokenKind::Identifier, TokenKind::EOF]; let expected = vec![TokenKind::Identifier, TokenKind::Eof];
assert_eq!(&tokens[0].value, input); assert_eq!(&tokens[0].value, input);
match_tokens(tokens, expected); match_tokens(tokens, expected);
@ -503,7 +497,7 @@ mod tests {
TokenKind::OpenParenthesis, TokenKind::OpenParenthesis,
TokenKind::Identifier, TokenKind::Identifier,
TokenKind::ClosedParenthesis, TokenKind::ClosedParenthesis,
TokenKind::EOF, TokenKind::Eof,
]; ];
match_tokens(tokens, expected); match_tokens(tokens, expected);

View File

@ -1,3 +1,4 @@
#![allow(clippy::unused_unit)]
mod analysis; mod analysis;
pub mod ast; pub mod ast;
pub mod calculation_result; pub mod calculation_result;

View File

@ -11,8 +11,8 @@ use crate::{
}; };
use wasm_bindgen::prelude::*; use wasm_bindgen::prelude::*;
pub const DECL_UNIT: &'static str = ".u"; pub const DECL_UNIT: &str = ".u";
pub const DEFAULT_ANGLE_UNIT: &'static str = "rad"; pub const DEFAULT_ANGLE_UNIT: &str = "rad";
/// Struct containing the current state of the parser. It stores user-defined functions and variables. /// Struct containing the current state of the parser. It stores user-defined functions and variables.
#[wasm_bindgen] #[wasm_bindgen]
@ -118,10 +118,10 @@ pub enum CalcError {
impl ToString for CalcError { impl ToString for CalcError {
fn to_string(&self) -> String { fn to_string(&self) -> String {
match self { match self {
CalcError::CanOnlyIndexVectors => format!("Indexing (getting an item with a specific index) is only possible on vectors."), CalcError::CanOnlyIndexVectors => String::from("Indexing (getting an item with a specific index) is only possible on vectors."),
CalcError::Expected(description) => format!("Expected: {}", description), CalcError::Expected(description) => format!("Expected: {}", description),
CalcError::ExpectedDx => format!("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."), CalcError::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."),
CalcError::ExpectedIf => format!("Expected 'if', with a condition after it."), CalcError::ExpectedIf => String::from("Expected 'if', with a condition after it."),
CalcError::IncorrectAmountOfArguments(expected, func, got) => format!( CalcError::IncorrectAmountOfArguments(expected, func, got) => format!(
"Expected {} arguments for function {}, but got {}.", "Expected {} arguments for function {}, but got {}.",
expected, func, got expected, func, got
@ -131,25 +131,25 @@ impl ToString for CalcError {
expected, got expected, got
), ),
CalcError::ItemOfIndexDoesNotExist(indexes) => format!("Item of index ⟦{}⟧ does not exist.", indexes.iter().map(|x| x.to_string()).collect::<Vec<String>>().join(", ")), CalcError::ItemOfIndexDoesNotExist(indexes) => format!("Item of index ⟦{}⟧ does not exist.", indexes.iter().map(|x| x.to_string()).collect::<Vec<String>>().join(", ")),
CalcError::InconsistentColumnWidths => format!("Inconsistent column widths. Matrix columns must be the same size."), CalcError::InconsistentColumnWidths => String::from("Inconsistent column widths. Matrix columns must be the same size."),
CalcError::InvalidComprehension(x) => format!("Invalid comprehension: {}", x), CalcError::InvalidComprehension(x) => format!("Invalid comprehension: {}", x),
CalcError::InvalidNumberLiteral(x) => format!("Invalid number literal: '{}'.", x), CalcError::InvalidNumberLiteral(x) => format!("Invalid number literal: '{}'.", x),
CalcError::InvalidOperator => format!("Invalid operator."), CalcError::InvalidOperator => String::from("Invalid operator."),
CalcError::InvalidUnit => format!("Invalid unit."), CalcError::InvalidUnit => String::from("Invalid unit."),
CalcError::TimedOut => format!("Operation took too long."), CalcError::TimedOut => String::from("Operation took too long."),
CalcError::VariableReferencesItself => format!("Variable references itself."), CalcError::VariableReferencesItself => String::from("Variable references itself."),
CalcError::PiecewiseConditionsAreFalse => format!("All the conditions in the piecewise are false."), CalcError::PiecewiseConditionsAreFalse => String::from("All the conditions in the piecewise are false."),
CalcError::UnexpectedToken(got, expected) => { CalcError::UnexpectedToken(got, expected) => {
format!("Unexpected token: '{:?}', expected '{:?}'.", got, expected) format!("Unexpected token: '{:?}', expected '{:?}'.", got, expected)
} }
CalcError::UnableToInvert(msg) => format!("Unable to invert: {}", msg), CalcError::UnableToInvert(msg) => format!("Unable to invert: {}", msg),
CalcError::UndefinedFn(name) => format!("Undefined function: '{}'.", name), CalcError::UndefinedFn(name) => format!("Undefined function: '{}'.", name),
CalcError::UndefinedVar(name) => format!("Undefined variable: '{}'.", name), CalcError::UndefinedVar(name) => format!("Undefined variable: '{}'.", name),
CalcError::UnableToParseExpression => format!("Unable to parse expression."), CalcError::UnableToParseExpression => String::from("Unable to parse expression."),
CalcError::UnableToSolveEquation => format!("Unable to solve equation."), CalcError::UnableToSolveEquation => String::from("Unable to solve equation."),
CalcError::UnableToOverrideConstant(name) => format!("Unable to override constant: '{}'.", name), CalcError::UnableToOverrideConstant(name) => format!("Unable to override constant: '{}'.", name),
CalcError::UnrecognizedBase => format!("Unrecognized base."), CalcError::UnrecognizedBase => String::from("Unrecognized base."),
CalcError::Unknown => format!("Unknown error."), CalcError::Unknown => String::from("Unknown error."),
} }
} }
} }
@ -164,17 +164,13 @@ pub fn eval(
) -> Result<Option<CalculationResult>, CalcError> { ) -> Result<Option<CalculationResult>, CalcError> {
let statements = parse(context, input)?; let statements = parse(context, input)?;
let mut symbol_table = context.symbol_table.get_mut(); let symbol_table = context.symbol_table.get_mut();
let mut interpreter = interpreter::Context::new( let mut interpreter = interpreter::Context::new(
&mut symbol_table, symbol_table,
&context.angle_unit, &context.angle_unit,
#[cfg(feature = "rug")] #[cfg(feature = "rug")]
precision, precision,
if let Some(timeout) = context.timeout { context.timeout.map(|timeout| timeout as u128),
Some(timeout as u128)
} else {
None
},
); );
let result = interpreter.interpret(statements); let result = interpreter.interpret(statements);
if let Ok(Some(mut num)) = result { if let Ok(Some(mut num)) = result {
@ -199,8 +195,8 @@ pub fn parse(context: &mut Context, input: &str) -> Result<Vec<Stmt>, CalcError>
let mut statements: Vec<Stmt> = Vec::new(); let mut statements: Vec<Stmt> = Vec::new();
while !is_at_end(context) { while !is_at_end(context) {
let parsed = parse_stmt(context)?; let parsed = parse_stmt(context)?;
let mut symbol_table = context.symbol_table.get_mut(); let symbol_table = context.symbol_table.get_mut();
let analysed = analysis::analyse_stmt(&mut symbol_table, parsed)?; let analysed = analysis::analyse_stmt(symbol_table, parsed)?;
statements.push(analysed); statements.push(analysed);
if match_token(context, TokenKind::Semicolon) { if match_token(context, TokenKind::Semicolon) {
@ -298,7 +294,7 @@ fn parse_unit_decl_stmt(context: &mut Context) -> Result<Stmt, CalcError> {
let stmt_inv = Stmt::UnitDecl( let stmt_inv = Stmt::UnitDecl(
base_unit.clone(), base_unit.clone(),
identifier.value.clone(), identifier.value.clone(),
Box::new(def.invert(&mut context.symbol_table.get_mut(), DECL_UNIT)?), Box::new(def.invert(context.symbol_table.get_mut(), DECL_UNIT)?),
); );
let stmt = Stmt::UnitDecl(identifier.value, base_unit, Box::new(def)); let stmt = Stmt::UnitDecl(identifier.value, base_unit, Box::new(def));
@ -309,7 +305,7 @@ fn parse_unit_decl_stmt(context: &mut Context) -> Result<Stmt, CalcError> {
} }
fn parse_expr(context: &mut Context) -> Result<Expr, CalcError> { fn parse_expr(context: &mut Context) -> Result<Expr, CalcError> {
Ok(parse_or(context)?) parse_or(context)
} }
fn parse_comprehension(context: &mut Context) -> Result<Expr, CalcError> { fn parse_comprehension(context: &mut Context) -> Result<Expr, CalcError> {
@ -386,9 +382,7 @@ fn parse_comparison(context: &mut Context) -> Result<Expr, CalcError> {
left = match right { left = match right {
Expr::Binary( Expr::Binary(
inner_left, inner_left,
inner_op inner_op @ (TokenKind::Equals
@
(TokenKind::Equals
| TokenKind::NotEquals | TokenKind::NotEquals
| TokenKind::GreaterThan | TokenKind::GreaterThan
| TokenKind::LessThan | TokenKind::LessThan
@ -451,11 +445,11 @@ fn parse_factor(context: &mut Context) -> Result<Expr, CalcError> {
if let Expr::Unary(TokenKind::Percent, percent_left) = left.clone() { if let Expr::Unary(TokenKind::Percent, percent_left) = left.clone() {
let try_parse = parse_factor(context); let try_parse = parse_factor(context);
if !try_parse.is_err() { if try_parse.is_ok() {
left = Expr::Binary( left = Expr::Binary(
percent_left, percent_left,
TokenKind::Percent, TokenKind::Percent,
Box::new(try_parse.unwrap()), Box::new(try_parse?),
); );
} }
} }
@ -633,7 +627,7 @@ fn parse_vector(context: &mut Context) -> Result<Expr, CalcError> {
items_in_row += 1; items_in_row += 1;
} }
if peek(context).kind == TokenKind::EOF { if peek(context).kind == TokenKind::Eof {
return Err(CalcError::Expected(String::from( return Err(CalcError::Expected(String::from(
"Closing group symbol, eg. )", "Closing group symbol, eg. )",
))); )));
@ -674,7 +668,7 @@ fn parse_identifier(context: &mut Context) -> Result<Expr, CalcError> {
fn peek(context: &Context) -> &Token { fn peek(context: &Context) -> &Token {
if context.pos >= context.tokens.len() { if context.pos >= context.tokens.len() {
&context.tokens.last().unwrap() // EOF context.tokens.last().unwrap() // Eof
} else { } else {
&context.tokens[context.pos] &context.tokens[context.pos]
} }
@ -710,7 +704,7 @@ fn consume(context: &mut Context, kind: TokenKind) -> Result<&Token, CalcError>
} }
fn is_at_end(context: &Context) -> bool { fn is_at_end(context: &Context) -> bool {
context.pos >= context.tokens.len() || peek(context).kind == TokenKind::EOF context.pos >= context.tokens.len() || peek(context).kind == TokenKind::Eof
} }
fn skip_newlines(context: &mut Context) { fn skip_newlines(context: &mut Context) {
@ -756,8 +750,8 @@ mod tests {
context.pos = 0; context.pos = 0;
let parsed = parse_stmt(context)?; let parsed = parse_stmt(context)?;
let mut symbol_table = context.symbol_table.get_mut(); let symbol_table = context.symbol_table.get_mut();
analysis::analyse_stmt(&mut symbol_table, parsed) analysis::analyse_stmt(symbol_table, parsed)
} }
fn parse(tokens: Vec<Token>) -> Result<Stmt, CalcError> { fn parse(tokens: Vec<Token>) -> Result<Stmt, CalcError> {
@ -766,15 +760,15 @@ mod tests {
context.pos = 0; context.pos = 0;
let parsed = parse_stmt(&mut context)?; let parsed = parse_stmt(&mut context)?;
let mut symbol_table = context.symbol_table.get_mut(); let symbol_table = context.symbol_table.get_mut();
analysis::analyse_stmt(&mut symbol_table, parsed) analysis::analyse_stmt(symbol_table, parsed)
} }
#[test] #[test]
#[wasm_bindgen_test] #[wasm_bindgen_test]
fn test_var() { fn test_var() {
// x // x
let tokens = vec![token(Identifier, "x"), token(EOF, "")]; let tokens = vec![token(Identifier, "x"), token(Eof, "")];
assert_eq!(parse(tokens).unwrap(), Stmt::Expr(var("x"))); assert_eq!(parse(tokens).unwrap(), Stmt::Expr(var("x")));
} }
@ -797,7 +791,7 @@ mod tests {
token(Identifier, "xy"), token(Identifier, "xy"),
token(Power, ""), token(Power, ""),
token(Literal, "2"), token(Literal, "2"),
token(EOF, ""), token(Eof, ""),
]; ];
assert_eq!( assert_eq!(
@ -826,7 +820,7 @@ mod tests {
token(Slash, ""), token(Slash, ""),
token(Literal, "5"), token(Literal, "5"),
token(ClosedParenthesis, ""), token(ClosedParenthesis, ""),
token(EOF, ""), token(Eof, ""),
]; ];
assert_eq!( assert_eq!(
@ -860,7 +854,7 @@ mod tests {
token(Literal, "4"), token(Literal, "4"),
token(Plus, ""), token(Plus, ""),
token(Literal, "5"), token(Literal, "5"),
token(EOF, ""), token(Eof, ""),
]; ];
assert_eq!( assert_eq!(
@ -891,7 +885,7 @@ mod tests {
token(Plus, ""), token(Plus, ""),
token(Literal, "5"), token(Literal, "5"),
token(Percent, ""), token(Percent, ""),
token(EOF, ""), token(Eof, ""),
]; ];
assert_eq!( assert_eq!(
@ -930,7 +924,7 @@ mod tests {
token(Literal, "1"), token(Literal, "1"),
token(Plus, ""), token(Plus, ""),
token(Literal, "2"), token(Literal, "2"),
token(EOF, ""), token(Eof, ""),
]; ];
assert_eq!( assert_eq!(
@ -954,7 +948,7 @@ mod tests {
token(Literal, "1"), token(Literal, "1"),
token(Plus, ""), token(Plus, ""),
token(Identifier, "x"), token(Identifier, "x"),
token(EOF, ""), token(Eof, ""),
]; ];
assert_eq!( assert_eq!(
@ -979,7 +973,7 @@ mod tests {
token(ClosedParenthesis, ""), token(ClosedParenthesis, ""),
token(Plus, ""), token(Plus, ""),
token(Literal, "3"), token(Literal, "3"),
token(EOF, ""), token(Eof, ""),
]; ];
let mut context = Context::new(); let mut context = Context::new();

View File

@ -22,27 +22,15 @@ use crate::interpreter;
pub use funcs::*; pub use funcs::*;
// `i` is added in the symbol_table module, since for some reason it didn't work here. // `i` is added in the symbol_table module, since for some reason it didn't work here.
pub const INIT: &'static str = "unit deg = (rad*180)/pi"; pub const INIT: &str = "unit deg = (rad*180)/pi";
lazy_static! { lazy_static! {
pub static ref CONSTANTS: HashMap<&'static str, f64> = { pub static ref CONSTANTS: HashMap<&'static str, f64> = {
let mut m = HashMap::new(); let mut m = HashMap::new();
m.insert( m.insert("pi", std::f64::consts::PI);
"pi", m.insert("e", std::f64::consts::E);
3.1415926535897932384626433832795028841971693993751058209749445923, m.insert("tau", std::f64::consts::TAU);
); m.insert("phi", 1.618_033_988_749_895);
m.insert(
"e",
2.7182818284590452353602874713526624977572470936999595749669676277,
);
m.insert(
"tau",
6.2831853071795864769252867665590057683943387987502116419498891846,
);
m.insert(
"phi",
1.6180339887498948482045868343656381177203091798057628621354486227,
);
m m
}; };
pub static ref UNARY_FUNCS: HashMap<&'static str, (UnaryFuncInfo, &'static str)> = { pub static ref UNARY_FUNCS: HashMap<&'static str, (UnaryFuncInfo, &'static str)> = {
@ -205,7 +193,7 @@ pub fn call_unary_func(
) -> Option<(KalkValue, String)> { ) -> Option<(KalkValue, String)> {
if let Some((func_info, func_unit)) = UNARY_FUNCS.get(name) { if let Some((func_info, func_unit)) = UNARY_FUNCS.get(name) {
Some(( Some((
func_info.call(context, x, &angle_unit), func_info.call(context, x, angle_unit),
func_unit.to_string(), func_unit.to_string(),
)) ))
} else { } else {
@ -231,11 +219,7 @@ pub fn call_binary_func(
} }
pub fn call_vector_func(name: &str, x: KalkValue) -> Option<KalkValue> { pub fn call_vector_func(name: &str, x: KalkValue) -> Option<KalkValue> {
if let Some(func_info) = VECTOR_FUNCS.get(name) { VECTOR_FUNCS.get(name).map(|func_info| func_info.call(x))
Some(func_info.call(x))
} else {
None
}
} }
fn to_angle_unit(context: &mut interpreter::Context, x: KalkValue, angle_unit: &str) -> KalkValue { fn to_angle_unit(context: &mut interpreter::Context, x: KalkValue, angle_unit: &str) -> KalkValue {
@ -286,7 +270,7 @@ pub mod funcs {
// -i * ln(i * sqrt(1 - z²) + z) // -i * ln(i * sqrt(1 - z²) + z)
let root = let root =
sqrt(KalkValue::from(1f64).sub_without_unit(&x.clone().mul_without_unit(&x))); sqrt(KalkValue::from(1f64).sub_without_unit(&x.clone().mul_without_unit(&x)));
let iroot = multiply_with_i(root.clone()); let iroot = multiply_with_i(root);
let (ln_real, ln_imaginary, ln_unit) = let (ln_real, ln_imaginary, ln_unit) =
as_number_or_return!(ln(iroot.add_without_unit(&x))); as_number_or_return!(ln(iroot.add_without_unit(&x)));
@ -305,11 +289,7 @@ pub mod funcs {
imaginary.clone(), imaginary.clone(),
unit.clone(), unit.clone(),
)); ));
let sqrt2 = sqrt(KalkValue::Number( let sqrt2 = sqrt(KalkValue::Number(real - 1f64, imaginary, unit));
real.clone() - 1f64,
imaginary.clone(),
unit,
));
ln(x.add_without_unit(&sqrt1.mul_without_unit(&sqrt2))) ln(x.add_without_unit(&sqrt1.mul_without_unit(&sqrt2)))
} else { } else {
@ -399,11 +379,7 @@ pub mod funcs {
inv_unit.clone(), inv_unit.clone(),
)); ));
// sqrt(1/z + 1) // sqrt(1/z + 1)
let sqrt2 = sqrt(KalkValue::Number( let sqrt2 = sqrt(KalkValue::Number(inv_real + 1f64, inv_imaginary, inv_unit));
inv_real.clone() + 1f64,
inv_imaginary.clone(),
inv_unit,
));
// ln(1/z + sqrt(1/z - 1) * sqrt(1/z + 1)) // ln(1/z + sqrt(1/z - 1) * sqrt(1/z + 1))
ln(sqrt1.mul_without_unit(&sqrt2).add_without_unit(&inv)) ln(sqrt1.mul_without_unit(&sqrt2).add_without_unit(&inv))
@ -418,7 +394,7 @@ pub mod funcs {
// i * ln(sqrt(1 - z²) - iz) // i * ln(sqrt(1 - z²) - iz)
let root = let root =
sqrt(KalkValue::from(1f64).sub_without_unit(&x.clone().mul_without_unit(&x))); sqrt(KalkValue::from(1f64).sub_without_unit(&x.clone().mul_without_unit(&x)));
let iz = multiply_with_i(x.clone()); let iz = multiply_with_i(x);
let ln = ln(root.sub_without_unit(&iz)); let ln = ln(root.sub_without_unit(&iz));
multiply_with_i(ln) multiply_with_i(ln)
} else { } else {
@ -600,10 +576,10 @@ pub mod funcs {
} }
if x.has_imaginary() || y.has_imaginary() { if x.has_imaginary() || y.has_imaginary() {
if real.clone().fract() != 0f64 if real.fract() != 0f64
|| real_rhs.clone().fract() != 0f64 || real_rhs.fract() != 0f64
|| imaginary.clone().fract() != 0f64 || imaginary.fract() != 0f64
|| imaginary_rhs.clone().fract() != 0f64 || imaginary_rhs.fract() != 0f64
{ {
// Not a Gaussian integer! // Not a Gaussian integer!
// TODO: throw an actual error instead of returning NaN // TODO: throw an actual error instead of returning NaN
@ -627,7 +603,7 @@ pub mod funcs {
let (b_real, b_imaginary, b_unit) = as_number_or_return!(b.clone()); let (b_real, b_imaginary, b_unit) = as_number_or_return!(b.clone());
let (c_real, c_imaginary, c_unit) = let (c_real, c_imaginary, c_unit) =
as_number_or_return!(a.clone().div_without_unit(&b.clone())); as_number_or_return!(a.clone().div_without_unit(&b));
if c_imaginary.clone().fract() == 0f64 { if c_imaginary.clone().fract() == 0f64 {
KalkValue::Number(b_real.abs(), b_imaginary, b_unit) KalkValue::Number(b_real.abs(), b_imaginary, b_unit)
} else { } else {
@ -646,8 +622,8 @@ pub mod funcs {
} }
// Euclidean GCD algorithm, but with modulus // Euclidean GCD algorithm, but with modulus
let mut x_a = real.clone(); let mut x_a = real;
let mut y_a = real_rhs.clone(); let mut y_a = real_rhs;
while !y_a.eq(&0f64) { while !y_a.eq(&0f64) {
let t = y_a.clone(); let t = y_a.clone();
y_a = x_a % y_a; y_a = x_a % y_a;
@ -686,10 +662,10 @@ pub mod funcs {
pub fn lcm(x: KalkValue, y: KalkValue) -> KalkValue { pub fn lcm(x: KalkValue, y: KalkValue) -> KalkValue {
let (real, imaginary, unit) = as_number_or_return!(x.clone()); let (real, imaginary, unit) = as_number_or_return!(x.clone());
let (real_rhs, imaginary_rhs, unit_rhs) = as_number_or_return!(y.clone()); let (real_rhs, imaginary_rhs, unit_rhs) = as_number_or_return!(y.clone());
let gcd = gcd(x.clone(), y.clone()); let gcd = gcd(x, y);
let absx = KalkValue::Number(real.abs(), imaginary, unit); let absx = KalkValue::Number(real.abs(), imaginary, unit);
let absy = KalkValue::Number(real_rhs.abs(), imaginary_rhs, unit_rhs); let absy = KalkValue::Number(real_rhs.abs(), imaginary_rhs, unit_rhs);
return absx.div_without_unit(&gcd).mul_without_unit(&absy); absx.div_without_unit(&gcd).mul_without_unit(&absy)
} }
pub fn log(x: KalkValue) -> KalkValue { pub fn log(x: KalkValue) -> KalkValue {
@ -728,7 +704,7 @@ pub mod funcs {
let values = as_vector_or_return!(x); let values = as_vector_or_return!(x);
let mut max = &values[0]; let mut max = &values[0];
for value in &values { for value in &values {
if let KalkValue::Boolean(greater) = value.greater_than_without_unit(&max) { if let KalkValue::Boolean(greater) = value.greater_than_without_unit(max) {
if greater { if greater {
max = value; max = value;
} }
@ -742,7 +718,7 @@ pub mod funcs {
let values = as_vector_or_return!(x); let values = as_vector_or_return!(x);
let mut min = &values[0]; let mut min = &values[0];
for value in &values { for value in &values {
if let KalkValue::Boolean(less) = value.less_than_without_unit(&min) { if let KalkValue::Boolean(less) = value.less_than_without_unit(min) {
if less { if less {
min = value; min = value;
} }
@ -795,7 +771,7 @@ pub mod funcs {
pub fn sqrt(x: KalkValue) -> KalkValue { pub fn sqrt(x: KalkValue) -> KalkValue {
let (real, imaginary, unit) = as_number_or_return!(x.clone()); let (real, imaginary, unit) = as_number_or_return!(x.clone());
if x.has_imaginary() { if x.has_imaginary() {
let (abs_real, _, abs_unit) = as_number_or_return!(abs(x.clone())); let (abs_real, _, abs_unit) = as_number_or_return!(abs(x));
let r = abs_real; let r = abs_real;
let a = real; let a = real;
let b = imaginary; let b = imaginary;
@ -949,6 +925,7 @@ mod tests {
} }
#[test] #[test]
#[allow(clippy::approx_constant)]
fn test_trig_funcs() { fn test_trig_funcs() {
// Auto-generated using kalk/scripts/generate_funcs_test_cases.py // Auto-generated using kalk/scripts/generate_funcs_test_cases.py
let in_out = vec![ let in_out = vec![
@ -1192,7 +1169,6 @@ mod tests {
|| actual_output.imaginary_to_f64().is_infinite(); || actual_output.imaginary_to_f64().is_infinite();
if expected_has_nan_or_inf || actual_has_nan_or_inf { if expected_has_nan_or_inf || actual_has_nan_or_inf {
assert!(true);
continue; continue;
} }

View File

@ -24,10 +24,10 @@ pub fn parse_float_radix(value: &str, radix: u8) -> Option<f64> {
i -= 1; i -= 1;
} }
return Some(sum); Some(sum)
} }
const DIGITS: &'static str = "0123456789abcdefghijklmnopqrstuvwxyz"; const DIGITS: &str = "0123456789abcdefghijklmnopqrstuvwxyz";
pub fn int_to_radix(value: i64, radix: u8) -> String { pub fn int_to_radix(value: i64, radix: u8) -> String {
let mut num = value.abs(); let mut num = value.abs();
let mut result_str = String::new(); let mut result_str = String::new();
@ -37,7 +37,7 @@ pub fn int_to_radix(value: i64, radix: u8) -> String {
num /= radix as i64; num /= radix as i64;
} }
if result_str == "" { if result_str.is_empty() {
return String::from("0"); return String::from("0");
} }
@ -52,7 +52,7 @@ pub fn float_to_radix(value: f64, radix: u8) -> String {
result.push('.'); result.push('.');
let precision = 10; let precision = 10;
let fract_digits = (fract * (radix as i64).pow(precision) as f64) as i64; let fract_digits = (fract * (radix as i64).pow(precision) as f64) as i64;
result.push_str(&int_to_radix(fract_digits, radix).trim_end_matches('0')) result.push_str(int_to_radix(fract_digits, radix).trim_end_matches('0'))
} }
result result

View File

@ -100,3 +100,9 @@ impl SymbolTable {
|| self.hashmap.contains_key(&format!("fn.{}", identifier)) || self.hashmap.contains_key(&format!("fn.{}", identifier))
} }
} }
impl Default for SymbolTable {
fn default() -> Self {
Self::new()
}
}

View File

@ -1,18 +1,10 @@
pub fn is_superscript(c: &char) -> bool { pub fn is_superscript(c: &char) -> bool {
match c { matches!(c, '⁰' | '¹' | '²' | '³' | '⁴' | '⁵' | '⁶' | '⁷' | '⁸' | '⁹' | '⁺' | '⁻' | '⁼' | '⁽' | '⁾')
'⁰' | '¹' | '²' | '³' | '⁴' | '⁵' | '⁶' | '⁷' | '⁸' | '⁹' | '⁺' | '⁻' | '⁼' | '⁽' | '⁾' => {
true
}
_ => false,
}
} }
pub fn is_subscript(c: &char) -> bool { pub fn is_subscript(c: &char) -> bool {
match c { matches!(c, '₀' | '₁' | '₂' | '₃' | '₄' | '₅' | '₆' | '₇' | '₈' | '₉' | '₊' | '₋' | '₌' | '₍' | '₎'
'₀' | '₁' | '₂' | '₃' | '₄' | '₅' | '₆' | '₇' | '₈' | '₉' | '₊' | '₋' | '₌' | '₍' | '₎' | 'ₖ' | 'ₗ' | 'ₘ' | 'ₙ' | 'ₓ')
| 'ₖ' | 'ₗ' | 'ₘ' | 'ₙ' | 'ₓ' => true,
_ => false,
}
} }
pub fn parse_subscript(chars: impl Iterator<Item = char>) -> Option<u8> { pub fn parse_subscript(chars: impl Iterator<Item = char>) -> Option<u8> {
@ -82,5 +74,5 @@ pub fn normal_to_subscript(chars: impl Iterator<Item = char>) -> String {
}); });
} }
return subscript; subscript
} }