Map in operator to contains function call.

This commit is contained in:
Stephen Chung
2021-03-09 13:44:54 +08:00
parent ff7844893d
commit 975bb3d6bf
11 changed files with 76 additions and 283 deletions

View File

@@ -202,9 +202,15 @@ pub const FN_IDX_GET: &str = "index$get$";
pub const FN_IDX_SET: &str = "index$set$";
#[cfg(not(feature = "no_function"))]
pub const FN_ANONYMOUS: &str = "anon$";
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
/// Standard equality comparison operator.
pub const OP_EQUALS: &str = "==";
/// Standard method function for containment testing.
///
/// The `in` operator is implemented as a call to this method.
pub const OP_CONTAINS: &str = "contains";
/// Method of chaining.
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
@@ -1609,78 +1615,6 @@ impl Engine {
}
}
// Evaluate an 'in' expression.
#[inline(always)]
fn eval_in_expr(
&self,
scope: &mut Scope,
mods: &mut Imports,
state: &mut State,
lib: &[&Module],
this_ptr: &mut Option<&mut Dynamic>,
lhs: &Expr,
rhs: &Expr,
level: usize,
) -> RhaiResult {
self.inc_operations(state, rhs.position())?;
let lhs_value = self.eval_expr(scope, mods, state, lib, this_ptr, lhs, level)?;
let mut rhs_target = if rhs.get_variable_access(false).is_some() {
let (rhs_ptr, pos) = self.search_namespace(scope, mods, state, lib, this_ptr, rhs)?;
self.inc_operations(state, pos)?;
rhs_ptr
} else {
self.eval_expr(scope, mods, state, lib, this_ptr, rhs, level)?
.into()
};
match rhs_target.as_mut() {
#[cfg(not(feature = "no_index"))]
Dynamic(Union::Array(rhs_value, _)) => {
// Call the `==` operator to compare each value
let hash = calc_fn_hash(empty(), OP_EQUALS, 2);
for value in rhs_value.iter_mut() {
let args = &mut [&mut lhs_value.clone(), &mut value.clone()];
let pos = rhs.position();
if self
.call_native_fn(mods, state, lib, OP_EQUALS, hash, args, false, false, pos)?
.0
.as_bool()
.unwrap_or(false)
{
return Ok(true.into());
}
}
Ok(false.into())
}
#[cfg(not(feature = "no_object"))]
Dynamic(Union::Map(rhs_value, _)) => {
// Only allows string or char
if let Ok(c) = lhs_value.as_char() {
Ok(rhs_value.contains_key(&c.to_string()).into())
} else if let Some(s) = lhs_value.read_lock::<ImmutableString>() {
Ok(rhs_value.contains_key(&*s).into())
} else {
EvalAltResult::ErrorInExpr(lhs.position()).into()
}
}
Dynamic(Union::Str(rhs_value, _)) => {
// Only allows string or char
if let Ok(c) = lhs_value.as_char() {
Ok(rhs_value.contains(c).into())
} else if let Some(s) = lhs_value.read_lock::<ImmutableString>() {
Ok(rhs_value.contains(s.as_str()).into())
} else {
EvalAltResult::ErrorInExpr(lhs.position()).into()
}
}
_ => EvalAltResult::ErrorInExpr(rhs.position()).into(),
}
}
/// Evaluate an expression.
pub(crate) fn eval_expr(
&self,
@@ -1792,10 +1726,6 @@ impl Engine {
)
}
Expr::In(x, _) => {
self.eval_in_expr(scope, mods, state, lib, this_ptr, &x.lhs, &x.rhs, level)
}
Expr::And(x, _) => {
Ok((self
.eval_expr(scope, mods, state, lib, this_ptr, &x.lhs, level)?