Merge ContextMut
with Context
and add eval_<type>_with_context_mut
methods
Trait objects of `ContextMut` cannot be converted into `Context`, even though `ContextMut` requires `Context`. Relates to #30
This commit is contained in:
parent
6bd68e6491
commit
e266f4fc0d
11
CHANGELOG.md
11
CHANGELOG.md
@ -2,12 +2,23 @@
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
### Notes
|
||||||
|
|
||||||
|
The 3.0.0 update includes further breaking changes that are necessary to allow assignments and chaining of expressions.
|
||||||
|
Rust does not allow trait objects to be converted into one another, even if one requires the other, so `ContextMut` had to be merged into `Context` for a more generic implementation of the (internal) `Operator` trait.
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
* Methods `Node::eval_<type>_with_context_mut`
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
|
* Generic arguments from `Context` traits are now static to allow using trait objects of `Context`
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
* Merge `ContextMut` trait into `Context` trait
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
### Deprecated
|
### Deprecated
|
||||||
|
18
README.md
18
README.md
@ -49,9 +49,9 @@ use evalexpr::*;
|
|||||||
use evalexpr::error::expect_number;
|
use evalexpr::error::expect_number;
|
||||||
|
|
||||||
let mut context = HashMapContext::new();
|
let mut context = HashMapContext::new();
|
||||||
context.set_value("five", 5).unwrap(); // Do proper error handling here
|
context.set_value("five".into(), 5.into()).unwrap(); // Do proper error handling here
|
||||||
context.set_value("twelve", 12).unwrap(); // Do proper error handling here
|
context.set_value("twelve".into(), 12.into()).unwrap(); // Do proper error handling here
|
||||||
context.set_function("f", Function::new(Some(1) /* argument amount */, Box::new(|arguments| {
|
context.set_function("f".into(), Function::new(Some(1) /* argument amount */, Box::new(|arguments| {
|
||||||
if let Value::Int(int) = arguments[0] {
|
if let Value::Int(int) = arguments[0] {
|
||||||
Ok(Value::Int(int / 2))
|
Ok(Value::Int(int / 2))
|
||||||
} else if let Value::Float(float) = arguments[0] {
|
} else if let Value::Float(float) = arguments[0] {
|
||||||
@ -60,7 +60,7 @@ context.set_function("f", Function::new(Some(1) /* argument amount */, Box::new(
|
|||||||
Err(EvalexprError::expected_number(arguments[0].clone()))
|
Err(EvalexprError::expected_number(arguments[0].clone()))
|
||||||
}
|
}
|
||||||
}))).unwrap(); // Do proper error handling here
|
}))).unwrap(); // Do proper error handling here
|
||||||
context.set_function("avg", Function::new(Some(2) /* argument amount */, Box::new(|arguments| {
|
context.set_function("avg".into(), Function::new(Some(2) /* argument amount */, Box::new(|arguments| {
|
||||||
expect_number(&arguments[0])?;
|
expect_number(&arguments[0])?;
|
||||||
expect_number(&arguments[1])?;
|
expect_number(&arguments[1])?;
|
||||||
|
|
||||||
@ -87,12 +87,12 @@ use evalexpr::*;
|
|||||||
let precompiled = build_operator_tree("a * b - c > 5").unwrap(); // Do proper error handling here
|
let precompiled = build_operator_tree("a * b - c > 5").unwrap(); // Do proper error handling here
|
||||||
|
|
||||||
let mut context = HashMapContext::new();
|
let mut context = HashMapContext::new();
|
||||||
context.set_value("a", 6).unwrap(); // Do proper error handling here
|
context.set_value("a".into(), 6.into()).unwrap(); // Do proper error handling here
|
||||||
context.set_value("b", 2).unwrap(); // Do proper error handling here
|
context.set_value("b".into(), 2.into()).unwrap(); // Do proper error handling here
|
||||||
context.set_value("c", 3).unwrap(); // Do proper error handling here
|
context.set_value("c".into(), 3.into()).unwrap(); // Do proper error handling here
|
||||||
assert_eq!(precompiled.eval_with_context(&context), Ok(Value::from(true)));
|
assert_eq!(precompiled.eval_with_context(&context), Ok(Value::from(true)));
|
||||||
|
|
||||||
context.set_value("c", 8).unwrap(); // Do proper error handling here
|
context.set_value("c".into(), 8.into()).unwrap(); // Do proper error handling here
|
||||||
assert_eq!(precompiled.eval_with_context(&context), Ok(Value::from(false)));
|
assert_eq!(precompiled.eval_with_context(&context), Ok(Value::from(false)));
|
||||||
// `Node::eval_with_context` returns a variant of the `Value` enum,
|
// `Node::eval_with_context` returns a variant of the `Value` enum,
|
||||||
// while `Node::eval_[type]_with_context` returns the respective type directly.
|
// while `Node::eval_[type]_with_context` returns the respective type directly.
|
||||||
@ -263,7 +263,7 @@ extern crate ron;
|
|||||||
use evalexpr::*;
|
use evalexpr::*;
|
||||||
|
|
||||||
let mut context = HashMapContext::new();
|
let mut context = HashMapContext::new();
|
||||||
context.set_value("five", 5).unwrap(); // Do proper error handling here
|
context.set_value("five".into(), 5.into()).unwrap(); // Do proper error handling here
|
||||||
|
|
||||||
// In ron format, strings are surrounded by "
|
// In ron format, strings are surrounded by "
|
||||||
let serialized_free = "\"five * five\"";
|
let serialized_free = "\"five * five\"";
|
||||||
|
@ -1,43 +1,34 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use function::Function;
|
|
||||||
use value::value_type::ValueType;
|
|
||||||
use EvalexprError;
|
use EvalexprError;
|
||||||
use EvalexprResult;
|
use EvalexprResult;
|
||||||
|
use function::Function;
|
||||||
|
use value::value_type::ValueType;
|
||||||
|
|
||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
|
|
||||||
/// A context for an expression tree.
|
/// A mutable context for an expression tree.
|
||||||
///
|
///
|
||||||
/// A context defines methods to retrieve values and functions for literals in an expression tree.
|
/// A context defines methods to retrieve values and functions for literals in an expression tree.
|
||||||
|
/// In addition, it also allows the manipulation of values and functions.
|
||||||
/// This crate implements two basic variants, the `EmptyContext`, that returns `None` for each identifier and cannot be manipulated, and the `HashMapContext`, that stores its mappings in hash maps.
|
/// This crate implements two basic variants, the `EmptyContext`, that returns `None` for each identifier and cannot be manipulated, and the `HashMapContext`, that stores its mappings in hash maps.
|
||||||
|
/// The HashMapContext is type-safe and returns an error if the user tries to assign a value of a different type than before to an identifier.
|
||||||
pub trait Context {
|
pub trait Context {
|
||||||
/// Returns the value that is linked to the given identifier.
|
/// Returns the value that is linked to the given identifier.
|
||||||
fn get_value(&self, identifier: &str) -> Option<&Value>;
|
fn get_value(&self, identifier: &str) -> Option<&Value>;
|
||||||
|
|
||||||
/// Returns the function that is linked to the given identifier.
|
/// Returns the function that is linked to the given identifier.
|
||||||
fn get_function(&self, identifier: &str) -> Option<&Function>;
|
fn get_function(&self, identifier: &str) -> Option<&Function>;
|
||||||
|
|
||||||
|
/// Links the given value to the given identifier.
|
||||||
|
fn set_value(&mut self, _identifier: String, _value: Value) -> EvalexprResult<()> {
|
||||||
|
Err(EvalexprError::ContextNotManipulable)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A mutable context for an expression tree.
|
|
||||||
///
|
|
||||||
/// 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 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<()>;
|
|
||||||
|
|
||||||
/// Links the given function to the given identifier.
|
/// Links the given function to the given identifier.
|
||||||
fn set_function<S: Into<String>>(
|
fn set_function(&mut self, _identifier: String, _function: Function) -> EvalexprResult<()> {
|
||||||
&mut self,
|
Err(EvalexprError::ContextNotManipulable)
|
||||||
identifier: S,
|
}
|
||||||
function: Function,
|
|
||||||
) -> EvalexprResult<()>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A context that returns `None` for each identifier.
|
/// A context that returns `None` for each identifier.
|
||||||
@ -53,24 +44,6 @@ 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)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_function<S: Into<String>>(
|
|
||||||
&mut self,
|
|
||||||
_identifier: S,
|
|
||||||
_function: Function,
|
|
||||||
) -> EvalexprResult<()> {
|
|
||||||
Err(EvalexprError::ContextNotManipulable)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A context that stores its mappings in hash maps.
|
/// A context that stores its mappings in hash maps.
|
||||||
///
|
///
|
||||||
/// *Value and function mappings are stored independently, meaning that there can be a function and a value with the same identifier.*
|
/// *Value and function mappings are stored independently, meaning that there can be a function and a value with the same identifier.*
|
||||||
@ -99,16 +72,8 @@ impl Context for HashMapContext {
|
|||||||
fn get_function(&self, identifier: &str) -> Option<&Function> {
|
fn get_function(&self, identifier: &str) -> Option<&Function> {
|
||||||
self.functions.get(identifier)
|
self.functions.get(identifier)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl ContextMut for HashMapContext {
|
fn set_value(&mut self, identifier: String, value: Value) -> EvalexprResult<()> {
|
||||||
fn set_value<S: Into<String>, V: Into<Value>>(
|
|
||||||
&mut self,
|
|
||||||
identifier: S,
|
|
||||||
value: V,
|
|
||||||
) -> EvalexprResult<()> {
|
|
||||||
let identifier = identifier.into();
|
|
||||||
let value = value.into();
|
|
||||||
if let Some(existing_value) = self.variables.get_mut(&identifier) {
|
if let Some(existing_value) = self.variables.get_mut(&identifier) {
|
||||||
if ValueType::from(&existing_value) == ValueType::from(&value) {
|
if ValueType::from(&existing_value) == ValueType::from(&value) {
|
||||||
*existing_value = value;
|
*existing_value = value;
|
||||||
@ -123,11 +88,7 @@ impl ContextMut for HashMapContext {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_function<S: Into<String>>(
|
fn set_function(&mut self, identifier: String, function: Function) -> EvalexprResult<()> {
|
||||||
&mut self,
|
|
||||||
identifier: S,
|
|
||||||
function: Function,
|
|
||||||
) -> EvalexprResult<()> {
|
|
||||||
self.functions.insert(identifier.into(), function);
|
self.functions.insert(identifier.into(), function);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
use token;
|
|
||||||
use tree;
|
|
||||||
use value::TupleType;
|
|
||||||
use Context;
|
use Context;
|
||||||
use EmptyContext;
|
use EmptyContext;
|
||||||
use EvalexprError;
|
use EvalexprError;
|
||||||
@ -8,7 +5,10 @@ use EvalexprResult;
|
|||||||
use FloatType;
|
use FloatType;
|
||||||
use IntType;
|
use IntType;
|
||||||
use Node;
|
use Node;
|
||||||
|
use token;
|
||||||
|
use tree;
|
||||||
use Value;
|
use Value;
|
||||||
|
use value::TupleType;
|
||||||
|
|
||||||
/// Evaluate the given expression string.
|
/// Evaluate the given expression string.
|
||||||
///
|
///
|
||||||
@ -33,9 +33,9 @@ pub fn eval(string: &str) -> EvalexprResult<Value> {
|
|||||||
/// use evalexpr::*;
|
/// use evalexpr::*;
|
||||||
///
|
///
|
||||||
/// let mut context = HashMapContext::new();
|
/// let mut context = HashMapContext::new();
|
||||||
/// context.set_value("one", 1).unwrap(); // Do proper error handling here
|
/// context.set_value("one".into(), 1.into()).unwrap(); // Do proper error handling here
|
||||||
/// context.set_value("two", 2).unwrap(); // Do proper error handling here
|
/// context.set_value("two".into(), 2.into()).unwrap(); // Do proper error handling here
|
||||||
/// context.set_value("three", 3).unwrap(); // Do proper error handling here
|
/// context.set_value("three".into(), 3.into()).unwrap(); // Do proper error handling here
|
||||||
/// assert_eq!(eval_with_context("one + two + three", &context), Ok(Value::from(6)));
|
/// assert_eq!(eval_with_context("one + two + three", &context), Ok(Value::from(6)));
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
@ -57,13 +57,13 @@ pub fn eval_with_context(string: &str, context: &Context) -> EvalexprResult<Valu
|
|||||||
/// let precomputed = build_operator_tree("one + two + three").unwrap(); // Do proper error handling here
|
/// let precomputed = build_operator_tree("one + two + three").unwrap(); // Do proper error handling here
|
||||||
///
|
///
|
||||||
/// let mut context = HashMapContext::new();
|
/// let mut context = HashMapContext::new();
|
||||||
/// context.set_value("one", 1).unwrap(); // Do proper error handling here
|
/// context.set_value("one".into(), 1.into()).unwrap(); // Do proper error handling here
|
||||||
/// context.set_value("two", 2).unwrap(); // Do proper error handling here
|
/// context.set_value("two".into(), 2.into()).unwrap(); // Do proper error handling here
|
||||||
/// context.set_value("three", 3).unwrap(); // Do proper error handling here
|
/// context.set_value("three".into(), 3.into()).unwrap(); // Do proper error handling here
|
||||||
///
|
///
|
||||||
/// assert_eq!(precomputed.eval_with_context(&context), Ok(Value::from(6)));
|
/// assert_eq!(precomputed.eval_with_context(&context), Ok(Value::from(6)));
|
||||||
///
|
///
|
||||||
/// context.set_value("three", 5).unwrap(); // Do proper error handling here
|
/// context.set_value("three".into(), 5.into()).unwrap(); // Do proper error handling here
|
||||||
/// assert_eq!(precomputed.eval_with_context(&context), Ok(Value::from(8)));
|
/// assert_eq!(precomputed.eval_with_context(&context), Ok(Value::from(8)));
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
22
src/lib.rs
22
src/lib.rs
@ -36,9 +36,9 @@
|
|||||||
//! use evalexpr::error::expect_number;
|
//! use evalexpr::error::expect_number;
|
||||||
//!
|
//!
|
||||||
//! let mut context = HashMapContext::new();
|
//! let mut context = HashMapContext::new();
|
||||||
//! context.set_value("five", 5).unwrap(); // Do proper error handling here
|
//! context.set_value("five".into(), 5.into()).unwrap(); // Do proper error handling here
|
||||||
//! context.set_value("twelve", 12).unwrap(); // Do proper error handling here
|
//! context.set_value("twelve".into(), 12.into()).unwrap(); // Do proper error handling here
|
||||||
//! context.set_function("f", Function::new(Some(1) /* argument amount */, Box::new(|arguments| {
|
//! context.set_function("f".into(), Function::new(Some(1) /* argument amount */, Box::new(|arguments| {
|
||||||
//! if let Value::Int(int) = arguments[0] {
|
//! if let Value::Int(int) = arguments[0] {
|
||||||
//! Ok(Value::Int(int / 2))
|
//! Ok(Value::Int(int / 2))
|
||||||
//! } else if let Value::Float(float) = arguments[0] {
|
//! } else if let Value::Float(float) = arguments[0] {
|
||||||
@ -47,7 +47,7 @@
|
|||||||
//! Err(EvalexprError::expected_number(arguments[0].clone()))
|
//! Err(EvalexprError::expected_number(arguments[0].clone()))
|
||||||
//! }
|
//! }
|
||||||
//! }))).unwrap(); // Do proper error handling here
|
//! }))).unwrap(); // Do proper error handling here
|
||||||
//! context.set_function("avg", Function::new(Some(2) /* argument amount */, Box::new(|arguments| {
|
//! context.set_function("avg".into(), Function::new(Some(2) /* argument amount */, Box::new(|arguments| {
|
||||||
//! expect_number(&arguments[0])?;
|
//! expect_number(&arguments[0])?;
|
||||||
//! expect_number(&arguments[1])?;
|
//! expect_number(&arguments[1])?;
|
||||||
//!
|
//!
|
||||||
@ -74,12 +74,12 @@
|
|||||||
//! let precompiled = build_operator_tree("a * b - c > 5").unwrap(); // Do proper error handling here
|
//! let precompiled = build_operator_tree("a * b - c > 5").unwrap(); // Do proper error handling here
|
||||||
//!
|
//!
|
||||||
//! let mut context = HashMapContext::new();
|
//! let mut context = HashMapContext::new();
|
||||||
//! context.set_value("a", 6).unwrap(); // Do proper error handling here
|
//! context.set_value("a".into(), 6.into()).unwrap(); // Do proper error handling here
|
||||||
//! context.set_value("b", 2).unwrap(); // Do proper error handling here
|
//! context.set_value("b".into(), 2.into()).unwrap(); // Do proper error handling here
|
||||||
//! context.set_value("c", 3).unwrap(); // Do proper error handling here
|
//! context.set_value("c".into(), 3.into()).unwrap(); // Do proper error handling here
|
||||||
//! assert_eq!(precompiled.eval_with_context(&context), Ok(Value::from(true)));
|
//! assert_eq!(precompiled.eval_with_context(&context), Ok(Value::from(true)));
|
||||||
//!
|
//!
|
||||||
//! context.set_value("c", 8).unwrap(); // Do proper error handling here
|
//! context.set_value("c".into(), 8.into()).unwrap(); // Do proper error handling here
|
||||||
//! assert_eq!(precompiled.eval_with_context(&context), Ok(Value::from(false)));
|
//! assert_eq!(precompiled.eval_with_context(&context), Ok(Value::from(false)));
|
||||||
//! // `Node::eval_with_context` returns a variant of the `Value` enum,
|
//! // `Node::eval_with_context` returns a variant of the `Value` enum,
|
||||||
//! // while `Node::eval_[type]_with_context` returns the respective type directly.
|
//! // while `Node::eval_[type]_with_context` returns the respective type directly.
|
||||||
@ -250,7 +250,7 @@
|
|||||||
//! use evalexpr::*;
|
//! use evalexpr::*;
|
||||||
//!
|
//!
|
||||||
//! let mut context = HashMapContext::new();
|
//! let mut context = HashMapContext::new();
|
||||||
//! context.set_value("five", 5).unwrap(); // Do proper error handling here
|
//! context.set_value("five".into(), 5.into()).unwrap(); // Do proper error handling here
|
||||||
//!
|
//!
|
||||||
//! // In ron format, strings are surrounded by "
|
//! // In ron format, strings are surrounded by "
|
||||||
//! let serialized_free = "\"five * five\"";
|
//! let serialized_free = "\"five * five\"";
|
||||||
@ -277,12 +277,12 @@ extern crate ron;
|
|||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
extern crate serde;
|
extern crate serde;
|
||||||
|
|
||||||
pub use context::{Context, ContextMut, EmptyContext, HashMapContext};
|
pub use context::{Context, EmptyContext, HashMapContext};
|
||||||
pub use error::{EvalexprError, EvalexprResult};
|
pub use error::{EvalexprError, EvalexprResult};
|
||||||
pub use function::Function;
|
pub use function::Function;
|
||||||
pub use interface::*;
|
pub use interface::*;
|
||||||
pub use tree::Node;
|
pub use tree::Node;
|
||||||
pub use value::{value_type::ValueType, FloatType, IntType, TupleType, Value};
|
pub use value::{FloatType, IntType, TupleType, Value, value_type::ValueType};
|
||||||
|
|
||||||
mod context;
|
mod context;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
use std::fmt::{Debug, Display};
|
use std::fmt::{Debug, Display};
|
||||||
|
|
||||||
use ::{ContextMut, ValueType};
|
|
||||||
use function::builtin::builtin_function;
|
use function::builtin::builtin_function;
|
||||||
|
|
||||||
use crate::{context::Context, error::*, value::Value};
|
use crate::{context::Context, error::*, value::Value};
|
||||||
@ -30,10 +29,10 @@ pub trait Operator: Debug + Display {
|
|||||||
fn argument_amount(&self) -> usize;
|
fn argument_amount(&self) -> usize;
|
||||||
|
|
||||||
/// Evaluates the operator with the given arguments and context.
|
/// Evaluates the operator with the given arguments and context.
|
||||||
fn eval(&self, arguments: &[Value], context: &Context) -> EvalexprResult<Value>;
|
fn eval(&self, arguments: &[Value], context: &dyn Context) -> EvalexprResult<Value>;
|
||||||
|
|
||||||
/// Evaluates the operator with the given arguments and mutable context.
|
/// Evaluates the operator with the given arguments and mutable context.
|
||||||
fn eval_mut(&self, arguments: &[Value], context: &mut ContextMut) -> EvalexprResult<Value> {
|
fn eval_mut(&self, arguments: &[Value], context: &mut dyn Context) -> EvalexprResult<Value> {
|
||||||
self.eval(arguments, context)
|
self.eval(arguments, context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use token::Token;
|
|
||||||
use value::TupleType;
|
|
||||||
use EmptyContext;
|
use EmptyContext;
|
||||||
use FloatType;
|
use FloatType;
|
||||||
use IntType;
|
use IntType;
|
||||||
|
use token::Token;
|
||||||
|
use value::TupleType;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
context::Context,
|
context::Context,
|
||||||
@ -25,7 +25,7 @@ mod display;
|
|||||||
/// use evalexpr::*;
|
/// use evalexpr::*;
|
||||||
///
|
///
|
||||||
/// let mut context = HashMapContext::new();
|
/// let mut context = HashMapContext::new();
|
||||||
/// context.set_value("alpha", 2).unwrap(); // Do proper error handling here
|
/// context.set_value("alpha".into(), 2.into()).unwrap(); // Do proper error handling here
|
||||||
/// let node = build_operator_tree("1 + alpha").unwrap(); // Do proper error handling here
|
/// let node = build_operator_tree("1 + alpha").unwrap(); // Do proper error handling here
|
||||||
/// assert_eq!(node.eval_with_context(&context), Ok(Value::from(3)));
|
/// assert_eq!(node.eval_with_context(&context), Ok(Value::from(3)));
|
||||||
/// ```
|
/// ```
|
||||||
@ -59,6 +59,17 @@ impl Node {
|
|||||||
self.operator().eval(&arguments, context)
|
self.operator().eval(&arguments, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Evaluates the operator tree rooted at this node with the given mutable context.
|
||||||
|
///
|
||||||
|
/// Fails, if one of the operators in the expression tree fails.
|
||||||
|
pub fn eval_with_context_mut(&self, context: &mut Context) -> EvalexprResult<Value> {
|
||||||
|
let mut arguments = Vec::new();
|
||||||
|
for child in self.children() {
|
||||||
|
arguments.push(child.eval_with_context_mut(context)?);
|
||||||
|
}
|
||||||
|
self.operator().eval(&arguments, context)
|
||||||
|
}
|
||||||
|
|
||||||
/// Evaluates the operator tree rooted at this node with an empty context.
|
/// Evaluates the operator tree rooted at this node with an empty context.
|
||||||
///
|
///
|
||||||
/// Fails, if one of the operators in the expression tree fails.
|
/// Fails, if one of the operators in the expression tree fails.
|
||||||
@ -134,6 +145,74 @@ impl Node {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Evaluates the operator tree rooted at this node into a string with an the given mutable context.
|
||||||
|
///
|
||||||
|
/// Fails, if one of the operators in the expression tree fails.
|
||||||
|
pub fn eval_string_with_context_mut(&self, context: &mut Context) -> EvalexprResult<String> {
|
||||||
|
match self.eval_with_context_mut(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 mutable context.
|
||||||
|
///
|
||||||
|
/// Fails, if one of the operators in the expression tree fails.
|
||||||
|
pub fn eval_float_with_context_mut(&self, context: &mut Context) -> EvalexprResult<FloatType> {
|
||||||
|
match self.eval_with_context_mut(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 mutable context.
|
||||||
|
///
|
||||||
|
/// Fails, if one of the operators in the expression tree fails.
|
||||||
|
pub fn eval_int_with_context_mut(&self, context: &mut Context) -> EvalexprResult<IntType> {
|
||||||
|
match self.eval_with_context_mut(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 float with an the given mutable context.
|
||||||
|
/// If the result of the expression is an integer, it is silently converted into a float.
|
||||||
|
///
|
||||||
|
/// Fails, if one of the operators in the expression tree fails.
|
||||||
|
pub fn eval_number_with_context_mut(&self, context: &mut Context) -> EvalexprResult<FloatType> {
|
||||||
|
match self.eval_with_context_mut(context) {
|
||||||
|
Ok(Value::Int(int)) => Ok(int as FloatType),
|
||||||
|
Ok(Value::Float(float)) => Ok(float),
|
||||||
|
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 mutable context.
|
||||||
|
///
|
||||||
|
/// Fails, if one of the operators in the expression tree fails.
|
||||||
|
pub fn eval_boolean_with_context_mut(&self, context: &mut Context) -> EvalexprResult<bool> {
|
||||||
|
match self.eval_with_context_mut(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 mutable context.
|
||||||
|
///
|
||||||
|
/// Fails, if one of the operators in the expression tree fails.
|
||||||
|
pub fn eval_tuple_with_context_mut(&self, context: &mut Context) -> EvalexprResult<TupleType> {
|
||||||
|
match self.eval_with_context_mut(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 context.
|
/// 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.
|
/// Fails, if one of the operators in the expression tree fails.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
extern crate evalexpr;
|
extern crate evalexpr;
|
||||||
|
|
||||||
use evalexpr::{error::*, *};
|
use evalexpr::{*, error::*};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_unary_examples() {
|
fn test_unary_examples() {
|
||||||
@ -100,12 +100,16 @@ fn test_boolean_examples() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_with_context() {
|
fn test_with_context() {
|
||||||
let mut context = HashMapContext::new();
|
let mut context = HashMapContext::new();
|
||||||
context.set_value("tr", Value::Boolean(true)).unwrap();
|
context
|
||||||
context.set_value("fa", Value::Boolean(false)).unwrap();
|
.set_value("tr".into(), Value::Boolean(true))
|
||||||
context.set_value("five", Value::Int(5)).unwrap();
|
.unwrap();
|
||||||
context.set_value("six", Value::Int(6)).unwrap();
|
context
|
||||||
context.set_value("half", Value::Float(0.5)).unwrap();
|
.set_value("fa".into(), Value::Boolean(false))
|
||||||
context.set_value("zero", Value::Int(0)).unwrap();
|
.unwrap();
|
||||||
|
context.set_value("five".into(), Value::Int(5)).unwrap();
|
||||||
|
context.set_value("six".into(), Value::Int(6)).unwrap();
|
||||||
|
context.set_value("half".into(), Value::Float(0.5)).unwrap();
|
||||||
|
context.set_value("zero".into(), Value::Int(0)).unwrap();
|
||||||
|
|
||||||
assert_eq!(eval_with_context("tr", &context), Ok(Value::Boolean(true)));
|
assert_eq!(eval_with_context("tr", &context), Ok(Value::Boolean(true)));
|
||||||
assert_eq!(eval_with_context("fa", &context), Ok(Value::Boolean(false)));
|
assert_eq!(eval_with_context("fa", &context), Ok(Value::Boolean(false)));
|
||||||
@ -166,7 +170,7 @@ fn test_n_ary_functions() {
|
|||||||
let mut context = HashMapContext::new();
|
let mut context = HashMapContext::new();
|
||||||
context
|
context
|
||||||
.set_function(
|
.set_function(
|
||||||
"sub2",
|
"sub2".into(),
|
||||||
Function::new(
|
Function::new(
|
||||||
Some(1),
|
Some(1),
|
||||||
Box::new(|arguments| {
|
Box::new(|arguments| {
|
||||||
@ -183,7 +187,7 @@ fn test_n_ary_functions() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
context
|
context
|
||||||
.set_function(
|
.set_function(
|
||||||
"avg",
|
"avg".into(),
|
||||||
Function::new(
|
Function::new(
|
||||||
Some(2),
|
Some(2),
|
||||||
Box::new(|arguments| {
|
Box::new(|arguments| {
|
||||||
@ -203,7 +207,7 @@ fn test_n_ary_functions() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
context
|
context
|
||||||
.set_function(
|
.set_function(
|
||||||
"muladd",
|
"muladd".into(),
|
||||||
Function::new(
|
Function::new(
|
||||||
Some(3),
|
Some(3),
|
||||||
Box::new(|arguments| {
|
Box::new(|arguments| {
|
||||||
@ -227,7 +231,7 @@ fn test_n_ary_functions() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
context
|
context
|
||||||
.set_function(
|
.set_function(
|
||||||
"count",
|
"count".into(),
|
||||||
Function::new(
|
Function::new(
|
||||||
None,
|
None,
|
||||||
Box::new(|arguments| Ok(Value::Int(arguments.len() as IntType))),
|
Box::new(|arguments| Ok(Value::Int(arguments.len() as IntType))),
|
||||||
@ -333,7 +337,7 @@ fn test_no_panic() {
|
|||||||
fn test_shortcut_functions() {
|
fn test_shortcut_functions() {
|
||||||
let mut context = HashMapContext::new();
|
let mut context = HashMapContext::new();
|
||||||
context
|
context
|
||||||
.set_value("string", Value::from("a string"))
|
.set_value("string".into(), Value::from("a string"))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// assert_eq!(eval_string("???"));
|
// assert_eq!(eval_string("???"));
|
||||||
|
Loading…
Reference in New Issue
Block a user