Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Array support #161

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 55 additions & 54 deletions README.md

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions src/error/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ impl fmt::Display for EvalexprError {
ExpectedBoolean { actual } => {
write!(f, "Expected a Value::Boolean, but got {:?}.", actual)
},
ExpectedArray { actual } => write!(f, "Expected a Value::Array, but got {:?}.", actual),
ExpectedTuple { actual } => write!(f, "Expected a Value::Tuple, but got {:?}.", actual),
ExpectedFixedLengthTuple {
expected_length,
Expand All @@ -60,6 +61,11 @@ impl fmt::Display for EvalexprError {
expected_length.end(),
actual
),
ExpectedVec { actual } => write!(
f,
"Expected a Value which can be interpreted as vec, but got {:?}.",
actual
),
ExpectedEmpty { actual } => write!(f, "Expected a Value::Empty, but got {:?}.", actual),
AppendedToLeafNode => write!(f, "Tried to append a node to a leaf node."),
PrecedenceViolation => write!(
Expand All @@ -86,6 +92,8 @@ impl fmt::Display for EvalexprError {
),
UnmatchedLBrace => write!(f, "Found an unmatched opening parenthesis '('."),
UnmatchedRBrace => write!(f, "Found an unmatched closing parenthesis ')'."),
UnmatchedLCurlyBrace => write!(f, "Found an unmatched opening curly brace '{{'."),
UnmatchedRCurlyBrace => write!(f, "Found an unmatched closing curly brace '}}'."),
UnmatchedDoubleQuote => write!(f, "Found an unmatched double quote '\"'"),
MissingOperatorOutsideOfBrace { .. } => write!(
f,
Expand Down
33 changes: 33 additions & 0 deletions src/error/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,12 @@ pub enum EvalexprError {
actual: Value,
},

/// A array value was expected.
ExpectedArray {
/// The actual value.
actual: Value,
},

/// A tuple value of a certain length was expected.
ExpectedFixedLengthTuple {
/// The expected length.
Expand All @@ -95,6 +101,12 @@ pub enum EvalexprError {
actual: Value,
},

/// A value which can be interpreted as vec was expected
ExpectedVec {
/// The actual value.
actual: Value,
},

/// An empty value was expected.
ExpectedEmpty {
/// The actual value.
Expand Down Expand Up @@ -139,6 +151,12 @@ pub enum EvalexprError {
/// A closing brace without a matching opening brace was found.
UnmatchedRBrace,

/// An opening curly brace without a matching closing brace was found.
UnmatchedLCurlyBrace,

/// A closing curly brace without a matching opening brace was found.
UnmatchedRCurlyBrace,

/// A double quote without a matching second double quote was found.
UnmatchedDoubleQuote,

Expand Down Expand Up @@ -296,6 +314,11 @@ impl EvalexprError {
EvalexprError::ExpectedTuple { actual }
}

/// Constructs `EvalexprError::ExpectedArray{actual}`.
pub fn expected_array(actual: Value) -> Self {
EvalexprError::ExpectedArray { actual }
}

/// Constructs `EvalexprError::ExpectedFixedLenTuple{expected_len, actual}`.
pub fn expected_fixed_len_tuple(expected_len: usize, actual: Value) -> Self {
EvalexprError::ExpectedFixedLengthTuple {
Expand All @@ -312,6 +335,11 @@ impl EvalexprError {
}
}

/// Constructs `EvalexprError::ExpectedVec{actual}`.
pub fn expected_vec(actual: Value) -> Self {
EvalexprError::ExpectedVec { actual }
}

/// Constructs `EvalexprError::ExpectedEmpty{actual}`.
pub fn expected_empty(actual: Value) -> Self {
EvalexprError::ExpectedEmpty { actual }
Expand All @@ -325,6 +353,7 @@ impl EvalexprError {
ValueType::Float => Self::expected_float(actual),
ValueType::Boolean => Self::expected_boolean(actual),
ValueType::Tuple => Self::expected_tuple(actual),
ValueType::Array => Self::expected_array(actual),
ValueType::Empty => Self::expected_empty(actual),
}
}
Expand Down Expand Up @@ -436,6 +465,10 @@ mod tests {
EvalexprError::expected_type(&Value::Tuple(vec![]), Value::Empty),
EvalexprError::expected_tuple(Value::Empty)
);
assert_eq!(
EvalexprError::expected_type(&Value::Array(vec![]), Value::Empty),
EvalexprError::expected_array(Value::Empty)
);
assert_eq!(
EvalexprError::expected_type(&Value::Empty, Value::String("abc".to_string())),
EvalexprError::expected_empty(Value::String("abc".to_string()))
Expand Down
77 changes: 33 additions & 44 deletions src/function/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ pub fn builtin_function(identifier: &str) -> Option<Function> {
Value::Int(_) => "int",
Value::Boolean(_) => "boolean",
Value::Tuple(_) => "tuple",
Value::Array(_) => "array",
Value::Empty => "empty",
}
.into())
Expand Down Expand Up @@ -159,67 +160,55 @@ pub fn builtin_function(identifier: &str) -> Option<Function> {
})),
"contains" => Some(Function::new(move |argument| {
let arguments = argument.as_fixed_len_tuple(2)?;
if let (Value::Tuple(a), b) = (&arguments[0].clone(), &arguments[1].clone()) {
if let Value::String(_) | Value::Int(_) | Value::Float(_) | Value::Boolean(_) = b {
Ok(a.contains(b).into())
} else {
Err(EvalexprError::type_error(
b.clone(),
vec![
ValueType::String,
ValueType::Int,
ValueType::Float,
ValueType::Boolean,
],
))
}
let (a, b) = (arguments[0].as_slice()?, &arguments[1].clone());
if let Value::String(_) | Value::Int(_) | Value::Float(_) | Value::Boolean(_) = b {
Ok(a.contains(b).into())
} else {
Err(EvalexprError::expected_tuple(arguments[0].clone()))
Err(EvalexprError::type_error(
b.clone(),
vec![
ValueType::String,
ValueType::Int,
ValueType::Float,
ValueType::Boolean,
],
))
}
})),
"contains_any" => Some(Function::new(move |argument| {
let arguments = argument.as_fixed_len_tuple(2)?;
if let (Value::Tuple(a), b) = (&arguments[0].clone(), &arguments[1].clone()) {
if let Value::Tuple(b) = b {
let mut contains = false;
for value in b {
if let Value::String(_)
| Value::Int(_)
| Value::Float(_)
| Value::Boolean(_) = value
{
if a.contains(value) {
contains = true;
}
} else {
return Err(EvalexprError::type_error(
value.clone(),
vec![
ValueType::String,
ValueType::Int,
ValueType::Float,
ValueType::Boolean,
],
));
}
let (a, b) = (arguments[0].as_slice()?, arguments[1].as_slice()?);
let mut contains = false;
for value in b {
if let Value::String(_) | Value::Int(_) | Value::Float(_) | Value::Boolean(_) =
value
{
if a.contains(value) {
contains = true;
}
Ok(contains.into())
} else {
Err(EvalexprError::expected_tuple(b.clone()))
return Err(EvalexprError::type_error(
value.clone(),
vec![
ValueType::String,
ValueType::Int,
ValueType::Float,
ValueType::Boolean,
],
));
}
} else {
Err(EvalexprError::expected_tuple(arguments[0].clone()))
}
Ok(contains.into())
})),
"len" => Some(Function::new(|argument| {
if let Ok(subject) = argument.as_string() {
Ok(Value::from(subject.len() as IntType))
} else if let Ok(subject) = argument.as_tuple() {
} else if let Ok(subject) = argument.as_slice() {
Ok(Value::from(subject.len() as IntType))
} else {
Err(EvalexprError::type_error(
argument.clone(),
vec![ValueType::String, ValueType::Tuple],
vec![ValueType::String, ValueType::Tuple, ValueType::Array],
))
}
})),
Expand Down
38 changes: 36 additions & 2 deletions src/interface/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use crate::{
token, tree, value::TupleType, Context, ContextWithMutableVariables, EmptyType, EvalexprError,
EvalexprResult, FloatType, HashMapContext, IntType, Node, Value, EMPTY_VALUE,
token, tree,
value::{ArrayType, TupleType},
Context, ContextWithMutableVariables, EmptyType, EvalexprError, EvalexprResult, FloatType,
HashMapContext, IntType, Node, Value, EMPTY_VALUE,
};

/// Evaluate the given expression string.
Expand Down Expand Up @@ -130,6 +132,13 @@ pub fn eval_tuple(string: &str) -> EvalexprResult<TupleType> {
eval_tuple_with_context_mut(string, &mut HashMapContext::new())
}

/// Evaluate the given expression string into a array.
///
/// *See the [crate doc](index.html) for more examples and explanations of the expression format.*
pub fn eval_array(string: &str) -> EvalexprResult<ArrayType> {
eval_array_with_context_mut(string, &mut HashMapContext::new())
}

/// Evaluate the given expression string into an empty value.
///
/// *See the [crate doc](index.html) for more examples and explanations of the expression format.*
Expand Down Expand Up @@ -208,6 +217,17 @@ pub fn eval_tuple_with_context<C: Context>(string: &str, context: &C) -> Evalexp
}
}

/// Evaluate the given expression string into an array with the given context.
///
/// *See the [crate doc](index.html) for more examples and explanations of the expression format.*
pub fn eval_array_with_context<C: Context>(string: &str, context: &C) -> EvalexprResult<TupleType> {
match eval_with_context(string, context) {
Ok(Value::Array(array)) => Ok(array),
Ok(value) => Err(EvalexprError::expected_array(value)),
Err(error) => Err(error),
}
}

/// Evaluate the given expression string into an empty value with the given context.
///
/// *See the [crate doc](index.html) for more examples and explanations of the expression format.*
Expand Down Expand Up @@ -305,6 +325,20 @@ pub fn eval_tuple_with_context_mut<C: ContextWithMutableVariables>(
}
}

/// Evaluate the given expression string into a array with the given mutable context.
///
/// *See the [crate doc](index.html) for more examples and explanations of the expression format.*
pub fn eval_array_with_context_mut<C: ContextWithMutableVariables>(
string: &str,
context: &mut C,
) -> EvalexprResult<ArrayType> {
match eval_with_context_mut(string, context) {
Ok(Value::Array(array)) => Ok(array),
Ok(value) => Err(EvalexprError::expected_array(value)),
Err(error) => Err(error),
}
}

/// Evaluate the given expression string into an empty value with the given mutable context.
///
/// *See the [crate doc](index.html) for more examples and explanations of the expression format.*
Expand Down
Loading
Loading