diff options
| author | Laurenz <laurmaedje@gmail.com> | 2022-03-15 15:27:36 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2022-03-15 15:27:36 +0100 |
| commit | 77d153d315a2a5909840ebcd47491e4cef14428b (patch) | |
| tree | 0886afd2ac4b03facb7c33a4e59924e30f55fd41 /src/eval | |
| parent | ae0a56cdffa515ed6bb7cb566c025cc66ff00f33 (diff) | |
Add `in` and `not in` operators
Diffstat (limited to 'src/eval')
| -rw-r--r-- | src/eval/array.rs | 5 | ||||
| -rw-r--r-- | src/eval/dict.rs | 5 | ||||
| -rw-r--r-- | src/eval/mod.rs | 2 | ||||
| -rw-r--r-- | src/eval/ops.rs | 28 |
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, + }) +} |
