summaryrefslogtreecommitdiff
path: root/src/eval
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2022-03-15 15:27:36 +0100
committerLaurenz <laurmaedje@gmail.com>2022-03-15 15:27:36 +0100
commit77d153d315a2a5909840ebcd47491e4cef14428b (patch)
tree0886afd2ac4b03facb7c33a4e59924e30f55fd41 /src/eval
parentae0a56cdffa515ed6bb7cb566c025cc66ff00f33 (diff)
Add `in` and `not in` operators
Diffstat (limited to 'src/eval')
-rw-r--r--src/eval/array.rs5
-rw-r--r--src/eval/dict.rs5
-rw-r--r--src/eval/mod.rs2
-rw-r--r--src/eval/ops.rs28
4 files changed, 40 insertions, 0 deletions
diff --git a/src/eval/array.rs b/src/eval/array.rs
index 5cd8df82..2da1a5f4 100644
--- a/src/eval/array.rs
+++ b/src/eval/array.rs
@@ -66,6 +66,11 @@ impl Array {
Arc::make_mut(&mut self.0).push(value);
}
+ /// Whether the array contains a specific value.
+ pub fn contains(&self, value: &Value) -> bool {
+ self.0.contains(value)
+ }
+
/// Clear the array.
pub fn clear(&mut self) {
if Arc::strong_count(&self.0) == 1 {
diff --git a/src/eval/dict.rs b/src/eval/dict.rs
index 03871fa0..9127b2eb 100644
--- a/src/eval/dict.rs
+++ b/src/eval/dict.rs
@@ -61,6 +61,11 @@ impl Dict {
Arc::make_mut(&mut self.0).insert(key, value);
}
+ /// Whether the dictionary contains a specific key.
+ pub fn contains_key(&self, key: &str) -> bool {
+ self.0.contains_key(key)
+ }
+
/// Clear the dictionary.
pub fn clear(&mut self) {
if Arc::strong_count(&self.0) == 1 {
diff --git a/src/eval/mod.rs b/src/eval/mod.rs
index 4ccf377b..2c864036 100644
--- a/src/eval/mod.rs
+++ b/src/eval/mod.rs
@@ -344,6 +344,8 @@ impl Eval for BinaryExpr {
BinOp::Leq => self.apply(ctx, scp, ops::leq),
BinOp::Gt => self.apply(ctx, scp, ops::gt),
BinOp::Geq => self.apply(ctx, scp, ops::geq),
+ BinOp::In => self.apply(ctx, scp, ops::in_),
+ BinOp::NotIn => self.apply(ctx, scp, ops::not_in),
BinOp::Assign => self.assign(ctx, scp, |_, b| Ok(b)),
BinOp::AddAssign => self.assign(ctx, scp, ops::add),
BinOp::SubAssign => self.assign(ctx, scp, ops::sub),
diff --git a/src/eval/ops.rs b/src/eval/ops.rs
index 04a13fd1..6a8f5284 100644
--- a/src/eval/ops.rs
+++ b/src/eval/ops.rs
@@ -335,3 +335,31 @@ pub fn compare(lhs: &Value, rhs: &Value) -> Option<Ordering> {
_ => Option::None,
}
}
+
+/// Test whether one value is "in" another one.
+pub fn in_(lhs: Value, rhs: Value) -> StrResult<Value> {
+ if let Some(b) = contains(&lhs, &rhs) {
+ Ok(Bool(b))
+ } else {
+ mismatch!("cannot apply 'in' to {} and {}", lhs, rhs)
+ }
+}
+
+/// Test whether one value is "not in" another one.
+pub fn not_in(lhs: Value, rhs: Value) -> StrResult<Value> {
+ if let Some(b) = contains(&lhs, &rhs) {
+ Ok(Bool(!b))
+ } else {
+ mismatch!("cannot apply 'not in' to {} and {}", lhs, rhs)
+ }
+}
+
+/// Test for containment.
+pub fn contains(lhs: &Value, rhs: &Value) -> Option<bool> {
+ Some(match (lhs, rhs) {
+ (Value::Str(a), Value::Str(b)) => b.contains(a.as_str()),
+ (Value::Str(a), Value::Dict(b)) => b.contains_key(a),
+ (a, Value::Array(b)) => b.contains(a),
+ _ => return Option::None,
+ })
+}