Rename Context to ContextMut and Configuration to Context

Get rid of two different words for the same concept.

Relates to #22
This commit is contained in:
Sebastian Schmidt 2019-03-27 18:09:20 +01:00
parent 7decb7c895
commit 9283d5412f
11 changed files with 245 additions and 244 deletions

View File

@ -4,7 +4,7 @@
### Added
* Add the `Context` trait, that is a manipulable configuration
* Add the `ContextMut` trait, that is a manipulable configuration/context
* Add `ContextNotManipulable` error variant for the `EmptyContext`
### Removed
@ -12,6 +12,7 @@
### Changed
* Get rid of some unwraps to improve safety
* Rename `Configuration` to `Context`
* Rename `HashMapConfiguration` to `HashMapContext` and `EmptyConfiguration` to `EmptyContext`
### Fixed

View File

@ -48,19 +48,19 @@ And you can use **variables** and **functions** in expressions like this:
use evalexpr::*;
use evalexpr::error::expect_number;
let mut configuration = HashMapConfiguration::new();
configuration.insert_variable("five", 5);
configuration.insert_variable("twelve", 12);
configuration.insert_function("f", Function::new(Some(1) /* argument amount */, Box::new(|arguments| {
let mut context = HashMapContext::new();
context.set_value("five", 5).unwrap(); // Do proper error handling here
context.set_value("twelve", 12).unwrap(); // Do proper error handling here
context.set_function("f", Function::new(Some(1) /* argument amount */, Box::new(|arguments| {
if let Value::Int(int) = arguments[0] {
Ok(Value::Int(int / 2))
} else if let Value::Float(float) = arguments[0] {
Ok(Value::Float(float / 2.0))
} else {
Err(Error::expected_number(arguments[0].clone()))
Err(EvalexprError::expected_number(arguments[0].clone()))
}
})));
configuration.insert_function("avg", Function::new(Some(2) /* argument amount */, Box::new(|arguments| {
}))).unwrap(); // Do proper error handling here
context.set_function("avg", Function::new(Some(2) /* argument amount */, Box::new(|arguments| {
expect_number(&arguments[0])?;
expect_number(&arguments[1])?;
@ -69,14 +69,14 @@ configuration.insert_function("avg", Function::new(Some(2) /* argument amount */
} else {
Ok(Value::Float((arguments[0].as_float()? + arguments[1].as_float()?) / 2.0))
}
})));
}))).unwrap(); // Do proper error handling here
assert_eq!(eval_with_configuration("five + 8 > f(twelve)", &configuration), Ok(Value::from(true)));
// `eval_with_configuration` returns a variant of the `Value` enum,
// while `eval_[type]_with_configuration` returns the respective type directly.
assert_eq!(eval_with_context("five + 8 > f(twelve)", &context), Ok(Value::from(true)));
// `eval_with_context` returns a variant of the `Value` enum,
// while `eval_[type]_with_context` returns the respective type directly.
// Both can be used interchangeably.
assert_eq!(eval_boolean_with_configuration("five + 8 > f(twelve)", &configuration), Ok(true));
assert_eq!(eval_with_configuration("avg(2, 4) == 3", &configuration), Ok(Value::from(true)));
assert_eq!(eval_boolean_with_context("five + 8 > f(twelve)", &context), Ok(true));
assert_eq!(eval_with_context("avg(2, 4) == 3", &context), Ok(Value::from(true)));
```
You can also **precompile** expressions like this:
@ -84,20 +84,20 @@ You can also **precompile** expressions like this:
```rust
use evalexpr::*;
let precompiled = build_operator_tree("a * b - c > 5").unwrap();
let precompiled = build_operator_tree("a * b - c > 5").unwrap(); // Do proper error handling here
let mut configuration = HashMapConfiguration::new();
configuration.insert_variable("a", 6);
configuration.insert_variable("b", 2);
configuration.insert_variable("c", 3);
assert_eq!(precompiled.eval_with_configuration(&configuration), Ok(Value::from(true)));
let mut context = HashMapContext::new();
context.set_value("a", 6).unwrap(); // Do proper error handling here
context.set_value("b", 2).unwrap(); // Do proper error handling here
context.set_value("c", 3).unwrap(); // Do proper error handling here
assert_eq!(precompiled.eval_with_context(&context), Ok(Value::from(true)));
configuration.insert_variable("c", 8);
assert_eq!(precompiled.eval_with_configuration(&configuration), Ok(Value::from(false)));
// `Node::eval_with_configuration` returns a variant of the `Value` enum,
// while `Node::eval_[type]_with_configuration` returns the respective type directly.
context.set_value("c", 8).unwrap(); // Do proper error handling here
assert_eq!(precompiled.eval_with_context(&context), Ok(Value::from(false)));
// `Node::eval_with_context` returns a variant of the `Value` enum,
// while `Node::eval_[type]_with_context` returns the respective type directly.
// Both can be used interchangeably.
assert_eq!(precompiled.eval_boolean_with_configuration(&configuration), Ok(false));
assert_eq!(precompiled.eval_boolean_with_context(&context), Ok(false));
```
## Features
@ -200,12 +200,12 @@ Values have a precedence of 200.
This crate allows to compile parameterizable formulas by using variables.
A variable is a literal in the formula, that does not contain whitespace or can be parsed as value.
The user needs to provide bindings to the variables for evaluation.
This is done with the `Configuration` trait.
This is done with the `Context` trait.
Two structs implementing this trait are predefined.
There is `EmptyConfiguration`, that returns `None` for each request, and `HashMapConfiguration`, that stores mappings from literals to variables in a hash map.
There is `EmptyContext`, that returns `None` for each request, and `HashMapContext`, that stores mappings from literals to variables in a hash map.
Variables do not have fixed types in the expression itself, but aer typed by the configuration.
The `Configuration` trait contains a function that takes a string literal and returns a `Value` enum.
Variables do not have fixed types in the expression itself, but aer typed by the context.
The `Context` trait contains a function that takes a string literal and returns a `Value` enum.
The variant of this enum decides the type on evaluation.
Variables have a precedence of 200.
@ -229,7 +229,7 @@ Also, most numeric functions need to differentiate between being called with int
Functions are identified by literals, like variables as well.
A literal identifies a function, if it is followed by an opening brace `(`, another literal, or a value.
Same as variables, function bindings are provided by the user via a `Configuration`.
Same as variables, function bindings are provided by the user via a `Context`.
Functions have a precedence of 190.
### Examplary variables and functions in expressions:
@ -254,15 +254,15 @@ Example parsing with [ron format](docs.rs/ron):
extern crate ron;
use evalexpr::*;
let mut configuration = HashMapConfiguration::new();
configuration.insert_variable("five", 5);
let mut context = HashMapContext::new();
context.set_value("five", 5).unwrap(); // Do proper error handling here
// In ron format, strings are surrounded by "
let serialized_free = "\"five * five\"";
match ron::de::from_str::<Node>(serialized_free) {
Ok(free) => assert_eq!(free.eval_with_configuration(&configuration), Ok(Value::from(25))),
Ok(free) => assert_eq!(free.eval_with_context(&context), Ok(Value::from(25))),
Err(error) => {
// Handle error
() // Handle error
},
}
```

View File

@ -7,11 +7,11 @@ use value::value_type::ValueType;
use crate::value::Value;
/// A configuration for an expression tree.
/// A context for an expression tree.
///
/// A configuration defines methods to retrieve values and functions for literals in an expression tree.
/// This crate implements two basic variants, the `EmptyContext`, that returns `None` for each identifier, and the `HashMapContext`, that stores its mappings in hash maps.
pub trait Configuration {
/// A context defines methods to retrieve values and functions for literals in an expression tree.
/// 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.
pub trait Context {
/// Returns the value that is linked to the given identifier.
fn get_value(&self, identifier: &str) -> Option<&Value>;
@ -19,12 +19,12 @@ pub trait Configuration {
fn get_function(&self, identifier: &str) -> Option<&Function>;
}
/// A context for an expression tree.
/// A mutable context for an expression tree.
///
/// In addition to all functionality of a `Configuration`, a context also allows the manipulation of values and functions.
/// This crate implements two basic variants, the `EmptyContext`, that returns `Err` for each identifier, and the `HashMapContext`, that stores its mappings in hash maps.
/// In addition to all functionality of a `Context`, a mutable context also allows the manipulation of values and functions.
/// This crate implements two basic variants, the `EmptyContext`, that returns an error for each manipulation, 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.
pub trait Context: Configuration {
pub trait ContextMut: Context {
/// Links the given value to the given identifier.
fn set_value<S: Into<String>, V: Into<Value>>(&mut self, identifier: S, value: V) -> EvalexprResult<()>;
@ -32,10 +32,10 @@ pub trait Context: Configuration {
fn set_function<S: Into<String>>(&mut self, identifier: S, function: Function) -> EvalexprResult<()>;
}
/// A configuration that returns `None` for each identifier.
/// A context that returns `None` for each identifier.
pub struct EmptyContext;
impl Configuration for EmptyContext {
impl Context for EmptyContext {
fn get_value(&self, _identifier: &str) -> Option<&Value> {
None
}
@ -45,7 +45,7 @@ impl Configuration for EmptyContext {
}
}
impl Context for EmptyContext {
impl ContextMut for EmptyContext {
fn set_value<S: Into<String>, V: Into<Value>>(&mut self, _identifier: S, _value: V) -> EvalexprResult<()> {
Err(EvalexprError::ContextNotManipulable)
}
@ -75,7 +75,7 @@ impl HashMapContext {
}
}
impl Configuration for HashMapContext {
impl Context for HashMapContext {
fn get_value(&self, identifier: &str) -> Option<&Value> {
self.variables.get(identifier)
}
@ -85,7 +85,7 @@ impl Configuration for HashMapContext {
}
}
impl Context for HashMapContext {
impl ContextMut for HashMapContext {
fn set_value<S: Into<String>, V: Into<Value>>(&mut self, identifier: S, value: V) -> Result<(), EvalexprError> {
let identifier = identifier.into();
let value = value.into();

View File

@ -40,12 +40,12 @@ impl fmt::Display for EvalexprError {
),
VariableIdentifierNotFound(identifier) => write!(
f,
"Variable identifier is not bound to anything by configuration: {:?}.",
"Variable identifier is not bound to anything by context: {:?}.",
identifier
),
FunctionIdentifierNotFound(identifier) => write!(
f,
"Function identifier is not bound to anything by configuration: {:?}.",
"Function identifier is not bound to anything by context: {:?}.",
identifier
),
TypeError { expected, actual } => {

View File

@ -81,10 +81,10 @@ pub enum EvalexprError {
/// If it does, please file a bug report.
PrecedenceViolation,
/// A `VariableIdentifier` operation did not find its value in the configuration.
/// A `VariableIdentifier` operation did not find its value in the context.
VariableIdentifierNotFound(String),
/// A `FunctionIdentifier` operation did not find its value in the configuration.
/// A `FunctionIdentifier` operation did not find its value in the context.
FunctionIdentifierNotFound(String),
/// A value has the wrong type.

View File

@ -4,18 +4,18 @@ use value::Value;
pub(crate) mod builtin;
/// A user-defined function.
/// Functions can be used in expressions by storing them in a `Configuration`.
/// Functions can be used in expressions by storing them in a `Context`.
///
/// # Examples
///
/// ```rust
/// use evalexpr::*;
///
/// let mut configuration = HashMapConfiguration::new();
/// configuration.insert_function("id", Function::new(Some(1), Box::new(|arguments| {
/// let mut context = HashMapContext::new();
/// context.set_function("id", Function::new(Some(1), Box::new(|arguments| {
/// Ok(arguments[0].clone())
/// })));
/// assert_eq!(eval_with_configuration("id(4)", &configuration), Ok(Value::from(4)));
/// }))).unwrap(); // Do proper error handling here
/// assert_eq!(eval_with_context("id(4)", &context), Ok(Value::from(4)));
/// ```
pub struct Function {
argument_amount: Option<usize>,

View File

@ -1,4 +1,4 @@
use Configuration;
use Context;
use EmptyContext;
use EvalexprError;
use FloatType;
@ -21,35 +21,35 @@ use value::TupleType;
///
/// *See the [crate doc](index.html) for more examples and explanations of the expression format.*
pub fn eval(string: &str) -> Result<Value, EvalexprError> {
eval_with_configuration(string, &EmptyContext)
eval_with_context(string, &EmptyContext)
}
/// Evaluate the given expression string with the given configuration.
/// Evaluate the given expression string with the given context.
///
/// # Examples
///
/// ```rust
/// use evalexpr::*;
///
/// let mut configuration = HashMapContext::new();
/// configuration.set_value("one", 1).unwrap(); // Do proper error handling here
/// configuration.set_value("two", 2).unwrap(); // Do proper error handling here
/// configuration.set_value("three", 3).unwrap(); // Do proper error handling here
/// assert_eq!(eval_with_configuration("one + two + three", &configuration), Ok(Value::from(6)));
/// let mut context = HashMapContext::new();
/// context.set_value("one", 1).unwrap(); // Do proper error handling here
/// context.set_value("two", 2).unwrap(); // Do proper error handling here
/// context.set_value("three", 3).unwrap(); // Do proper error handling here
/// assert_eq!(eval_with_context("one + two + three", &context), Ok(Value::from(6)));
/// ```
///
/// *See the [crate doc](index.html) for more examples and explanations of the expression format.*
pub fn eval_with_configuration(
pub fn eval_with_context(
string: &str,
configuration: &Configuration,
context: &Context,
) -> Result<Value, EvalexprError> {
tree::tokens_to_operator_tree(token::tokenize(string)?)?.eval_with_configuration(configuration)
tree::tokens_to_operator_tree(token::tokenize(string)?)?.eval_with_context(context)
}
/// Build the operator tree for the given expression string.
///
/// The operator tree can later on be evaluated directly.
/// This saves runtime if a single expression should be evaluated multiple times, for example with differing configurations.
/// This saves runtime if a single expression should be evaluated multiple times, for example with differing contexts.
///
/// # Examples
///
@ -58,15 +58,15 @@ pub fn eval_with_configuration(
///
/// let precomputed = build_operator_tree("one + two + three").unwrap(); // Do proper error handling here
///
/// let mut configuration = HashMapContext::new();
/// configuration.set_value("one", 1).unwrap(); // Do proper error handling here
/// configuration.set_value("two", 2).unwrap(); // Do proper error handling here
/// configuration.set_value("three", 3).unwrap(); // Do proper error handling here
/// let mut context = HashMapContext::new();
/// context.set_value("one", 1).unwrap(); // Do proper error handling here
/// context.set_value("two", 2).unwrap(); // Do proper error handling here
/// context.set_value("three", 3).unwrap(); // Do proper error handling here
///
/// assert_eq!(precomputed.eval_with_configuration(&configuration), Ok(Value::from(6)));
/// assert_eq!(precomputed.eval_with_context(&context), Ok(Value::from(6)));
///
/// configuration.set_value("three", 5).unwrap(); // Do proper error handling here
/// assert_eq!(precomputed.eval_with_configuration(&configuration), Ok(Value::from(8)));
/// context.set_value("three", 5).unwrap(); // Do proper error handling here
/// assert_eq!(precomputed.eval_with_context(&context), Ok(Value::from(8)));
/// ```
///
/// *See the [crate doc](index.html) for more examples and explanations of the expression format.*
@ -129,70 +129,70 @@ pub fn eval_tuple(string: &str) -> Result<TupleType, EvalexprError> {
}
}
/// Evaluate the given expression string into a string with the given configuration.
/// 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_configuration(
pub fn eval_string_with_context(
string: &str,
configuration: &Configuration,
context: &Context,
) -> Result<String, EvalexprError> {
match eval_with_configuration(string, configuration) {
match eval_with_context(string, context) {
Ok(Value::String(string)) => Ok(string),
Ok(value) => Err(EvalexprError::expected_string(value)),
Err(error) => Err(error),
}
}
/// Evaluate the given expression string into an integer with the given configuration.
/// 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_configuration(
pub fn eval_int_with_context(
string: &str,
configuration: &Configuration,
context: &Context,
) -> Result<IntType, EvalexprError> {
match eval_with_configuration(string, configuration) {
match eval_with_context(string, context) {
Ok(Value::Int(int)) => Ok(int),
Ok(value) => Err(EvalexprError::expected_int(value)),
Err(error) => Err(error),
}
}
/// Evaluate the given expression string into a float with the given configuration.
/// 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_configuration(
pub fn eval_float_with_context(
string: &str,
configuration: &Configuration,
context: &Context,
) -> Result<FloatType, EvalexprError> {
match eval_with_configuration(string, configuration) {
match eval_with_context(string, context) {
Ok(Value::Float(float)) => Ok(float),
Ok(value) => Err(EvalexprError::expected_float(value)),
Err(error) => Err(error),
}
}
/// Evaluate the given expression string into a boolean with the given configuration.
/// 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_configuration(
pub fn eval_boolean_with_context(
string: &str,
configuration: &Configuration,
context: &Context,
) -> Result<bool, EvalexprError> {
match eval_with_configuration(string, configuration) {
match eval_with_context(string, context) {
Ok(Value::Boolean(boolean)) => Ok(boolean),
Ok(value) => Err(EvalexprError::expected_boolean(value)),
Err(error) => Err(error),
}
}
/// Evaluate the given expression string into a tuple with the given configuration.
/// 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_configuration(
pub fn eval_tuple_with_context(
string: &str,
configuration: &Configuration,
context: &Context,
) -> Result<TupleType, EvalexprError> {
match eval_with_configuration(string, configuration) {
match eval_with_context(string, context) {
Ok(Value::Tuple(tuple)) => Ok(tuple),
Ok(value) => Err(EvalexprError::expected_tuple(value)),
Err(error) => Err(error),

View File

@ -35,10 +35,10 @@
//! use evalexpr::*;
//! use evalexpr::error::expect_number;
//!
//! let mut configuration = HashMapContext::new();
//! configuration.set_value("five", 5).unwrap(); // Do proper error handling here
//! configuration.set_value("twelve", 12).unwrap(); // Do proper error handling here
//! configuration.set_function("f", Function::new(Some(1) /* argument amount */, Box::new(|arguments| {
//! let mut context = HashMapContext::new();
//! context.set_value("five", 5).unwrap(); // Do proper error handling here
//! context.set_value("twelve", 12).unwrap(); // Do proper error handling here
//! context.set_function("f", Function::new(Some(1) /* argument amount */, Box::new(|arguments| {
//! if let Value::Int(int) = arguments[0] {
//! Ok(Value::Int(int / 2))
//! } else if let Value::Float(float) = arguments[0] {
@ -47,7 +47,7 @@
//! Err(EvalexprError::expected_number(arguments[0].clone()))
//! }
//! }))).unwrap(); // Do proper error handling here
//! configuration.set_function("avg", Function::new(Some(2) /* argument amount */, Box::new(|arguments| {
//! context.set_function("avg", Function::new(Some(2) /* argument amount */, Box::new(|arguments| {
//! expect_number(&arguments[0])?;
//! expect_number(&arguments[1])?;
//!
@ -58,12 +58,12 @@
//! }
//! }))).unwrap(); // Do proper error handling here
//!
//! assert_eq!(eval_with_configuration("five + 8 > f(twelve)", &configuration), Ok(Value::from(true)));
//! // `eval_with_configuration` returns a variant of the `Value` enum,
//! // while `eval_[type]_with_configuration` returns the respective type directly.
//! assert_eq!(eval_with_context("five + 8 > f(twelve)", &context), Ok(Value::from(true)));
//! // `eval_with_context` returns a variant of the `Value` enum,
//! // while `eval_[type]_with_context` returns the respective type directly.
//! // Both can be used interchangeably.
//! assert_eq!(eval_boolean_with_configuration("five + 8 > f(twelve)", &configuration), Ok(true));
//! assert_eq!(eval_with_configuration("avg(2, 4) == 3", &configuration), Ok(Value::from(true)));
//! assert_eq!(eval_boolean_with_context("five + 8 > f(twelve)", &context), Ok(true));
//! assert_eq!(eval_with_context("avg(2, 4) == 3", &context), Ok(Value::from(true)));
//! ```
//!
//! You can also **precompile** expressions like this:
@ -73,18 +73,18 @@
//!
//! let precompiled = build_operator_tree("a * b - c > 5").unwrap(); // Do proper error handling here
//!
//! let mut configuration = HashMapContext::new();
//! configuration.set_value("a", 6).unwrap(); // Do proper error handling here
//! configuration.set_value("b", 2).unwrap(); // Do proper error handling here
//! configuration.set_value("c", 3).unwrap(); // Do proper error handling here
//! assert_eq!(precompiled.eval_with_configuration(&configuration), Ok(Value::from(true)));
//! let mut context = HashMapContext::new();
//! context.set_value("a", 6).unwrap(); // Do proper error handling here
//! context.set_value("b", 2).unwrap(); // Do proper error handling here
//! context.set_value("c", 3).unwrap(); // Do proper error handling here
//! assert_eq!(precompiled.eval_with_context(&context), Ok(Value::from(true)));
//!
//! configuration.set_value("c", 8).unwrap(); // Do proper error handling here
//! assert_eq!(precompiled.eval_with_configuration(&configuration), Ok(Value::from(false)));
//! // `Node::eval_with_configuration` returns a variant of the `Value` enum,
//! // while `Node::eval_[type]_with_configuration` returns the respective type directly.
//! context.set_value("c", 8).unwrap(); // Do proper error handling here
//! assert_eq!(precompiled.eval_with_context(&context), Ok(Value::from(false)));
//! // `Node::eval_with_context` returns a variant of the `Value` enum,
//! // while `Node::eval_[type]_with_context` returns the respective type directly.
//! // Both can be used interchangeably.
//! assert_eq!(precompiled.eval_boolean_with_configuration(&configuration), Ok(false));
//! assert_eq!(precompiled.eval_boolean_with_context(&context), Ok(false));
//! ```
//!
//! ## Features
@ -187,12 +187,12 @@
//! This crate allows to compile parameterizable formulas by using variables.
//! A variable is a literal in the formula, that does not contain whitespace or can be parsed as value.
//! The user needs to provide bindings to the variables for evaluation.
//! This is done with the `Configuration` trait.
//! This is done with the `Context` trait.
//! Two structs implementing this trait are predefined.
//! There is `EmptyConfiguration`, that returns `None` for each request, and `HashMapConfiguration`, that stores mappings from literals to variables in a hash map.
//! There is `EmptyContext`, that returns `None` for each request, and `HashMapContext`, that stores mappings from literals to variables in a hash map.
//!
//! Variables do not have fixed types in the expression itself, but aer typed by the configuration.
//! The `Configuration` trait contains a function that takes a string literal and returns a `Value` enum.
//! Variables do not have fixed types in the expression itself, but aer typed by the context.
//! The `Context` trait contains a function that takes a string literal and returns a `Value` enum.
//! The variant of this enum decides the type on evaluation.
//!
//! Variables have a precedence of 200.
@ -216,7 +216,7 @@
//! Functions are identified by literals, like variables as well.
//! A literal identifies a function, if it is followed by an opening brace `(`, another literal, or a value.
//!
//! Same as variables, function bindings are provided by the user via a `Configuration`.
//! Same as variables, function bindings are provided by the user via a `Context`.
//! Functions have a precedence of 190.
//!
//! ### Examplary variables and functions in expressions:
@ -241,15 +241,15 @@
//! extern crate ron;
//! use evalexpr::*;
//!
//! let mut configuration = HashMapContext::new();
//! configuration.set_value("five", 5).unwrap(); // Do proper error handling here
//! let mut context = HashMapContext::new();
//! context.set_value("five", 5).unwrap(); // Do proper error handling here
//!
//! // In ron format, strings are surrounded by "
//! let serialized_free = "\"five * five\"";
//! match ron::de::from_str::<Node>(serialized_free) {
//! Ok(free) => assert_eq!(free.eval_with_configuration(&configuration), Ok(Value::from(25))),
//! Ok(free) => assert_eq!(free.eval_with_context(&context), Ok(Value::from(25))),
//! Err(error) => {
//! // Handle error
//! () // Handle error
//! },
//! }
//! ```
@ -269,7 +269,7 @@ extern crate ron;
#[cfg(feature = "serde")]
extern crate serde;
pub use context::{Configuration, Context, EmptyContext, HashMapContext};
pub use context::{Context, ContextMut, EmptyContext, HashMapContext};
pub use error::{EvalexprError, EvalexprResult};
pub use function::Function;
pub use interface::*;

View File

@ -2,7 +2,7 @@ use std::fmt::{Debug, Display};
use function::builtin::builtin_function;
use crate::{context::Configuration, error::*, value::Value};
use crate::{context::Context, error::*, value::Value};
mod display;
@ -28,11 +28,11 @@ pub trait Operator: Debug + Display {
// Make this a const fn once #57563 is resolved
fn argument_amount(&self) -> usize;
/// Evaluates the operator with the given arguments and configuration.
/// Evaluates the operator with the given arguments and context.
fn eval(
&self,
arguments: &[Value],
configuration: &Configuration,
context: &Context,
) -> Result<Value, EvalexprError>;
}
@ -125,7 +125,7 @@ impl Operator for RootNode {
fn eval(
&self,
arguments: &[Value],
_configuration: &Configuration,
_context: &Context,
) -> Result<Value, EvalexprError> {
expect_operator_argument_amount(arguments.len(), 1)?;
Ok(arguments[0].clone())
@ -148,7 +148,7 @@ impl Operator for Add {
fn eval(
&self,
arguments: &[Value],
_configuration: &Configuration,
_context: &Context,
) -> Result<Value, EvalexprError> {
expect_operator_argument_amount(arguments.len(), 2)?;
expect_number(&arguments[0])?;
@ -188,7 +188,7 @@ impl Operator for Sub {
fn eval(
&self,
arguments: &[Value],
_configuration: &Configuration,
_context: &Context,
) -> Result<Value, EvalexprError> {
expect_operator_argument_amount(arguments.len(), 2)?;
expect_number(&arguments[0])?;
@ -228,7 +228,7 @@ impl Operator for Neg {
fn eval(
&self,
arguments: &[Value],
_configuration: &Configuration,
_context: &Context,
) -> Result<Value, EvalexprError> {
expect_operator_argument_amount(arguments.len(), 1)?;
expect_number(&arguments[0])?;
@ -262,7 +262,7 @@ impl Operator for Mul {
fn eval(
&self,
arguments: &[Value],
_configuration: &Configuration,
_context: &Context,
) -> Result<Value, EvalexprError> {
expect_operator_argument_amount(arguments.len(), 2)?;
expect_number(&arguments[0])?;
@ -302,7 +302,7 @@ impl Operator for Div {
fn eval(
&self,
arguments: &[Value],
_configuration: &Configuration,
_context: &Context,
) -> Result<Value, EvalexprError> {
expect_operator_argument_amount(arguments.len(), 2)?;
expect_number(&arguments[0])?;
@ -342,7 +342,7 @@ impl Operator for Mod {
fn eval(
&self,
arguments: &[Value],
_configuration: &Configuration,
_context: &Context,
) -> Result<Value, EvalexprError> {
expect_operator_argument_amount(arguments.len(), 2)?;
expect_number(&arguments[0])?;
@ -382,7 +382,7 @@ impl Operator for Exp {
fn eval(
&self,
arguments: &[Value],
_configuration: &Configuration,
_context: &Context,
) -> Result<Value, EvalexprError> {
expect_operator_argument_amount(arguments.len(), 2)?;
expect_number(&arguments[0])?;
@ -413,7 +413,7 @@ impl Operator for Eq {
fn eval(
&self,
arguments: &[Value],
_configuration: &Configuration,
_context: &Context,
) -> Result<Value, EvalexprError> {
expect_operator_argument_amount(arguments.len(), 2)?;
@ -441,7 +441,7 @@ impl Operator for Neq {
fn eval(
&self,
arguments: &[Value],
_configuration: &Configuration,
_context: &Context,
) -> Result<Value, EvalexprError> {
expect_operator_argument_amount(arguments.len(), 2)?;
@ -469,7 +469,7 @@ impl Operator for Gt {
fn eval(
&self,
arguments: &[Value],
_configuration: &Configuration,
_context: &Context,
) -> Result<Value, EvalexprError> {
expect_operator_argument_amount(arguments.len(), 2)?;
expect_number(&arguments[0])?;
@ -507,7 +507,7 @@ impl Operator for Lt {
fn eval(
&self,
arguments: &[Value],
_configuration: &Configuration,
_context: &Context,
) -> Result<Value, EvalexprError> {
expect_operator_argument_amount(arguments.len(), 2)?;
expect_number(&arguments[0])?;
@ -545,7 +545,7 @@ impl Operator for Geq {
fn eval(
&self,
arguments: &[Value],
_configuration: &Configuration,
_context: &Context,
) -> Result<Value, EvalexprError> {
expect_operator_argument_amount(arguments.len(), 2)?;
expect_number(&arguments[0])?;
@ -583,7 +583,7 @@ impl Operator for Leq {
fn eval(
&self,
arguments: &[Value],
_configuration: &Configuration,
_context: &Context,
) -> Result<Value, EvalexprError> {
expect_operator_argument_amount(arguments.len(), 2)?;
expect_number(&arguments[0])?;
@ -621,7 +621,7 @@ impl Operator for And {
fn eval(
&self,
arguments: &[Value],
_configuration: &Configuration,
_context: &Context,
) -> Result<Value, EvalexprError> {
expect_operator_argument_amount(arguments.len(), 2)?;
let a = expect_boolean(&arguments[0])?;
@ -651,7 +651,7 @@ impl Operator for Or {
fn eval(
&self,
arguments: &[Value],
_configuration: &Configuration,
_context: &Context,
) -> Result<Value, EvalexprError> {
expect_operator_argument_amount(arguments.len(), 2)?;
let a = expect_boolean(&arguments[0])?;
@ -681,7 +681,7 @@ impl Operator for Not {
fn eval(
&self,
arguments: &[Value],
_configuration: &Configuration,
_context: &Context,
) -> Result<Value, EvalexprError> {
expect_operator_argument_amount(arguments.len(), 1)?;
let a = expect_boolean(&arguments[0])?;
@ -710,7 +710,7 @@ impl Operator for Tuple {
fn eval(
&self,
arguments: &[Value],
_configuration: &Configuration,
_context: &Context,
) -> Result<Value, EvalexprError> {
if let Value::Tuple(tuple) = &arguments[0] {
let mut tuple = tuple.clone();
@ -751,7 +751,7 @@ impl Operator for Const {
fn eval(
&self,
arguments: &[Value],
_configuration: &Configuration,
_context: &Context,
) -> Result<Value, EvalexprError> {
expect_operator_argument_amount(arguments.len(), 0)?;
@ -775,9 +775,9 @@ impl Operator for VariableIdentifier {
fn eval(
&self,
_arguments: &[Value],
configuration: &Configuration,
context: &Context,
) -> Result<Value, EvalexprError> {
if let Some(value) = configuration.get_value(&self.identifier).cloned() {
if let Some(value) = context.get_value(&self.identifier).cloned() {
Ok(value)
} else {
Err(EvalexprError::VariableIdentifierNotFound(
@ -803,7 +803,7 @@ impl Operator for FunctionIdentifier {
fn eval(
&self,
arguments: &[Value],
configuration: &Configuration,
context: &Context,
) -> Result<Value, EvalexprError> {
expect_operator_argument_amount(arguments.len(), 1)?;
@ -813,7 +813,7 @@ impl Operator for FunctionIdentifier {
arguments
};
if let Some(function) = configuration.get_function(&self.identifier) {
if let Some(function) = context.get_function(&self.identifier) {
function.call(arguments)
} else if let Some(builtin_function) = builtin_function(&self.identifier) {
builtin_function.call(arguments)

View File

@ -4,25 +4,25 @@ use IntType;
use token::Token;
use value::TupleType;
use crate::{context::Configuration, error::EvalexprError, operator::*, value::Value};
use crate::{context::Context, error::EvalexprError, operator::*, value::Value};
mod display;
/// A node in the operator tree.
/// The operator tree is created by the crate-level `build_operator_tree` method.
/// It can be evaluated for a given configuration with the `Node::eval` method.
/// It can be evaluated for a given context with the `Node::eval` method.
///
/// The advantage of constructing the operator tree separately from the actual evaluation is that it can be evaluated arbitrarily often with different configurations.
/// The advantage of constructing the operator tree separately from the actual evaluation is that it can be evaluated arbitrarily often with different contexts.
///
/// # Examples
///
/// ```rust
/// use evalexpr::*;
///
/// let mut configuration = HashMapContext::new();
/// configuration.set_value("alpha", 2).unwrap(); // Do proper error handling here
/// let mut context = HashMapContext::new();
/// context.set_value("alpha", 2).unwrap(); // Do proper error handling here
/// let node = build_operator_tree("1 + alpha").unwrap(); // Do proper error handling here
/// assert_eq!(node.eval_with_configuration(&configuration), Ok(Value::from(3)));
/// assert_eq!(node.eval_with_context(&context), Ok(Value::from(3)));
/// ```
///
#[derive(Debug)]
@ -43,130 +43,130 @@ impl Node {
Self::new(RootNode)
}
/// Evaluates the operator tree rooted at this node with the given configuration.
/// 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_configuration(
pub fn eval_with_context(
&self,
configuration: &Configuration,
context: &Context,
) -> Result<Value, EvalexprError> {
let mut arguments = Vec::new();
for child in self.children() {
arguments.push(child.eval_with_configuration(configuration)?);
arguments.push(child.eval_with_context(context)?);
}
self.operator().eval(&arguments, configuration)
self.operator().eval(&arguments, context)
}
/// Evaluates the operator tree rooted at this node with an empty configuration.
/// Evaluates the operator tree rooted at this node with an empty context.
///
/// Fails, if one of the operators in the expression tree fails.
pub fn eval(&self) -> Result<Value, EvalexprError> {
self.eval_with_configuration(&EmptyContext)
self.eval_with_context(&EmptyContext)
}
/// Evaluates the operator tree rooted at this node into a string with an the given configuration.
/// 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_configuration(
pub fn eval_string_with_context(
&self,
configuration: &Configuration,
context: &Context,
) -> Result<String, EvalexprError> {
match self.eval_with_configuration(configuration) {
match self.eval_with_context(context) {
Ok(Value::String(string)) => Ok(string),
Ok(value) => Err(EvalexprError::expected_string(value)),
Err(error) => Err(error),
}
}
/// Evaluates the operator tree rooted at this node into a float with an the given configuration.
/// 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_configuration(
pub fn eval_float_with_context(
&self,
configuration: &Configuration,
context: &Context,
) -> Result<FloatType, EvalexprError> {
match self.eval_with_configuration(configuration) {
match self.eval_with_context(context) {
Ok(Value::Float(float)) => Ok(float),
Ok(value) => Err(EvalexprError::expected_float(value)),
Err(error) => Err(error),
}
}
/// Evaluates the operator tree rooted at this node into an integer with an the given configuration.
/// 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_configuration(
pub fn eval_int_with_context(
&self,
configuration: &Configuration,
context: &Context,
) -> Result<IntType, EvalexprError> {
match self.eval_with_configuration(configuration) {
match self.eval_with_context(context) {
Ok(Value::Int(int)) => Ok(int),
Ok(value) => Err(EvalexprError::expected_int(value)),
Err(error) => Err(error),
}
}
/// Evaluates the operator tree rooted at this node into a boolean with an the given configuration.
/// 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_configuration(
pub fn eval_boolean_with_context(
&self,
configuration: &Configuration,
context: &Context,
) -> Result<bool, EvalexprError> {
match self.eval_with_configuration(configuration) {
match self.eval_with_context(context) {
Ok(Value::Boolean(boolean)) => Ok(boolean),
Ok(value) => Err(EvalexprError::expected_boolean(value)),
Err(error) => Err(error),
}
}
/// Evaluates the operator tree rooted at this node into a tuple with an the given configuration.
/// 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_configuration(
pub fn eval_tuple_with_context(
&self,
configuration: &Configuration,
context: &Context,
) -> Result<TupleType, EvalexprError> {
match self.eval_with_configuration(configuration) {
match self.eval_with_context(context) {
Ok(Value::Tuple(tuple)) => Ok(tuple),
Ok(value) => Err(EvalexprError::expected_tuple(value)),
Err(error) => Err(error),
}
}
/// Evaluates the operator tree rooted at this node into a string with an empty configuration.
/// Evaluates the operator tree rooted at this node into a string with an empty context.
///
/// Fails, if one of the operators in the expression tree fails.
pub fn eval_string(&self) -> Result<String, EvalexprError> {
self.eval_string_with_configuration(&EmptyContext)
self.eval_string_with_context(&EmptyContext)
}
/// Evaluates the operator tree rooted at this node into a float with an empty configuration.
/// Evaluates the operator tree rooted at this node into a float with an empty context.
///
/// Fails, if one of the operators in the expression tree fails.
pub fn eval_float(&self) -> Result<FloatType, EvalexprError> {
self.eval_float_with_configuration(&EmptyContext)
self.eval_float_with_context(&EmptyContext)
}
/// Evaluates the operator tree rooted at this node into an integer with an empty configuration.
/// Evaluates the operator tree rooted at this node into an integer with an empty context.
///
/// Fails, if one of the operators in the expression tree fails.
pub fn eval_int(&self) -> Result<IntType, EvalexprError> {
self.eval_int_with_configuration(&EmptyContext)
self.eval_int_with_context(&EmptyContext)
}
/// Evaluates the operator tree rooted at this node into a boolean with an empty configuration.
/// Evaluates the operator tree rooted at this node into a boolean with an empty context.
///
/// Fails, if one of the operators in the expression tree fails.
pub fn eval_boolean(&self) -> Result<bool, EvalexprError> {
self.eval_boolean_with_configuration(&EmptyContext)
self.eval_boolean_with_context(&EmptyContext)
}
/// Evaluates the operator tree rooted at this node into a tuple with an empty configuration.
/// Evaluates the operator tree rooted at this node into a tuple with an empty context.
///
/// Fails, if one of the operators in the expression tree fails.
pub fn eval_tuple(&self) -> Result<TupleType, EvalexprError> {
self.eval_tuple_with_configuration(&EmptyContext)
self.eval_tuple_with_context(&EmptyContext)
}
fn children(&self) -> &[Node] {

View File

@ -98,45 +98,45 @@ fn test_boolean_examples() {
}
#[test]
fn test_with_configuration() {
let mut configuration = HashMapContext::new();
configuration.set_value("tr", Value::Boolean(true)).unwrap();
configuration.set_value("fa", Value::Boolean(false)).unwrap();
configuration.set_value("five", Value::Int(5)).unwrap();
configuration.set_value("six", Value::Int(6)).unwrap();
configuration.set_value("half", Value::Float(0.5)).unwrap();
configuration.set_value("zero", Value::Int(0)).unwrap();
fn test_with_context() {
let mut context = HashMapContext::new();
context.set_value("tr", Value::Boolean(true)).unwrap();
context.set_value("fa", Value::Boolean(false)).unwrap();
context.set_value("five", Value::Int(5)).unwrap();
context.set_value("six", Value::Int(6)).unwrap();
context.set_value("half", Value::Float(0.5)).unwrap();
context.set_value("zero", Value::Int(0)).unwrap();
assert_eq!(
eval_with_configuration("tr", &configuration),
eval_with_context("tr", &context),
Ok(Value::Boolean(true))
);
assert_eq!(
eval_with_configuration("fa", &configuration),
eval_with_context("fa", &context),
Ok(Value::Boolean(false))
);
assert_eq!(
eval_with_configuration("tr && false", &configuration),
eval_with_context("tr && false", &context),
Ok(Value::Boolean(false))
);
assert_eq!(
eval_with_configuration("five + six", &configuration),
eval_with_context("five + six", &context),
Ok(Value::Int(11))
);
assert_eq!(
eval_with_configuration("five * half", &configuration),
eval_with_context("five * half", &context),
Ok(Value::Float(2.5))
);
assert_eq!(
eval_with_configuration("five < six && true", &configuration),
eval_with_context("five < six && true", &context),
Ok(Value::Boolean(true))
);
}
#[test]
fn test_functions() {
let mut configuration = HashMapContext::new();
configuration.set_function(
let mut context = HashMapContext::new();
context.set_function(
"sub2".to_string(),
Function::new(
Some(1),
@ -151,34 +151,34 @@ fn test_functions() {
}),
),
).unwrap();
configuration.set_value("five".to_string(), Value::Int(5)).unwrap();
context.set_value("five".to_string(), Value::Int(5)).unwrap();
assert_eq!(
eval_with_configuration("sub2 5", &configuration),
eval_with_context("sub2 5", &context),
Ok(Value::Int(3))
);
assert_eq!(
eval_with_configuration("sub2(5)", &configuration),
eval_with_context("sub2(5)", &context),
Ok(Value::Int(3))
);
assert_eq!(
eval_with_configuration("sub2 five", &configuration),
eval_with_context("sub2 five", &context),
Ok(Value::Int(3))
);
assert_eq!(
eval_with_configuration("sub2(five)", &configuration),
eval_with_context("sub2(five)", &context),
Ok(Value::Int(3))
);
assert_eq!(
eval_with_configuration("sub2(3) + five", &configuration),
eval_with_context("sub2(3) + five", &context),
Ok(Value::Int(6))
);
}
#[test]
fn test_n_ary_functions() {
let mut configuration = HashMapContext::new();
configuration.set_function(
let mut context = HashMapContext::new();
context.set_function(
"sub2",
Function::new(
Some(1),
@ -193,7 +193,7 @@ fn test_n_ary_functions() {
}),
),
).unwrap();
configuration.set_function(
context.set_function(
"avg",
Function::new(
Some(2),
@ -211,7 +211,7 @@ fn test_n_ary_functions() {
}),
),
).unwrap();
configuration.set_function(
context.set_function(
"muladd",
Function::new(
Some(3),
@ -233,57 +233,57 @@ fn test_n_ary_functions() {
}),
),
).unwrap();
configuration.set_function(
context.set_function(
"count",
Function::new(
None,
Box::new(|arguments| Ok(Value::Int(arguments.len() as IntType))),
),
).unwrap();
configuration.set_value("five".to_string(), Value::Int(5)).unwrap();
context.set_value("five".to_string(), Value::Int(5)).unwrap();
assert_eq!(
eval_with_configuration("avg(7, 5)", &configuration),
eval_with_context("avg(7, 5)", &context),
Ok(Value::Int(6))
);
assert_eq!(
eval_with_configuration("avg(sub2 5, 5)", &configuration),
eval_with_context("avg(sub2 5, 5)", &context),
Ok(Value::Int(4))
);
assert_eq!(
eval_with_configuration("sub2(avg(3, 6))", &configuration),
eval_with_context("sub2(avg(3, 6))", &context),
Ok(Value::Int(2))
);
assert_eq!(
eval_with_configuration("sub2 avg(3, 6)", &configuration),
eval_with_context("sub2 avg(3, 6)", &context),
Ok(Value::Int(2))
);
assert_eq!(
eval_with_configuration("muladd(3, 6, -4)", &configuration),
eval_with_context("muladd(3, 6, -4)", &context),
Ok(Value::Int(14))
);
assert_eq!(
eval_with_configuration("count()", &configuration),
eval_with_context("count()", &context),
Err(EvalexprError::WrongOperatorArgumentAmount {
actual: 0,
expected: 1
})
);
assert_eq!(
eval_with_configuration("count(3, 5.5, 2)", &configuration),
eval_with_context("count(3, 5.5, 2)", &context),
Ok(Value::Int(3))
);
assert_eq!(
eval_with_configuration("count 5", &configuration),
eval_with_context("count 5", &context),
Ok(Value::Int(1))
);
assert_eq!(
eval_with_configuration("min(4.0, 3)", &configuration),
eval_with_context("min(4.0, 3)", &context),
Ok(Value::Int(3))
);
assert_eq!(
eval_with_configuration("max(4.0, 3)", &configuration),
eval_with_context("max(4.0, 3)", &context),
Ok(Value::Float(4.0))
);
}
@ -341,29 +341,29 @@ fn test_no_panic() {
#[test]
fn test_shortcut_functions() {
let mut configuration = HashMapContext::new();
configuration.set_value("string", Value::from("a string")).unwrap();
let mut context = HashMapContext::new();
context.set_value("string", Value::from("a string")).unwrap();
// assert_eq!(eval_string("???"));
assert_eq!(
eval_string_with_configuration("string", &configuration),
eval_string_with_context("string", &context),
Ok("a string".to_string())
);
assert_eq!(eval_float("3.3"), Ok(3.3));
assert_eq!(
eval_float_with_configuration("3.3", &configuration),
eval_float_with_context("3.3", &context),
Ok(3.3)
);
assert_eq!(eval_int("3"), Ok(3));
assert_eq!(eval_int_with_configuration("3", &configuration), Ok(3));
assert_eq!(eval_int_with_context("3", &context), Ok(3));
assert_eq!(eval_boolean("true"), Ok(true));
assert_eq!(
eval_boolean_with_configuration("true", &configuration),
eval_boolean_with_context("true", &context),
Ok(true)
);
assert_eq!(eval_tuple("3,3"), Ok(vec![Value::Int(3), Value::Int(3)]));
assert_eq!(
eval_tuple_with_configuration("3,3", &configuration),
eval_tuple_with_context("3,3", &context),
Ok(vec![Value::Int(3), Value::Int(3)])
);
@ -371,21 +371,21 @@ fn test_shortcut_functions() {
assert_eq!(
build_operator_tree("string")
.unwrap()
.eval_string_with_configuration(&configuration),
.eval_string_with_context(&context),
Ok("a string".to_string())
);
assert_eq!(build_operator_tree("3.3").unwrap().eval_float(), Ok(3.3));
assert_eq!(
build_operator_tree("3.3")
.unwrap()
.eval_float_with_configuration(&configuration),
.eval_float_with_context(&context),
Ok(3.3)
);
assert_eq!(build_operator_tree("3").unwrap().eval_int(), Ok(3));
assert_eq!(
build_operator_tree("3")
.unwrap()
.eval_int_with_configuration(&configuration),
.eval_int_with_context(&context),
Ok(3)
);
assert_eq!(
@ -395,7 +395,7 @@ fn test_shortcut_functions() {
assert_eq!(
build_operator_tree("true")
.unwrap()
.eval_boolean_with_configuration(&configuration),
.eval_boolean_with_context(&context),
Ok(true)
);
assert_eq!(
@ -405,7 +405,7 @@ fn test_shortcut_functions() {
assert_eq!(
build_operator_tree("3,3")
.unwrap()
.eval_tuple_with_configuration(&configuration),
.eval_tuple_with_context(&context),
Ok(vec![Value::Int(3), Value::Int(3)])
);
}