Add map type functionality
This commit is contained in:
parent
44170697cb
commit
f2ae0d952f
7
src/bin/expressive.rs
Normal file
7
src/bin/expressive.rs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
pub fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let args = std::env::args().skip(1).collect::<Vec<String>>().join(" ");
|
||||||
|
|
||||||
|
println!("{}", evalexpr::eval(&args)?);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
@ -4,7 +4,7 @@
|
|||||||
//! 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.
|
//! The HashMapContext is type-safe and returns an error if the user tries to assign a value of a different type than before to an identifier.
|
||||||
|
|
||||||
use std::{collections::HashMap, iter};
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
function::Function,
|
function::Function,
|
||||||
@ -27,7 +27,7 @@ pub trait Context {
|
|||||||
/// A context that allows to assign to variables.
|
/// A context that allows to assign to variables.
|
||||||
pub trait ContextWithMutableVariables: Context {
|
pub trait ContextWithMutableVariables: Context {
|
||||||
/// Sets the variable with the given identifier to the given value.
|
/// Sets the variable with the given identifier to the given value.
|
||||||
fn set_value(&mut self, _identifier: String, _value: Value) -> EvalexprResult<()> {
|
fn set_value(&mut self, _identifier: &str, _value: Value) -> EvalexprResult<()> {
|
||||||
Err(EvalexprError::ContextNotMutable)
|
Err(EvalexprError::ContextNotMutable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -40,105 +40,81 @@ pub trait ContextWithMutableFunctions: Context {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A context that allows to iterate over its variable names with their values.
|
|
||||||
///
|
|
||||||
/// **Note:** this trait will change after GATs are stabilised, because then we can get rid of the lifetime in the trait definition.
|
|
||||||
pub trait IterateVariablesContext {
|
|
||||||
/// The iterator type for iterating over variable name-value pairs.
|
|
||||||
type VariableIterator<'a>: Iterator<Item = (String, Value)>
|
|
||||||
where
|
|
||||||
Self: 'a;
|
|
||||||
/// The iterator type for iterating over variable names.
|
|
||||||
type VariableNameIterator<'a>: Iterator<Item = String>
|
|
||||||
where
|
|
||||||
Self: 'a;
|
|
||||||
|
|
||||||
/// Returns an iterator over pairs of variable names and values.
|
|
||||||
fn iter_variables(&self) -> Self::VariableIterator<'_>;
|
|
||||||
|
|
||||||
/// Returns an iterator over variable names.
|
|
||||||
fn iter_variable_names(&self) -> Self::VariableNameIterator<'_>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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.*
|
|
||||||
///
|
|
||||||
/// 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.
|
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct ContextData {
|
pub struct VariableMap {
|
||||||
map_name: String,
|
variables: BTreeMap<String, Value>,
|
||||||
|
|
||||||
variables: HashMap<String, Value>,
|
|
||||||
|
|
||||||
functions: HashMap<String, Function>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ContextData {
|
impl PartialEq for VariableMap {
|
||||||
/// Constructs a `HashMapContext` with no mappings.
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
if self.variables.len() != other.variables.len() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for variable in &self.variables {
|
||||||
|
for other in &other.variables {
|
||||||
|
if variable != other {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VariableMap {
|
||||||
|
/// Create a new instace.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Default::default()
|
Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Context for ContextData {
|
impl Context for VariableMap {
|
||||||
fn get_value(&self, identifier: &str) -> Option<&Value> {
|
fn get_value(&self, identifier: &str) -> Option<&Value> {
|
||||||
self.variables.get(identifier)
|
self.variables.get(identifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call_function(&self, identifier: &str, argument: &Value) -> EvalexprResult<Value> {
|
fn call_function(&self, identifier: &str, argument: &Value) -> EvalexprResult<Value> {
|
||||||
match identifier {
|
match identifier {
|
||||||
"map" => {
|
|
||||||
let map = Value::Map(self.variables.clone());
|
|
||||||
self.variables.insert(identifier.to_string(), map);
|
|
||||||
Ok(Value::Empty)
|
|
||||||
},
|
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ContextWithMutableVariables for ContextData {
|
impl ContextWithMutableVariables for VariableMap {
|
||||||
fn set_value(&mut self, identifier: String, value: Value) -> EvalexprResult<()> {
|
fn set_value(&mut self, identifier: &str, value: Value) -> EvalexprResult<()> {
|
||||||
if let Some(existing_value) = self.variables.get_mut(&identifier) {
|
println!("{:#?}", self);
|
||||||
if ValueType::from(&existing_value) == ValueType::from(&value) {
|
println!("{}", identifier);
|
||||||
*existing_value = value;
|
|
||||||
return Ok(());
|
let split = identifier.split_once(".");
|
||||||
|
if let Some((map_name, next_identifier)) = split {
|
||||||
|
if let Some(map_value) = self.variables.get_mut(map_name) {
|
||||||
|
if let Value::Map(map) = map_value {
|
||||||
|
map.set_value(next_identifier, value)?;
|
||||||
|
} else {
|
||||||
|
return Err(EvalexprError::ExpectedMap {
|
||||||
|
actual: map_value.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(EvalexprError::expected_type(existing_value, value));
|
let mut new_map = BTreeMap::new();
|
||||||
|
new_map.insert(next_identifier.to_string(), value);
|
||||||
|
let map_var = Value::Map(VariableMap { variables: new_map });
|
||||||
|
self.variables.insert(map_name.to_string(), map_var);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
self.variables.insert(identifier.to_string(), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implicit else, because `self.variables` and `identifier` are not unborrowed in else
|
|
||||||
self.variables.insert(identifier, value);
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ContextWithMutableFunctions for ContextData {
|
impl ContextWithMutableFunctions for VariableMap {
|
||||||
fn set_function(&mut self, identifier: String, function: Function) -> EvalexprResult<()> {
|
fn set_function(&mut self, identifier: String, function: Function) -> EvalexprResult<()> {
|
||||||
self.functions.insert(identifier, function);
|
todo!()
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IterateVariablesContext for ContextData {
|
|
||||||
type VariableIterator<'a> = std::iter::Map<
|
|
||||||
std::collections::hash_map::Iter<'a, String, Value>,
|
|
||||||
fn((&String, &Value)) -> (String, Value),
|
|
||||||
>;
|
|
||||||
type VariableNameIterator<'a> =
|
|
||||||
std::iter::Cloned<std::collections::hash_map::Keys<'a, String, Value>>;
|
|
||||||
|
|
||||||
fn iter_variables(&self) -> Self::VariableIterator<'_> {
|
|
||||||
self.variables
|
|
||||||
.iter()
|
|
||||||
.map(|(string, value)| (string.clone(), value.clone()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn iter_variable_names(&self) -> Self::VariableNameIterator<'_> {
|
|
||||||
self.variables.keys().cloned()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,7 +155,7 @@ macro_rules! context_map {
|
|||||||
|
|
||||||
// Create a context, then recurse to add the values in it
|
// Create a context, then recurse to add the values in it
|
||||||
( $($tt:tt)* ) => {{
|
( $($tt:tt)* ) => {{
|
||||||
let mut context = $crate::HashMapContext::new();
|
let mut context = $crate::VariableMap::new();
|
||||||
$crate::context_map!((&mut context) $($tt)*)
|
$crate::context_map!((&mut context) $($tt)*)
|
||||||
.map(|_| context)
|
.map(|_| context)
|
||||||
}};
|
}};
|
||||||
|
@ -5,7 +5,10 @@ use crate::{
|
|||||||
value::{FloatType, IntType},
|
value::{FloatType, IntType},
|
||||||
EvalexprError, Function, Value, ValueType,
|
EvalexprError, Function, Value, ValueType,
|
||||||
};
|
};
|
||||||
use std::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr};
|
use std::{
|
||||||
|
collections::HashSet,
|
||||||
|
ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr},
|
||||||
|
};
|
||||||
|
|
||||||
macro_rules! simple_math {
|
macro_rules! simple_math {
|
||||||
($func:ident) => {
|
($func:ident) => {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
token, tree, value::TupleType, Context, ContextWithMutableVariables, EmptyType, EvalexprError,
|
token, tree, value::TupleType, Context, ContextWithMutableVariables, EmptyType, EvalexprError,
|
||||||
EvalexprResult, FloatType, ContextData, IntType, Node, Value, EMPTY_VALUE,
|
EvalexprResult, FloatType, IntType, Node, Value, VariableMap, EMPTY_VALUE,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Evaluate the given expression string.
|
/// Evaluate the given expression string.
|
||||||
@ -15,7 +15,7 @@ use crate::{
|
|||||||
///
|
///
|
||||||
/// *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) -> EvalexprResult<Value> {
|
pub fn eval(string: &str) -> EvalexprResult<Value> {
|
||||||
eval_with_context_mut(string, &mut ContextData::new())
|
eval_with_context_mut(string, &mut VariableMap::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate the given expression string with the given context.
|
/// Evaluate the given expression string with the given context.
|
||||||
@ -91,21 +91,21 @@ pub fn build_operator_tree(string: &str) -> EvalexprResult<Node> {
|
|||||||
///
|
///
|
||||||
/// *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(string: &str) -> EvalexprResult<String> {
|
pub fn eval_string(string: &str) -> EvalexprResult<String> {
|
||||||
eval_string_with_context_mut(string, &mut ContextData::new())
|
eval_string_with_context_mut(string, &mut VariableMap::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate the given expression string into an integer.
|
/// Evaluate the given expression string into an integer.
|
||||||
///
|
///
|
||||||
/// *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_int(string: &str) -> EvalexprResult<IntType> {
|
pub fn eval_int(string: &str) -> EvalexprResult<IntType> {
|
||||||
eval_int_with_context_mut(string, &mut ContextData::new())
|
eval_int_with_context_mut(string, &mut VariableMap::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate the given expression string into a float.
|
/// Evaluate the given expression string into a float.
|
||||||
///
|
///
|
||||||
/// *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_float(string: &str) -> EvalexprResult<FloatType> {
|
pub fn eval_float(string: &str) -> EvalexprResult<FloatType> {
|
||||||
eval_float_with_context_mut(string, &mut ContextData::new())
|
eval_float_with_context_mut(string, &mut VariableMap::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate the given expression string into a float.
|
/// Evaluate the given expression string into a float.
|
||||||
@ -113,28 +113,28 @@ pub fn eval_float(string: &str) -> EvalexprResult<FloatType> {
|
|||||||
///
|
///
|
||||||
/// *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_number(string: &str) -> EvalexprResult<FloatType> {
|
pub fn eval_number(string: &str) -> EvalexprResult<FloatType> {
|
||||||
eval_number_with_context_mut(string, &mut ContextData::new())
|
eval_number_with_context_mut(string, &mut VariableMap::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate the given expression string into a boolean.
|
/// Evaluate the given expression string into a boolean.
|
||||||
///
|
///
|
||||||
/// *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_boolean(string: &str) -> EvalexprResult<bool> {
|
pub fn eval_boolean(string: &str) -> EvalexprResult<bool> {
|
||||||
eval_boolean_with_context_mut(string, &mut ContextData::new())
|
eval_boolean_with_context_mut(string, &mut VariableMap::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate the given expression string into a tuple.
|
/// Evaluate the given expression string into a tuple.
|
||||||
///
|
///
|
||||||
/// *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_tuple(string: &str) -> EvalexprResult<TupleType> {
|
pub fn eval_tuple(string: &str) -> EvalexprResult<TupleType> {
|
||||||
eval_tuple_with_context_mut(string, &mut ContextData::new())
|
eval_tuple_with_context_mut(string, &mut VariableMap::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate the given expression string into an empty value.
|
/// Evaluate the given expression string into an empty value.
|
||||||
///
|
///
|
||||||
/// *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_empty(string: &str) -> EvalexprResult<EmptyType> {
|
pub fn eval_empty(string: &str) -> EvalexprResult<EmptyType> {
|
||||||
eval_empty_with_context_mut(string, &mut ContextData::new())
|
eval_empty_with_context_mut(string, &mut VariableMap::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate the given expression string into a string with the given context.
|
/// Evaluate the given expression string into a string with the given context.
|
||||||
|
@ -560,9 +560,7 @@ extern crate serde;
|
|||||||
extern crate serde_derive;
|
extern crate serde_derive;
|
||||||
|
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
context::{
|
context::{Context, ContextWithMutableFunctions, ContextWithMutableVariables, VariableMap},
|
||||||
Context, ContextWithMutableFunctions, ContextWithMutableVariables, ContextData, IterateVariablesContext,
|
|
||||||
},
|
|
||||||
error::{EvalexprError, EvalexprResult},
|
error::{EvalexprError, EvalexprResult},
|
||||||
function::Function,
|
function::Function,
|
||||||
interface::*,
|
interface::*,
|
||||||
|
@ -459,8 +459,7 @@ impl Operator {
|
|||||||
let arguments = &arguments[0];
|
let arguments = &arguments[0];
|
||||||
|
|
||||||
match context.call_function(identifier, arguments) {
|
match context.call_function(identifier, arguments) {
|
||||||
Err(EvalexprError::FunctionIdentifierNotFound(_)) =>
|
Err(EvalexprError::FunctionIdentifierNotFound(_)) => {
|
||||||
{
|
|
||||||
if let Some(builtin_function) = builtin_function(identifier) {
|
if let Some(builtin_function) = builtin_function(identifier) {
|
||||||
builtin_function.call(arguments)
|
builtin_function.call(arguments)
|
||||||
} else {
|
} else {
|
||||||
@ -486,7 +485,7 @@ impl Operator {
|
|||||||
Assign => {
|
Assign => {
|
||||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||||
let target = arguments[0].as_string()?;
|
let target = arguments[0].as_string()?;
|
||||||
context.set_value(target, arguments[1].clone())?;
|
context.set_value(&target, arguments[1].clone())?;
|
||||||
|
|
||||||
Ok(Value::Empty)
|
Ok(Value::Empty)
|
||||||
},
|
},
|
||||||
@ -515,7 +514,7 @@ impl Operator {
|
|||||||
self
|
self
|
||||||
),
|
),
|
||||||
}?;
|
}?;
|
||||||
context.set_value(target, result)?;
|
context.set_value(&target, result)?;
|
||||||
|
|
||||||
Ok(Value::Empty)
|
Ok(Value::Empty)
|
||||||
},
|
},
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
token::Token,
|
token::Token,
|
||||||
value::{TupleType, EMPTY_VALUE},
|
value::{TupleType, EMPTY_VALUE},
|
||||||
Context, ContextWithMutableVariables, EmptyType, FloatType, ContextData, IntType,
|
Context, ContextWithMutableVariables, EmptyType, FloatType, IntType, VariableMap,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -346,7 +346,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) -> EvalexprResult<Value> {
|
pub fn eval(&self) -> EvalexprResult<Value> {
|
||||||
self.eval_with_context_mut(&mut ContextData::new())
|
self.eval_with_context_mut(&mut VariableMap::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluates the operator tree rooted at this node into a string with an the given context.
|
/// Evaluates the operator tree rooted at this node into a string with an the given context.
|
||||||
@ -532,21 +532,21 @@ 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) -> EvalexprResult<String> {
|
pub fn eval_string(&self) -> EvalexprResult<String> {
|
||||||
self.eval_string_with_context_mut(&mut ContextData::new())
|
self.eval_string_with_context_mut(&mut VariableMap::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluates the operator tree rooted at this node into a float.
|
/// Evaluates the operator tree rooted at this node into a float.
|
||||||
///
|
///
|
||||||
/// 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) -> EvalexprResult<FloatType> {
|
pub fn eval_float(&self) -> EvalexprResult<FloatType> {
|
||||||
self.eval_float_with_context_mut(&mut ContextData::new())
|
self.eval_float_with_context_mut(&mut VariableMap::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluates the operator tree rooted at this node into an integer.
|
/// Evaluates the operator tree rooted at this node into an integer.
|
||||||
///
|
///
|
||||||
/// 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) -> EvalexprResult<IntType> {
|
pub fn eval_int(&self) -> EvalexprResult<IntType> {
|
||||||
self.eval_int_with_context_mut(&mut ContextData::new())
|
self.eval_int_with_context_mut(&mut VariableMap::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluates the operator tree rooted at this node into a float.
|
/// Evaluates the operator tree rooted at this node into a float.
|
||||||
@ -554,28 +554,28 @@ 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_number(&self) -> EvalexprResult<FloatType> {
|
pub fn eval_number(&self) -> EvalexprResult<FloatType> {
|
||||||
self.eval_number_with_context_mut(&mut ContextData::new())
|
self.eval_number_with_context_mut(&mut VariableMap::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluates the operator tree rooted at this node into a boolean.
|
/// Evaluates the operator tree rooted at this node into a boolean.
|
||||||
///
|
///
|
||||||
/// 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) -> EvalexprResult<bool> {
|
pub fn eval_boolean(&self) -> EvalexprResult<bool> {
|
||||||
self.eval_boolean_with_context_mut(&mut ContextData::new())
|
self.eval_boolean_with_context_mut(&mut VariableMap::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluates the operator tree rooted at this node into a tuple.
|
/// Evaluates the operator tree rooted at this node into a tuple.
|
||||||
///
|
///
|
||||||
/// 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) -> EvalexprResult<TupleType> {
|
pub fn eval_tuple(&self) -> EvalexprResult<TupleType> {
|
||||||
self.eval_tuple_with_context_mut(&mut ContextData::new())
|
self.eval_tuple_with_context_mut(&mut VariableMap::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluates the operator tree rooted at this node into an empty value.
|
/// Evaluates the operator tree rooted at this node into an empty value.
|
||||||
///
|
///
|
||||||
/// 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_empty(&self) -> EvalexprResult<EmptyType> {
|
pub fn eval_empty(&self) -> EvalexprResult<EmptyType> {
|
||||||
self.eval_empty_with_context_mut(&mut ContextData::new())
|
self.eval_empty_with_context_mut(&mut VariableMap::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the children of this node as a slice.
|
/// Returns the children of this node as a slice.
|
||||||
|
@ -1,5 +1,11 @@
|
|||||||
use crate::error::{EvalexprError, EvalexprResult};
|
use crate::{
|
||||||
use std::{convert::TryFrom, collections::HashMap};
|
error::{EvalexprError, EvalexprResult},
|
||||||
|
VariableMap,
|
||||||
|
};
|
||||||
|
use std::{
|
||||||
|
collections::{BTreeMap, HashMap},
|
||||||
|
convert::TryFrom,
|
||||||
|
};
|
||||||
|
|
||||||
mod display;
|
mod display;
|
||||||
pub mod value_type;
|
pub mod value_type;
|
||||||
@ -37,7 +43,7 @@ pub enum Value {
|
|||||||
/// An empty value.
|
/// An empty value.
|
||||||
Empty,
|
Empty,
|
||||||
/// Collection of key-value pairs.
|
/// Collection of key-value pairs.
|
||||||
Map(HashMap<String, Value>),
|
Map(VariableMap),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Value {
|
impl Value {
|
||||||
|
@ -110,7 +110,7 @@ fn test_boolean_examples() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_with_context() {
|
fn test_with_context() {
|
||||||
let mut context = ContextData::new();
|
let mut context = VariableMap::new();
|
||||||
context
|
context
|
||||||
.set_value("tr".into(), Value::Boolean(true))
|
.set_value("tr".into(), Value::Boolean(true))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -144,7 +144,7 @@ fn test_with_context() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_functions() {
|
fn test_functions() {
|
||||||
let mut context = ContextData::new();
|
let mut context = VariableMap::new();
|
||||||
context
|
context
|
||||||
.set_function(
|
.set_function(
|
||||||
"sub2".to_string(),
|
"sub2".to_string(),
|
||||||
@ -175,7 +175,7 @@ fn test_functions() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_n_ary_functions() {
|
fn test_n_ary_functions() {
|
||||||
let mut context = ContextData::new();
|
let mut context = VariableMap::new();
|
||||||
context
|
context
|
||||||
.set_function(
|
.set_function(
|
||||||
"sub2".into(),
|
"sub2".into(),
|
||||||
@ -282,7 +282,7 @@ fn test_n_ary_functions() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_capturing_functions() {
|
fn test_capturing_functions() {
|
||||||
let mut context = ContextData::new();
|
let mut context = VariableMap::new();
|
||||||
// this variable is captured by the function
|
// this variable is captured by the function
|
||||||
let three = 3;
|
let three = 3;
|
||||||
context
|
context
|
||||||
@ -601,7 +601,7 @@ fn test_no_panic() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_shortcut_functions() {
|
fn test_shortcut_functions() {
|
||||||
let mut context = ContextData::new();
|
let mut context = VariableMap::new();
|
||||||
context
|
context
|
||||||
.set_value("string".into(), Value::from("a string"))
|
.set_value("string".into(), Value::from("a string"))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -1284,7 +1284,7 @@ fn test_whitespace() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_assignment() {
|
fn test_assignment() {
|
||||||
let mut context = ContextData::new();
|
let mut context = VariableMap::new();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
eval_empty_with_context_mut("int = 3", &mut context),
|
eval_empty_with_context_mut("int = 3", &mut context),
|
||||||
Ok(EMPTY_VALUE)
|
Ok(EMPTY_VALUE)
|
||||||
@ -1324,7 +1324,7 @@ fn test_assignment() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_expression_chaining() {
|
fn test_expression_chaining() {
|
||||||
let mut context = ContextData::new();
|
let mut context = VariableMap::new();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
eval_int_with_context_mut("a = 5; a = a + 2; a", &mut context),
|
eval_int_with_context_mut("a = 5; a = a + 2; a", &mut context),
|
||||||
Ok(7)
|
Ok(7)
|
||||||
@ -1333,7 +1333,7 @@ fn test_expression_chaining() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_strings() {
|
fn test_strings() {
|
||||||
let mut context = ContextData::new();
|
let mut context = VariableMap::new();
|
||||||
assert_eq!(eval("\"string\""), Ok(Value::from("string")));
|
assert_eq!(eval("\"string\""), Ok(Value::from("string")));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
eval_with_context_mut("a = \"a string\"", &mut context),
|
eval_with_context_mut("a = \"a string\"", &mut context),
|
||||||
@ -1441,7 +1441,7 @@ fn test_implicit_context() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_operator_assignments() {
|
fn test_operator_assignments() {
|
||||||
let mut context = ContextData::new();
|
let mut context = VariableMap::new();
|
||||||
assert_eq!(eval_empty_with_context_mut("a = 5", &mut context), Ok(()));
|
assert_eq!(eval_empty_with_context_mut("a = 5", &mut context), Ok(()));
|
||||||
assert_eq!(eval_empty_with_context_mut("a += 5", &mut context), Ok(()));
|
assert_eq!(eval_empty_with_context_mut("a += 5", &mut context), Ok(()));
|
||||||
assert_eq!(eval_empty_with_context_mut("a -= 5", &mut context), Ok(()));
|
assert_eq!(eval_empty_with_context_mut("a -= 5", &mut context), Ok(()));
|
||||||
@ -1463,7 +1463,7 @@ fn test_operator_assignments() {
|
|||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut context = ContextData::new();
|
let mut context = VariableMap::new();
|
||||||
assert_eq!(eval_int_with_context_mut("a = 5; a", &mut context), Ok(5));
|
assert_eq!(eval_int_with_context_mut("a = 5; a", &mut context), Ok(5));
|
||||||
assert_eq!(eval_int_with_context_mut("a += 3; a", &mut context), Ok(8));
|
assert_eq!(eval_int_with_context_mut("a += 3; a", &mut context), Ok(8));
|
||||||
assert_eq!(eval_int_with_context_mut("a -= 5; a", &mut context), Ok(3));
|
assert_eq!(eval_int_with_context_mut("a -= 5; a", &mut context), Ok(3));
|
||||||
@ -1643,7 +1643,7 @@ fn test_hashmap_context_type_safety() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_hashmap_context_clone_debug() {
|
fn test_hashmap_context_clone_debug() {
|
||||||
let mut context = ContextData::new();
|
let mut context = VariableMap::new();
|
||||||
// this variable is captured by the function
|
// this variable is captured by the function
|
||||||
let three = 3;
|
let three = 3;
|
||||||
context
|
context
|
||||||
@ -2228,7 +2228,7 @@ fn assignment_lhs_is_identifier() {
|
|||||||
let tree = build_operator_tree("a = 1").unwrap();
|
let tree = build_operator_tree("a = 1").unwrap();
|
||||||
let operators: Vec<_> = tree.iter().map(|node| node.operator().clone()).collect();
|
let operators: Vec<_> = tree.iter().map(|node| node.operator().clone()).collect();
|
||||||
|
|
||||||
let mut context = ContextData::new();
|
let mut context = VariableMap::new();
|
||||||
tree.eval_with_context_mut(&mut context).unwrap();
|
tree.eval_with_context_mut(&mut context).unwrap();
|
||||||
assert_eq!(context.get_value("a"), Some(&Value::Int(1)));
|
assert_eq!(context.get_value("a"), Some(&Value::Int(1)));
|
||||||
|
|
||||||
@ -2250,7 +2250,7 @@ fn assignment_lhs_is_identifier() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_variable_assignment_and_iteration() {
|
fn test_variable_assignment_and_iteration() {
|
||||||
let mut context = ContextData::new();
|
let mut context = VariableMap::new();
|
||||||
eval_with_context_mut("a = 5; b = 5.0", &mut context).unwrap();
|
eval_with_context_mut("a = 5; b = 5.0", &mut context).unwrap();
|
||||||
|
|
||||||
let mut variables: Vec<_> = context.iter_variables().collect();
|
let mut variables: Vec<_> = context.iter_variables().collect();
|
||||||
@ -2278,7 +2278,7 @@ fn test_negative_power() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_builtin_functions_context() {
|
fn test_builtin_functions_context() {
|
||||||
let mut context = ContextData::new();
|
let mut context = VariableMap::new();
|
||||||
// Builtin functions are enabled by default for HashMapContext.
|
// Builtin functions are enabled by default for HashMapContext.
|
||||||
assert_eq!(eval_with_context("max(1,3)", &context), Ok(Value::from(3)));
|
assert_eq!(eval_with_context("max(1,3)", &context), Ok(Value::from(3)));
|
||||||
// Disabling builtin function in Context.
|
// Disabling builtin function in Context.
|
||||||
|
Loading…
Reference in New Issue
Block a user