This repository has been archived on 2023-09-03. You can view files and clone it, but cannot push or open issues or pull requests.
rclc/src/expression_parser.rs

154 lines
5.6 KiB
Rust
Raw Normal View History

2023-02-11 16:07:28 +01:00
use std::fmt;
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(),
}
}
}
/*
* 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
// find children
2023-02-11 18:42:18 +01:00
// TODO add error for unused task parameters
2023-02-11 19:41:03 +01:00
// TODO add supprot for truly recursie expressions, currently only one expression can be in
// a root expression.
let re_sub_expression = Regex::new(r"\w+\(.+?\)").unwrap(); // FIXME doesnt support nested
// expressions!!!
2023-02-11 16:07:28 +01:00
if re_sub_expression.is_match(&expression_text) {
2023-02-11 18:42:18 +01:00
let mut children: Vec<Expression> = Vec::new();
2023-02-11 16:07:28 +01:00
for sub_expression_text in re_sub_expression.captures_iter(&expression_text) {
2023-02-11 18:42:18 +01:00
// if any task parameters are set ( syntax: task_para(expression) )
if sub_expression_text[0].contains('_') {
2023-02-11 19:41:03 +01:00
let task_and_expr: Vec<&str> = sub_expression_text[0].split(['_', '(']).collect();
#[cfg(debug_assertions)]
dbg!(&task_and_expr);
let task = Task::new(task_and_expr[0], task_and_expr[1]);
let mut expression_inner = task_and_expr[2].clone().to_string();
#[cfg(debug_assertions)]
dbg!(&expression_inner);
expression_inner.pop();
#[cfg(debug_assertions)]
dbg!(&expression_inner);
children.push(Expression::new(expression_inner, task));
2023-02-11 18:42:18 +01:00
}
// if there are no parameters we need to do diffrent splitting and assume defaults
else {
2023-02-11 19:41:03 +01:00
let task_and_expr: Vec<&str> = sub_expression_text[0].split(['(']).collect();
#[cfg(debug_assertions)]
dbg!(&task_and_expr);
let task_text = task_and_expr[0].clone().to_lowercase();
let task = Task::new(&task_text, "");
let mut expression_inner = task_and_expr[1].clone().to_string();
expression_inner.pop();
#[cfg(debug_assertions)]
dbg!(&expression_inner);
children.push(Expression::new(expression_inner, task));
2023-02-11 18:42:18 +01:00
}
2023-02-11 16:07:28 +01:00
}
}
let expression = Expression {
text: expression_text,
// TODO generate these from the 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