diff options
| author | Nathan Reiner <nathan@nathanreiner.xyz> | 2024-01-17 18:24:21 +0100 |
|---|---|---|
| committer | Nathan Reiner <nathan@nathanreiner.xyz> | 2024-01-17 18:24:21 +0100 |
| commit | 5ccc6e5ec8a433f68bfeb17e8dcedec5b62a36a9 (patch) | |
| tree | 1101f7eeffd038a68d0a6a3e8a6cb77e39a537e5 /src/expression.rs | |
First sketch of matheval
Diffstat (limited to 'src/expression.rs')
| -rw-r--r-- | src/expression.rs | 73 |
1 files changed, 73 insertions, 0 deletions
diff --git a/src/expression.rs b/src/expression.rs new file mode 100644 index 0000000..5f2660b --- /dev/null +++ b/src/expression.rs @@ -0,0 +1,73 @@ +use crate::context::Context; +use crate::function::FunctionArgument; +use crate::string::{ContainsAndSkipBrackets, SplitMatchingBracket}; + +pub struct Expression { + repr: String, +} + +impl Expression { + pub fn from_string(str: &str) -> Self { + Self { + repr: str.replace(' ', ""), + } + } + + pub fn evaluate(&self, context: &Context) -> Result<f64, String> { + let (repr, oprepr) = { + if self.repr.starts_with('(') { + let (oprepr, r) = self.repr.split_on_matching_bracket(); + if r.is_empty() { + let repr = oprepr[1..oprepr.len() - 1].to_string(); + (repr.clone(), repr) + } else { + (self.repr.to_string(), r.to_string()) + } + } else { + (self.repr.to_string(), self.repr.to_string()) + } + }; + + let curop: Option<_> = { + let mut o = None; + for op in context.operations() { + if oprepr.contains_and_skip_brackets(op.sign().to_string().as_str()) { + o = Some(op); + break; + } + } + o + }; + + if let Some(op) = curop { + let (first, rest) = repr.split_once_and_skipt_brackets(op.sign()).unwrap(); + let first_expr = Expression::from_string(first); + let rest_expr = Expression::from_string(rest); + Ok(op.evaluate(first_expr.evaluate(context)?, rest_expr.evaluate(context)?)) + } else { + if let Ok(r) = repr.parse::<f64>() { + Ok(r) + } else { + if let Some((func, args)) = repr.split_once('(') { + let mut argv = Vec::new(); + + for arg in args[..args.len() - 1].split(',') { + argv.push(Expression::from_string(arg).evaluate(context)?); + } + + if let Some(func) = context.function(func) { + Ok(func.eval(FunctionArgument::new(argv))) + } else { + Err(format!("function '{func}' not found")) + } + } else { + if let Some(res) = context.variable(&repr) { + Ok(*res) + } else { + Err(format!("variable '{repr}' not found")) + } + } + } + } + } +} |