use super::complex::Complex; use super::context::Context; use super::function::FunctionArgument; use super::string::{ContainsAndSkipBrackets, SplitMatchingBracket}; use super::operation::Operation; enum ExpressionType { Value(Complex), Variable(String), Function(String, FunctionArgument), Operation(Operation, Box, Box), } impl Default for ExpressionType { fn default() -> Self { ExpressionType::Value(Complex::default()) } } #[derive(Default)] pub struct Expression { expr_type: ExpressionType, repr: String, } impl Expression { pub fn from_string(str: &str, operations: &Vec) -> Self { let mut ex = Self::default(); ex.repr = str.to_string(); ex.set_operations(operations); ex } pub fn content(&self) -> &str { &self.repr } pub fn set_operations(&mut self, operations: &Vec) { 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 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, operations); let rest_expr = Expression::from_string(rest, operations); self.expr_type = ExpressionType::Operation(op.clone(), Box::new(first_expr), Box::new(rest_expr)); } else if let Ok(r) = repr.parse::() { self.expr_type = ExpressionType::Value(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, operations)); } self.expr_type = ExpressionType::Function(func.to_string(), FunctionArgument::from_expressions(argv)); } else { self.expr_type = ExpressionType::Variable(repr); } } pub fn evaluate(&self, ctx: &Context) -> Result { match &self.expr_type { ExpressionType::Value(v) => Ok(*v), ExpressionType::Variable(var) => { if let Some(v) = ctx.variable(&var) { Ok(*v) } else { Err(format!("variable '{var}' not found")) } }, ExpressionType::Function(func, args) => { if let Some(f) = ctx.function(&func) { f.eval(args, ctx) } else { Err(format!("function '{func}' not found")) } } ExpressionType::Operation(op, a, b) => { Ok(op.evaluate(a.evaluate(ctx)?, b.evaluate(ctx)?)) } } } }