aboutsummaryrefslogtreecommitdiff
path: root/src/expression.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/expression.rs')
-rw-r--r--src/expression.rs73
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"))
+ }
+ }
+ }
+ }
+ }
+}