Fix op-assignment overrides.

This commit is contained in:
Stephen Chung
2020-09-21 16:15:52 +08:00
parent 748d4d2f36
commit 83f9df2852
6 changed files with 61 additions and 32 deletions

View File

@@ -1360,40 +1360,56 @@ impl Engine {
let arg_types = once(lhs_ptr.type_id()).chain(once(rhs_val.type_id()));
let hash_fn = calc_fn_hash(empty(), op, 2, arg_types);
if let Some(CallableFunction::Method(func)) = self
match self
.global_module
.get_fn(hash_fn, false)
.or_else(|| self.packages.get_fn(hash_fn, false))
{
if cfg!(not(feature = "no_closure")) && lhs_ptr.is_shared() {
let mut lock_guard = lhs_ptr.write_lock::<Dynamic>().unwrap();
let lhs_ptr_inner = lock_guard.deref_mut();
// op= function registered as method
Some(func) if func.is_method() => {
let mut lock_guard;
let lhs_ptr_inner;
if cfg!(not(feature = "no_closure")) && lhs_ptr.is_shared() {
lock_guard = lhs_ptr.write_lock::<Dynamic>().unwrap();
lhs_ptr_inner = lock_guard.deref_mut();
} else {
lhs_ptr_inner = lhs_ptr;
}
let args = &mut [lhs_ptr_inner, &mut rhs_val];
// Overriding exact implementation
func(self, lib, &mut [lhs_ptr_inner, &mut rhs_val])?;
} else {
// Overriding exact implementation
func(self, lib, &mut [lhs_ptr, &mut rhs_val])?;
if func.is_plugin_fn() {
func.get_plugin_fn().call(args)?;
} else {
func.get_native_fn()(self, lib, args)?;
}
}
} else if run_builtin_op_assignment(op, lhs_ptr, &rhs_val)?.is_none() {
// Not built in, map to `var = var op rhs`
let op = &op[..op.len() - 1]; // extract operator without =
// Built-in op-assignment function
_ if run_builtin_op_assignment(op, lhs_ptr, &rhs_val)?.is_some() => {}
// Not built-in: expand to `var = var op rhs`
_ => {
let op = &op[..op.len() - 1]; // extract operator without =
// Clone the LHS value
let args = &mut [&mut lhs_ptr.clone(), &mut rhs_val];
// Clone the LHS value
let args = &mut [&mut lhs_ptr.clone(), &mut rhs_val];
// Run function
let (value, _) = self
.exec_fn_call(
state, lib, op, 0, args, false, false, false, None, None, level,
)
.map_err(|err| err.new_position(*op_pos))?;
// Run function
let (value, _) = self
.exec_fn_call(
state, lib, op, 0, args, false, false, false, None, None,
level,
)
.map_err(|err| err.new_position(*op_pos))?;
let value = value.flatten();
if cfg!(not(feature = "no_closure")) && lhs_ptr.is_shared() {
*lhs_ptr.write_lock::<Dynamic>().unwrap() = value;
} else {
*lhs_ptr = value;
let value = value.flatten();
if cfg!(not(feature = "no_closure")) && lhs_ptr.is_shared() {
*lhs_ptr.write_lock::<Dynamic>().unwrap() = value;
} else {
*lhs_ptr = value;
}
}
}
Ok(Default::default())