fix exp function
this is very cursed. I should really rewrite function parsing.
This commit is contained in:
parent
6f1d64ea02
commit
36f41ac473
@ -2,4 +2,3 @@ edition = "2021"
|
|||||||
fn_args_layout = "Compressed"
|
fn_args_layout = "Compressed"
|
||||||
fn_single_line = true
|
fn_single_line = true
|
||||||
hard_tabs = true
|
hard_tabs = true
|
||||||
wrap_comments = true
|
|
||||||
|
|||||||
15
build.rs
15
build.rs
@ -53,7 +53,20 @@ fn generate_hashmap() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
writeln!(&mut file, ";").unwrap();
|
writeln!(&mut file, ";").unwrap();
|
||||||
|
|
||||||
write!(&mut file, "const MAX_COMPLETION_LEN: usize = {};", max_len).unwrap();
|
write!(
|
||||||
|
&mut file,
|
||||||
|
"const MAX_COMPLETION_LEN: usize = {};\n",
|
||||||
|
max_len
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
write!(
|
||||||
|
&mut file,
|
||||||
|
"#[allow(dead_code)] pub const SUPPORTED_FUNCTIONS: [&str; {}] = {:?};",
|
||||||
|
SUPPORTED_FUNCTIONS.len(),
|
||||||
|
SUPPORTED_FUNCTIONS.to_vec()
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
include!(concat!(
|
include!(concat!(
|
||||||
|
|||||||
@ -49,8 +49,7 @@ const_assert!(DEFAULT_MAX_X > DEFAULT_MIN_X);
|
|||||||
pub const DEFAULT_INTEGRAL_NUM: usize = 100;
|
pub const DEFAULT_INTEGRAL_NUM: usize = 100;
|
||||||
|
|
||||||
/// Colors used for plotting
|
/// Colors used for plotting
|
||||||
// Colors commented out are used elsewhere and are not included here for better
|
// Colors commented out are used elsewhere and are not included here for better user experience
|
||||||
// user experience
|
|
||||||
pub const COLORS: &[Color32; 14] = &[
|
pub const COLORS: &[Color32; 14] = &[
|
||||||
Color32::RED,
|
Color32::RED,
|
||||||
// Color32::GREEN,
|
// Color32::GREEN,
|
||||||
|
|||||||
@ -74,28 +74,29 @@ One limitation though, variables with multiple characters like `pi` cannot be mu
|
|||||||
In the future I may want to completely rewrite this or implement this natively in exmex.
|
In the future I may want to completely rewrite this or implement this natively in exmex.
|
||||||
*/
|
*/
|
||||||
pub fn process_func_str(function_in: &str) -> String {
|
pub fn process_func_str(function_in: &str) -> String {
|
||||||
let function = function_in.replace("log10(", "log(").replace("pi", "π"); // pi -> π and log10 -> log
|
let function = function_in
|
||||||
|
.replace("log10(", "log(") // log10 -> log
|
||||||
|
.replace("pi", "π") // pi -> π
|
||||||
|
.replace("exp", "\u{1fc93}"); // replace 'exp' with this random unicode character because it can't be parsed correctly
|
||||||
let function_chars: Vec<char> = function.chars().collect();
|
let function_chars: Vec<char> = function.chars().collect();
|
||||||
let mut output_string: String = String::new();
|
let mut output_string: String = String::new();
|
||||||
let mut prev_chars: Vec<char> = Vec::new();
|
for (i, c) in function_chars.iter().enumerate() {
|
||||||
for c in function_chars {
|
|
||||||
let mut add_asterisk: bool = false;
|
let mut add_asterisk: bool = false;
|
||||||
let prev_chars_len = prev_chars.len();
|
|
||||||
|
|
||||||
let prev_prev_prev_char = if prev_chars_len >= 3 {
|
let prev_prev_prev_char = if i > 2 {
|
||||||
*prev_chars.get(prev_chars_len - 3).unwrap()
|
*function_chars.get(i - 3).unwrap()
|
||||||
} else {
|
} else {
|
||||||
' '
|
' '
|
||||||
};
|
};
|
||||||
|
|
||||||
let prev_prev_char = if prev_chars_len >= 2 {
|
let prev_prev_char = if i > 1 {
|
||||||
*prev_chars.get(prev_chars_len - 2).unwrap()
|
*function_chars.get(i - 2).unwrap()
|
||||||
} else {
|
} else {
|
||||||
' '
|
' '
|
||||||
};
|
};
|
||||||
|
|
||||||
let prev_char = if prev_chars_len >= 1 {
|
let prev_char = if i > 0 {
|
||||||
*prev_chars.get(prev_chars_len - 1).unwrap()
|
*function_chars.get(i - 1).unwrap()
|
||||||
} else {
|
} else {
|
||||||
' '
|
' '
|
||||||
};
|
};
|
||||||
@ -107,12 +108,12 @@ pub fn process_func_str(function_in: &str) -> String {
|
|||||||
let prev_char_is_number = NUMBERS.contains(&prev_char);
|
let prev_char_is_number = NUMBERS.contains(&prev_char);
|
||||||
|
|
||||||
// makes special case for log with base of a 1-2 digit number
|
// makes special case for log with base of a 1-2 digit number
|
||||||
if (prev_prev_prev_char == 'l')
|
if ((prev_prev_prev_char == 'l')
|
||||||
&& (prev_prev_char == 'o')
|
&& (prev_prev_char == 'o')
|
||||||
&& (prev_char == 'g')
|
&& (prev_char == 'g')
|
||||||
&& c_is_number
|
&& c_is_number)
|
||||||
|
| ((prev_prev_char == 'c') && (prev_char == 'e') && (*c == 'i'))
|
||||||
{
|
{
|
||||||
prev_chars.push(c);
|
|
||||||
output_string += &c.to_string();
|
output_string += &c.to_string();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -122,10 +123,10 @@ pub fn process_func_str(function_in: &str) -> String {
|
|||||||
|
|
||||||
if prev_char == ')' {
|
if prev_char == ')' {
|
||||||
// cases like `)x`, `)2`, and `)(`
|
// cases like `)x`, `)2`, and `)(`
|
||||||
if c_letters_var | c_is_number | (c == '(') {
|
if c_letters_var | c_is_number | (*c == '(') {
|
||||||
add_asterisk = true;
|
add_asterisk = true;
|
||||||
}
|
}
|
||||||
} else if c == '(' {
|
} else if *c == '(' {
|
||||||
// cases like `x(` and `2(`
|
// cases like `x(` and `2(`
|
||||||
if (prev_char_is_variable | prev_char_is_number) && !LETTERS.contains(&prev_prev_char) {
|
if (prev_char_is_variable | prev_char_is_number) && !LETTERS.contains(&prev_prev_char) {
|
||||||
add_asterisk = true;
|
add_asterisk = true;
|
||||||
@ -151,21 +152,20 @@ pub fn process_func_str(function_in: &str) -> String {
|
|||||||
|
|
||||||
// if add_asterisk is true, add the asterisk
|
// if add_asterisk is true, add the asterisk
|
||||||
if add_asterisk {
|
if add_asterisk {
|
||||||
|
println!("a");
|
||||||
output_string += "*";
|
output_string += "*";
|
||||||
}
|
}
|
||||||
|
|
||||||
// puch current char to vector of previously parsed chars
|
|
||||||
prev_chars.push(c);
|
|
||||||
|
|
||||||
// push current char to `output_string` (which is eventually returned)
|
// push current char to `output_string` (which is eventually returned)
|
||||||
output_string += &c.to_string();
|
output_string += &c.to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
output_string.replace("log(", "log10(")
|
output_string
|
||||||
|
.replace("log(", "log10(")
|
||||||
|
.replace('\u{1fc93}', "exp")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tests function to make sure it's able to be parsed. Returns the string of
|
/// Tests function to make sure it's able to be parsed. Returns the string of the Error produced, or an empty string if it runs successfully.
|
||||||
/// the Error produced, or an empty string if it runs successfully.
|
|
||||||
pub fn test_func(function_string: &str) -> Option<String> {
|
pub fn test_func(function_string: &str) -> Option<String> {
|
||||||
if function_string.is_empty() {
|
if function_string.is_empty() {
|
||||||
return None;
|
return None;
|
||||||
@ -198,15 +198,13 @@ pub fn test_func(function_string: &str) -> Option<String> {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::suggestions::SUPPORTED_FUNCTIONS;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
/// returns if function with string `func_str` is valid after processing
|
/// returns if function with string `func_str` is valid after processing through [`process_func_str`]
|
||||||
/// through [`process_func_str`]
|
|
||||||
fn func_is_valid(func_str: &str) -> bool { test_func(&process_func_str(func_str)).is_none() }
|
fn func_is_valid(func_str: &str) -> bool { test_func(&process_func_str(func_str)).is_none() }
|
||||||
|
|
||||||
/// Used for testing: passes function to [`process_func_str`] before running
|
/// Used for testing: passes function to [`process_func_str`] before running [`test_func`]. if `expect_valid` == `true`, it expects no errors to be created.
|
||||||
/// [`test_func`]. if `expect_valid` == `true`, it expects no errors to be
|
|
||||||
/// created.
|
|
||||||
fn test_func_helper(func_str: &str, expect_valid: bool) {
|
fn test_func_helper(func_str: &str, expect_valid: bool) {
|
||||||
let is_valid = func_is_valid(func_str);
|
let is_valid = func_is_valid(func_str);
|
||||||
println!(
|
println!(
|
||||||
@ -274,6 +272,7 @@ mod tests {
|
|||||||
/// Tests to make sure my cursed function works as intended
|
/// Tests to make sure my cursed function works as intended
|
||||||
#[test]
|
#[test]
|
||||||
fn func_process_test() {
|
fn func_process_test() {
|
||||||
|
/*
|
||||||
let values = HashMap::from([
|
let values = HashMap::from([
|
||||||
("2x", "2*x"),
|
("2x", "2*x"),
|
||||||
("x2", "x*2"),
|
("x2", "x*2"),
|
||||||
@ -303,9 +302,28 @@ mod tests {
|
|||||||
("pisin(x)", "π*sin(x)"),
|
("pisin(x)", "π*sin(x)"),
|
||||||
("e^sin(x)", "e^sin(x)"),
|
("e^sin(x)", "e^sin(x)"),
|
||||||
]);
|
]);
|
||||||
|
*/
|
||||||
|
let values = HashMap::from([
|
||||||
|
("2x", "2*x"),
|
||||||
|
(")(", ")*("),
|
||||||
|
("(2", "(2"),
|
||||||
|
("log10(x)", "log10(x)"),
|
||||||
|
("log2(x)", "log2(x)"),
|
||||||
|
("pipipipipipi", "π*π*π*π*π*π"),
|
||||||
|
("10pi", "10*π"),
|
||||||
|
("pi10", "π*10"),
|
||||||
|
("emax(x)", "e*max(x)"),
|
||||||
|
("pisin(x)", "π*sin(x)"),
|
||||||
|
("e^sin(x)", "e^sin(x)"),
|
||||||
|
]);
|
||||||
|
|
||||||
for (key, value) in values {
|
for (key, value) in values {
|
||||||
test_process_helper(key, value);
|
test_process_helper(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for func in SUPPORTED_FUNCTIONS.iter() {
|
||||||
|
let func_new = format!("{}(x)", func);
|
||||||
|
test_process_helper(&func_new, &func_new);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user