From 95ba627a9c5e4e6e1d79f7aaff1854eb831511b4 Mon Sep 17 00:00:00 2001 From: Nathan Reiner Date: Wed, 17 Jan 2024 23:54:52 +0100 Subject: hand context on to Function trait --- src/commonsense.rs | 15 ++++++++------- src/context.rs | 20 ++++++++++---------- src/expression.rs | 2 +- src/expression_function.rs | 18 +++++++----------- src/function.rs | 19 ++++++++++++++----- src/main.rs | 2 +- src/operation.rs | 7 ++++--- 7 files changed, 45 insertions(+), 38 deletions(-) (limited to 'src') diff --git a/src/commonsense.rs b/src/commonsense.rs index df688fb..4570109 100644 --- a/src/commonsense.rs +++ b/src/commonsense.rs @@ -40,7 +40,8 @@ pub fn tan(a: Complex) -> Complex { macro_rules! commonsense_functions { {$($x:expr => $y:expr), *} => { { - let mut h : HashMap> = HashMap::new(); + use std::sync::Arc; + let mut h : HashMap> = HashMap::new(); h.extend(functions!{ "sqrt" => &crate::commonsense::sqrt, "sin" => &crate::commonsense::sin, @@ -48,7 +49,7 @@ macro_rules! commonsense_functions { "tan" => &crate::commonsense::tan }); $( - h.insert($x.to_string(), Box::new($y)); + h.insert($x.to_string(), Arc::new($y)); )* h } @@ -59,11 +60,11 @@ macro_rules! commonsense_functions { macro_rules! commonsense_operations { {$($x:expr => $y:expr), *} => { vec![ - Operation::new('+', Box::new(&crate::commonsense::add)), - Operation::new('-', Box::new(&crate::commonsense::sub)), - Operation::new('*', Box::new(&crate::commonsense::mul)), - Operation::new('/', Box::new(&crate::commonsense::div)), - Operation::new('^', Box::new(&crate::commonsense::pow)) + Operation::new('+', crate::commonsense::add), + Operation::new('-', crate::commonsense::sub), + Operation::new('*', crate::commonsense::mul), + Operation::new('/', crate::commonsense::div), + Operation::new('^', crate::commonsense::pow) $( Operation::new($x, Box::new($y)), )*] diff --git a/src/context.rs b/src/context.rs index de1d09d..04e27f7 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1,13 +1,14 @@ +use crate::complex::Complex; use crate::function::Function; use crate::operation::Operation; -use crate::complex::Complex; +use std::sync::Arc; use std::collections::HashMap; -#[derive(Default)] +#[derive(Default, Clone)] pub struct Context { ops: Vec, vars: HashMap, - funcs: HashMap>, + funcs: HashMap>, } impl Context { @@ -25,7 +26,7 @@ impl Context { self } - pub fn with_functions(mut self, funcs: HashMap>) -> Self { + pub fn with_functions(mut self, funcs: HashMap>) -> Self { self.funcs = funcs; self } @@ -34,12 +35,12 @@ impl Context { &self.ops } - pub fn variable_mut(&mut self, name: &str) -> Option<&mut Complex> { - self.vars.get_mut(name) + pub fn set_variable(&mut self, name: &str, value: Complex) { + self.vars.insert(name.to_string(), value); } - pub fn function_mut(&mut self, name: &str) -> Option<&mut Box> { - self.funcs.get_mut(name) + pub fn set_function(&mut self, name: &str, func: Arc) { + self.funcs.insert(name.to_string(), func); } pub fn variable(&self, name: &str) -> Option<&Complex> { @@ -47,7 +48,7 @@ impl Context { } #[allow(clippy::borrowed_box)] - pub fn function(&self, name: &str) -> Option<&Box> { + pub fn function(&self, name: &str) -> Option<&Arc> { self.funcs.get(name) } } @@ -64,4 +65,3 @@ macro_rules! variables { } }; } - diff --git a/src/expression.rs b/src/expression.rs index 4029f93..c7574a9 100644 --- a/src/expression.rs +++ b/src/expression.rs @@ -55,7 +55,7 @@ impl Expression { } if let Some(func) = context.function(func) { - Ok(func.eval(FunctionArgument::new(argv))?) + Ok(func.eval(FunctionArgument::new(argv), context)?) } else { Err(format!("function '{func}' not found")) } diff --git a/src/expression_function.rs b/src/expression_function.rs index 35eba5f..138891f 100644 --- a/src/expression_function.rs +++ b/src/expression_function.rs @@ -1,12 +1,11 @@ use std::{collections::HashMap, iter::zip}; +use std::sync::Arc; use crate::{ - commonsense_functions, commonsense_operations, functions, complex::Complex, context::Context, expression::Expression, - operation::Operation, - function::{Function, FunctionArgument} + function::{Function, FunctionArgument, EmptyFunction} }; pub struct ExpressionFunction { @@ -38,17 +37,14 @@ impl ExpressionFunction { } impl Function for ExpressionFunction { - fn eval(&self, args: FunctionArgument) -> Result { + fn eval(&self, args: FunctionArgument, ctx: &Context) -> Result { if args.len() == self.args.len() { - let mut vars = HashMap::new(); + let mut nctx = ctx.clone(); for (n, v) in zip(self.args.iter(), args.data().iter()) { - vars.insert(n.to_string(), v.clone()); + nctx.set_variable(n, *v) } - let ctx = Context::new() - .with_variables(vars) - .with_functions(commonsense_functions! {}) - .with_operations(commonsense_operations! {}); - self.expr.evaluate(&ctx) + nctx.set_function(self.name(), Arc::new(EmptyFunction {})); + self.expr.evaluate(&nctx) } else { Err(format!( "{} takes {} parameters", diff --git a/src/function.rs b/src/function.rs index 0da4574..126477c 100644 --- a/src/function.rs +++ b/src/function.rs @@ -1,4 +1,4 @@ -use crate::complex::Complex; +use crate::{complex::Complex, context::Context}; pub struct FunctionArgument { args : Vec, @@ -23,16 +23,16 @@ impl FunctionArgument { } pub trait Function { - fn eval(&self, args: FunctionArgument) -> Result; + fn eval(&self, args: FunctionArgument, ctx: &Context) -> Result; } #[macro_export] macro_rules! functions { {$($x:expr => $y:expr), *} => { { - let mut h : HashMap> = HashMap::new(); + let mut h : HashMap> = HashMap::new(); $( - h.insert($x.to_string(), Box::new($y)); + h.insert($x.to_string(), Arc::new($y)); )* h } @@ -45,7 +45,7 @@ impl Function for T where T: Fn(Complex) -> Complex, { - fn eval(&self, args: FunctionArgument) -> Result { + fn eval(&self, args: FunctionArgument, _ctx: &Context) -> Result { if args.len() == 1 { Ok(self(args.get(0))) } else { @@ -53,3 +53,12 @@ where } } } + + +pub struct EmptyFunction {} + +impl Function for EmptyFunction { + fn eval(&self, _args: FunctionArgument, _ctx: &Context) -> Result { + Err("function not implemented in this scope".to_string()) + } +} diff --git a/src/main.rs b/src/main.rs index 466ad09..614eba6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,7 +19,7 @@ use expression_function::ExpressionFunction; fn main() { let func = ExpressionFunction::from_string("f(x) = x^2".to_string()); - let expr = "f(3)"; + let expr = "f(5)"; let ctx: Context = Context::new() .with_operations(commonsense_operations!{}) diff --git a/src/operation.rs b/src/operation.rs index a61ae1f..7eca774 100644 --- a/src/operation.rs +++ b/src/operation.rs @@ -1,14 +1,15 @@ use crate::complex::Complex; -pub type Operator = dyn Fn(Complex, Complex) -> Complex; +pub type Operator = fn(Complex, Complex) -> Complex; +#[derive(Clone)] pub struct Operation { sign: char, - func: Box + func: Operator } impl Operation { - pub fn new(sign: char, func: Box) -> Self { + pub fn new(sign: char, func: Operator) -> Self { Self { sign, func } } -- cgit v1.2.3-70-g09d2