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);
}
if context.args.len() == 0 {
if context.args.is_empty() {
// REPL
repl::start(&mut parser_context, precision);
} else {

View File

@ -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()
}
}

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)?
}
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);
}

View File

@ -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 {

View File

@ -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)
}
}

View File

@ -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,
"",

View File

@ -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());
}

View File

@ -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())),
}
}

View File

@ -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()
}
}

View File

@ -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()

View File

@ -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);

View File

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

View File

@ -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();

View File

@ -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;
}

View File

@ -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

View File

@ -100,3 +100,9 @@ impl SymbolTable {
|| 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 {
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
}