Add Context
trait
* Rename `HashMapConfiguration` to `HashMapContext` * Rename `EmptyConfiguration` to `EmptyContext` * Implement `Context` for both predefined contexts * Update tests and doctests Relates to #22
This commit is contained in:
parent
fd879193b6
commit
3da6019dae
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "evalexpr"
|
name = "evalexpr"
|
||||||
version = "1.2.1-alpha.0"
|
version = "2.0.0-alpha.0"
|
||||||
description = "A powerful arithmetic and boolean expression evaluator"
|
description = "A powerful arithmetic and boolean expression evaluator"
|
||||||
keywords = ["expression", "evaluate", "evaluator", "arithmetic", "boolean"]
|
keywords = ["expression", "evaluate", "evaluator", "arithmetic", "boolean"]
|
||||||
categories = ["parsing", "game-engines"]
|
categories = ["parsing", "game-engines"]
|
||||||
|
@ -1,70 +0,0 @@
|
|||||||
use crate::value::Value;
|
|
||||||
use function::Function;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
/// A configuration 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 `EmptyConfiguration`, that returns `None` for each identifier, and the `HashMapConfiguration`, that stores its mappings in hash maps.
|
|
||||||
pub trait Configuration {
|
|
||||||
/// Returns the value that is linked to the given identifier.
|
|
||||||
fn get_value(&self, identifier: &str) -> Option<&Value>;
|
|
||||||
|
|
||||||
/// Returns the function that is linked to the given identifier.
|
|
||||||
fn get_function(&self, identifier: &str) -> Option<&Function>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A configuration that returns `None` for each identifier.
|
|
||||||
pub struct EmptyConfiguration;
|
|
||||||
|
|
||||||
impl Configuration for EmptyConfiguration {
|
|
||||||
fn get_value(&self, _identifier: &str) -> Option<&Value> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_function(&self, _identifier: &str) -> Option<&Function> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A configuration 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.*
|
|
||||||
pub struct HashMapConfiguration {
|
|
||||||
variables: HashMap<String, Value>,
|
|
||||||
functions: HashMap<String, Function>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HashMapConfiguration {
|
|
||||||
/// Constructs a `HashMapConfiguration` with no mappings.
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
variables: Default::default(),
|
|
||||||
functions: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Adds a variable mapping to the configuration.
|
|
||||||
///
|
|
||||||
/// *Value and function mappings are stored independently, meaning that there can be a function and a variable with the same identifier.*
|
|
||||||
pub fn insert_variable<S: Into<String>, V: Into<Value>>(&mut self, identifier: S, value: V) {
|
|
||||||
self.variables.insert(identifier.into(), value.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Adds a function mappign to the configuration.
|
|
||||||
///
|
|
||||||
/// *Value and function mappings are stored independently, meaning that there can be a function and a variable with the same identifier.*
|
|
||||||
pub fn insert_function<S: Into<String>>(&mut self, identifier: S, function: Function) {
|
|
||||||
self.functions.insert(identifier.into(), function);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Configuration for HashMapConfiguration {
|
|
||||||
fn get_value(&self, identifier: &str) -> Option<&Value> {
|
|
||||||
self.variables.get(identifier)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_function(&self, identifier: &str) -> Option<&Function> {
|
|
||||||
self.functions.get(identifier)
|
|
||||||
}
|
|
||||||
}
|
|
110
src/context/mod.rs
Normal file
110
src/context/mod.rs
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use EvalexprError;
|
||||||
|
use EvalexprResult;
|
||||||
|
use function::Function;
|
||||||
|
use value::value_type::ValueType;
|
||||||
|
|
||||||
|
use crate::value::Value;
|
||||||
|
|
||||||
|
/// A configuration 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 {
|
||||||
|
/// Returns the value that is linked to the given identifier.
|
||||||
|
fn get_value(&self, identifier: &str) -> Option<&Value>;
|
||||||
|
|
||||||
|
/// Returns the function that is linked to the given identifier.
|
||||||
|
fn get_function(&self, identifier: &str) -> Option<&Function>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A 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.
|
||||||
|
/// 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 {
|
||||||
|
/// 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.
|
||||||
|
fn set_function<S: Into<String>>(&mut self, identifier: S, function: Function) -> EvalexprResult<()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A configuration that returns `None` for each identifier.
|
||||||
|
pub struct EmptyContext;
|
||||||
|
|
||||||
|
impl Configuration for EmptyContext {
|
||||||
|
fn get_value(&self, _identifier: &str) -> Option<&Value> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_function(&self, _identifier: &str) -> Option<&Function> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Context 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.
|
||||||
|
///
|
||||||
|
/// *Value and function mappings are stored independently, meaning that there can be a function and a value with the same identifier.*
|
||||||
|
///
|
||||||
|
/// This context is type-safe, meaning that an identifier that is assigned a value of some type once cannot be assigned a value of another type.
|
||||||
|
pub struct HashMapContext {
|
||||||
|
variables: HashMap<String, Value>,
|
||||||
|
functions: HashMap<String, Function>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HashMapContext {
|
||||||
|
/// Constructs a `HashMapContext` with no mappings.
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
variables: Default::default(),
|
||||||
|
functions: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Configuration for HashMapContext {
|
||||||
|
fn get_value(&self, identifier: &str) -> Option<&Value> {
|
||||||
|
self.variables.get(identifier)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_function(&self, identifier: &str) -> Option<&Function> {
|
||||||
|
self.functions.get(identifier)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Context 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();
|
||||||
|
if let Some(existing_value) = self.variables.get_mut(&identifier) {
|
||||||
|
if ValueType::from(&existing_value) == ValueType::from(&value) {
|
||||||
|
*existing_value = value;
|
||||||
|
return Ok(());
|
||||||
|
} else {
|
||||||
|
return Err(EvalexprError::expected_type(existing_value, value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implicit else, because `self.variables` and `identifier` are not unborrowed in else
|
||||||
|
self.variables.insert(identifier, value);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_function<S: Into<String>>(&mut self, identifier: S, function: Function) -> Result<(), EvalexprError> {
|
||||||
|
self.functions.insert(identifier.into(), function);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
@ -85,6 +85,7 @@ impl fmt::Display for EvalexprError {
|
|||||||
ModulationError { dividend, divisor } => {
|
ModulationError { dividend, divisor } => {
|
||||||
write!(f, "Error modulating {} % {}", dividend, divisor)
|
write!(f, "Error modulating {} % {}", dividend, divisor)
|
||||||
},
|
},
|
||||||
|
ContextNotManipulable => write!(f, "Cannot manipulate context"),
|
||||||
CustomMessage(message) => write!(f, "Error: {}", message),
|
CustomMessage(message) => write!(f, "Error: {}", message),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
use token::PartialToken;
|
use token::PartialToken;
|
||||||
use value::TupleType;
|
use value::TupleType;
|
||||||
|
use value::value_type::ValueType;
|
||||||
|
|
||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
|
|
||||||
@ -76,6 +77,8 @@ pub enum EvalexprError {
|
|||||||
AppendedToLeafNode,
|
AppendedToLeafNode,
|
||||||
|
|
||||||
/// Tried to append a child to a node such that the precedence of the child is not higher.
|
/// Tried to append a child to a node such that the precedence of the child is not higher.
|
||||||
|
/// This error should never occur.
|
||||||
|
/// If it does, please file a bug report.
|
||||||
PrecedenceViolation,
|
PrecedenceViolation,
|
||||||
|
|
||||||
/// A `VariableIdentifier` operation did not find its value in the configuration.
|
/// A `VariableIdentifier` operation did not find its value in the configuration.
|
||||||
@ -155,6 +158,9 @@ pub enum EvalexprError {
|
|||||||
divisor: Value,
|
divisor: Value,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// A `set_`-function was called on a `Context` that does not allow modifications.
|
||||||
|
ContextNotManipulable,
|
||||||
|
|
||||||
/// A custom error explained by its message.
|
/// A custom error explained by its message.
|
||||||
CustomMessage(String),
|
CustomMessage(String),
|
||||||
}
|
}
|
||||||
@ -203,6 +209,17 @@ impl EvalexprError {
|
|||||||
EvalexprError::ExpectedTuple { actual }
|
EvalexprError::ExpectedTuple { actual }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Constructs an error that expresses that the type of `expected` was expected, but `actual` was found.
|
||||||
|
pub(crate) fn expected_type(expected: &Value, actual: Value) -> Self {
|
||||||
|
match ValueType::from(expected) {
|
||||||
|
ValueType::String => Self::expected_string(actual),
|
||||||
|
ValueType::Int => Self::expected_int(actual),
|
||||||
|
ValueType::Float => Self::expected_float(actual),
|
||||||
|
ValueType::Boolean => Self::expected_boolean(actual),
|
||||||
|
ValueType::Tuple => Self::expected_tuple(actual),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn unmatched_partial_token(
|
pub(crate) fn unmatched_partial_token(
|
||||||
first: PartialToken,
|
first: PartialToken,
|
||||||
second: Option<PartialToken>,
|
second: Option<PartialToken>,
|
||||||
@ -242,20 +259,30 @@ impl EvalexprError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `Ok(())` if the actual and expected parameters are equal, and `Err(Error::WrongOperatorArgumentAmount)` otherwise.
|
/// Returns `Ok(())` if the actual and expected parameters are equal, and `Err(Error::WrongOperatorArgumentAmount)` otherwise.
|
||||||
pub(crate) fn expect_operator_argument_amount(actual: usize, expected: usize) -> Result<(), EvalexprError> {
|
pub(crate) fn expect_operator_argument_amount(
|
||||||
|
actual: usize,
|
||||||
|
expected: usize,
|
||||||
|
) -> Result<(), EvalexprError> {
|
||||||
if actual == expected {
|
if actual == expected {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(EvalexprError::wrong_operator_argument_amount(actual, expected))
|
Err(EvalexprError::wrong_operator_argument_amount(
|
||||||
|
actual, expected,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `Ok(())` if the actual and expected parameters are equal, and `Err(Error::WrongFunctionArgumentAmount)` otherwise.
|
/// Returns `Ok(())` if the actual and expected parameters are equal, and `Err(Error::WrongFunctionArgumentAmount)` otherwise.
|
||||||
pub(crate) fn expect_function_argument_amount(actual: usize, expected: usize) -> Result<(), EvalexprError> {
|
pub(crate) fn expect_function_argument_amount(
|
||||||
|
actual: usize,
|
||||||
|
expected: usize,
|
||||||
|
) -> Result<(), EvalexprError> {
|
||||||
if actual == expected {
|
if actual == expected {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(EvalexprError::wrong_function_argument_amount(actual, expected))
|
Err(EvalexprError::wrong_function_argument_amount(
|
||||||
|
actual, expected,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -279,4 +306,5 @@ pub fn expect_boolean(actual: &Value) -> Result<bool, EvalexprError> {
|
|||||||
|
|
||||||
impl std::error::Error for EvalexprError {}
|
impl std::error::Error for EvalexprError {}
|
||||||
|
|
||||||
|
/// Standard result type used by this crate.
|
||||||
pub type EvalexprResult<T> = Result<T, EvalexprError>;
|
pub type EvalexprResult<T> = Result<T, EvalexprError>;
|
@ -1,5 +1,5 @@
|
|||||||
use Configuration;
|
use Configuration;
|
||||||
use EmptyConfiguration;
|
use EmptyContext;
|
||||||
use EvalexprError;
|
use EvalexprError;
|
||||||
use FloatType;
|
use FloatType;
|
||||||
use IntType;
|
use IntType;
|
||||||
@ -21,7 +21,7 @@ use value::TupleType;
|
|||||||
///
|
///
|
||||||
/// *See the [crate doc](index.html) for more examples and explanations of the expression format.*
|
/// *See the [crate doc](index.html) for more examples and explanations of the expression format.*
|
||||||
pub fn eval(string: &str) -> Result<Value, EvalexprError> {
|
pub fn eval(string: &str) -> Result<Value, EvalexprError> {
|
||||||
eval_with_configuration(string, &EmptyConfiguration)
|
eval_with_configuration(string, &EmptyContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate the given expression string with the given configuration.
|
/// Evaluate the given expression string with the given configuration.
|
||||||
@ -31,10 +31,10 @@ pub fn eval(string: &str) -> Result<Value, EvalexprError> {
|
|||||||
/// ```rust
|
/// ```rust
|
||||||
/// use evalexpr::*;
|
/// use evalexpr::*;
|
||||||
///
|
///
|
||||||
/// let mut configuration = HashMapConfiguration::new();
|
/// let mut configuration = HashMapContext::new();
|
||||||
/// configuration.insert_variable("one", 1);
|
/// configuration.set_value("one", 1).unwrap(); // Do proper error handling here
|
||||||
/// configuration.insert_variable("two", 2);
|
/// configuration.set_value("two", 2).unwrap(); // Do proper error handling here
|
||||||
/// configuration.insert_variable("three", 3);
|
/// configuration.set_value("three", 3).unwrap(); // Do proper error handling here
|
||||||
/// assert_eq!(eval_with_configuration("one + two + three", &configuration), Ok(Value::from(6)));
|
/// assert_eq!(eval_with_configuration("one + two + three", &configuration), Ok(Value::from(6)));
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
@ -58,14 +58,14 @@ pub fn eval_with_configuration(
|
|||||||
///
|
///
|
||||||
/// 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 configuration = HashMapConfiguration::new();
|
/// let mut configuration = HashMapContext::new();
|
||||||
/// configuration.insert_variable("one", 1);
|
/// configuration.set_value("one", 1).unwrap(); // Do proper error handling here
|
||||||
/// configuration.insert_variable("two", 2);
|
/// configuration.set_value("two", 2).unwrap(); // Do proper error handling here
|
||||||
/// configuration.insert_variable("three", 3);
|
/// configuration.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_configuration(&configuration), Ok(Value::from(6)));
|
||||||
///
|
///
|
||||||
/// configuration.insert_variable("three", 5);
|
/// configuration.set_value("three", 5).unwrap(); // Do proper error handling here
|
||||||
/// assert_eq!(precomputed.eval_with_configuration(&configuration), Ok(Value::from(8)));
|
/// assert_eq!(precomputed.eval_with_configuration(&configuration), Ok(Value::from(8)));
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
33
src/lib.rs
33
src/lib.rs
@ -35,10 +35,10 @@
|
|||||||
//! use evalexpr::*;
|
//! use evalexpr::*;
|
||||||
//! use evalexpr::error::expect_number;
|
//! use evalexpr::error::expect_number;
|
||||||
//!
|
//!
|
||||||
//! let mut configuration = HashMapConfiguration::new();
|
//! let mut configuration = HashMapContext::new();
|
||||||
//! configuration.insert_variable("five", 5);
|
//! configuration.set_value("five", 5).unwrap(); // Do proper error handling here
|
||||||
//! configuration.insert_variable("twelve", 12);
|
//! configuration.set_value("twelve", 12).unwrap(); // Do proper error handling here
|
||||||
//! configuration.insert_function("f", Function::new(Some(1) /* argument amount */, Box::new(|arguments| {
|
//! configuration.set_function("f", 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] {
|
||||||
@ -46,8 +46,8 @@
|
|||||||
//! } else {
|
//! } else {
|
||||||
//! Err(EvalexprError::expected_number(arguments[0].clone()))
|
//! Err(EvalexprError::expected_number(arguments[0].clone()))
|
||||||
//! }
|
//! }
|
||||||
//! })));
|
//! }))).unwrap(); // Do proper error handling here
|
||||||
//! configuration.insert_function("avg", Function::new(Some(2) /* argument amount */, Box::new(|arguments| {
|
//! configuration.set_function("avg", 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])?;
|
||||||
//!
|
//!
|
||||||
@ -56,7 +56,7 @@
|
|||||||
//! } else {
|
//! } else {
|
||||||
//! Ok(Value::Float((arguments[0].as_float()? + arguments[1].as_float()?) / 2.0))
|
//! 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)));
|
//! assert_eq!(eval_with_configuration("five + 8 > f(twelve)", &configuration), Ok(Value::from(true)));
|
||||||
//! // `eval_with_configuration` returns a variant of the `Value` enum,
|
//! // `eval_with_configuration` returns a variant of the `Value` enum,
|
||||||
@ -73,13 +73,13 @@
|
|||||||
//!
|
//!
|
||||||
//! 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 configuration = HashMapConfiguration::new();
|
//! let mut configuration = HashMapContext::new();
|
||||||
//! configuration.insert_variable("a", 6);
|
//! configuration.set_value("a", 6).unwrap(); // Do proper error handling here
|
||||||
//! configuration.insert_variable("b", 2);
|
//! configuration.set_value("b", 2).unwrap(); // Do proper error handling here
|
||||||
//! configuration.insert_variable("c", 3);
|
//! configuration.set_value("c", 3).unwrap(); // Do proper error handling here
|
||||||
//! assert_eq!(precompiled.eval_with_configuration(&configuration), Ok(Value::from(true)));
|
//! assert_eq!(precompiled.eval_with_configuration(&configuration), Ok(Value::from(true)));
|
||||||
//!
|
//!
|
||||||
//! configuration.insert_variable("c", 8);
|
//! configuration.set_value("c", 8).unwrap(); // Do proper error handling here
|
||||||
//! assert_eq!(precompiled.eval_with_configuration(&configuration), Ok(Value::from(false)));
|
//! assert_eq!(precompiled.eval_with_configuration(&configuration), Ok(Value::from(false)));
|
||||||
//! // `Node::eval_with_configuration` returns a variant of the `Value` enum,
|
//! // `Node::eval_with_configuration` returns a variant of the `Value` enum,
|
||||||
//! // while `Node::eval_[type]_with_configuration` returns the respective type directly.
|
//! // while `Node::eval_[type]_with_configuration` returns the respective type directly.
|
||||||
@ -241,8 +241,8 @@
|
|||||||
//! extern crate ron;
|
//! extern crate ron;
|
||||||
//! use evalexpr::*;
|
//! use evalexpr::*;
|
||||||
//!
|
//!
|
||||||
//! let mut configuration = HashMapConfiguration::new();
|
//! let mut configuration = HashMapContext::new();
|
||||||
//! configuration.insert_variable("five", 5);
|
//! configuration.set_value("five", 5).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\"";
|
||||||
@ -269,14 +269,14 @@ extern crate ron;
|
|||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
extern crate serde;
|
extern crate serde;
|
||||||
|
|
||||||
pub use configuration::{Configuration, EmptyConfiguration, HashMapConfiguration};
|
pub use context::{Configuration, 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::{FloatType, IntType, Value};
|
pub use value::{FloatType, IntType, Value};
|
||||||
|
|
||||||
mod configuration;
|
mod context;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
mod feature_serde;
|
mod feature_serde;
|
||||||
@ -288,4 +288,3 @@ mod tree;
|
|||||||
mod value;
|
mod value;
|
||||||
|
|
||||||
// Exports
|
// Exports
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ use std::fmt::{Debug, Display};
|
|||||||
|
|
||||||
use function::builtin::builtin_function;
|
use function::builtin::builtin_function;
|
||||||
|
|
||||||
use crate::{configuration::Configuration, error::*, value::Value};
|
use crate::{context::Configuration, error::*, value::Value};
|
||||||
|
|
||||||
mod display;
|
mod display;
|
||||||
|
|
||||||
@ -29,7 +29,11 @@ pub trait Operator: Debug + Display {
|
|||||||
fn argument_amount(&self) -> usize;
|
fn argument_amount(&self) -> usize;
|
||||||
|
|
||||||
/// Evaluates the operator with the given arguments and configuration.
|
/// Evaluates the operator with the given arguments and configuration.
|
||||||
fn eval(&self, arguments: &[Value], configuration: &Configuration) -> Result<Value, EvalexprError>;
|
fn eval(
|
||||||
|
&self,
|
||||||
|
arguments: &[Value],
|
||||||
|
configuration: &Configuration,
|
||||||
|
) -> Result<Value, EvalexprError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -118,7 +122,11 @@ impl Operator for RootNode {
|
|||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, EvalexprError> {
|
fn eval(
|
||||||
|
&self,
|
||||||
|
arguments: &[Value],
|
||||||
|
_configuration: &Configuration,
|
||||||
|
) -> Result<Value, EvalexprError> {
|
||||||
expect_operator_argument_amount(arguments.len(), 1)?;
|
expect_operator_argument_amount(arguments.len(), 1)?;
|
||||||
Ok(arguments[0].clone())
|
Ok(arguments[0].clone())
|
||||||
}
|
}
|
||||||
@ -137,7 +145,11 @@ impl Operator for Add {
|
|||||||
2
|
2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, EvalexprError> {
|
fn eval(
|
||||||
|
&self,
|
||||||
|
arguments: &[Value],
|
||||||
|
_configuration: &Configuration,
|
||||||
|
) -> Result<Value, EvalexprError> {
|
||||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||||
expect_number(&arguments[0])?;
|
expect_number(&arguments[0])?;
|
||||||
expect_number(&arguments[1])?;
|
expect_number(&arguments[1])?;
|
||||||
@ -173,7 +185,11 @@ impl Operator for Sub {
|
|||||||
2
|
2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, EvalexprError> {
|
fn eval(
|
||||||
|
&self,
|
||||||
|
arguments: &[Value],
|
||||||
|
_configuration: &Configuration,
|
||||||
|
) -> Result<Value, EvalexprError> {
|
||||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||||
expect_number(&arguments[0])?;
|
expect_number(&arguments[0])?;
|
||||||
expect_number(&arguments[1])?;
|
expect_number(&arguments[1])?;
|
||||||
@ -209,7 +225,11 @@ impl Operator for Neg {
|
|||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, EvalexprError> {
|
fn eval(
|
||||||
|
&self,
|
||||||
|
arguments: &[Value],
|
||||||
|
_configuration: &Configuration,
|
||||||
|
) -> Result<Value, EvalexprError> {
|
||||||
expect_operator_argument_amount(arguments.len(), 1)?;
|
expect_operator_argument_amount(arguments.len(), 1)?;
|
||||||
expect_number(&arguments[0])?;
|
expect_number(&arguments[0])?;
|
||||||
|
|
||||||
@ -239,7 +259,11 @@ impl Operator for Mul {
|
|||||||
2
|
2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, EvalexprError> {
|
fn eval(
|
||||||
|
&self,
|
||||||
|
arguments: &[Value],
|
||||||
|
_configuration: &Configuration,
|
||||||
|
) -> Result<Value, EvalexprError> {
|
||||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||||
expect_number(&arguments[0])?;
|
expect_number(&arguments[0])?;
|
||||||
expect_number(&arguments[1])?;
|
expect_number(&arguments[1])?;
|
||||||
@ -275,7 +299,11 @@ impl Operator for Div {
|
|||||||
2
|
2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, EvalexprError> {
|
fn eval(
|
||||||
|
&self,
|
||||||
|
arguments: &[Value],
|
||||||
|
_configuration: &Configuration,
|
||||||
|
) -> Result<Value, EvalexprError> {
|
||||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||||
expect_number(&arguments[0])?;
|
expect_number(&arguments[0])?;
|
||||||
expect_number(&arguments[1])?;
|
expect_number(&arguments[1])?;
|
||||||
@ -311,7 +339,11 @@ impl Operator for Mod {
|
|||||||
2
|
2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, EvalexprError> {
|
fn eval(
|
||||||
|
&self,
|
||||||
|
arguments: &[Value],
|
||||||
|
_configuration: &Configuration,
|
||||||
|
) -> Result<Value, EvalexprError> {
|
||||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||||
expect_number(&arguments[0])?;
|
expect_number(&arguments[0])?;
|
||||||
expect_number(&arguments[1])?;
|
expect_number(&arguments[1])?;
|
||||||
@ -347,7 +379,11 @@ impl Operator for Exp {
|
|||||||
2
|
2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, EvalexprError> {
|
fn eval(
|
||||||
|
&self,
|
||||||
|
arguments: &[Value],
|
||||||
|
_configuration: &Configuration,
|
||||||
|
) -> Result<Value, EvalexprError> {
|
||||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||||
expect_number(&arguments[0])?;
|
expect_number(&arguments[0])?;
|
||||||
expect_number(&arguments[1])?;
|
expect_number(&arguments[1])?;
|
||||||
@ -374,7 +410,11 @@ impl Operator for Eq {
|
|||||||
2
|
2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, EvalexprError> {
|
fn eval(
|
||||||
|
&self,
|
||||||
|
arguments: &[Value],
|
||||||
|
_configuration: &Configuration,
|
||||||
|
) -> Result<Value, EvalexprError> {
|
||||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||||
|
|
||||||
if arguments[0] == arguments[1] {
|
if arguments[0] == arguments[1] {
|
||||||
@ -398,7 +438,11 @@ impl Operator for Neq {
|
|||||||
2
|
2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, EvalexprError> {
|
fn eval(
|
||||||
|
&self,
|
||||||
|
arguments: &[Value],
|
||||||
|
_configuration: &Configuration,
|
||||||
|
) -> Result<Value, EvalexprError> {
|
||||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||||
|
|
||||||
if arguments[0] != arguments[1] {
|
if arguments[0] != arguments[1] {
|
||||||
@ -422,7 +466,11 @@ impl Operator for Gt {
|
|||||||
2
|
2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, EvalexprError> {
|
fn eval(
|
||||||
|
&self,
|
||||||
|
arguments: &[Value],
|
||||||
|
_configuration: &Configuration,
|
||||||
|
) -> Result<Value, EvalexprError> {
|
||||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||||
expect_number(&arguments[0])?;
|
expect_number(&arguments[0])?;
|
||||||
expect_number(&arguments[1])?;
|
expect_number(&arguments[1])?;
|
||||||
@ -456,7 +504,11 @@ impl Operator for Lt {
|
|||||||
2
|
2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, EvalexprError> {
|
fn eval(
|
||||||
|
&self,
|
||||||
|
arguments: &[Value],
|
||||||
|
_configuration: &Configuration,
|
||||||
|
) -> Result<Value, EvalexprError> {
|
||||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||||
expect_number(&arguments[0])?;
|
expect_number(&arguments[0])?;
|
||||||
expect_number(&arguments[1])?;
|
expect_number(&arguments[1])?;
|
||||||
@ -490,7 +542,11 @@ impl Operator for Geq {
|
|||||||
2
|
2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, EvalexprError> {
|
fn eval(
|
||||||
|
&self,
|
||||||
|
arguments: &[Value],
|
||||||
|
_configuration: &Configuration,
|
||||||
|
) -> Result<Value, EvalexprError> {
|
||||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||||
expect_number(&arguments[0])?;
|
expect_number(&arguments[0])?;
|
||||||
expect_number(&arguments[1])?;
|
expect_number(&arguments[1])?;
|
||||||
@ -524,7 +580,11 @@ impl Operator for Leq {
|
|||||||
2
|
2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, EvalexprError> {
|
fn eval(
|
||||||
|
&self,
|
||||||
|
arguments: &[Value],
|
||||||
|
_configuration: &Configuration,
|
||||||
|
) -> Result<Value, EvalexprError> {
|
||||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||||
expect_number(&arguments[0])?;
|
expect_number(&arguments[0])?;
|
||||||
expect_number(&arguments[1])?;
|
expect_number(&arguments[1])?;
|
||||||
@ -558,7 +618,11 @@ impl Operator for And {
|
|||||||
2
|
2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, EvalexprError> {
|
fn eval(
|
||||||
|
&self,
|
||||||
|
arguments: &[Value],
|
||||||
|
_configuration: &Configuration,
|
||||||
|
) -> Result<Value, EvalexprError> {
|
||||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||||
let a = expect_boolean(&arguments[0])?;
|
let a = expect_boolean(&arguments[0])?;
|
||||||
let b = expect_boolean(&arguments[1])?;
|
let b = expect_boolean(&arguments[1])?;
|
||||||
@ -584,7 +648,11 @@ impl Operator for Or {
|
|||||||
2
|
2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, EvalexprError> {
|
fn eval(
|
||||||
|
&self,
|
||||||
|
arguments: &[Value],
|
||||||
|
_configuration: &Configuration,
|
||||||
|
) -> Result<Value, EvalexprError> {
|
||||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||||
let a = expect_boolean(&arguments[0])?;
|
let a = expect_boolean(&arguments[0])?;
|
||||||
let b = expect_boolean(&arguments[1])?;
|
let b = expect_boolean(&arguments[1])?;
|
||||||
@ -610,7 +678,11 @@ impl Operator for Not {
|
|||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, EvalexprError> {
|
fn eval(
|
||||||
|
&self,
|
||||||
|
arguments: &[Value],
|
||||||
|
_configuration: &Configuration,
|
||||||
|
) -> Result<Value, EvalexprError> {
|
||||||
expect_operator_argument_amount(arguments.len(), 1)?;
|
expect_operator_argument_amount(arguments.len(), 1)?;
|
||||||
let a = expect_boolean(&arguments[0])?;
|
let a = expect_boolean(&arguments[0])?;
|
||||||
|
|
||||||
@ -635,7 +707,11 @@ impl Operator for Tuple {
|
|||||||
2
|
2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, EvalexprError> {
|
fn eval(
|
||||||
|
&self,
|
||||||
|
arguments: &[Value],
|
||||||
|
_configuration: &Configuration,
|
||||||
|
) -> Result<Value, EvalexprError> {
|
||||||
if let Value::Tuple(tuple) = &arguments[0] {
|
if let Value::Tuple(tuple) = &arguments[0] {
|
||||||
let mut tuple = tuple.clone();
|
let mut tuple = tuple.clone();
|
||||||
if let Value::Tuple(tuple2) = &arguments[1] {
|
if let Value::Tuple(tuple2) = &arguments[1] {
|
||||||
@ -672,7 +748,11 @@ impl Operator for Const {
|
|||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _configuration: &Configuration) -> Result<Value, EvalexprError> {
|
fn eval(
|
||||||
|
&self,
|
||||||
|
arguments: &[Value],
|
||||||
|
_configuration: &Configuration,
|
||||||
|
) -> Result<Value, EvalexprError> {
|
||||||
expect_operator_argument_amount(arguments.len(), 0)?;
|
expect_operator_argument_amount(arguments.len(), 0)?;
|
||||||
|
|
||||||
Ok(self.value.clone())
|
Ok(self.value.clone())
|
||||||
@ -692,11 +772,17 @@ impl Operator for VariableIdentifier {
|
|||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&self, _arguments: &[Value], configuration: &Configuration) -> Result<Value, EvalexprError> {
|
fn eval(
|
||||||
|
&self,
|
||||||
|
_arguments: &[Value],
|
||||||
|
configuration: &Configuration,
|
||||||
|
) -> Result<Value, EvalexprError> {
|
||||||
if let Some(value) = configuration.get_value(&self.identifier).cloned() {
|
if let Some(value) = configuration.get_value(&self.identifier).cloned() {
|
||||||
Ok(value)
|
Ok(value)
|
||||||
} else {
|
} else {
|
||||||
Err(EvalexprError::VariableIdentifierNotFound(self.identifier.clone()))
|
Err(EvalexprError::VariableIdentifierNotFound(
|
||||||
|
self.identifier.clone(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -714,7 +800,11 @@ impl Operator for FunctionIdentifier {
|
|||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], configuration: &Configuration) -> Result<Value, EvalexprError> {
|
fn eval(
|
||||||
|
&self,
|
||||||
|
arguments: &[Value],
|
||||||
|
configuration: &Configuration,
|
||||||
|
) -> Result<Value, EvalexprError> {
|
||||||
expect_operator_argument_amount(arguments.len(), 1)?;
|
expect_operator_argument_amount(arguments.len(), 1)?;
|
||||||
|
|
||||||
let arguments = if let Value::Tuple(arguments) = &arguments[0] {
|
let arguments = if let Value::Tuple(arguments) = &arguments[0] {
|
||||||
@ -728,7 +818,9 @@ impl Operator for FunctionIdentifier {
|
|||||||
} else if let Some(builtin_function) = builtin_function(&self.identifier) {
|
} else if let Some(builtin_function) = builtin_function(&self.identifier) {
|
||||||
builtin_function.call(arguments)
|
builtin_function.call(arguments)
|
||||||
} else {
|
} else {
|
||||||
Err(EvalexprError::FunctionIdentifierNotFound(self.identifier.clone()))
|
Err(EvalexprError::FunctionIdentifierNotFound(
|
||||||
|
self.identifier.clone(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
use EmptyConfiguration;
|
use EmptyContext;
|
||||||
use FloatType;
|
use FloatType;
|
||||||
use IntType;
|
use IntType;
|
||||||
use token::Token;
|
use token::Token;
|
||||||
use value::TupleType;
|
use value::TupleType;
|
||||||
|
|
||||||
use crate::{configuration::Configuration, error::EvalexprError, operator::*, value::Value};
|
use crate::{context::Configuration, error::EvalexprError, operator::*, value::Value};
|
||||||
|
|
||||||
mod display;
|
mod display;
|
||||||
|
|
||||||
@ -19,8 +19,8 @@ mod display;
|
|||||||
/// ```rust
|
/// ```rust
|
||||||
/// use evalexpr::*;
|
/// use evalexpr::*;
|
||||||
///
|
///
|
||||||
/// let mut configuration = HashMapConfiguration::new();
|
/// let mut configuration = HashMapContext::new();
|
||||||
/// configuration.insert_variable("alpha", 2);
|
/// configuration.set_value("alpha", 2).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_configuration(&configuration), Ok(Value::from(3)));
|
/// assert_eq!(node.eval_with_configuration(&configuration), Ok(Value::from(3)));
|
||||||
/// ```
|
/// ```
|
||||||
@ -46,7 +46,10 @@ impl Node {
|
|||||||
/// Evaluates the operator tree rooted at this node with the given configuration.
|
/// Evaluates the operator tree rooted at this node with the given configuration.
|
||||||
///
|
///
|
||||||
/// Fails, if one of the operators in the expression tree fails.
|
/// Fails, if one of the operators in the expression tree fails.
|
||||||
pub fn eval_with_configuration(&self, configuration: &Configuration) -> Result<Value, EvalexprError> {
|
pub fn eval_with_configuration(
|
||||||
|
&self,
|
||||||
|
configuration: &Configuration,
|
||||||
|
) -> Result<Value, EvalexprError> {
|
||||||
let mut arguments = Vec::new();
|
let mut arguments = Vec::new();
|
||||||
for child in self.children() {
|
for child in self.children() {
|
||||||
arguments.push(child.eval_with_configuration(configuration)?);
|
arguments.push(child.eval_with_configuration(configuration)?);
|
||||||
@ -58,7 +61,7 @@ impl Node {
|
|||||||
///
|
///
|
||||||
/// Fails, if one of the operators in the expression tree fails.
|
/// Fails, if one of the operators in the expression tree fails.
|
||||||
pub fn eval(&self) -> Result<Value, EvalexprError> {
|
pub fn eval(&self) -> Result<Value, EvalexprError> {
|
||||||
self.eval_with_configuration(&EmptyConfiguration)
|
self.eval_with_configuration(&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 configuration.
|
||||||
@ -135,35 +138,35 @@ impl Node {
|
|||||||
///
|
///
|
||||||
/// Fails, if one of the operators in the expression tree fails.
|
/// Fails, if one of the operators in the expression tree fails.
|
||||||
pub fn eval_string(&self) -> Result<String, EvalexprError> {
|
pub fn eval_string(&self) -> Result<String, EvalexprError> {
|
||||||
self.eval_string_with_configuration(&EmptyConfiguration)
|
self.eval_string_with_configuration(&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 configuration.
|
||||||
///
|
///
|
||||||
/// Fails, if one of the operators in the expression tree fails.
|
/// Fails, if one of the operators in the expression tree fails.
|
||||||
pub fn eval_float(&self) -> Result<FloatType, EvalexprError> {
|
pub fn eval_float(&self) -> Result<FloatType, EvalexprError> {
|
||||||
self.eval_float_with_configuration(&EmptyConfiguration)
|
self.eval_float_with_configuration(&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 configuration.
|
||||||
///
|
///
|
||||||
/// Fails, if one of the operators in the expression tree fails.
|
/// Fails, if one of the operators in the expression tree fails.
|
||||||
pub fn eval_int(&self) -> Result<IntType, EvalexprError> {
|
pub fn eval_int(&self) -> Result<IntType, EvalexprError> {
|
||||||
self.eval_int_with_configuration(&EmptyConfiguration)
|
self.eval_int_with_configuration(&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 configuration.
|
||||||
///
|
///
|
||||||
/// Fails, if one of the operators in the expression tree fails.
|
/// Fails, if one of the operators in the expression tree fails.
|
||||||
pub fn eval_boolean(&self) -> Result<bool, EvalexprError> {
|
pub fn eval_boolean(&self) -> Result<bool, EvalexprError> {
|
||||||
self.eval_boolean_with_configuration(&EmptyConfiguration)
|
self.eval_boolean_with_configuration(&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 configuration.
|
||||||
///
|
///
|
||||||
/// Fails, if one of the operators in the expression tree fails.
|
/// Fails, if one of the operators in the expression tree fails.
|
||||||
pub fn eval_tuple(&self) -> Result<TupleType, EvalexprError> {
|
pub fn eval_tuple(&self) -> Result<TupleType, EvalexprError> {
|
||||||
self.eval_tuple_with_configuration(&EmptyConfiguration)
|
self.eval_tuple_with_configuration(&EmptyContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn children(&self) -> &[Node] {
|
fn children(&self) -> &[Node] {
|
||||||
@ -178,7 +181,11 @@ impl Node {
|
|||||||
self.children().len() == self.operator().argument_amount()
|
self.children().len() == self.operator().argument_amount()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_back_prioritized(&mut self, node: Node, is_root_node: bool) -> Result<(), EvalexprError> {
|
fn insert_back_prioritized(
|
||||||
|
&mut self,
|
||||||
|
node: Node,
|
||||||
|
is_root_node: bool,
|
||||||
|
) -> Result<(), EvalexprError> {
|
||||||
if self.operator().precedence() < node.operator().precedence() || is_root_node
|
if self.operator().precedence() < node.operator().precedence() || is_root_node
|
||||||
// Right-to-left chaining
|
// Right-to-left chaining
|
||||||
|| (self.operator().precedence() == node.operator().precedence() && !self.operator().is_left_to_right() && !node.operator().is_left_to_right())
|
|| (self.operator().precedence() == node.operator().precedence() && !self.operator().is_left_to_right() && !node.operator().is_left_to_right())
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use error::EvalexprError;
|
use error::EvalexprError;
|
||||||
|
|
||||||
mod display;
|
mod display;
|
||||||
|
pub mod value_type;
|
||||||
|
|
||||||
/// The type used to represent integers in `Value::Int`.
|
/// The type used to represent integers in `Value::Int`.
|
||||||
pub type IntType = i64;
|
pub type IntType = i64;
|
||||||
|
35
src/value/value_type.rs
Normal file
35
src/value/value_type.rs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
use Value;
|
||||||
|
|
||||||
|
/// The type of a `Value`.
|
||||||
|
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||||
|
pub enum ValueType {
|
||||||
|
String,
|
||||||
|
Float,
|
||||||
|
Int,
|
||||||
|
Boolean,
|
||||||
|
Tuple,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&Value> for ValueType {
|
||||||
|
fn from(value: &Value) -> Self {
|
||||||
|
match value {
|
||||||
|
Value::String(_) => ValueType::String,
|
||||||
|
Value::Float(_) => ValueType::Float,
|
||||||
|
Value::Int(_) => ValueType::Int,
|
||||||
|
Value::Boolean(_) => ValueType::Boolean,
|
||||||
|
Value::Tuple(_) => ValueType::Tuple,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&mut Value> for ValueType {
|
||||||
|
fn from(value: &mut Value) -> Self {
|
||||||
|
From::<&Value>::from(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&&mut Value> for ValueType {
|
||||||
|
fn from(value: &&mut Value) -> Self {
|
||||||
|
From::<&Value>::from(*value)
|
||||||
|
}
|
||||||
|
}
|
@ -10,7 +10,9 @@ fn test_unary_examples() {
|
|||||||
assert_eq!(eval("false"), Ok(Value::Boolean(false)));
|
assert_eq!(eval("false"), Ok(Value::Boolean(false)));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
eval("blub"),
|
eval("blub"),
|
||||||
Err(EvalexprError::VariableIdentifierNotFound("blub".to_string()))
|
Err(EvalexprError::VariableIdentifierNotFound(
|
||||||
|
"blub".to_string()
|
||||||
|
))
|
||||||
);
|
);
|
||||||
assert_eq!(eval("-3"), Ok(Value::Int(-3)));
|
assert_eq!(eval("-3"), Ok(Value::Int(-3)));
|
||||||
assert_eq!(eval("-3.6"), Ok(Value::Float(-3.6)));
|
assert_eq!(eval("-3.6"), Ok(Value::Float(-3.6)));
|
||||||
@ -97,13 +99,13 @@ fn test_boolean_examples() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_with_configuration() {
|
fn test_with_configuration() {
|
||||||
let mut configuration = HashMapConfiguration::new();
|
let mut configuration = HashMapContext::new();
|
||||||
configuration.insert_variable("tr".to_string(), Value::Boolean(true));
|
configuration.set_value("tr", Value::Boolean(true)).unwrap();
|
||||||
configuration.insert_variable("fa".to_string(), Value::Boolean(false));
|
configuration.set_value("fa", Value::Boolean(false)).unwrap();
|
||||||
configuration.insert_variable("five".to_string(), Value::Int(5));
|
configuration.set_value("five", Value::Int(5)).unwrap();
|
||||||
configuration.insert_variable("six".to_string(), Value::Int(6));
|
configuration.set_value("six", Value::Int(6)).unwrap();
|
||||||
configuration.insert_variable("half".to_string(), Value::Float(0.5));
|
configuration.set_value("half", Value::Float(0.5)).unwrap();
|
||||||
configuration.insert_variable("zero".to_string(), Value::Int(0));
|
configuration.set_value("zero", Value::Int(0)).unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
eval_with_configuration("tr", &configuration),
|
eval_with_configuration("tr", &configuration),
|
||||||
@ -133,8 +135,8 @@ fn test_with_configuration() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_functions() {
|
fn test_functions() {
|
||||||
let mut configuration = HashMapConfiguration::new();
|
let mut configuration = HashMapContext::new();
|
||||||
configuration.insert_function(
|
configuration.set_function(
|
||||||
"sub2".to_string(),
|
"sub2".to_string(),
|
||||||
Function::new(
|
Function::new(
|
||||||
Some(1),
|
Some(1),
|
||||||
@ -148,8 +150,8 @@ fn test_functions() {
|
|||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
);
|
).unwrap();
|
||||||
configuration.insert_variable("five".to_string(), Value::Int(5));
|
configuration.set_value("five".to_string(), Value::Int(5)).unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
eval_with_configuration("sub2 5", &configuration),
|
eval_with_configuration("sub2 5", &configuration),
|
||||||
@ -175,8 +177,8 @@ fn test_functions() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_n_ary_functions() {
|
fn test_n_ary_functions() {
|
||||||
let mut configuration = HashMapConfiguration::new();
|
let mut configuration = HashMapContext::new();
|
||||||
configuration.insert_function(
|
configuration.set_function(
|
||||||
"sub2",
|
"sub2",
|
||||||
Function::new(
|
Function::new(
|
||||||
Some(1),
|
Some(1),
|
||||||
@ -190,8 +192,8 @@ fn test_n_ary_functions() {
|
|||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
);
|
).unwrap();
|
||||||
configuration.insert_function(
|
configuration.set_function(
|
||||||
"avg",
|
"avg",
|
||||||
Function::new(
|
Function::new(
|
||||||
Some(2),
|
Some(2),
|
||||||
@ -208,8 +210,8 @@ fn test_n_ary_functions() {
|
|||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
);
|
).unwrap();
|
||||||
configuration.insert_function(
|
configuration.set_function(
|
||||||
"muladd",
|
"muladd",
|
||||||
Function::new(
|
Function::new(
|
||||||
Some(3),
|
Some(3),
|
||||||
@ -230,15 +232,15 @@ fn test_n_ary_functions() {
|
|||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
);
|
).unwrap();
|
||||||
configuration.insert_function(
|
configuration.set_function(
|
||||||
"count",
|
"count",
|
||||||
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))),
|
||||||
),
|
),
|
||||||
);
|
).unwrap();
|
||||||
configuration.insert_variable("five".to_string(), Value::Int(5));
|
configuration.set_value("five".to_string(), Value::Int(5)).unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
eval_with_configuration("avg(7, 5)", &configuration),
|
eval_with_configuration("avg(7, 5)", &configuration),
|
||||||
@ -339,8 +341,8 @@ fn test_no_panic() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_shortcut_functions() {
|
fn test_shortcut_functions() {
|
||||||
let mut configuration = HashMapConfiguration::new();
|
let mut configuration = HashMapContext::new();
|
||||||
configuration.insert_variable("string", Value::from("a string"));
|
configuration.set_value("string", Value::from("a string")).unwrap();
|
||||||
|
|
||||||
// assert_eq!(eval_string("???"));
|
// assert_eq!(eval_string("???"));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
Loading…
Reference in New Issue
Block a user