2023-02-11 16:07:28 +01:00
|
|
|
use std::fmt;
|
2023-02-12 03:50:33 +01:00
|
|
|
use std::collections::HashMap;
|
|
|
|
use std::hash::Hash;
|
2023-02-11 16:07:28 +01:00
|
|
|
use regex::Regex;
|
2023-02-11 00:20:43 +01:00
|
|
|
|
2023-02-11 16:07:28 +01:00
|
|
|
// In an expression like `sqrt(25)` the Task would correspond to `sqrt`. This is the enum to
|
|
|
|
// configure possible Tasks.
|
|
|
|
// None means, the Expression doesn't send it's Value to a Task Handler
|
|
|
|
#[derive(Debug)] // automatically generate Debug Formatter
|
2023-02-11 18:42:18 +01:00
|
|
|
pub enum Task {
|
2023-02-11 16:07:28 +01:00
|
|
|
None,
|
|
|
|
Sqrt,
|
|
|
|
Power,
|
2023-02-11 18:42:18 +01:00
|
|
|
Log(u64),
|
2023-02-11 16:07:28 +01:00
|
|
|
}
|
2023-02-11 00:20:43 +01:00
|
|
|
|
2023-02-11 16:07:28 +01:00
|
|
|
// How to clone a Task, i was supprised I had to do it myself.
|
|
|
|
impl Clone for Task {
|
|
|
|
fn clone(&self) -> Self {
|
|
|
|
// This can probably be done cleaner than with a verbose match. FIXME
|
|
|
|
match self {
|
|
|
|
Task::None => Task::None,
|
|
|
|
Task::Sqrt => Task::Sqrt,
|
|
|
|
Task::Power => Task::Power,
|
2023-02-11 18:42:18 +01:00
|
|
|
Task::Log(base) => Task::Log(*base), // TODO add base for log
|
2023-02-11 16:07:28 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-11 18:42:18 +01:00
|
|
|
impl Task {
|
2023-02-11 19:41:03 +01:00
|
|
|
pub fn new(task_text: &str, task_param: &str) -> Task {
|
|
|
|
let task_text = task_text.to_lowercase();
|
|
|
|
match task_text.as_str() {
|
2023-02-11 18:42:18 +01:00
|
|
|
"none" => Task::None,
|
|
|
|
"sqrt" => Task::Sqrt,
|
|
|
|
"power"|"pow" => Task::Power,
|
|
|
|
"log"|"ln" => Task::Log(10), // TODO add base
|
|
|
|
// what to do if a bad task was given:
|
|
|
|
&_ => {eprintln!("Bad Task: {}", task_text); std::process::exit(1); },
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-02-11 16:07:28 +01:00
|
|
|
// An Expression is something that can be calculated. 20+5 is an expression. Expressions can
|
|
|
|
// contain other
|
|
|
|
// Expressions and have tasks: 20+sqrt(20+5)
|
|
|
|
// Expressions are marked down with braces and a task before those braces:
|
|
|
|
// task(Expression)
|
|
|
|
// once the Value of the Expression got calculated, the calculated value should be sent to the
|
|
|
|
// TaskHandler, if the Task of the Expression is not Task::None
|
|
|
|
pub struct Expression {
|
|
|
|
text: String,
|
|
|
|
task: Task,
|
|
|
|
complex: bool,
|
|
|
|
inner_value: f64,
|
|
|
|
outer_value: f64,
|
|
|
|
children: Vec<Expression>,
|
|
|
|
}
|
|
|
|
|
|
|
|
// Debug Formatter for Expression
|
|
|
|
impl fmt::Debug for Expression {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
f.debug_struct("Expression")
|
|
|
|
.field("text", &self.text)
|
|
|
|
.field("task", &self.task)
|
|
|
|
.field("is complex?", &self.complex)
|
|
|
|
.field("inner value", &self.inner_value)
|
|
|
|
.field("outer value", &self.outer_value)
|
|
|
|
.field("children", &self.children)
|
|
|
|
.finish()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// implement clone by ourselves, as it's not automatically done for us.
|
|
|
|
impl Clone for Expression{
|
|
|
|
fn clone(&self) -> Self {
|
|
|
|
Expression {
|
|
|
|
text: self.text.clone(),
|
|
|
|
task: self.task.clone(),
|
|
|
|
complex: self.complex.clone(), // TODO add support for complex numbers
|
|
|
|
inner_value: self.inner_value.clone(),
|
|
|
|
outer_value: self.outer_value.clone(),
|
|
|
|
children: self.children.clone(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-12 03:50:33 +01:00
|
|
|
fn find_brace_groups(haystack: String) -> Vec<Vec<(usize, usize)>> {
|
|
|
|
|
|
|
|
// TODO add support for diffrent braces
|
|
|
|
// TODO add error if not all braces are closed
|
|
|
|
let mut parenthesis_group: Vec<(usize, usize)> = Vec::new();
|
|
|
|
let mut parenthesis_open: usize = 0;
|
|
|
|
let mut parenthesis_open_processed: usize = 0;
|
|
|
|
let mut parenthesis_closed_processed: usize = 0;
|
|
|
|
let mut parenthesis_last_opened: Vec<usize> = Vec::new();
|
|
|
|
//let mut brackets_group: Vec<(usize, usize)> = Vec::new();
|
|
|
|
//let mut brackets_open: usize = 0;
|
|
|
|
//let mut square_braces_group: Vec<(usize, usize)> = Vec::new();
|
|
|
|
//let mut square_braces_open: usize = 0;
|
|
|
|
// first open stuff
|
|
|
|
for (index, char) in haystack.chars().enumerate() {
|
|
|
|
match char {
|
|
|
|
'(' => {
|
|
|
|
#[cfg(debug_assertions)]
|
|
|
|
{
|
|
|
|
dbg!(char);
|
|
|
|
dbg!(index);
|
|
|
|
}
|
|
|
|
parenthesis_group.push((index, 0));
|
|
|
|
parenthesis_open = parenthesis_open + 1;
|
|
|
|
parenthesis_last_opened.push(parenthesis_open_processed);
|
|
|
|
parenthesis_open_processed = parenthesis_open_processed + 1;
|
|
|
|
},
|
|
|
|
')' => {
|
|
|
|
let len = parenthesis_group.len();
|
|
|
|
#[cfg(debug_assertions)]
|
|
|
|
{
|
|
|
|
dbg!(char);
|
|
|
|
dbg!(index);
|
|
|
|
dbg!(parenthesis_last_opened.len());
|
|
|
|
dbg!(parenthesis_last_opened[parenthesis_last_opened.len() - 1]);
|
|
|
|
}
|
|
|
|
parenthesis_group[parenthesis_last_opened[parenthesis_last_opened.len() - 1]].1 = index;
|
|
|
|
parenthesis_open = parenthesis_open - 1;
|
|
|
|
parenthesis_closed_processed = parenthesis_closed_processed + 1;
|
|
|
|
parenthesis_last_opened.pop();
|
|
|
|
// TODO add error if no parenthesis is open yet.
|
|
|
|
},
|
|
|
|
_ => (),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// now iterate backwards and search for closing things
|
|
|
|
|
|
|
|
let brace_groups = vec![parenthesis_group/*, square_braces_group, brackets_group*/];
|
|
|
|
#[cfg(debug_assertions)]
|
|
|
|
dbg!(&brace_groups);
|
|
|
|
return brace_groups;
|
|
|
|
}
|
|
|
|
|
2023-02-11 16:07:28 +01:00
|
|
|
/*
|
|
|
|
* Main logic for the Expression struct
|
|
|
|
*/
|
|
|
|
impl Expression {
|
|
|
|
/*
|
|
|
|
* Main function for making text into Expression
|
2023-02-11 18:42:18 +01:00
|
|
|
* example: "12 + log_10(10 + 15) + 3"
|
|
|
|
* has a sub expression log_10(10 + 5), which has Task::Log with base 10
|
2023-02-11 16:07:28 +01:00
|
|
|
*/
|
2023-02-11 18:42:18 +01:00
|
|
|
pub fn new(expression_text: String, task: Task) -> Expression {
|
2023-02-11 16:07:28 +01:00
|
|
|
|
2023-02-12 03:50:33 +01:00
|
|
|
let re_contains_sub_expression= Regex::new(r"(\(.*\))|(\[.*\])|(\{.*\})").unwrap();
|
|
|
|
if re_contains_sub_expression.is_match(expression_text.as_str()) {
|
|
|
|
let brace_groups: Vec<Vec<(usize, usize)>> = find_brace_groups(expression_text.clone());
|
|
|
|
|
|
|
|
let mut brace_groups_texts: Vec<String> = Vec::new();
|
2023-02-11 18:42:18 +01:00
|
|
|
let mut children: Vec<Expression> = Vec::new();
|
2023-02-12 03:50:33 +01:00
|
|
|
|
|
|
|
for brace_group in brace_groups {
|
|
|
|
for pair in brace_group {
|
|
|
|
let text = &expression_text[pair.0..pair.1 + 1];
|
|
|
|
let text = &text[1..text.len() - 1];
|
|
|
|
dbg!(text);
|
2023-02-11 18:42:18 +01:00
|
|
|
}
|
2023-02-11 16:07:28 +01:00
|
|
|
}
|
2023-02-12 03:50:33 +01:00
|
|
|
}
|
|
|
|
|
2023-02-11 16:07:28 +01:00
|
|
|
|
|
|
|
let expression = Expression {
|
|
|
|
text: expression_text,
|
2023-02-11 18:42:18 +01:00
|
|
|
task: task,
|
2023-02-11 16:07:28 +01:00
|
|
|
complex: false,
|
|
|
|
inner_value: 0.0,
|
|
|
|
outer_value: 0.0,
|
|
|
|
children: Vec::new(),
|
|
|
|
};
|
2023-02-11 19:41:03 +01:00
|
|
|
#[cfg(debug_assertions)]
|
|
|
|
dbg!(&expression);
|
2023-02-11 16:07:28 +01:00
|
|
|
expression
|
|
|
|
}
|
2023-02-11 18:42:18 +01:00
|
|
|
|
|
|
|
pub fn process(&self) {
|
|
|
|
println!("{}", self.text);
|
|
|
|
}
|
2023-02-11 16:07:28 +01:00
|
|
|
}
|
2023-02-11 18:42:18 +01:00
|
|
|
|
2023-02-12 03:50:33 +01:00
|
|
|
enum Brace {
|
|
|
|
Open(char),
|
|
|
|
Closed(char),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Brace {
|
|
|
|
pub fn new(c: char) -> Option<Brace> {
|
|
|
|
match c {
|
|
|
|
'{' | '[' | '(' => Some(Brace::Open(c)),
|
|
|
|
'}' | ']' | ')' => Some(Brace::Closed(c)),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|