mirror of
https://github.com/PaddiM8/kalker.git
synced 2024-12-13 10:00:51 +01:00
Fixed clippy lints
This commit is contained in:
parent
a36d9849d5
commit
4704095cd9
@ -63,7 +63,7 @@ fn default_action(context: &Context) {
|
||||
load_input_file(&input_file_path, precision, &mut parser_context);
|
||||
}
|
||||
|
||||
if context.args.len() == 0 {
|
||||
if context.args.is_empty() {
|
||||
// REPL
|
||||
repl::start(&mut parser_context, precision);
|
||||
} else {
|
||||
|
@ -20,7 +20,7 @@ use std::collections::HashMap;
|
||||
use std::fs;
|
||||
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();
|
||||
editor.set_helper(Some(RLHelper {
|
||||
highlighter: LineHighlighter {},
|
||||
@ -31,9 +31,9 @@ pub fn start(mut parser: &mut parser::Context, precision: u32) {
|
||||
// Load history
|
||||
let mut history_path = None;
|
||||
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");
|
||||
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");
|
||||
let history = config_path.into_os_string().into_string().unwrap();
|
||||
editor.load_history(&history).ok();
|
||||
@ -61,7 +61,7 @@ pub fn start(mut parser: &mut parser::Context, precision: u32) {
|
||||
match readline {
|
||||
Ok(input) => {
|
||||
editor.add_history_entry(input.as_str());
|
||||
eval_repl(&mut parser, &input, precision);
|
||||
eval_repl(parser, &input, precision);
|
||||
}
|
||||
Err(ReadlineError::Interrupted) => 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) {
|
||||
if input.starts_with("load ") {
|
||||
let file_name = &input[5..];
|
||||
if let Some(file_name) = input.strip_prefix("load ") {
|
||||
if let Some(file_path) = crate::get_input_file_by_name(file_name) {
|
||||
crate::load_input_file(&file_path, precision, parser);
|
||||
} else {
|
||||
@ -216,7 +215,7 @@ impl Completer for RLHelper {
|
||||
fn update(&self, line: &mut rustyline::line_buffer::LineBuffer, start: usize, elected: &str) {
|
||||
line.backspace(line.pos() - start);
|
||||
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
|
||||
} else {
|
||||
elected.chars().count()
|
||||
@ -242,7 +241,7 @@ impl Highlighter for RLHelper {
|
||||
}
|
||||
|
||||
fn highlight_char(&self, line: &str, _: usize) -> bool {
|
||||
line.len() > 0
|
||||
!line.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)?
|
||||
}
|
||||
Expr::Var(identifier) if !context.in_conditional => {
|
||||
if inverter::contains_var(
|
||||
&mut context.symbol_table,
|
||||
&right,
|
||||
&identifier.full_name,
|
||||
) {
|
||||
if inverter::contains_var(context.symbol_table, &right, &identifier.full_name) {
|
||||
return Err(CalcError::VariableReferencesItself);
|
||||
}
|
||||
|
||||
if prelude::is_constant(&identifier.full_name) {
|
||||
return Err(CalcError::UnableToOverrideConstant(
|
||||
identifier.pure_name.into(),
|
||||
));
|
||||
return Err(CalcError::UnableToOverrideConstant(identifier.pure_name));
|
||||
}
|
||||
|
||||
let result =
|
||||
@ -129,14 +123,10 @@ fn build_fn_decl(
|
||||
Expr::Vector(exprs) => {
|
||||
exprs
|
||||
.iter()
|
||||
.any(|x| if let Expr::Var(_) = x { true } else { false })
|
||||
.any(|x| matches!(x, Expr::Var(_)))
|
||||
}
|
||||
Expr::Group(expr) => {
|
||||
if let Expr::Var(_) = &**expr {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
matches!(&**expr, Expr::Var(_))
|
||||
}
|
||||
_ => false,
|
||||
};
|
||||
@ -266,8 +256,8 @@ fn analyse_expr(context: &mut Context, expr: Expr) -> Result<Expr, CalcError> {
|
||||
})
|
||||
}
|
||||
|
||||
fn analyse_binary<'a>(
|
||||
context: &'a mut Context,
|
||||
fn analyse_binary(
|
||||
context: &mut Context,
|
||||
left: Expr,
|
||||
op: TokenKind,
|
||||
right: Expr,
|
||||
@ -286,7 +276,7 @@ fn analyse_binary<'a>(
|
||||
|
||||
// If it has already been set to false manually somewhere else,
|
||||
// abort and analyse as a comparison instead.
|
||||
if context.in_equation == false {
|
||||
if !context.in_equation {
|
||||
context.in_conditional = true;
|
||||
let result = analyse_binary(context, left, op, right);
|
||||
context.in_conditional = previous_in_conditional;
|
||||
@ -306,7 +296,7 @@ fn analyse_binary<'a>(
|
||||
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)?
|
||||
} else {
|
||||
right.invert_to_target(context.symbol_table, left, var_name)?
|
||||
@ -441,20 +431,20 @@ fn analyse_comparison_with_var(
|
||||
match op {
|
||||
TokenKind::GreaterThan => {
|
||||
ranged_var.min = Expr::Binary(
|
||||
Box::new(right.clone()),
|
||||
Box::new(right),
|
||||
TokenKind::Plus,
|
||||
Box::new(Expr::Literal(1f64)),
|
||||
);
|
||||
}
|
||||
TokenKind::LessThan => {
|
||||
ranged_var.max = right.clone();
|
||||
ranged_var.max = right;
|
||||
}
|
||||
TokenKind::GreaterOrEquals => {
|
||||
ranged_var.min = right.clone();
|
||||
ranged_var.min = right;
|
||||
}
|
||||
TokenKind::LessOrEquals => {
|
||||
ranged_var.max = Expr::Binary(
|
||||
Box::new(right.clone()),
|
||||
Box::new(right),
|
||||
TokenKind::Plus,
|
||||
Box::new(Expr::Literal(1f64)),
|
||||
);
|
||||
@ -526,7 +516,7 @@ fn analyse_var(
|
||||
)
|
||||
} else if context
|
||||
.symbol_table
|
||||
.contains_var(&identifier.get_name_without_lowered())
|
||||
.contains_var(identifier.get_name_without_lowered())
|
||||
{
|
||||
with_adjacent(
|
||||
build_indexed_var(context, identifier)?,
|
||||
@ -653,21 +643,22 @@ fn build_fn_call(
|
||||
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> {
|
||||
let underscore_pos = identifier.pure_name.find('_').unwrap();
|
||||
let var_name = &identifier.pure_name[0..underscore_pos];
|
||||
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))
|
||||
} else {
|
||||
build_var(context, lowered)
|
||||
};
|
||||
|
||||
Ok(Expr::Indexer(
|
||||
Box::new(build_var(context, &var_name)),
|
||||
Box::new(build_var(context, var_name)),
|
||||
vec![lowered_expr],
|
||||
))
|
||||
}
|
||||
@ -677,10 +668,10 @@ fn build_dx(
|
||||
name_without_dx: &str,
|
||||
char_after_d: char,
|
||||
) -> Result<Expr, CalcError> {
|
||||
if name_without_dx.len() == 0 {
|
||||
if name_without_dx.is_empty() {
|
||||
Ok(Expr::Var(Identifier::from_full_name(&format!(
|
||||
"d{}",
|
||||
char_after_d.to_string()
|
||||
char_after_d
|
||||
))))
|
||||
} else {
|
||||
Ok(Expr::Binary(
|
||||
@ -693,7 +684,7 @@ fn build_dx(
|
||||
TokenKind::Star,
|
||||
Box::new(Expr::Var(Identifier::from_full_name(&format!(
|
||||
"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_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) {
|
||||
return Expr::Var(identifier);
|
||||
}
|
||||
|
@ -116,7 +116,7 @@ fn separate_identifier_and_prime(identifier: &str) -> (String, u32) {
|
||||
let mut pure_identifier = identifier.to_string();
|
||||
|
||||
loop {
|
||||
if pure_identifier.ends_with("'") {
|
||||
if pure_identifier.ends_with('\'') {
|
||||
pure_identifier.pop();
|
||||
prim_count += 1;
|
||||
} else {
|
||||
|
@ -22,8 +22,8 @@ impl CalculationResult {
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = toString)]
|
||||
pub fn to_string(&self) -> String {
|
||||
self.value.to_string()
|
||||
pub fn to_js_string(&self) -> String {
|
||||
self.to_string()
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = toStringBig)]
|
||||
@ -71,3 +71,9 @@ impl CalculationResult {
|
||||
self.value.estimate()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for CalculationResult {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.value)
|
||||
}
|
||||
}
|
@ -42,7 +42,7 @@ pub fn integrate_with_unknown_variable(
|
||||
// integral(a, b, expr dx)
|
||||
if let Expr::Binary(_, TokenKind::Star, right) = expr {
|
||||
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
|
||||
integration_variable = Some(&right_name.full_name[1..]);
|
||||
}
|
||||
@ -89,7 +89,7 @@ fn simpsons_rule(
|
||||
const N: i32 = 900;
|
||||
let a = interpreter::eval_expr(context, a_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 {
|
||||
let variable_value = a
|
||||
.clone()
|
||||
@ -143,7 +143,7 @@ mod tests {
|
||||
use crate::symbol_table::SymbolTable;
|
||||
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(
|
||||
symbol_table,
|
||||
"",
|
||||
|
@ -35,7 +35,7 @@ impl<'a> Context<'a> {
|
||||
precision,
|
||||
sum_n_value: None,
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
timeout: timeout,
|
||||
timeout,
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
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::FnDecl(_, _, _) => eval_fn_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> {
|
||||
eval_expr(context, &expr, "")
|
||||
eval_expr(context, expr, "")
|
||||
}
|
||||
|
||||
pub(crate) fn eval_expr(
|
||||
@ -114,12 +114,12 @@ pub(crate) fn eval_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::Unit(identifier, expr) => eval_unit_expr(context, identifier, expr),
|
||||
Expr::Var(identifier) => eval_var_expr(context, identifier, 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) => {
|
||||
eval_fn_call_expr(context, identifier, expressions, unit)
|
||||
}
|
||||
@ -177,7 +177,7 @@ fn eval_binary_expr(
|
||||
_ => KalkValue::from(1),
|
||||
};
|
||||
|
||||
if unit.len() > 0 {
|
||||
if !unit.is_empty() {
|
||||
if let KalkValue::Number(real, imaginary, _) = result {
|
||||
return Ok(KalkValue::Number(real, imaginary, unit.to_string()));
|
||||
}
|
||||
@ -192,7 +192,7 @@ fn eval_unary_expr(
|
||||
expr: &Expr,
|
||||
unit: &str,
|
||||
) -> Result<KalkValue, CalcError> {
|
||||
let num = eval_expr(context, &expr, unit)?;
|
||||
let num = eval_expr(context, expr, unit)?;
|
||||
|
||||
match op {
|
||||
TokenKind::Minus => Ok(num.mul(context, KalkValue::from(-1f64))),
|
||||
@ -318,7 +318,7 @@ pub(crate) fn eval_fn_call_expr(
|
||||
|
||||
return Ok(
|
||||
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 => {
|
||||
let x = eval_expr(context, &expressions[0], "")?;
|
||||
if identifier.prime_count > 0 {
|
||||
return calculus::derive_func(context, &identifier, x);
|
||||
return calculus::derive_func(context, identifier, x);
|
||||
} else {
|
||||
prelude::call_unary_func(
|
||||
context,
|
||||
@ -496,7 +496,7 @@ pub(crate) fn eval_fn_call_expr(
|
||||
// Initialise the arguments as their own variables.
|
||||
let mut new_argument_values = Vec::new();
|
||||
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();
|
||||
Identifier::parameter_from_name(identifier_parts[1], identifier_parts[0])
|
||||
} else {
|
||||
@ -533,10 +533,8 @@ pub(crate) fn eval_fn_call_expr(
|
||||
let fn_value = eval_expr(context, &fn_body, unit);
|
||||
|
||||
// Revert to original argument values
|
||||
for old_argument_value in old_argument_values {
|
||||
if let Some(old_argument_value) = old_argument_value {
|
||||
context.symbol_table.insert(old_argument_value);
|
||||
}
|
||||
for old_argument_value in old_argument_values.into_iter().flatten() {
|
||||
context.symbol_table.insert(old_argument_value);
|
||||
}
|
||||
|
||||
fn_value
|
||||
@ -547,13 +545,13 @@ pub(crate) fn eval_fn_call_expr(
|
||||
|
||||
fn eval_piecewise(
|
||||
context: &mut Context,
|
||||
pieces: &Vec<crate::ast::ConditionalPiece>,
|
||||
pieces: &[crate::ast::ConditionalPiece],
|
||||
unit: &str,
|
||||
) -> Result<KalkValue, CalcError> {
|
||||
for piece in pieces {
|
||||
if let KalkValue::Boolean(condition_is_true) = eval_expr(context, &piece.condition, unit)? {
|
||||
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)
|
||||
}
|
||||
|
||||
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();
|
||||
for value in values {
|
||||
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))
|
||||
}
|
||||
|
||||
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();
|
||||
for row in rows {
|
||||
let mut eval_row = Vec::new();
|
||||
@ -783,27 +781,27 @@ mod tests {
|
||||
assert_eq!(interpret(pow).unwrap().unwrap().to_f64(), 8f64);
|
||||
|
||||
let result = interpret(equals).unwrap().unwrap();
|
||||
assert_eq!(bool(&result), false);
|
||||
assert!(!bool(&result));
|
||||
assert!(result.to_f64().is_nan());
|
||||
|
||||
let result = interpret(not_equals).unwrap().unwrap();
|
||||
assert_eq!(bool(&result), true);
|
||||
assert!(bool(&result));
|
||||
assert!(result.to_f64().is_nan());
|
||||
|
||||
let result = interpret(greater_than).unwrap().unwrap();
|
||||
assert_eq!(bool(&result), false);
|
||||
assert!(!bool(&result));
|
||||
assert!(result.to_f64().is_nan());
|
||||
|
||||
let result = interpret(less_than).unwrap().unwrap();
|
||||
assert_eq!(bool(&result), true);
|
||||
assert!(bool(&result));
|
||||
assert!(result.to_f64().is_nan());
|
||||
|
||||
let result = interpret(greater_or_equals).unwrap().unwrap();
|
||||
assert_eq!(bool(&result), false);
|
||||
assert!(!bool(&result));
|
||||
assert!(result.to_f64().is_nan());
|
||||
|
||||
let result = interpret(less_or_equals).unwrap().unwrap();
|
||||
assert_eq!(bool(&result), true);
|
||||
assert!(bool(&result));
|
||||
assert!(result.to_f64().is_nan());
|
||||
}
|
||||
|
||||
|
@ -70,11 +70,11 @@ fn invert(
|
||||
) -> Result<(Expr, Expr), CalcError> {
|
||||
match expr {
|
||||
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) => {
|
||||
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::Group(expr) => Ok((target_expr, *expr.clone())),
|
||||
@ -153,7 +153,7 @@ fn invert_binary(
|
||||
return invert(
|
||||
target_expr,
|
||||
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,
|
||||
);
|
||||
}
|
||||
@ -164,7 +164,7 @@ fn invert_binary(
|
||||
return invert(
|
||||
target_expr,
|
||||
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,
|
||||
);
|
||||
}
|
||||
@ -208,17 +208,17 @@ fn invert_binary(
|
||||
)));
|
||||
}
|
||||
|
||||
return Ok(invert(
|
||||
return invert(
|
||||
Expr::Binary(Box::new(target_expr), op_inv, Box::new(right.clone())),
|
||||
symbol_table,
|
||||
left,
|
||||
unknown_var,
|
||||
)?);
|
||||
);
|
||||
}
|
||||
|
||||
// Otherwise, invert the left side.
|
||||
let final_target_expr = Expr::Binary(Box::new(target_expr), op_inv, Box::new(left.clone()));
|
||||
Ok(invert(
|
||||
invert(
|
||||
// Eg. 2-a
|
||||
// If the operator is minus (and the left expression is being inverted),
|
||||
// make the target expression negative to keep balance.
|
||||
@ -230,7 +230,7 @@ fn invert_binary(
|
||||
symbol_table,
|
||||
right, // Then invert the right expression.
|
||||
unknown_var,
|
||||
)?)
|
||||
)
|
||||
}
|
||||
|
||||
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.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,
|
||||
symbol_table: &mut SymbolTable,
|
||||
identifier: &Identifier,
|
||||
arguments: &Vec<Expr>,
|
||||
arguments: &[Expr],
|
||||
unknown_var: &str,
|
||||
) -> Result<(Expr, Expr), CalcError> {
|
||||
// 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 {
|
||||
// If + or -, multiply the expression with each term.
|
||||
TokenKind::Plus | TokenKind::Minus => Ok(Expr::Binary(
|
||||
Box::new(multiply_into(expr, &left)?),
|
||||
op.clone(),
|
||||
Box::new(multiply_into(expr, &right)?),
|
||||
Box::new(multiply_into(expr, left)?),
|
||||
*op,
|
||||
Box::new(multiply_into(expr, right)?),
|
||||
)),
|
||||
// If * or /, only multiply with the first factor.
|
||||
TokenKind::Star | TokenKind::Slash => Ok(Expr::Binary(
|
||||
Box::new(multiply_into(expr, &left)?),
|
||||
op.clone(),
|
||||
Box::new(multiply_into(expr, left)?),
|
||||
*op,
|
||||
right.clone(),
|
||||
)),
|
||||
_ => return Err(CalcError::UnableToInvert(String::new())),
|
||||
_ => Err(CalcError::UnableToInvert(String::new())),
|
||||
},
|
||||
// If it's a literal, just multiply them together.
|
||||
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(
|
||||
"Parenthesis multiplied with parenthesis (this should be possible in the future).",
|
||||
))),
|
||||
_ => return Err(CalcError::UnableToInvert(String::new())),
|
||||
_ => Err(CalcError::UnableToInvert(String::new())),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -147,7 +147,13 @@ pub enum ComplexNumberType {
|
||||
#[wasm_bindgen]
|
||||
impl ScientificNotation {
|
||||
#[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 digits_and_mul = if self.value == 1f64 {
|
||||
String::new()
|
||||
@ -155,7 +161,8 @@ impl ScientificNotation {
|
||||
format!("{}×", format_number(self.value))
|
||||
};
|
||||
|
||||
format!(
|
||||
write!(
|
||||
f,
|
||||
"{}{}10^{} {}",
|
||||
sign,
|
||||
digits_and_mul,
|
||||
@ -176,12 +183,8 @@ pub enum KalkValue {
|
||||
Matrix(Vec<Vec<KalkValue>>),
|
||||
}
|
||||
|
||||
impl KalkValue {
|
||||
pub fn nan() -> Self {
|
||||
KalkValue::Number(float!(f64::NAN), float!(0f64), String::new())
|
||||
}
|
||||
|
||||
pub fn to_string(&self) -> String {
|
||||
impl std::fmt::Display for KalkValue {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
KalkValue::Number(real, imaginary, _) => {
|
||||
let as_str = format_number(primitive!(real));
|
||||
@ -191,23 +194,24 @@ impl KalkValue {
|
||||
let sign = if imaginary < &0f64 { "-" } else { "+" };
|
||||
|
||||
if &as_str == "0" {
|
||||
imaginary_as_str
|
||||
write!(f, "{}", imaginary_as_str)
|
||||
} else {
|
||||
format!("{} {} {}i", as_str, sign, imaginary_as_str)
|
||||
write!(f, "{} {} {}i", as_str, sign, imaginary_as_str)
|
||||
}
|
||||
} else {
|
||||
as_str
|
||||
write!(f, "{}", as_str)
|
||||
}
|
||||
}
|
||||
KalkValue::Boolean(is_true) => {
|
||||
if *is_true {
|
||||
String::from("true")
|
||||
write!(f, "true")
|
||||
} else {
|
||||
String::from("false")
|
||||
write!(f, "false")
|
||||
}
|
||||
}
|
||||
KalkValue::Vector(values) => {
|
||||
format!(
|
||||
write!(
|
||||
f,
|
||||
"({})",
|
||||
values
|
||||
.iter()
|
||||
@ -245,10 +249,16 @@ impl KalkValue {
|
||||
result.pop(); // Trailing comma
|
||||
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 {
|
||||
if let KalkValue::Number(real, imaginary, _) = self {
|
||||
@ -257,7 +267,7 @@ impl KalkValue {
|
||||
}
|
||||
|
||||
let sign = if imaginary < &0f64 { "-" } else { "+" };
|
||||
format!("{} {} {}", real.to_string(), sign, imaginary.to_string())
|
||||
format!("{} {} {}", real, sign, imaginary)
|
||||
} else {
|
||||
self.to_string()
|
||||
}
|
||||
@ -304,12 +314,10 @@ impl KalkValue {
|
||||
} else if sci_notation_real.exponent <= -14 {
|
||||
new_real = float!(0);
|
||||
String::from("0")
|
||||
} else if radix == 10 {
|
||||
sci_notation_real.to_string().trim().to_string()
|
||||
} else {
|
||||
if radix == 10 {
|
||||
sci_notation_real.to_string().trim().to_string()
|
||||
} else {
|
||||
return String::new();
|
||||
}
|
||||
return String::new();
|
||||
};
|
||||
|
||||
let sci_notation_imaginary = self.to_scientific_notation(ComplexNumberType::Imaginary);
|
||||
@ -321,12 +329,10 @@ impl KalkValue {
|
||||
} else if sci_notation_imaginary.exponent <= -14 {
|
||||
new_imaginary = float!(0);
|
||||
String::from("0")
|
||||
} else if radix == 10 {
|
||||
sci_notation_imaginary.to_string().trim().to_string()
|
||||
} else {
|
||||
if radix == 10 {
|
||||
format!("{}", sci_notation_imaginary.to_string().trim())
|
||||
} else {
|
||||
return String::new();
|
||||
}
|
||||
return String::new();
|
||||
};
|
||||
|
||||
let mut output = result_str;
|
||||
@ -338,18 +344,18 @@ impl KalkValue {
|
||||
}
|
||||
|
||||
// If there is a real value as well
|
||||
if output.len() > 0 {
|
||||
if !output.is_empty() {
|
||||
output.push_str(&format!(
|
||||
" {} {}",
|
||||
if imaginary < &0f64 { "-" } else { "+" },
|
||||
result_str_imaginary.trim_start_matches("-"),
|
||||
result_str_imaginary.trim_start_matches('-'),
|
||||
));
|
||||
} 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));
|
||||
}
|
||||
|
||||
@ -370,7 +376,7 @@ impl KalkValue {
|
||||
|
||||
pub fn to_string_with_unit(&self) -> String {
|
||||
match self {
|
||||
KalkValue::Number(_, _, unit) => format!("{} {}", self.to_string(), unit),
|
||||
KalkValue::Number(_, _, unit) => format!("{} {}", self, unit),
|
||||
_ => self.to_string(),
|
||||
}
|
||||
}
|
||||
@ -408,11 +414,11 @@ impl KalkValue {
|
||||
if value == "0" {
|
||||
// If both values ended up being estimated as zero,
|
||||
// return zero.
|
||||
if output.len() == 0 {
|
||||
if output.is_empty() {
|
||||
return Some(String::from("0"));
|
||||
}
|
||||
} else {
|
||||
let sign = if value.starts_with("-") { "-" } else { "+" };
|
||||
let sign = if value.starts_with('-') { "-" } else { "+" };
|
||||
let value = match value.as_ref() {
|
||||
"1" => String::from("i"),
|
||||
"-1" => String::from("-i"),
|
||||
@ -420,8 +426,8 @@ impl KalkValue {
|
||||
};
|
||||
|
||||
// If there is a real value as well
|
||||
if output.len() > 0 {
|
||||
output.push_str(&format!(" {} {}", sign, value.trim_start_matches("-")));
|
||||
if !output.is_empty() {
|
||||
output.push_str(&format!(" {} {}", sign, value.trim_start_matches('-')));
|
||||
} else {
|
||||
output.push_str(&value);
|
||||
}
|
||||
@ -500,7 +506,7 @@ impl KalkValue {
|
||||
ComplexNumberType::Real => self.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 {
|
||||
negative: value < 0f64,
|
||||
@ -513,7 +519,7 @@ impl KalkValue {
|
||||
|
||||
pub fn has_unit(&self) -> bool {
|
||||
if let KalkValue::Number(_, _, unit) = self {
|
||||
unit.len() > 0
|
||||
!unit.is_empty()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
@ -536,7 +542,7 @@ impl KalkValue {
|
||||
let result = crate::interpreter::convert_unit(
|
||||
context,
|
||||
&Expr::Literal(primitive!(real)),
|
||||
&unit,
|
||||
unit,
|
||||
to_unit,
|
||||
);
|
||||
|
||||
@ -582,7 +588,7 @@ impl KalkValue {
|
||||
context: &mut crate::interpreter::Context,
|
||||
rhs: 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)
|
||||
}
|
||||
|
||||
@ -649,7 +655,7 @@ impl KalkValue {
|
||||
context: &mut crate::interpreter::Context,
|
||||
rhs: 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)) = (
|
||||
self.greater_than_without_unit(&right),
|
||||
self.eq_without_unit(&right),
|
||||
@ -665,7 +671,7 @@ impl KalkValue {
|
||||
context: &mut crate::interpreter::Context,
|
||||
rhs: 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)) = (
|
||||
self.less_than_without_unit(&right),
|
||||
self.eq_without_unit(&right),
|
||||
@ -824,10 +830,7 @@ impl KalkValue {
|
||||
|
||||
pub(crate) fn div_without_unit(self, rhs: &KalkValue) -> KalkValue {
|
||||
match (self.clone(), rhs.clone()) {
|
||||
(
|
||||
KalkValue::Number(real, _, _),
|
||||
KalkValue::Number(real_rhs, _, unit),
|
||||
) => {
|
||||
(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)
|
||||
@ -836,7 +839,7 @@ impl KalkValue {
|
||||
// with the conjugate of the denominator, and divide.
|
||||
let conjugate = rhs.get_conjugate();
|
||||
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();
|
||||
KalkValue::Number(
|
||||
numerator / denominator.clone(),
|
||||
@ -861,10 +864,12 @@ impl KalkValue {
|
||||
KalkValue::Number(real, imaginary, _),
|
||||
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 b = imaginary.clone();
|
||||
let a = real;
|
||||
let b = imaginary;
|
||||
let c = real_rhs;
|
||||
let d = imaginary_rhs;
|
||||
let arg = crate::prelude::funcs::arg(self).values().0;
|
||||
@ -935,7 +940,7 @@ impl KalkValue {
|
||||
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;
|
||||
}
|
||||
@ -949,7 +954,7 @@ impl KalkValue {
|
||||
(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;
|
||||
}
|
||||
@ -1025,13 +1030,13 @@ impl KalkValue {
|
||||
|
||||
pub fn format_number(input: f64) -> String {
|
||||
let rounded = format!("{:.1$}", input, 10);
|
||||
if rounded.contains(".") {
|
||||
if rounded.contains('.') {
|
||||
rounded
|
||||
.trim_end_matches('0')
|
||||
.trim_end_matches('.')
|
||||
.to_string()
|
||||
} else {
|
||||
rounded.into()
|
||||
rounded
|
||||
}
|
||||
}
|
||||
|
||||
@ -1053,7 +1058,7 @@ fn calculate_vector(
|
||||
values
|
||||
.iter()
|
||||
.zip(values_rhs)
|
||||
.map(|(x, y)| action(x.clone(), &y))
|
||||
.map(|(x, y)| action(x.clone(), y))
|
||||
.collect(),
|
||||
)
|
||||
} else {
|
||||
@ -1158,9 +1163,9 @@ fn pow(x: Float, y: Float) -> Float {
|
||||
x.pow(y)
|
||||
}
|
||||
|
||||
impl Into<String> for ScientificNotation {
|
||||
fn into(self) -> String {
|
||||
self.to_string()
|
||||
impl From<ScientificNotation> for String {
|
||||
fn from(val: ScientificNotation) -> Self {
|
||||
val.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
@ -1178,15 +1183,15 @@ impl std::iter::Sum<KalkValue> for KalkValue {
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<String> for KalkValue {
|
||||
fn into(self) -> String {
|
||||
self.to_string()
|
||||
impl From<KalkValue> for String {
|
||||
fn from(val: KalkValue) -> Self {
|
||||
val.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<f64> for KalkValue {
|
||||
fn into(self) -> f64 {
|
||||
self.to_f64()
|
||||
impl From<KalkValue> for f64 {
|
||||
fn from(val: KalkValue) -> Self {
|
||||
val.to_f64()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,19 +31,19 @@ pub(super) fn estimate(
|
||||
}
|
||||
|
||||
// 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 { "" };
|
||||
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") {
|
||||
return Some(format!("{}1/2", sign));
|
||||
}
|
||||
if as_abs_string.starts_with("0.5")
|
||||
&& (as_abs_string.len() == 3 || (as_abs_string.len() > 6 && &as_abs_string[3..5] == "00"))
|
||||
{
|
||||
return Some(format!("{}1/2", sign));
|
||||
}
|
||||
|
||||
// Eg. 1.33333333 to 1 + 1/3
|
||||
if fract_as_string.len() >= 7 {
|
||||
let first_five_decimals = &fract_as_string[2..7];
|
||||
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",
|
||||
"66666" => "2/3",
|
||||
_ => "?",
|
||||
@ -52,7 +52,7 @@ pub(super) fn estimate(
|
||||
if integer == 0f64 {
|
||||
return Some(format!("{}{}", sign, fraction));
|
||||
} else {
|
||||
let explicit_sign = if sign == "" { "+" } else { "-" };
|
||||
let explicit_sign = if sign.is_empty() { "+" } else { "-" };
|
||||
return Some(format!(
|
||||
"{} {} {}",
|
||||
trim_zeroes(&integer.to_string()),
|
||||
@ -66,7 +66,7 @@ pub(super) fn estimate(
|
||||
// Match with common numbers, eg. π, 2π/3, √2
|
||||
if as_abs_string.len() >= 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()
|
||||
.0;
|
||||
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)
|
||||
} else if (1f64 - fract.clone()).log10() < limit_ceil {
|
||||
} else if (1f64 - fract).log10() < limit_ceil {
|
||||
// If eg. 0.999
|
||||
// .abs() this before ceiling to make sure it rounds correctly. The sign is re-added afterwards.
|
||||
let new_value = value.clone().abs().ceil() * sign;
|
||||
@ -155,10 +155,10 @@ pub(super) fn round(
|
||||
}
|
||||
|
||||
pub(super) fn trim_zeroes(input: &str) -> String {
|
||||
if input.contains(".") {
|
||||
if input.contains('.') {
|
||||
input
|
||||
.trim_end_matches("0")
|
||||
.trim_end_matches(".")
|
||||
.trim_end_matches('0')
|
||||
.trim_end_matches('.')
|
||||
.to_string()
|
||||
} else {
|
||||
input.into()
|
||||
|
@ -49,7 +49,7 @@ pub enum TokenKind {
|
||||
Semicolon,
|
||||
Newline,
|
||||
|
||||
EOF,
|
||||
Eof,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
@ -80,7 +80,7 @@ impl<'a> Lexer<'a> {
|
||||
loop {
|
||||
let next = self.next();
|
||||
|
||||
if let TokenKind::EOF = next.kind {
|
||||
if let TokenKind::Eof = next.kind {
|
||||
tokens.push(next);
|
||||
break;
|
||||
} else {
|
||||
@ -96,7 +96,7 @@ impl<'a> Lexer<'a> {
|
||||
}
|
||||
|
||||
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() {
|
||||
*c
|
||||
} else {
|
||||
@ -104,7 +104,7 @@ impl<'a> Lexer<'a> {
|
||||
};
|
||||
|
||||
while c == ' ' || c == '\t' || c == '\r' {
|
||||
if let None = self.advance() {
|
||||
if self.advance().is_none() {
|
||||
return eof;
|
||||
}
|
||||
|
||||
@ -210,13 +210,7 @@ impl<'a> Lexer<'a> {
|
||||
let mut leading_zero = self.peek().unwrap_or(&'\0') == &'0';
|
||||
let mut base = 10u8;
|
||||
|
||||
loop {
|
||||
let c = if let Some(c) = self.peek() {
|
||||
*c
|
||||
} else {
|
||||
break;
|
||||
};
|
||||
|
||||
while let Some(c) = self.peek() {
|
||||
// If at the second character and
|
||||
// the first character is a zero,
|
||||
// allow a letter
|
||||
@ -239,15 +233,15 @@ impl<'a> Lexer<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
if !c.is_digit(base as u32) && c != '.' && c != '_' && !c.is_whitespace()
|
||||
|| c == '\n'
|
||||
|| c == '\r'
|
||||
if !c.is_digit(base as u32) && *c != '.' && *c != '_' && !c.is_whitespace()
|
||||
|| *c == '\n'
|
||||
|| *c == '\r'
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
end += 1;
|
||||
value.push(c);
|
||||
value.push(*c);
|
||||
self.advance();
|
||||
}
|
||||
|
||||
@ -258,7 +252,7 @@ impl<'a> Lexer<'a> {
|
||||
self.advance();
|
||||
}
|
||||
|
||||
if base_str != "" {
|
||||
if !base_str.is_empty() {
|
||||
base = crate::text_utils::subscript_to_normal(base_str.chars())
|
||||
.parse::<u8>()
|
||||
.unwrap_or(10);
|
||||
@ -295,7 +289,7 @@ impl<'a> Lexer<'a> {
|
||||
self.advance();
|
||||
let num = self.next().value;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -353,7 +347,7 @@ impl<'a> Lexer<'a> {
|
||||
_ => value, // things like log_2 are handled in the parser
|
||||
};
|
||||
|
||||
if subscript.len() > 0 {
|
||||
if !subscript.is_empty() {
|
||||
build(
|
||||
kind,
|
||||
&format!(
|
||||
@ -433,7 +427,7 @@ mod tests {
|
||||
TokenKind::Equals,
|
||||
TokenKind::Exclamation,
|
||||
TokenKind::Comma,
|
||||
TokenKind::EOF,
|
||||
TokenKind::Eof,
|
||||
];
|
||||
|
||||
match_tokens(tokens, expected);
|
||||
@ -449,7 +443,7 @@ mod tests {
|
||||
TokenKind::LessThan,
|
||||
TokenKind::Literal,
|
||||
TokenKind::ClosedBracket,
|
||||
TokenKind::EOF,
|
||||
TokenKind::Eof,
|
||||
];
|
||||
|
||||
match_tokens(tokens, expected);
|
||||
@ -465,10 +459,10 @@ mod tests {
|
||||
let tokens = Lexer::new(input).lex();
|
||||
|
||||
if regex::Regex::new(r"^\s*$").unwrap().is_match(input) {
|
||||
let expected = vec![TokenKind::EOF];
|
||||
let expected = vec![TokenKind::Eof];
|
||||
match_tokens(tokens, expected);
|
||||
} else {
|
||||
let expected = vec![TokenKind::Identifier, TokenKind::EOF];
|
||||
let expected = vec![TokenKind::Identifier, TokenKind::Eof];
|
||||
match_tokens(tokens, expected);
|
||||
}
|
||||
}
|
||||
@ -479,7 +473,7 @@ mod tests {
|
||||
#[test_case("56.4")]
|
||||
fn test_number_literal(input: &str) {
|
||||
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);
|
||||
match_tokens(tokens, expected);
|
||||
@ -489,7 +483,7 @@ mod tests {
|
||||
#[test_case("xy")]
|
||||
fn test_identifier(input: &str) {
|
||||
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);
|
||||
match_tokens(tokens, expected);
|
||||
@ -503,7 +497,7 @@ mod tests {
|
||||
TokenKind::OpenParenthesis,
|
||||
TokenKind::Identifier,
|
||||
TokenKind::ClosedParenthesis,
|
||||
TokenKind::EOF,
|
||||
TokenKind::Eof,
|
||||
];
|
||||
|
||||
match_tokens(tokens, expected);
|
||||
|
@ -1,3 +1,4 @@
|
||||
#![allow(clippy::unused_unit)]
|
||||
mod analysis;
|
||||
pub mod ast;
|
||||
pub mod calculation_result;
|
||||
|
@ -11,8 +11,8 @@ use crate::{
|
||||
};
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
pub const DECL_UNIT: &'static str = ".u";
|
||||
pub const DEFAULT_ANGLE_UNIT: &'static str = "rad";
|
||||
pub const DECL_UNIT: &str = ".u";
|
||||
pub const DEFAULT_ANGLE_UNIT: &str = "rad";
|
||||
|
||||
/// Struct containing the current state of the parser. It stores user-defined functions and variables.
|
||||
#[wasm_bindgen]
|
||||
@ -118,10 +118,10 @@ pub enum CalcError {
|
||||
impl ToString for CalcError {
|
||||
fn to_string(&self) -> String {
|
||||
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::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::ExpectedIf => format!("Expected 'if', with a condition after it."),
|
||||
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 => String::from("Expected 'if', with a condition after it."),
|
||||
CalcError::IncorrectAmountOfArguments(expected, func, got) => format!(
|
||||
"Expected {} arguments for function {}, but got {}.",
|
||||
expected, func, got
|
||||
@ -131,25 +131,25 @@ impl ToString for CalcError {
|
||||
expected, got
|
||||
),
|
||||
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::InvalidNumberLiteral(x) => format!("Invalid number literal: '{}'.", x),
|
||||
CalcError::InvalidOperator => format!("Invalid operator."),
|
||||
CalcError::InvalidUnit => format!("Invalid unit."),
|
||||
CalcError::TimedOut => format!("Operation took too long."),
|
||||
CalcError::VariableReferencesItself => format!("Variable references itself."),
|
||||
CalcError::PiecewiseConditionsAreFalse => format!("All the conditions in the piecewise are false."),
|
||||
CalcError::InvalidOperator => String::from("Invalid operator."),
|
||||
CalcError::InvalidUnit => String::from("Invalid unit."),
|
||||
CalcError::TimedOut => String::from("Operation took too long."),
|
||||
CalcError::VariableReferencesItself => String::from("Variable references itself."),
|
||||
CalcError::PiecewiseConditionsAreFalse => String::from("All the conditions in the piecewise are false."),
|
||||
CalcError::UnexpectedToken(got, expected) => {
|
||||
format!("Unexpected token: '{:?}', expected '{:?}'.", got, expected)
|
||||
}
|
||||
CalcError::UnableToInvert(msg) => format!("Unable to invert: {}", msg),
|
||||
CalcError::UndefinedFn(name) => format!("Undefined function: '{}'.", name),
|
||||
CalcError::UndefinedVar(name) => format!("Undefined variable: '{}'.", name),
|
||||
CalcError::UnableToParseExpression => format!("Unable to parse expression."),
|
||||
CalcError::UnableToSolveEquation => format!("Unable to solve equation."),
|
||||
CalcError::UnableToParseExpression => String::from("Unable to parse expression."),
|
||||
CalcError::UnableToSolveEquation => String::from("Unable to solve equation."),
|
||||
CalcError::UnableToOverrideConstant(name) => format!("Unable to override constant: '{}'.", name),
|
||||
CalcError::UnrecognizedBase => format!("Unrecognized base."),
|
||||
CalcError::Unknown => format!("Unknown error."),
|
||||
CalcError::UnrecognizedBase => String::from("Unrecognized base."),
|
||||
CalcError::Unknown => String::from("Unknown error."),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -164,17 +164,13 @@ pub fn eval(
|
||||
) -> Result<Option<CalculationResult>, CalcError> {
|
||||
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(
|
||||
&mut symbol_table,
|
||||
symbol_table,
|
||||
&context.angle_unit,
|
||||
#[cfg(feature = "rug")]
|
||||
precision,
|
||||
if let Some(timeout) = context.timeout {
|
||||
Some(timeout as u128)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
context.timeout.map(|timeout| timeout as u128),
|
||||
);
|
||||
let result = interpreter.interpret(statements);
|
||||
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();
|
||||
while !is_at_end(context) {
|
||||
let parsed = parse_stmt(context)?;
|
||||
let mut symbol_table = context.symbol_table.get_mut();
|
||||
let analysed = analysis::analyse_stmt(&mut symbol_table, parsed)?;
|
||||
let symbol_table = context.symbol_table.get_mut();
|
||||
let analysed = analysis::analyse_stmt(symbol_table, parsed)?;
|
||||
statements.push(analysed);
|
||||
|
||||
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(
|
||||
base_unit.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));
|
||||
|
||||
@ -309,7 +305,7 @@ fn parse_unit_decl_stmt(context: &mut Context) -> Result<Stmt, 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> {
|
||||
@ -386,9 +382,7 @@ fn parse_comparison(context: &mut Context) -> Result<Expr, CalcError> {
|
||||
left = match right {
|
||||
Expr::Binary(
|
||||
inner_left,
|
||||
inner_op
|
||||
@
|
||||
(TokenKind::Equals
|
||||
inner_op @ (TokenKind::Equals
|
||||
| TokenKind::NotEquals
|
||||
| TokenKind::GreaterThan
|
||||
| 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() {
|
||||
let try_parse = parse_factor(context);
|
||||
if !try_parse.is_err() {
|
||||
if try_parse.is_ok() {
|
||||
left = Expr::Binary(
|
||||
percent_left,
|
||||
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;
|
||||
}
|
||||
|
||||
if peek(context).kind == TokenKind::EOF {
|
||||
if peek(context).kind == TokenKind::Eof {
|
||||
return Err(CalcError::Expected(String::from(
|
||||
"Closing group symbol, eg. )",
|
||||
)));
|
||||
@ -674,7 +668,7 @@ fn parse_identifier(context: &mut Context) -> Result<Expr, CalcError> {
|
||||
|
||||
fn peek(context: &Context) -> &Token {
|
||||
if context.pos >= context.tokens.len() {
|
||||
&context.tokens.last().unwrap() // EOF
|
||||
context.tokens.last().unwrap() // Eof
|
||||
} else {
|
||||
&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 {
|
||||
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) {
|
||||
@ -756,8 +750,8 @@ mod tests {
|
||||
context.pos = 0;
|
||||
|
||||
let parsed = parse_stmt(context)?;
|
||||
let mut symbol_table = context.symbol_table.get_mut();
|
||||
analysis::analyse_stmt(&mut symbol_table, parsed)
|
||||
let symbol_table = context.symbol_table.get_mut();
|
||||
analysis::analyse_stmt(symbol_table, parsed)
|
||||
}
|
||||
|
||||
fn parse(tokens: Vec<Token>) -> Result<Stmt, CalcError> {
|
||||
@ -766,15 +760,15 @@ mod tests {
|
||||
context.pos = 0;
|
||||
|
||||
let parsed = parse_stmt(&mut context)?;
|
||||
let mut symbol_table = context.symbol_table.get_mut();
|
||||
analysis::analyse_stmt(&mut symbol_table, parsed)
|
||||
let symbol_table = context.symbol_table.get_mut();
|
||||
analysis::analyse_stmt(symbol_table, parsed)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[wasm_bindgen_test]
|
||||
fn test_var() {
|
||||
// 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")));
|
||||
}
|
||||
@ -797,7 +791,7 @@ mod tests {
|
||||
token(Identifier, "xy"),
|
||||
token(Power, ""),
|
||||
token(Literal, "2"),
|
||||
token(EOF, ""),
|
||||
token(Eof, ""),
|
||||
];
|
||||
|
||||
assert_eq!(
|
||||
@ -826,7 +820,7 @@ mod tests {
|
||||
token(Slash, ""),
|
||||
token(Literal, "5"),
|
||||
token(ClosedParenthesis, ""),
|
||||
token(EOF, ""),
|
||||
token(Eof, ""),
|
||||
];
|
||||
|
||||
assert_eq!(
|
||||
@ -860,7 +854,7 @@ mod tests {
|
||||
token(Literal, "4"),
|
||||
token(Plus, ""),
|
||||
token(Literal, "5"),
|
||||
token(EOF, ""),
|
||||
token(Eof, ""),
|
||||
];
|
||||
|
||||
assert_eq!(
|
||||
@ -891,7 +885,7 @@ mod tests {
|
||||
token(Plus, ""),
|
||||
token(Literal, "5"),
|
||||
token(Percent, ""),
|
||||
token(EOF, ""),
|
||||
token(Eof, ""),
|
||||
];
|
||||
|
||||
assert_eq!(
|
||||
@ -930,7 +924,7 @@ mod tests {
|
||||
token(Literal, "1"),
|
||||
token(Plus, ""),
|
||||
token(Literal, "2"),
|
||||
token(EOF, ""),
|
||||
token(Eof, ""),
|
||||
];
|
||||
|
||||
assert_eq!(
|
||||
@ -954,7 +948,7 @@ mod tests {
|
||||
token(Literal, "1"),
|
||||
token(Plus, ""),
|
||||
token(Identifier, "x"),
|
||||
token(EOF, ""),
|
||||
token(Eof, ""),
|
||||
];
|
||||
|
||||
assert_eq!(
|
||||
@ -979,7 +973,7 @@ mod tests {
|
||||
token(ClosedParenthesis, ""),
|
||||
token(Plus, ""),
|
||||
token(Literal, "3"),
|
||||
token(EOF, ""),
|
||||
token(Eof, ""),
|
||||
];
|
||||
|
||||
let mut context = Context::new();
|
||||
|
@ -22,27 +22,15 @@ use crate::interpreter;
|
||||
pub use funcs::*;
|
||||
|
||||
// `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! {
|
||||
pub static ref CONSTANTS: HashMap<&'static str, f64> = {
|
||||
let mut m = HashMap::new();
|
||||
m.insert(
|
||||
"pi",
|
||||
3.1415926535897932384626433832795028841971693993751058209749445923,
|
||||
);
|
||||
m.insert(
|
||||
"e",
|
||||
2.7182818284590452353602874713526624977572470936999595749669676277,
|
||||
);
|
||||
m.insert(
|
||||
"tau",
|
||||
6.2831853071795864769252867665590057683943387987502116419498891846,
|
||||
);
|
||||
m.insert(
|
||||
"phi",
|
||||
1.6180339887498948482045868343656381177203091798057628621354486227,
|
||||
);
|
||||
m.insert("pi", std::f64::consts::PI);
|
||||
m.insert("e", std::f64::consts::E);
|
||||
m.insert("tau", std::f64::consts::TAU);
|
||||
m.insert("phi", 1.618_033_988_749_895);
|
||||
m
|
||||
};
|
||||
pub static ref UNARY_FUNCS: HashMap<&'static str, (UnaryFuncInfo, &'static str)> = {
|
||||
@ -205,7 +193,7 @@ pub fn call_unary_func(
|
||||
) -> Option<(KalkValue, String)> {
|
||||
if let Some((func_info, func_unit)) = UNARY_FUNCS.get(name) {
|
||||
Some((
|
||||
func_info.call(context, x, &angle_unit),
|
||||
func_info.call(context, x, angle_unit),
|
||||
func_unit.to_string(),
|
||||
))
|
||||
} else {
|
||||
@ -231,11 +219,7 @@ pub fn call_binary_func(
|
||||
}
|
||||
|
||||
pub fn call_vector_func(name: &str, x: KalkValue) -> Option<KalkValue> {
|
||||
if let Some(func_info) = VECTOR_FUNCS.get(name) {
|
||||
Some(func_info.call(x))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
VECTOR_FUNCS.get(name).map(|func_info| func_info.call(x))
|
||||
}
|
||||
|
||||
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)
|
||||
let root =
|
||||
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) =
|
||||
as_number_or_return!(ln(iroot.add_without_unit(&x)));
|
||||
|
||||
@ -305,11 +289,7 @@ pub mod funcs {
|
||||
imaginary.clone(),
|
||||
unit.clone(),
|
||||
));
|
||||
let sqrt2 = sqrt(KalkValue::Number(
|
||||
real.clone() - 1f64,
|
||||
imaginary.clone(),
|
||||
unit,
|
||||
));
|
||||
let sqrt2 = sqrt(KalkValue::Number(real - 1f64, imaginary, unit));
|
||||
|
||||
ln(x.add_without_unit(&sqrt1.mul_without_unit(&sqrt2)))
|
||||
} else {
|
||||
@ -399,11 +379,7 @@ pub mod funcs {
|
||||
inv_unit.clone(),
|
||||
));
|
||||
// sqrt(1/z + 1)
|
||||
let sqrt2 = sqrt(KalkValue::Number(
|
||||
inv_real.clone() + 1f64,
|
||||
inv_imaginary.clone(),
|
||||
inv_unit,
|
||||
));
|
||||
let sqrt2 = sqrt(KalkValue::Number(inv_real + 1f64, inv_imaginary, inv_unit));
|
||||
|
||||
// ln(1/z + sqrt(1/z - 1) * sqrt(1/z + 1))
|
||||
ln(sqrt1.mul_without_unit(&sqrt2).add_without_unit(&inv))
|
||||
@ -418,7 +394,7 @@ pub mod funcs {
|
||||
// i * ln(sqrt(1 - z²) - iz)
|
||||
let root =
|
||||
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));
|
||||
multiply_with_i(ln)
|
||||
} else {
|
||||
@ -600,10 +576,10 @@ pub mod funcs {
|
||||
}
|
||||
|
||||
if x.has_imaginary() || y.has_imaginary() {
|
||||
if real.clone().fract() != 0f64
|
||||
|| real_rhs.clone().fract() != 0f64
|
||||
|| imaginary.clone().fract() != 0f64
|
||||
|| imaginary_rhs.clone().fract() != 0f64
|
||||
if real.fract() != 0f64
|
||||
|| real_rhs.fract() != 0f64
|
||||
|| imaginary.fract() != 0f64
|
||||
|| imaginary_rhs.fract() != 0f64
|
||||
{
|
||||
// Not a Gaussian integer!
|
||||
// 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 (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 {
|
||||
KalkValue::Number(b_real.abs(), b_imaginary, b_unit)
|
||||
} else {
|
||||
@ -646,8 +622,8 @@ pub mod funcs {
|
||||
}
|
||||
|
||||
// Euclidean GCD algorithm, but with modulus
|
||||
let mut x_a = real.clone();
|
||||
let mut y_a = real_rhs.clone();
|
||||
let mut x_a = real;
|
||||
let mut y_a = real_rhs;
|
||||
while !y_a.eq(&0f64) {
|
||||
let t = y_a.clone();
|
||||
y_a = x_a % y_a;
|
||||
@ -686,10 +662,10 @@ pub mod funcs {
|
||||
pub fn lcm(x: KalkValue, y: KalkValue) -> KalkValue {
|
||||
let (real, imaginary, unit) = as_number_or_return!(x.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 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 {
|
||||
@ -728,7 +704,7 @@ pub mod funcs {
|
||||
let values = as_vector_or_return!(x);
|
||||
let mut max = &values[0];
|
||||
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 {
|
||||
max = value;
|
||||
}
|
||||
@ -742,7 +718,7 @@ pub mod funcs {
|
||||
let values = as_vector_or_return!(x);
|
||||
let mut min = &values[0];
|
||||
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 {
|
||||
min = value;
|
||||
}
|
||||
@ -795,7 +771,7 @@ pub mod funcs {
|
||||
pub fn sqrt(x: KalkValue) -> KalkValue {
|
||||
let (real, imaginary, unit) = as_number_or_return!(x.clone());
|
||||
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 a = real;
|
||||
let b = imaginary;
|
||||
@ -949,6 +925,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(clippy::approx_constant)]
|
||||
fn test_trig_funcs() {
|
||||
// Auto-generated using kalk/scripts/generate_funcs_test_cases.py
|
||||
let in_out = vec![
|
||||
@ -1192,7 +1169,6 @@ mod tests {
|
||||
|| actual_output.imaginary_to_f64().is_infinite();
|
||||
|
||||
if expected_has_nan_or_inf || actual_has_nan_or_inf {
|
||||
assert!(true);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -24,10 +24,10 @@ pub fn parse_float_radix(value: &str, radix: u8) -> Option<f64> {
|
||||
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 {
|
||||
let mut num = value.abs();
|
||||
let mut result_str = String::new();
|
||||
@ -37,7 +37,7 @@ pub fn int_to_radix(value: i64, radix: u8) -> String {
|
||||
num /= radix as i64;
|
||||
}
|
||||
|
||||
if result_str == "" {
|
||||
if result_str.is_empty() {
|
||||
return String::from("0");
|
||||
}
|
||||
|
||||
@ -52,7 +52,7 @@ pub fn float_to_radix(value: f64, radix: u8) -> String {
|
||||
result.push('.');
|
||||
let precision = 10;
|
||||
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
|
||||
|
@ -100,3 +100,9 @@ impl SymbolTable {
|
||||
|| self.hashmap.contains_key(&format!("fn.{}", identifier))
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for SymbolTable {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +1,10 @@
|
||||
pub fn is_superscript(c: &char) -> bool {
|
||||
match c {
|
||||
'⁰' | '¹' | '²' | '³' | '⁴' | '⁵' | '⁶' | '⁷' | '⁸' | '⁹' | '⁺' | '⁻' | '⁼' | '⁽' | '⁾' => {
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
matches!(c, '⁰' | '¹' | '²' | '³' | '⁴' | '⁵' | '⁶' | '⁷' | '⁸' | '⁹' | '⁺' | '⁻' | '⁼' | '⁽' | '⁾')
|
||||
}
|
||||
|
||||
pub fn is_subscript(c: &char) -> bool {
|
||||
match c {
|
||||
'₀' | '₁' | '₂' | '₃' | '₄' | '₅' | '₆' | '₇' | '₈' | '₉' | '₊' | '₋' | '₌' | '₍' | '₎'
|
||||
| 'ₖ' | 'ₗ' | 'ₘ' | 'ₙ' | 'ₓ' => true,
|
||||
_ => false,
|
||||
}
|
||||
matches!(c, '₀' | '₁' | '₂' | '₃' | '₄' | '₅' | '₆' | '₇' | '₈' | '₉' | '₊' | '₋' | '₌' | '₍' | '₎'
|
||||
| 'ₖ' | 'ₗ' | 'ₘ' | 'ₙ' | 'ₓ')
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user