Code cleanup and refactor.
This commit is contained in:
@@ -5,7 +5,7 @@ use super::{Caches, GlobalRuntimeState, Target};
|
||||
use crate::ast::{ASTFlags, Expr, OpAssignment};
|
||||
use crate::config::hashing::SusLock;
|
||||
use crate::engine::{FN_IDX_GET, FN_IDX_SET};
|
||||
use crate::tokenizer::Token;
|
||||
use crate::tokenizer::NO_TOKEN;
|
||||
use crate::types::{dynamic::Union, RestoreOnDrop};
|
||||
use crate::{
|
||||
calc_fn_hash, Dynamic, Engine, FnArgsVec, Position, RhaiResult, RhaiResultOf, Scope, ERR,
|
||||
@@ -72,17 +72,11 @@ impl Engine {
|
||||
global.level += 1;
|
||||
let global = &mut *RestoreOnDrop::lock(global, move |g| g.level = orig_level);
|
||||
|
||||
self.exec_native_fn_call(
|
||||
global,
|
||||
caches,
|
||||
FN_IDX_GET,
|
||||
Token::NonToken,
|
||||
hash_idx().0,
|
||||
&mut [target, idx],
|
||||
true,
|
||||
pos,
|
||||
)
|
||||
.map(|(r, ..)| r)
|
||||
let hash = hash_idx().0;
|
||||
let args = &mut [target, idx];
|
||||
|
||||
self.exec_native_fn_call(global, caches, FN_IDX_GET, NO_TOKEN, hash, args, true, pos)
|
||||
.map(|(r, ..)| r)
|
||||
}
|
||||
|
||||
/// Call a set indexer.
|
||||
@@ -101,15 +95,11 @@ impl Engine {
|
||||
global.level += 1;
|
||||
let global = &mut *RestoreOnDrop::lock(global, move |g| g.level = orig_level);
|
||||
|
||||
let hash = hash_idx().1;
|
||||
let args = &mut [target, idx, new_val];
|
||||
|
||||
self.exec_native_fn_call(
|
||||
global,
|
||||
caches,
|
||||
FN_IDX_SET,
|
||||
Token::NonToken,
|
||||
hash_idx().1,
|
||||
&mut [target, idx, new_val],
|
||||
is_ref_mut,
|
||||
pos,
|
||||
global, caches, FN_IDX_SET, NO_TOKEN, hash, args, is_ref_mut, pos,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -766,15 +756,10 @@ impl Engine {
|
||||
|
||||
if op_info.is_op_assignment() {
|
||||
let args = &mut [target.as_mut()];
|
||||
|
||||
let (mut orig_val, ..) = self
|
||||
.exec_native_fn_call(
|
||||
global,
|
||||
caches,
|
||||
getter,
|
||||
Token::NonToken,
|
||||
*hash_get,
|
||||
args,
|
||||
is_ref_mut,
|
||||
global, caches, getter, NO_TOKEN, *hash_get, args, is_ref_mut,
|
||||
*pos,
|
||||
)
|
||||
.or_else(|err| match *err {
|
||||
@@ -807,15 +792,9 @@ impl Engine {
|
||||
}
|
||||
|
||||
let args = &mut [target.as_mut(), &mut new_val];
|
||||
|
||||
self.exec_native_fn_call(
|
||||
global,
|
||||
caches,
|
||||
setter,
|
||||
Token::NonToken,
|
||||
*hash_set,
|
||||
args,
|
||||
is_ref_mut,
|
||||
*pos,
|
||||
global, caches, setter, NO_TOKEN, *hash_set, args, is_ref_mut, *pos,
|
||||
)
|
||||
.or_else(|err| match *err {
|
||||
// Try an indexer if property does not exist
|
||||
@@ -840,15 +819,9 @@ impl Engine {
|
||||
|
||||
let ((getter, hash_get), _, name) = &**x;
|
||||
let args = &mut [target.as_mut()];
|
||||
|
||||
self.exec_native_fn_call(
|
||||
global,
|
||||
caches,
|
||||
getter,
|
||||
Token::NonToken,
|
||||
*hash_get,
|
||||
args,
|
||||
is_ref_mut,
|
||||
*pos,
|
||||
global, caches, getter, NO_TOKEN, *hash_get, args, is_ref_mut, *pos,
|
||||
)
|
||||
.map_or_else(
|
||||
|err| match *err {
|
||||
@@ -938,20 +911,13 @@ impl Engine {
|
||||
self.run_debugger(global, caches, scope, this_ptr, _node)?;
|
||||
|
||||
let ((getter, hash_get), (setter, hash_set), name) = &**p;
|
||||
let mut arg_values = [target.as_mut(), &mut Dynamic::UNIT.clone()];
|
||||
let args = &mut arg_values[..1];
|
||||
let args = &mut [target.as_mut()];
|
||||
|
||||
// Assume getters are always pure
|
||||
let (mut val, ..) = self
|
||||
.exec_native_fn_call(
|
||||
global,
|
||||
caches,
|
||||
getter,
|
||||
Token::NonToken,
|
||||
*hash_get,
|
||||
args,
|
||||
is_ref_mut,
|
||||
pos,
|
||||
global, caches, getter, NO_TOKEN, *hash_get, args,
|
||||
is_ref_mut, pos,
|
||||
)
|
||||
.or_else(|err| match *err {
|
||||
// Try an indexer if property does not exist
|
||||
@@ -981,19 +947,13 @@ impl Engine {
|
||||
// Feed the value back via a setter just in case it has been updated
|
||||
if may_be_changed {
|
||||
// Re-use args because the first &mut parameter will not be consumed
|
||||
let mut arg_values = [target.as_mut(), val.as_mut()];
|
||||
let args = &mut arg_values;
|
||||
let args = &mut [target.as_mut(), val.as_mut()];
|
||||
|
||||
// The return value is thrown away and not used.
|
||||
let _ = self
|
||||
.exec_native_fn_call(
|
||||
global,
|
||||
caches,
|
||||
setter,
|
||||
Token::NonToken,
|
||||
*hash_set,
|
||||
args,
|
||||
is_ref_mut,
|
||||
pos,
|
||||
global, caches, setter, NO_TOKEN, *hash_set, args,
|
||||
is_ref_mut, pos,
|
||||
)
|
||||
.or_else(|err| match *err {
|
||||
// Try an indexer if property does not exist
|
||||
|
@@ -508,11 +508,10 @@ impl Engine {
|
||||
node: ASTNode<'a>,
|
||||
event: DebuggerEvent,
|
||||
) -> Result<Option<DebuggerStatus>, Box<crate::EvalAltResult>> {
|
||||
let src = global.source_raw().cloned();
|
||||
let src = src.as_ref().map(|s| s.as_str());
|
||||
let context = crate::EvalContext::new(self, global, caches, scope, this_ptr);
|
||||
|
||||
if let Some(ref x) = self.debugger_interface {
|
||||
let src = global.source_raw().cloned();
|
||||
let src = src.as_ref().map(|s| s.as_str());
|
||||
let context = EvalContext::new(self, global, caches, scope, this_ptr);
|
||||
let (.., ref on_debugger) = **x;
|
||||
|
||||
let command = on_debugger(context, event, node, src, node.position())?;
|
||||
|
@@ -7,7 +7,6 @@ use std::prelude::v1::*;
|
||||
|
||||
/// Context of a script evaluation process.
|
||||
#[derive(Debug)]
|
||||
#[allow(dead_code)]
|
||||
pub struct EvalContext<'a, 's, 'ps, 'g, 'c, 't> {
|
||||
/// The current [`Engine`].
|
||||
engine: &'a Engine,
|
||||
|
@@ -6,13 +6,26 @@ use crate::ast::{
|
||||
ASTFlags, BinaryExpr, Expr, Ident, OpAssignment, Stmt, SwitchCasesCollection, TryCatchBlock,
|
||||
};
|
||||
use crate::func::{get_builtin_op_assignment_fn, get_hasher};
|
||||
use crate::types::dynamic::AccessMode;
|
||||
use crate::types::dynamic::{AccessMode, Union};
|
||||
use crate::types::RestoreOnDrop;
|
||||
use crate::{Dynamic, Engine, RhaiResult, RhaiResultOf, Scope, ERR, INT};
|
||||
use std::hash::{Hash, Hasher};
|
||||
#[cfg(feature = "no_std")]
|
||||
use std::prelude::v1::*;
|
||||
|
||||
impl Dynamic {
|
||||
/// If the value is a string, intern it.
|
||||
#[inline(always)]
|
||||
fn intern_string(self, engine: &Engine) -> Self {
|
||||
match self.0 {
|
||||
Union::Str(..) => engine
|
||||
.get_interned_string(self.into_immutable_string().expect("`ImmutableString`"))
|
||||
.into(),
|
||||
_ => self,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Engine {
|
||||
/// Evaluate a statements block.
|
||||
pub(crate) fn eval_stmt_block(
|
||||
@@ -169,14 +182,13 @@ impl Engine {
|
||||
self.check_data_size(&*args[0], root.position())?;
|
||||
} else {
|
||||
// Normal assignment
|
||||
|
||||
// If value is a string, intern it
|
||||
if new_val.is_string() {
|
||||
let value = new_val.into_immutable_string().expect("`ImmutableString`");
|
||||
new_val = self.get_interned_string(value).into();
|
||||
match target {
|
||||
// Lock it again just in case it is shared
|
||||
Target::RefMut(_) | Target::TempValue(_) => {
|
||||
*target.write_lock::<Dynamic>().unwrap() = new_val
|
||||
}
|
||||
_ => **target = new_val,
|
||||
}
|
||||
|
||||
*target.write_lock::<Dynamic>().unwrap() = new_val;
|
||||
}
|
||||
|
||||
target.propagate_changed_value(op_info.pos)
|
||||
@@ -224,14 +236,13 @@ impl Engine {
|
||||
|
||||
let mut target = self.search_namespace(global, caches, scope, this_ptr, lhs)?;
|
||||
|
||||
let is_temp_result = !target.is_ref();
|
||||
let var_name = x.3.as_str();
|
||||
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
// Also handle case where target is a `Dynamic` shared value
|
||||
// (returned by a variable resolver, for example)
|
||||
let is_temp_result = !target.is_ref() && !target.is_shared();
|
||||
#[cfg(feature = "no_closure")]
|
||||
let is_temp_result = !target.is_ref();
|
||||
let is_temp_result = is_temp_result && !target.is_shared();
|
||||
|
||||
// Cannot assign to temp result from expression
|
||||
if is_temp_result {
|
||||
@@ -251,36 +262,31 @@ impl Engine {
|
||||
|
||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||
{
|
||||
let mut rhs_val = self
|
||||
let rhs_val = self
|
||||
.eval_expr(global, caches, scope, this_ptr, rhs)?
|
||||
.flatten();
|
||||
|
||||
// If value is a string, intern it
|
||||
if rhs_val.is_string() {
|
||||
let value = rhs_val.into_immutable_string().expect("`ImmutableString`");
|
||||
rhs_val = self.get_interned_string(value).into();
|
||||
}
|
||||
.flatten()
|
||||
.intern_string(self);
|
||||
|
||||
let _new_val = Some((rhs_val, op_info));
|
||||
|
||||
// Must be either `var[index] op= val` or `var.prop op= val`
|
||||
match lhs {
|
||||
// name op= rhs (handled above)
|
||||
Expr::Variable(..) => {
|
||||
unreachable!("Expr::Variable case is already handled")
|
||||
}
|
||||
// idx_lhs[idx_expr] op= rhs
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
Expr::Index(..) => {
|
||||
self.eval_dot_index_chain(global, caches, scope, this_ptr, lhs, _new_val)
|
||||
}
|
||||
// dot_lhs.dot_rhs op= rhs
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
Expr::Dot(..) => {
|
||||
self.eval_dot_index_chain(global, caches, scope, this_ptr, lhs, _new_val)
|
||||
}
|
||||
_ => unreachable!("cannot assign to expression: {:?}", lhs),
|
||||
}?;
|
||||
// Must be either `var[index] op= val` or `var.prop op= val`.
|
||||
// The return value of any op-assignment (should be `()`) is thrown away and not used.
|
||||
let _ =
|
||||
match lhs {
|
||||
// name op= rhs (handled above)
|
||||
Expr::Variable(..) => {
|
||||
unreachable!("Expr::Variable case is already handled")
|
||||
}
|
||||
// idx_lhs[idx_expr] op= rhs
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
Expr::Index(..) => self
|
||||
.eval_dot_index_chain(global, caches, scope, this_ptr, lhs, _new_val),
|
||||
// dot_lhs.dot_rhs op= rhs
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
Expr::Dot(..) => self
|
||||
.eval_dot_index_chain(global, caches, scope, this_ptr, lhs, _new_val),
|
||||
_ => unreachable!("cannot assign to expression: {:?}", lhs),
|
||||
}?;
|
||||
|
||||
return Ok(Dynamic::UNIT);
|
||||
}
|
||||
@@ -723,7 +729,8 @@ impl Engine {
|
||||
// Evaluate initial value
|
||||
let mut value = self
|
||||
.eval_expr(global, caches, scope, this_ptr, expr)?
|
||||
.flatten();
|
||||
.flatten()
|
||||
.intern_string(self);
|
||||
|
||||
let _alias = if !rewind_scope {
|
||||
// Put global constants into global module
|
||||
|
@@ -89,9 +89,9 @@ pub enum Target<'a> {
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
SharedValue {
|
||||
/// Lock guard to the shared [`Dynamic`].
|
||||
source: crate::types::dynamic::DynamicWriteLock<'a, Dynamic>,
|
||||
/// Copy of the value.
|
||||
value: Dynamic,
|
||||
guard: crate::types::dynamic::DynamicWriteLock<'a, Dynamic>,
|
||||
/// Copy of the shared value.
|
||||
shared_value: Dynamic,
|
||||
},
|
||||
/// The target is a temporary [`Dynamic`] value (i.e. its mutation can cause no side effects).
|
||||
TempValue(Dynamic),
|
||||
@@ -178,21 +178,21 @@ impl<'a> Target<'a> {
|
||||
}
|
||||
}
|
||||
/// Is the [`Target`] a shared value?
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn is_shared(&self) -> bool {
|
||||
match self {
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
return match self {
|
||||
Self::RefMut(r) => r.is_shared(),
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
Self::SharedValue { .. } => true,
|
||||
Self::TempValue(value) => value.is_shared(),
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
Self::Bit { .. }
|
||||
| Self::BitField { .. }
|
||||
| Self::BlobByte { .. }
|
||||
| Self::StringChar { .. } => false,
|
||||
}
|
||||
};
|
||||
#[cfg(feature = "no_closure")]
|
||||
return false;
|
||||
}
|
||||
/// Get the value of the [`Target`] as a [`Dynamic`], cloning a referenced value if necessary.
|
||||
#[inline]
|
||||
@@ -200,7 +200,7 @@ impl<'a> Target<'a> {
|
||||
match self {
|
||||
Self::RefMut(r) => r.clone(), // Referenced value is cloned
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
Self::SharedValue { value, .. } => value, // Original shared value is simply taken
|
||||
Self::SharedValue { shared_value, .. } => shared_value, // Original shared value is simply taken
|
||||
Self::TempValue(value) => value, // Owned value is simply taken
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
Self::Bit { value, .. } => value, // boolean is taken
|
||||
@@ -227,7 +227,7 @@ impl<'a> Target<'a> {
|
||||
match self {
|
||||
Self::RefMut(r) => Self::TempValue(r.clone()),
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
Self::SharedValue { value, .. } => Self::TempValue(value),
|
||||
Self::SharedValue { shared_value, .. } => Self::TempValue(shared_value),
|
||||
_ => self,
|
||||
}
|
||||
}
|
||||
@@ -239,7 +239,7 @@ impl<'a> Target<'a> {
|
||||
match self {
|
||||
Self::RefMut(r) => r,
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
Self::SharedValue { source, .. } => source,
|
||||
Self::SharedValue { guard, .. } => guard,
|
||||
Self::TempValue(value) => value,
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
Self::Bit { source, .. } => source,
|
||||
@@ -365,9 +365,12 @@ impl<'a> From<&'a mut Dynamic> for Target<'a> {
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
if value.is_shared() {
|
||||
// Cloning is cheap for a shared value
|
||||
let val = value.clone();
|
||||
let source = value.write_lock::<Dynamic>().expect("`Dynamic`");
|
||||
return Self::SharedValue { source, value: val };
|
||||
let shared_value = value.clone();
|
||||
let guard = value.write_lock::<Dynamic>().expect("`Dynamic`");
|
||||
return Self::SharedValue {
|
||||
guard,
|
||||
shared_value,
|
||||
};
|
||||
}
|
||||
|
||||
Self::RefMut(value)
|
||||
@@ -382,7 +385,7 @@ impl Deref for Target<'_> {
|
||||
match self {
|
||||
Self::RefMut(r) => r,
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
Self::SharedValue { source, .. } => source,
|
||||
Self::SharedValue { guard, .. } => guard,
|
||||
Self::TempValue(ref value) => value,
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
Self::Bit { ref value, .. }
|
||||
@@ -415,7 +418,7 @@ impl DerefMut for Target<'_> {
|
||||
match self {
|
||||
Self::RefMut(r) => r,
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
Self::SharedValue { source, .. } => &mut *source,
|
||||
Self::SharedValue { guard, .. } => &mut *guard,
|
||||
Self::TempValue(ref mut value) => value,
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
Self::Bit { ref mut value, .. }
|
||||
|
Reference in New Issue
Block a user