From 9283d5412f59fe6f706045401ecd005dad1948bd Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Wed, 27 Mar 2019 18:09:20 +0100 Subject: [PATCH] Rename `Context` to `ContextMut` and `Configuration` to `Context` Get rid of two different words for the same concept. Relates to #22 --- CHANGELOG.md | 3 +- README.md | 66 ++++++++++++++-------------- src/context/mod.rs | 26 +++++------ src/error/display.rs | 4 +- src/error/mod.rs | 4 +- src/function/mod.rs | 10 ++--- src/interface/mod.rs | 78 ++++++++++++++++----------------- src/lib.rs | 60 +++++++++++++------------- src/operator/mod.rs | 52 +++++++++++----------- src/tree/mod.rs | 86 ++++++++++++++++++------------------- tests/integration.rs | 100 +++++++++++++++++++++---------------------- 11 files changed, 245 insertions(+), 244 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 19ed923..a96247e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/README.md b/README.md index f0d7c98..01909bb 100644 --- a/README.md +++ b/README.md @@ -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::(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 }, } ``` diff --git a/src/context/mod.rs b/src/context/mod.rs index 9af07cf..568f7e2 100644 --- a/src/context/mod.rs +++ b/src/context/mod.rs @@ -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, V: Into>(&mut self, identifier: S, value: V) -> EvalexprResult<()>; @@ -32,10 +32,10 @@ pub trait Context: Configuration { fn set_function>(&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, V: Into>(&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, V: Into>(&mut self, identifier: S, value: V) -> Result<(), EvalexprError> { let identifier = identifier.into(); let value = value.into(); diff --git a/src/error/display.rs b/src/error/display.rs index 22682da..40b53f2 100644 --- a/src/error/display.rs +++ b/src/error/display.rs @@ -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 } => { diff --git a/src/error/mod.rs b/src/error/mod.rs index b4b4101..08c2359 100644 --- a/src/error/mod.rs +++ b/src/error/mod.rs @@ -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. diff --git a/src/function/mod.rs b/src/function/mod.rs index b3d33f1..a4bf5da 100644 --- a/src/function/mod.rs +++ b/src/function/mod.rs @@ -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, diff --git a/src/interface/mod.rs b/src/interface/mod.rs index a7b96e0..2b404fc 100644 --- a/src/interface/mod.rs +++ b/src/interface/mod.rs @@ -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 { - 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 { - 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 { } } -/// 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 { - 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 { - 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 { - 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 { - 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 { - 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), diff --git a/src/lib.rs b/src/lib.rs index 2f283c7..f42379a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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::(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::*; diff --git a/src/operator/mod.rs b/src/operator/mod.rs index 0b40a27..9d97a5c 100644 --- a/src/operator/mod.rs +++ b/src/operator/mod.rs @@ -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; } @@ -125,7 +125,7 @@ impl Operator for RootNode { fn eval( &self, arguments: &[Value], - _configuration: &Configuration, + _context: &Context, ) -> Result { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { - 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 { 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) diff --git a/src/tree/mod.rs b/src/tree/mod.rs index 2578ccc..6551dc7 100644 --- a/src/tree/mod.rs +++ b/src/tree/mod.rs @@ -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 { 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - self.eval_tuple_with_configuration(&EmptyContext) + self.eval_tuple_with_context(&EmptyContext) } fn children(&self) -> &[Node] { diff --git a/tests/integration.rs b/tests/integration.rs index 40cf21f..f99373f 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -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)]) ); }