Change context trait.

Instead of one catchall trait for contexts, there are now several:

 * `Context` is now a "use-only" context, allowing only to retrieve variable names and call functions.
 * `ContextWithMutableVariables` also allows to mutate variables.
 * `ContextWithMutableFunctions` also allows to mutate functions. However this is not used anywhere at the moment. It will come in handy when the evalexpr language gets a function definition feature.
 * `GetFunctionContext` also allows to retrieve functions as `Function` type. This is uncommented at the moment, as it does not have any use in the crate as of now, and likely also not with planned future features.

 Additionally, this commit makes functions generic over the context type, as opposed to having a dynamic reference to a context type.

Relates to #73
This commit is contained in:
Sebastian Schmidt 2021-05-28 10:27:32 +03:00
parent fd3063fc64
commit 9fc86a934f
7 changed files with 138 additions and 85 deletions

View File

@ -1,33 +1,50 @@
//! A context defines methods to retrieve variable values and call functions for literals in an expression tree.
//! If mutable, it also allows to assign to variables.
//!
//! This crate implements two basic variants, the `EmptyContext`, that returns `None` for each identifier and cannot be manipulated, and the `HashMapContext`, that stores its mappings in hash maps.
//! The HashMapContext is type-safe and returns an error if the user tries to assign a value of a different type than before to an identifier.
use std::collections::HashMap;
use crate::{function::Function, value::value_type::ValueType, EvalexprError, EvalexprResult};
use crate::value::Value;
/// A mutable context for an expression tree.
///
/// A context defines methods to retrieve values and functions for literals in an expression tree.
/// In addition, it also allows the manipulation of values and functions.
/// This crate implements two basic variants, the `EmptyContext`, that returns `None` for each identifier and cannot be manipulated, and the `HashMapContext`, that stores its mappings in hash maps.
/// The HashMapContext is type-safe and returns an error if the user tries to assign a value of a different type than before to an identifier.
/// An immutable context.
pub trait Context {
/// Returns the value that is linked to the given identifier.
fn get_value(&self, identifier: &str) -> Option<&Value>;
/// Returns the function that is linked to the given identifier.
fn get_function(&self, identifier: &str) -> Option<&Function>;
/// Calls the function that is linked to the given identifier with the given argument.
/// If no function with the given identifier is found, this method returns `EvalexprError::FunctionIdentifierNotFound`.
fn call_function(&self, identifier: &str, argument: &Value) -> EvalexprResult<Value>;
}
/// Links the given value to the given identifier.
/// A context that allows to assign to variables.
pub trait ContextWithMutableVariables: Context {
/// Sets the variable with the given identifier to the given value.
fn set_value(&mut self, _identifier: String, _value: Value) -> EvalexprResult<()> {
Err(EvalexprError::ContextNotManipulable)
Err(EvalexprError::ContextNotMutable)
}
}
/// Links the given function to the given identifier.
/// A context that allows to assign to function identifiers.
pub trait ContextWithMutableFunctions: Context {
/// Sets the function with the given identifier to the given function.
fn set_function(&mut self, _identifier: String, _function: Function) -> EvalexprResult<()> {
Err(EvalexprError::ContextNotManipulable)
Err(EvalexprError::ContextNotMutable)
}
}
/*/// A context that allows to retrieve functions programmatically.
pub trait GetFunctionContext: Context {
/// Returns the function that is linked to the given identifier.
///
/// This might not be possible for all functions, as some might be hard-coded.
/// In this case, a special error variant should be returned (Not yet implemented).
fn get_function(&self, identifier: &str) -> Option<&Function>;
}*/
/// A context that returns `None` for each identifier.
pub struct EmptyContext;
@ -36,8 +53,10 @@ impl Context for EmptyContext {
None
}
fn get_function(&self, _identifier: &str) -> Option<&Function> {
None
fn call_function(&self, identifier: &str, _argument: &Value) -> EvalexprResult<Value> {
Err(EvalexprError::FunctionIdentifierNotFound(
identifier.to_string(),
))
}
}
@ -66,10 +85,18 @@ impl Context for HashMapContext {
self.variables.get(identifier)
}
fn get_function(&self, identifier: &str) -> Option<&Function> {
self.functions.get(identifier)
fn call_function(&self, identifier: &str, argument: &Value) -> EvalexprResult<Value> {
if let Some(function) = self.functions.get(identifier) {
function.call(argument)
} else {
Err(EvalexprError::FunctionIdentifierNotFound(
identifier.to_string(),
))
}
}
}
impl ContextWithMutableVariables for HashMapContext {
fn set_value(&mut self, identifier: String, value: Value) -> EvalexprResult<()> {
if let Some(existing_value) = self.variables.get_mut(&identifier) {
if ValueType::from(&existing_value) == ValueType::from(&value) {
@ -84,7 +111,9 @@ impl Context for HashMapContext {
self.variables.insert(identifier, value);
Ok(())
}
}
impl ContextWithMutableFunctions for HashMapContext {
fn set_function(&mut self, identifier: String, function: Function) -> EvalexprResult<()> {
self.functions.insert(identifier, function);
Ok(())

View File

@ -106,7 +106,7 @@ impl fmt::Display for EvalexprError {
"Regular expression {:?} is invalid: {:?}",
regex, message
),
ContextNotManipulable => write!(f, "Cannot manipulate context"),
ContextNotMutable => write!(f, "Cannot manipulate context"),
IllegalEscapeSequence(string) => write!(f, "Illegal escape sequence: {}", string),
CustomMessage(message) => write!(f, "Error: {}", message),
}

View File

@ -191,7 +191,7 @@ pub enum EvalexprError {
},
/// A modification was attempted on a `Context` that does not allow modifications.
ContextNotManipulable,
ContextNotMutable,
/// An escape sequence within a string literal is illegal.
IllegalEscapeSequence(String),

View File

@ -1,6 +1,6 @@
use crate::{
token, tree, value::TupleType, Context, EmptyType, EvalexprError, EvalexprResult, FloatType,
HashMapContext, IntType, Node, Value, EMPTY_VALUE,
token, tree, value::TupleType, Context, ContextWithMutableVariables, EmptyType, EvalexprError,
EvalexprResult, FloatType, HashMapContext, IntType, Node, Value, EMPTY_VALUE,
};
/// Evaluate the given expression string.
@ -33,7 +33,7 @@ pub fn eval(string: &str) -> EvalexprResult<Value> {
/// ```
///
/// *See the [crate doc](index.html) for more examples and explanations of the expression format.*
pub fn eval_with_context(string: &str, context: &dyn Context) -> EvalexprResult<Value> {
pub fn eval_with_context<C: Context>(string: &str, context: &C) -> EvalexprResult<Value> {
tree::tokens_to_operator_tree(token::tokenize(string)?)?.eval_with_context(context)
}
@ -52,7 +52,10 @@ pub fn eval_with_context(string: &str, context: &dyn Context) -> EvalexprResult<
/// ```
///
/// *See the [crate doc](index.html) for more examples and explanations of the expression format.*
pub fn eval_with_context_mut(string: &str, context: &mut dyn Context) -> EvalexprResult<Value> {
pub fn eval_with_context_mut<C: ContextWithMutableVariables>(
string: &str,
context: &mut C,
) -> EvalexprResult<Value> {
tree::tokens_to_operator_tree(token::tokenize(string)?)?.eval_with_context_mut(context)
}
@ -137,7 +140,7 @@ pub fn eval_empty(string: &str) -> EvalexprResult<EmptyType> {
/// Evaluate the given expression string into a string with the given context.
///
/// *See the [crate doc](index.html) for more examples and explanations of the expression format.*
pub fn eval_string_with_context(string: &str, context: &dyn Context) -> EvalexprResult<String> {
pub fn eval_string_with_context<C: Context>(string: &str, context: &C) -> EvalexprResult<String> {
match eval_with_context(string, context) {
Ok(Value::String(string)) => Ok(string),
Ok(value) => Err(EvalexprError::expected_string(value)),
@ -148,7 +151,7 @@ pub fn eval_string_with_context(string: &str, context: &dyn Context) -> Evalexpr
/// Evaluate the given expression string into an integer with the given context.
///
/// *See the [crate doc](index.html) for more examples and explanations of the expression format.*
pub fn eval_int_with_context(string: &str, context: &dyn Context) -> EvalexprResult<IntType> {
pub fn eval_int_with_context<C: Context>(string: &str, context: &C) -> EvalexprResult<IntType> {
match eval_with_context(string, context) {
Ok(Value::Int(int)) => Ok(int),
Ok(value) => Err(EvalexprError::expected_int(value)),
@ -159,7 +162,7 @@ pub fn eval_int_with_context(string: &str, context: &dyn Context) -> EvalexprRes
/// Evaluate the given expression string into a float with the given context.
///
/// *See the [crate doc](index.html) for more examples and explanations of the expression format.*
pub fn eval_float_with_context(string: &str, context: &dyn Context) -> EvalexprResult<FloatType> {
pub fn eval_float_with_context<C: Context>(string: &str, context: &C) -> EvalexprResult<FloatType> {
match eval_with_context(string, context) {
Ok(Value::Float(float)) => Ok(float),
Ok(value) => Err(EvalexprError::expected_float(value)),
@ -171,7 +174,10 @@ pub fn eval_float_with_context(string: &str, context: &dyn Context) -> EvalexprR
/// If the result of the expression is an integer, it is silently converted into a float.
///
/// *See the [crate doc](index.html) for more examples and explanations of the expression format.*
pub fn eval_number_with_context(string: &str, context: &dyn Context) -> EvalexprResult<FloatType> {
pub fn eval_number_with_context<C: Context>(
string: &str,
context: &C,
) -> EvalexprResult<FloatType> {
match eval_with_context(string, context) {
Ok(Value::Float(float)) => Ok(float),
Ok(Value::Int(int)) => Ok(int as FloatType),
@ -183,7 +189,7 @@ pub fn eval_number_with_context(string: &str, context: &dyn Context) -> Evalexpr
/// Evaluate the given expression string into a boolean with the given context.
///
/// *See the [crate doc](index.html) for more examples and explanations of the expression format.*
pub fn eval_boolean_with_context(string: &str, context: &dyn Context) -> EvalexprResult<bool> {
pub fn eval_boolean_with_context<C: Context>(string: &str, context: &C) -> EvalexprResult<bool> {
match eval_with_context(string, context) {
Ok(Value::Boolean(boolean)) => Ok(boolean),
Ok(value) => Err(EvalexprError::expected_boolean(value)),
@ -194,7 +200,7 @@ pub fn eval_boolean_with_context(string: &str, context: &dyn Context) -> Evalexp
/// Evaluate the given expression string into a tuple with the given context.
///
/// *See the [crate doc](index.html) for more examples and explanations of the expression format.*
pub fn eval_tuple_with_context(string: &str, context: &dyn Context) -> EvalexprResult<TupleType> {
pub fn eval_tuple_with_context<C: Context>(string: &str, context: &C) -> EvalexprResult<TupleType> {
match eval_with_context(string, context) {
Ok(Value::Tuple(tuple)) => Ok(tuple),
Ok(value) => Err(EvalexprError::expected_tuple(value)),
@ -205,7 +211,7 @@ pub fn eval_tuple_with_context(string: &str, context: &dyn Context) -> EvalexprR
/// Evaluate the given expression string into an empty value with the given context.
///
/// *See the [crate doc](index.html) for more examples and explanations of the expression format.*
pub fn eval_empty_with_context(string: &str, context: &dyn Context) -> EvalexprResult<EmptyType> {
pub fn eval_empty_with_context<C: Context>(string: &str, context: &C) -> EvalexprResult<EmptyType> {
match eval_with_context(string, context) {
Ok(Value::Empty) => Ok(EMPTY_VALUE),
Ok(value) => Err(EvalexprError::expected_empty(value)),
@ -216,9 +222,9 @@ pub fn eval_empty_with_context(string: &str, context: &dyn Context) -> EvalexprR
/// Evaluate the given expression string into a string with the given mutable context.
///
/// *See the [crate doc](index.html) for more examples and explanations of the expression format.*
pub fn eval_string_with_context_mut(
pub fn eval_string_with_context_mut<C: ContextWithMutableVariables>(
string: &str,
context: &mut dyn Context,
context: &mut C,
) -> EvalexprResult<String> {
match eval_with_context_mut(string, context) {
Ok(Value::String(string)) => Ok(string),
@ -230,9 +236,9 @@ pub fn eval_string_with_context_mut(
/// Evaluate the given expression string into an integer with the given mutable context.
///
/// *See the [crate doc](index.html) for more examples and explanations of the expression format.*
pub fn eval_int_with_context_mut(
pub fn eval_int_with_context_mut<C: ContextWithMutableVariables>(
string: &str,
context: &mut dyn Context,
context: &mut C,
) -> EvalexprResult<IntType> {
match eval_with_context_mut(string, context) {
Ok(Value::Int(int)) => Ok(int),
@ -244,9 +250,9 @@ pub fn eval_int_with_context_mut(
/// Evaluate the given expression string into a float with the given mutable context.
///
/// *See the [crate doc](index.html) for more examples and explanations of the expression format.*
pub fn eval_float_with_context_mut(
pub fn eval_float_with_context_mut<C: ContextWithMutableVariables>(
string: &str,
context: &mut dyn Context,
context: &mut C,
) -> EvalexprResult<FloatType> {
match eval_with_context_mut(string, context) {
Ok(Value::Float(float)) => Ok(float),
@ -259,9 +265,9 @@ pub fn eval_float_with_context_mut(
/// If the result of the expression is an integer, it is silently converted into a float.
///
/// *See the [crate doc](index.html) for more examples and explanations of the expression format.*
pub fn eval_number_with_context_mut(
pub fn eval_number_with_context_mut<C: ContextWithMutableVariables>(
string: &str,
context: &mut dyn Context,
context: &mut C,
) -> EvalexprResult<FloatType> {
match eval_with_context_mut(string, context) {
Ok(Value::Float(float)) => Ok(float),
@ -274,9 +280,9 @@ pub fn eval_number_with_context_mut(
/// Evaluate the given expression string into a boolean with the given mutable context.
///
/// *See the [crate doc](index.html) for more examples and explanations of the expression format.*
pub fn eval_boolean_with_context_mut(
pub fn eval_boolean_with_context_mut<C: ContextWithMutableVariables>(
string: &str,
context: &mut dyn Context,
context: &mut C,
) -> EvalexprResult<bool> {
match eval_with_context_mut(string, context) {
Ok(Value::Boolean(boolean)) => Ok(boolean),
@ -288,9 +294,9 @@ pub fn eval_boolean_with_context_mut(
/// Evaluate the given expression string into a tuple with the given mutable context.
///
/// *See the [crate doc](index.html) for more examples and explanations of the expression format.*
pub fn eval_tuple_with_context_mut(
pub fn eval_tuple_with_context_mut<C: ContextWithMutableVariables>(
string: &str,
context: &mut dyn Context,
context: &mut C,
) -> EvalexprResult<TupleType> {
match eval_with_context_mut(string, context) {
Ok(Value::Tuple(tuple)) => Ok(tuple),
@ -302,9 +308,9 @@ pub fn eval_tuple_with_context_mut(
/// Evaluate the given expression string into an empty value with the given mutable context.
///
/// *See the [crate doc](index.html) for more examples and explanations of the expression format.*
pub fn eval_empty_with_context_mut(
pub fn eval_empty_with_context_mut<C: ContextWithMutableVariables>(
string: &str,
context: &mut dyn Context,
context: &mut C,
) -> EvalexprResult<EmptyType> {
match eval_with_context_mut(string, context) {
Ok(Value::Empty) => Ok(EMPTY_VALUE),

View File

@ -196,7 +196,7 @@
//! use evalexpr::*;
//!
//! let mut context = HashMapContext::new();
//! assert_eq!(eval_with_context("a = 5", &context), Err(EvalexprError::ContextNotManipulable));
//! assert_eq!(eval_with_context("a = 5", &context), Err(EvalexprError::ContextNotMutable));
//! assert_eq!(eval_empty_with_context_mut("a = 5", &mut context), Ok(EMPTY_VALUE));
//! assert_eq!(eval_empty_with_context_mut("a = 5.0", &mut context),
//! Err(EvalexprError::expected_int(5.0.into())));
@ -259,7 +259,7 @@
//! let mut context = HashMapContext::new();
//! assert_eq!(eval_with_context_mut("a = 5;", &mut context), Ok(Value::from(())));
//! // Assignments require mutable contexts
//! assert_eq!(eval_with_context("a = 6", &context), Err(EvalexprError::ContextNotManipulable));
//! assert_eq!(eval_with_context("a = 6", &context), Err(EvalexprError::ContextNotMutable));
//! // The HashMapContext is type safe
//! assert_eq!(eval_with_context_mut("a = 5.5", &mut context),
//! Err(EvalexprError::ExpectedInt { actual: Value::from(5.5) }));
@ -488,7 +488,10 @@ extern crate serde;
extern crate serde_derive;
pub use crate::{
context::{Context, EmptyContext, HashMapContext},
context::{
Context, ContextWithMutableFunctions, ContextWithMutableVariables, EmptyContext,
HashMapContext,
},
error::{EvalexprError, EvalexprResult},
function::Function,
interface::*,

View File

@ -1,6 +1,6 @@
use crate::function::builtin::builtin_function;
use crate::{context::Context, error::*, value::Value};
use crate::{context::Context, error::*, value::Value, ContextWithMutableVariables};
use std::borrow::Borrow;
mod display;
@ -169,7 +169,11 @@ impl Operator {
}
/// Evaluates the operator with the given arguments and context.
pub(crate) fn eval(&self, arguments: &[Value], context: &dyn Context) -> EvalexprResult<Value> {
pub(crate) fn eval<C: Context>(
&self,
arguments: &[Value],
context: &C,
) -> EvalexprResult<Value> {
use crate::operator::Operator::*;
match self {
RootNode => {
@ -408,7 +412,7 @@ impl Operator {
Ok(Value::Boolean(!a))
},
Assign | AddAssign | SubAssign | MulAssign | DivAssign | ModAssign | ExpAssign
| AndAssign | OrAssign => Err(EvalexprError::ContextNotManipulable),
| AndAssign | OrAssign => Err(EvalexprError::ContextNotMutable),
Tuple => Ok(Value::Tuple(arguments.into())),
Chain => {
if arguments.is_empty() {
@ -437,9 +441,9 @@ impl Operator {
expect_operator_argument_amount(arguments.len(), 1)?;
let arguments = &arguments[0];
if let Some(function) = context.get_function(&identifier) {
function.call(arguments)
} else if let Some(builtin_function) = builtin_function(&identifier) {
match context.call_function(&identifier, arguments) {
Err(EvalexprError::FunctionIdentifierNotFound(_)) => {
if let Some(builtin_function) = builtin_function(&identifier) {
builtin_function.call(arguments)
} else {
Err(EvalexprError::FunctionIdentifierNotFound(
@ -447,14 +451,17 @@ impl Operator {
))
}
},
result => result,
}
},
}
}
/// Evaluates the operator with the given arguments and mutable context.
pub(crate) fn eval_mut(
pub(crate) fn eval_mut<C: ContextWithMutableVariables>(
&self,
arguments: &[Value],
context: &mut dyn Context,
context: &mut C,
) -> EvalexprResult<Value> {
use crate::operator::Operator::*;
match self {

View File

@ -1,11 +1,10 @@
use crate::{
token::Token,
value::{TupleType, EMPTY_VALUE},
EmptyType, FloatType, HashMapContext, IntType,
Context, ContextWithMutableVariables, EmptyType, FloatType, HashMapContext, IntType,
};
use crate::{
context::Context,
error::{EvalexprError, EvalexprResult},
operator::*,
value::Value,
@ -119,7 +118,7 @@ impl Node {
/// Evaluates the operator tree rooted at this node with the given context.
///
/// Fails, if one of the operators in the expression tree fails.
pub fn eval_with_context(&self, context: &dyn Context) -> EvalexprResult<Value> {
pub fn eval_with_context<C: Context>(&self, context: &C) -> EvalexprResult<Value> {
let mut arguments = Vec::new();
for child in self.children() {
arguments.push(child.eval_with_context(context)?);
@ -130,7 +129,10 @@ impl Node {
/// Evaluates the operator tree rooted at this node with the given mutable context.
///
/// Fails, if one of the operators in the expression tree fails.
pub fn eval_with_context_mut(&self, context: &mut dyn Context) -> EvalexprResult<Value> {
pub fn eval_with_context_mut<C: ContextWithMutableVariables>(
&self,
context: &mut C,
) -> EvalexprResult<Value> {
let mut arguments = Vec::new();
for child in self.children() {
arguments.push(child.eval_with_context_mut(context)?);
@ -148,7 +150,7 @@ impl Node {
/// Evaluates the operator tree rooted at this node into a string with an the given context.
///
/// Fails, if one of the operators in the expression tree fails.
pub fn eval_string_with_context(&self, context: &dyn Context) -> EvalexprResult<String> {
pub fn eval_string_with_context<C: Context>(&self, context: &C) -> EvalexprResult<String> {
match self.eval_with_context(context) {
Ok(Value::String(string)) => Ok(string),
Ok(value) => Err(EvalexprError::expected_string(value)),
@ -159,7 +161,7 @@ impl Node {
/// Evaluates the operator tree rooted at this node into a float with an the given context.
///
/// Fails, if one of the operators in the expression tree fails.
pub fn eval_float_with_context(&self, context: &dyn Context) -> EvalexprResult<FloatType> {
pub fn eval_float_with_context<C: Context>(&self, context: &C) -> EvalexprResult<FloatType> {
match self.eval_with_context(context) {
Ok(Value::Float(float)) => Ok(float),
Ok(value) => Err(EvalexprError::expected_float(value)),
@ -170,7 +172,7 @@ impl Node {
/// Evaluates the operator tree rooted at this node into an integer with an the given context.
///
/// Fails, if one of the operators in the expression tree fails.
pub fn eval_int_with_context(&self, context: &dyn Context) -> EvalexprResult<IntType> {
pub fn eval_int_with_context<C: Context>(&self, context: &C) -> EvalexprResult<IntType> {
match self.eval_with_context(context) {
Ok(Value::Int(int)) => Ok(int),
Ok(value) => Err(EvalexprError::expected_int(value)),
@ -182,7 +184,7 @@ impl Node {
/// If the result of the expression is an integer, it is silently converted into a float.
///
/// Fails, if one of the operators in the expression tree fails.
pub fn eval_number_with_context(&self, context: &dyn Context) -> EvalexprResult<FloatType> {
pub fn eval_number_with_context<C: Context>(&self, context: &C) -> EvalexprResult<FloatType> {
match self.eval_with_context(context) {
Ok(Value::Int(int)) => Ok(int as FloatType),
Ok(Value::Float(float)) => Ok(float),
@ -194,7 +196,7 @@ impl Node {
/// Evaluates the operator tree rooted at this node into a boolean with an the given context.
///
/// Fails, if one of the operators in the expression tree fails.
pub fn eval_boolean_with_context(&self, context: &dyn Context) -> EvalexprResult<bool> {
pub fn eval_boolean_with_context<C: Context>(&self, context: &C) -> EvalexprResult<bool> {
match self.eval_with_context(context) {
Ok(Value::Boolean(boolean)) => Ok(boolean),
Ok(value) => Err(EvalexprError::expected_boolean(value)),
@ -205,7 +207,7 @@ impl Node {
/// Evaluates the operator tree rooted at this node into a tuple with an the given context.
///
/// Fails, if one of the operators in the expression tree fails.
pub fn eval_tuple_with_context(&self, context: &dyn Context) -> EvalexprResult<TupleType> {
pub fn eval_tuple_with_context<C: Context>(&self, context: &C) -> EvalexprResult<TupleType> {
match self.eval_with_context(context) {
Ok(Value::Tuple(tuple)) => Ok(tuple),
Ok(value) => Err(EvalexprError::expected_tuple(value)),
@ -216,7 +218,7 @@ impl Node {
/// Evaluates the operator tree rooted at this node into an empty value with an the given context.
///
/// Fails, if one of the operators in the expression tree fails.
pub fn eval_empty_with_context(&self, context: &dyn Context) -> EvalexprResult<EmptyType> {
pub fn eval_empty_with_context<C: Context>(&self, context: &C) -> EvalexprResult<EmptyType> {
match self.eval_with_context(context) {
Ok(Value::Empty) => Ok(EMPTY_VALUE),
Ok(value) => Err(EvalexprError::expected_empty(value)),
@ -227,9 +229,9 @@ impl Node {
/// Evaluates the operator tree rooted at this node into a string with an the given mutable context.
///
/// Fails, if one of the operators in the expression tree fails.
pub fn eval_string_with_context_mut(
pub fn eval_string_with_context_mut<C: ContextWithMutableVariables>(
&self,
context: &mut dyn Context,
context: &mut C,
) -> EvalexprResult<String> {
match self.eval_with_context_mut(context) {
Ok(Value::String(string)) => Ok(string),
@ -241,9 +243,9 @@ impl Node {
/// Evaluates the operator tree rooted at this node into a float with an the given mutable context.
///
/// Fails, if one of the operators in the expression tree fails.
pub fn eval_float_with_context_mut(
pub fn eval_float_with_context_mut<C: ContextWithMutableVariables>(
&self,
context: &mut dyn Context,
context: &mut C,
) -> EvalexprResult<FloatType> {
match self.eval_with_context_mut(context) {
Ok(Value::Float(float)) => Ok(float),
@ -255,7 +257,10 @@ impl Node {
/// Evaluates the operator tree rooted at this node into an integer with an the given mutable context.
///
/// Fails, if one of the operators in the expression tree fails.
pub fn eval_int_with_context_mut(&self, context: &mut dyn Context) -> EvalexprResult<IntType> {
pub fn eval_int_with_context_mut<C: ContextWithMutableVariables>(
&self,
context: &mut C,
) -> EvalexprResult<IntType> {
match self.eval_with_context_mut(context) {
Ok(Value::Int(int)) => Ok(int),
Ok(value) => Err(EvalexprError::expected_int(value)),
@ -267,9 +272,9 @@ impl Node {
/// If the result of the expression is an integer, it is silently converted into a float.
///
/// Fails, if one of the operators in the expression tree fails.
pub fn eval_number_with_context_mut(
pub fn eval_number_with_context_mut<C: ContextWithMutableVariables>(
&self,
context: &mut dyn Context,
context: &mut C,
) -> EvalexprResult<FloatType> {
match self.eval_with_context_mut(context) {
Ok(Value::Int(int)) => Ok(int as FloatType),
@ -282,7 +287,10 @@ impl Node {
/// Evaluates the operator tree rooted at this node into a boolean with an the given mutable context.
///
/// Fails, if one of the operators in the expression tree fails.
pub fn eval_boolean_with_context_mut(&self, context: &mut dyn Context) -> EvalexprResult<bool> {
pub fn eval_boolean_with_context_mut<C: ContextWithMutableVariables>(
&self,
context: &mut C,
) -> EvalexprResult<bool> {
match self.eval_with_context_mut(context) {
Ok(Value::Boolean(boolean)) => Ok(boolean),
Ok(value) => Err(EvalexprError::expected_boolean(value)),
@ -293,9 +301,9 @@ impl Node {
/// Evaluates the operator tree rooted at this node into a tuple with an the given mutable context.
///
/// Fails, if one of the operators in the expression tree fails.
pub fn eval_tuple_with_context_mut(
pub fn eval_tuple_with_context_mut<C: ContextWithMutableVariables>(
&self,
context: &mut dyn Context,
context: &mut C,
) -> EvalexprResult<TupleType> {
match self.eval_with_context_mut(context) {
Ok(Value::Tuple(tuple)) => Ok(tuple),
@ -307,9 +315,9 @@ impl Node {
/// Evaluates the operator tree rooted at this node into an empty value with an the given mutable context.
///
/// Fails, if one of the operators in the expression tree fails.
pub fn eval_empty_with_context_mut(
pub fn eval_empty_with_context_mut<C: ContextWithMutableVariables>(
&self,
context: &mut dyn Context,
context: &mut C,
) -> EvalexprResult<EmptyType> {
match self.eval_with_context_mut(context) {
Ok(Value::Empty) => Ok(EMPTY_VALUE),