Fix calling functions without arguments

This commit is contained in:
Jeff 2023-06-24 01:11:36 -04:00
parent da7d52caef
commit e730028185
2 changed files with 31 additions and 18 deletions

View File

@ -5,6 +5,7 @@
//! 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::{ use std::{
cell::Cell,
collections::BTreeMap, collections::BTreeMap,
fmt::Display, fmt::Display,
fs, fs,
@ -25,7 +26,7 @@ mod predefined;
/// An immutable context. /// An immutable context.
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) -> EvalexprResult<Option<Value>>;
/// Calls the function that is linked to the given identifier with the given argument. /// Calls the function that is linked to the given identifier with the given argument.
/// If no function with the given identifier is found, this method returns `EvalexprError::FunctionIdentifierNotFound`. /// If no function with the given identifier is found, this method returns `EvalexprError::FunctionIdentifierNotFound`.
@ -49,7 +50,7 @@ pub trait ContextWithMutableFunctions: Context {
} }
/// A context that stores its mappings in hash maps. /// A context that stores its mappings in hash maps.
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug)]
pub struct VariableMap { pub struct VariableMap {
variables: BTreeMap<String, Value>, variables: BTreeMap<String, Value>,
} }
@ -87,25 +88,36 @@ impl PartialEq for VariableMap {
impl VariableMap { impl VariableMap {
/// Create a new instace. /// Create a new instace.
pub fn new() -> Self { pub fn new() -> Self {
Default::default() VariableMap {
variables: BTreeMap::new(),
}
} }
} }
impl Context for VariableMap { impl Context for VariableMap {
fn get_value(&self, identifier: &str) -> Option<&Value> { fn get_value(&self, identifier: &str) -> EvalexprResult<Option<Value>> {
let split = identifier.split_once("."); let split = identifier.split_once(".");
if let Some((map_name, next_identifier)) = split { if let Some((identifier, next_identifier)) = split {
let value = self.variables.get(map_name)?; if let Some(value) = self.variables.get(identifier) {
if let Value::Map(map) = value { if let Value::Map(map) = value {
map.get_value(next_identifier) map.get_value(next_identifier)
} else { } else {
None Err(EvalexprError::ExpectedMap {
actual: value.clone(),
})
} }
} else { } else {
self.variables.get(identifier).or_else(|| { Ok(None)
self.call_function(identifier, &Value::Empty); }
None } else {
}) let value = self.variables.get(identifier);
if let Some(value) = value {
Ok(Some(value.clone()))
} else {
self.call_function(identifier, &Value::Empty)
.map(|value| Some(value))
}
} }
} }
@ -119,7 +131,9 @@ impl ContextWithMutableVariables for VariableMap {
let split = identifier.split_once("."); let split = identifier.split_once(".");
if let Some((map_name, next_identifier)) = split { if let Some((map_name, next_identifier)) = split {
if let Some(map_value) = self.variables.get_mut(map_name) { let get_value = self.variables.get_mut(map_name);
if let Some(map_value) = get_value {
if let Value::Map(map) = map_value { if let Value::Map(map) = map_value {
map.set_value(next_identifier, value) map.set_value(next_identifier, value)
} else { } else {
@ -128,11 +142,10 @@ impl ContextWithMutableVariables for VariableMap {
}); });
} }
} else { } else {
let mut new_map = VariableMap { let mut new_map = VariableMap::new();
variables: BTreeMap::new(),
};
new_map.set_value(next_identifier, value)?; new_map.set_value(next_identifier, value)?;
self.variables self.variables
.insert(map_name.to_string(), Value::Map(new_map)); .insert(map_name.to_string(), Value::Map(new_map));

View File

@ -446,7 +446,7 @@ impl Operator {
VariableIdentifierRead { identifier } => { VariableIdentifierRead { identifier } => {
expect_operator_argument_amount(arguments.len(), 0)?; expect_operator_argument_amount(arguments.len(), 0)?;
if let Some(value) = context.get_value(identifier).cloned() { if let Some(value) = context.get_value(identifier)? {
Ok(value) Ok(value)
} else { } else {
Err(EvalexprError::VariableIdentifierNotFound( Err(EvalexprError::VariableIdentifierNotFound(