Remove Dynamic::NULL, use .as_deref_mut() for this_ptr.

This commit is contained in:
Stephen Chung 2022-12-20 16:52:55 +08:00
parent 99080be91d
commit babc0b5466
16 changed files with 235 additions and 255 deletions

View File

@ -219,17 +219,11 @@ impl Engine {
let orig_lib_len = global.lib.len(); let orig_lib_len = global.lib.len();
let mut orig_tag = None; let orig_tag = options.tag.map(|v| mem::replace(&mut global.tag, v));
let mut this_ptr = options.this_ptr;
if let Some(value) = options.tag {
orig_tag = Some(mem::replace(&mut global.tag, value));
}
global.lib.push(ast.shared_lib().clone()); global.lib.push(ast.shared_lib().clone());
let mut no_this_ptr = Dynamic::NULL;
let this_ptr = options.this_ptr.unwrap_or(&mut no_this_ptr);
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
let orig_embedded_module_resolver = std::mem::replace( let orig_embedded_module_resolver = std::mem::replace(
&mut global.embedded_module_resolver, &mut global.embedded_module_resolver,
@ -264,7 +258,7 @@ impl Engine {
global, global,
caches, caches,
scope, scope,
this_ptr, this_ptr.as_deref_mut(),
None, None,
fn_def, fn_def,
args, args,
@ -279,7 +273,7 @@ impl Engine {
if self.is_debugger_registered() { if self.is_debugger_registered() {
global.debugger_mut().status = crate::eval::DebuggerStatus::Terminate; global.debugger_mut().status = crate::eval::DebuggerStatus::Terminate;
let node = &crate::ast::Stmt::Noop(Position::NONE); let node = &crate::ast::Stmt::Noop(Position::NONE);
self.run_debugger(global, caches, scope, this_ptr, node)?; self.run_debugger(global, caches, scope, this_ptr.as_deref_mut(), node)?;
} }
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]

View File

@ -250,9 +250,8 @@ impl Engine {
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
if self.is_debugger_registered() { if self.is_debugger_registered() {
global.debugger_mut().status = crate::eval::DebuggerStatus::Terminate; global.debugger_mut().status = crate::eval::DebuggerStatus::Terminate;
let mut this_ptr = Dynamic::NULL;
let node = &crate::ast::Stmt::Noop(Position::NONE); let node = &crate::ast::Stmt::Noop(Position::NONE);
self.run_debugger(global, caches, scope, &mut this_ptr, node)?; self.run_debugger(global, caches, scope, None, node)?;
} }
Ok(r) Ok(r)
}) })

View File

@ -131,9 +131,8 @@ impl Engine {
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
if self.is_debugger_registered() { if self.is_debugger_registered() {
global.debugger_mut().status = crate::eval::DebuggerStatus::Terminate; global.debugger_mut().status = crate::eval::DebuggerStatus::Terminate;
let mut this_ptr = crate::Dynamic::NULL;
let node = &crate::ast::Stmt::Noop(crate::Position::NONE); let node = &crate::ast::Stmt::Noop(crate::Position::NONE);
self.run_debugger(global, caches, scope, &mut this_ptr, node)?; self.run_debugger(global, caches, scope, None, node)?;
} }
Ok(()) Ok(())
}) })

View File

@ -340,7 +340,7 @@ impl Engine {
global: &mut GlobalRuntimeState, global: &mut GlobalRuntimeState,
caches: &mut Caches, caches: &mut Caches,
scope: &mut Scope, scope: &mut Scope,
this_ptr: &mut Dynamic, mut this_ptr: Option<&mut Dynamic>,
expr: &Expr, expr: &Expr,
new_val: Option<(Dynamic, &OpAssignment)>, new_val: Option<(Dynamic, &OpAssignment)>,
) -> RhaiResult { ) -> RhaiResult {
@ -379,7 +379,13 @@ impl Engine {
} }
// All other patterns - evaluate the arguments chain // All other patterns - evaluate the arguments chain
_ => self.eval_dot_index_chain_arguments( _ => self.eval_dot_index_chain_arguments(
global, caches, scope, this_ptr, expr, rhs, idx_values, global,
caches,
scope,
this_ptr.as_deref_mut(),
expr,
rhs,
idx_values,
)?, )?,
} }
@ -387,22 +393,13 @@ impl Engine {
// id.??? or id[???] // id.??? or id[???]
Expr::Variable(.., var_pos) => { Expr::Variable(.., var_pos) => {
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
self.run_debugger(global, caches, scope, this_ptr, lhs)?; self.run_debugger(global, caches, scope, this_ptr.as_deref_mut(), lhs)?;
self.track_operation(global, *var_pos)?; self.track_operation(global, *var_pos)?;
let target = &mut self.search_namespace(global, caches, scope, this_ptr, lhs)?; let target = &mut self.search_namespace(global, caches, scope, this_ptr, lhs)?;
let mut this_ptr = Dynamic::NULL;
self.eval_dot_index_chain_raw( self.eval_dot_index_chain_raw(
global, global, caches, None, lhs, expr, target, rhs, idx_values, new_val,
caches,
&mut this_ptr,
lhs,
expr,
target,
rhs,
idx_values,
new_val,
) )
} }
// {expr}.??? = ??? or {expr}[???] = ??? // {expr}.??? = ??? or {expr}[???] = ???
@ -410,7 +407,7 @@ impl Engine {
// {expr}.??? or {expr}[???] // {expr}.??? or {expr}[???]
lhs_expr => { lhs_expr => {
let value = self let value = self
.eval_expr(global, caches, scope, this_ptr, lhs_expr)? .eval_expr(global, caches, scope, this_ptr.as_deref_mut(), lhs_expr)?
.flatten(); .flatten();
let obj_ptr = &mut value.into(); let obj_ptr = &mut value.into();
@ -428,7 +425,7 @@ impl Engine {
global: &mut GlobalRuntimeState, global: &mut GlobalRuntimeState,
caches: &mut Caches, caches: &mut Caches,
scope: &mut Scope, scope: &mut Scope,
this_ptr: &mut Dynamic, mut this_ptr: Option<&mut Dynamic>,
parent: &Expr, parent: &Expr,
expr: &Expr, expr: &Expr,
idx_values: &mut FnArgsVec<Dynamic>, idx_values: &mut FnArgsVec<Dynamic>,
@ -440,12 +437,10 @@ impl Engine {
match expr { match expr {
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
Expr::MethodCall(x, ..) if chain_type == ChainType::Dotting && !x.is_qualified() => { Expr::MethodCall(x, ..) if chain_type == ChainType::Dotting && !x.is_qualified() => {
for arg_expr in &x.args { for expr in &x.args {
idx_values.push( let arg_value =
self.get_arg_value(global, caches, scope, this_ptr, arg_expr)? self.get_arg_value(global, caches, scope, this_ptr.as_deref_mut(), expr)?;
.0 idx_values.push(arg_value.0.flatten());
.flatten(),
);
} }
} }
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
@ -474,12 +469,15 @@ impl Engine {
Expr::MethodCall(x, ..) Expr::MethodCall(x, ..)
if chain_type == ChainType::Dotting && !x.is_qualified() => if chain_type == ChainType::Dotting && !x.is_qualified() =>
{ {
for arg_expr in &x.args { for expr in &x.args {
_arg_values.push( let arg_value = self.get_arg_value(
self.get_arg_value(global, caches, scope, this_ptr, arg_expr)? global,
.0 caches,
.flatten(), scope,
); this_ptr.as_deref_mut(),
expr,
)?;
_arg_values.push(arg_value.0.flatten());
} }
} }
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
@ -493,7 +491,7 @@ impl Engine {
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
_ if chain_type == ChainType::Indexing => { _ if chain_type == ChainType::Indexing => {
_arg_values.push( _arg_values.push(
self.eval_expr(global, caches, scope, this_ptr, lhs)? self.eval_expr(global, caches, scope, this_ptr.as_deref_mut(), lhs)?
.flatten(), .flatten(),
); );
} }
@ -530,7 +528,7 @@ impl Engine {
&self, &self,
global: &mut GlobalRuntimeState, global: &mut GlobalRuntimeState,
caches: &mut Caches, caches: &mut Caches,
this_ptr: &mut Dynamic, mut this_ptr: Option<&mut Dynamic>,
root: &Expr, root: &Expr,
parent: &Expr, parent: &Expr,
target: &mut Target, target: &mut Target,
@ -560,7 +558,7 @@ impl Engine {
if !parent.options().contains(ASTFlags::BREAK) => if !parent.options().contains(ASTFlags::BREAK) =>
{ {
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
self.run_debugger(global, caches, scope, this_ptr, parent)?; self.run_debugger(global, caches, scope, this_ptr.as_deref_mut(), parent)?;
let idx_val = &mut idx_values.pop().unwrap(); let idx_val = &mut idx_values.pop().unwrap();
let mut idx_val_for_setter = idx_val.clone(); let mut idx_val_for_setter = idx_val.clone();
@ -843,7 +841,13 @@ impl Engine {
let val_target = &mut match x.lhs { let val_target = &mut match x.lhs {
Expr::Property(ref p, pos) => { Expr::Property(ref p, pos) => {
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
self.run_debugger(global, caches, scope, this_ptr, _node)?; self.run_debugger(
global,
caches,
scope,
this_ptr.as_deref_mut(),
_node,
)?;
let index = &mut p.2.clone().into(); let index = &mut p.2.clone().into();
self.get_indexed_mut( self.get_indexed_mut(
@ -854,7 +858,11 @@ impl Engine {
Expr::MethodCall(ref x, pos) if !x.is_qualified() => { Expr::MethodCall(ref x, pos) if !x.is_qualified() => {
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
let reset = self.run_debugger_with_reset( let reset = self.run_debugger_with_reset(
global, caches, scope, this_ptr, _node, global,
caches,
scope,
this_ptr.as_deref_mut(),
_node,
)?; )?;
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
auto_restore!(global if Some(reset) => move |g| g.debugger_mut().reset_status(reset)); auto_restore!(global if Some(reset) => move |g| g.debugger_mut().reset_status(reset));
@ -896,7 +904,13 @@ impl Engine {
// xxx.prop[expr] | xxx.prop.expr // xxx.prop[expr] | xxx.prop.expr
Expr::Property(ref p, pos) => { Expr::Property(ref p, pos) => {
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
self.run_debugger(global, caches, scope, this_ptr, _node)?; self.run_debugger(
global,
caches,
scope,
this_ptr.as_deref_mut(),
_node,
)?;
let ((getter, hash_get), (setter, hash_set), name) = &**p; let ((getter, hash_get), (setter, hash_set), name) = &**p;
let args = &mut [target.as_mut()]; let args = &mut [target.as_mut()];
@ -972,7 +986,11 @@ impl Engine {
let val = { let val = {
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
let reset = self.run_debugger_with_reset( let reset = self.run_debugger_with_reset(
global, caches, scope, this_ptr, _node, global,
caches,
scope,
this_ptr.as_deref_mut(),
_node,
)?; )?;
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
auto_restore!(global if Some(reset) => move |g| g.debugger_mut().reset_status(reset)); auto_restore!(global if Some(reset) => move |g| g.debugger_mut().reset_status(reset));

View File

@ -410,7 +410,7 @@ impl Engine {
global: &mut GlobalRuntimeState, global: &mut GlobalRuntimeState,
caches: &mut Caches, caches: &mut Caches,
scope: &mut Scope, scope: &mut Scope,
this_ptr: &mut Dynamic, this_ptr: Option<&mut Dynamic>,
node: impl Into<ASTNode<'a>>, node: impl Into<ASTNode<'a>>,
) -> RhaiResultOf<()> { ) -> RhaiResultOf<()> {
if self.is_debugger_registered() { if self.is_debugger_registered() {
@ -435,7 +435,7 @@ impl Engine {
global: &mut GlobalRuntimeState, global: &mut GlobalRuntimeState,
caches: &mut Caches, caches: &mut Caches,
scope: &mut Scope, scope: &mut Scope,
this_ptr: &mut Dynamic, this_ptr: Option<&mut Dynamic>,
node: impl Into<ASTNode<'a>>, node: impl Into<ASTNode<'a>>,
) -> RhaiResultOf<Option<DebuggerStatus>> { ) -> RhaiResultOf<Option<DebuggerStatus>> {
if self.is_debugger_registered() { if self.is_debugger_registered() {
@ -456,7 +456,7 @@ impl Engine {
global: &mut GlobalRuntimeState, global: &mut GlobalRuntimeState,
caches: &mut Caches, caches: &mut Caches,
scope: &mut Scope, scope: &mut Scope,
this_ptr: &mut Dynamic, this_ptr: Option<&mut Dynamic>,
node: impl Into<ASTNode<'a>>, node: impl Into<ASTNode<'a>>,
) -> RhaiResultOf<Option<DebuggerStatus>> { ) -> RhaiResultOf<Option<DebuggerStatus>> {
let node = node.into(); let node = node.into();
@ -502,7 +502,7 @@ impl Engine {
global: &mut GlobalRuntimeState, global: &mut GlobalRuntimeState,
caches: &mut Caches, caches: &mut Caches,
scope: &mut Scope, scope: &mut Scope,
this_ptr: &mut Dynamic, this_ptr: Option<&mut Dynamic>,
node: ASTNode<'a>, node: ASTNode<'a>,
event: DebuggerEvent, event: DebuggerEvent,
) -> Result<Option<DebuggerStatus>, Box<crate::EvalAltResult>> { ) -> Result<Option<DebuggerStatus>, Box<crate::EvalAltResult>> {

View File

@ -17,7 +17,7 @@ pub struct EvalContext<'a, 's, 'ps, 'g, 'c, 't> {
/// The current [`Scope`]. /// The current [`Scope`].
scope: &'s mut Scope<'ps>, scope: &'s mut Scope<'ps>,
/// The current bound `this` pointer, if any. /// The current bound `this` pointer, if any.
this_ptr: &'t mut Dynamic, this_ptr: Option<&'t mut Dynamic>,
} }
impl<'a, 's, 'ps, 'g, 'c, 't> EvalContext<'a, 's, 'ps, 'g, 'c, 't> { impl<'a, 's, 'ps, 'g, 'c, 't> EvalContext<'a, 's, 'ps, 'g, 'c, 't> {
@ -29,7 +29,7 @@ impl<'a, 's, 'ps, 'g, 'c, 't> EvalContext<'a, 's, 'ps, 'g, 'c, 't> {
global: &'g mut GlobalRuntimeState, global: &'g mut GlobalRuntimeState,
caches: &'c mut Caches, caches: &'c mut Caches,
scope: &'s mut Scope<'ps>, scope: &'s mut Scope<'ps>,
this_ptr: &'t mut Dynamic, this_ptr: Option<&'t mut Dynamic>,
) -> Self { ) -> Self {
Self { Self {
engine, engine,
@ -118,24 +118,16 @@ impl<'a, 's, 'ps, 'g, 'c, 't> EvalContext<'a, 's, 'ps, 'g, 'c, 't> {
&self.global.lib &self.global.lib
} }
/// The current bound `this` pointer, if any. /// The current bound `this` pointer, if any.
#[inline] #[inline(always)]
#[must_use] #[must_use]
pub fn this_ptr(&self) -> Option<&Dynamic> { pub fn this_ptr(&self) -> Option<&Dynamic> {
if self.this_ptr.is_null() { self.this_ptr.as_deref()
None
} else {
Some(self.this_ptr)
}
} }
/// Mutable reference to the current bound `this` pointer, if any. /// Mutable reference to the current bound `this` pointer, if any.
#[inline] #[inline(always)]
#[must_use] #[must_use]
pub fn this_ptr_mut(&mut self) -> Option<&mut Dynamic> { pub fn this_ptr_mut(&mut self) -> Option<&mut Dynamic> {
if self.this_ptr.is_null() { self.this_ptr.as_deref_mut()
None
} else {
Some(self.this_ptr)
}
} }
/// The current nesting level of function calls. /// The current nesting level of function calls.
#[inline(always)] #[inline(always)]
@ -177,19 +169,20 @@ impl<'a, 's, 'ps, 'g, 'c, 't> EvalContext<'a, 's, 'ps, 'g, 'c, 't> {
rewind_scope: bool, rewind_scope: bool,
) -> crate::RhaiResult { ) -> crate::RhaiResult {
let expr: &crate::ast::Expr = expr; let expr: &crate::ast::Expr = expr;
let this_ptr = self.this_ptr.as_deref_mut();
match expr { match expr {
crate::ast::Expr::Stmt(statements) => self.engine.eval_stmt_block( crate::ast::Expr::Stmt(stmts) => self.engine.eval_stmt_block(
self.global, self.global,
self.caches, self.caches,
self.scope, self.scope,
self.this_ptr, this_ptr,
statements, stmts,
rewind_scope, rewind_scope,
), ),
_ => self _ => self
.engine .engine
.eval_expr(self.global, self.caches, self.scope, self.this_ptr, expr), .eval_expr(self.global, self.caches, self.scope, this_ptr, expr),
} }
} }
} }

View File

@ -53,7 +53,7 @@ impl Engine {
global: &mut GlobalRuntimeState, global: &mut GlobalRuntimeState,
caches: &mut Caches, caches: &mut Caches,
scope: &'s mut Scope, scope: &'s mut Scope,
this_ptr: &'s mut Dynamic, this_ptr: Option<&'s mut Dynamic>,
expr: &Expr, expr: &Expr,
) -> RhaiResultOf<Target<'s>> { ) -> RhaiResultOf<Target<'s>> {
match expr { match expr {
@ -132,7 +132,7 @@ impl Engine {
global: &mut GlobalRuntimeState, global: &mut GlobalRuntimeState,
caches: &mut Caches, caches: &mut Caches,
scope: &'s mut Scope, scope: &'s mut Scope,
this_ptr: &'s mut Dynamic, this_ptr: Option<&'s mut Dynamic>,
expr: &Expr, expr: &Expr,
) -> RhaiResultOf<Target<'s>> { ) -> RhaiResultOf<Target<'s>> {
// Make sure that the pointer indirection is taken only when absolutely necessary. // Make sure that the pointer indirection is taken only when absolutely necessary.
@ -142,10 +142,10 @@ impl Engine {
Expr::Variable(v, None, ..) Expr::Variable(v, None, ..)
if v.0.is_none() && v.1.is_empty() && v.3 == KEYWORD_THIS => if v.0.is_none() && v.1.is_empty() && v.3 == KEYWORD_THIS =>
{ {
return if this_ptr.is_null() { return if let Some(this_ptr) = this_ptr {
Err(ERR::ErrorUnboundThis(expr.position()).into())
} else {
Ok(this_ptr.into()) Ok(this_ptr.into())
} else {
Err(ERR::ErrorUnboundThis(expr.position()).into())
}; };
} }
@ -223,7 +223,7 @@ impl Engine {
global: &mut GlobalRuntimeState, global: &mut GlobalRuntimeState,
caches: &mut Caches, caches: &mut Caches,
scope: &mut Scope, scope: &mut Scope,
this_ptr: &mut Dynamic, mut this_ptr: Option<&mut Dynamic>,
expr: &Expr, expr: &Expr,
) -> RhaiResult { ) -> RhaiResult {
// Coded this way for better branch prediction. // Coded this way for better branch prediction.
@ -233,7 +233,8 @@ impl Engine {
// binary operators are also function calls. // binary operators are also function calls.
if let Expr::FnCall(x, pos) = expr { if let Expr::FnCall(x, pos) = expr {
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
let reset = self.run_debugger_with_reset(global, caches, scope, this_ptr, expr)?; let reset =
self.run_debugger_with_reset(global, caches, scope, this_ptr.as_deref_mut(), expr)?;
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
auto_restore!(global if Some(reset) => move |g| g.debugger_mut().reset_status(reset)); auto_restore!(global if Some(reset) => move |g| g.debugger_mut().reset_status(reset));
@ -247,16 +248,14 @@ impl Engine {
// will cost more than the mis-predicted `match` branch. // will cost more than the mis-predicted `match` branch.
if let Expr::Variable(x, index, var_pos) = expr { if let Expr::Variable(x, index, var_pos) = expr {
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
self.run_debugger(global, caches, scope, this_ptr, expr)?; self.run_debugger(global, caches, scope, this_ptr.as_deref_mut(), expr)?;
self.track_operation(global, expr.position())?; self.track_operation(global, expr.position())?;
return if index.is_none() && x.0.is_none() && x.3 == KEYWORD_THIS { return if index.is_none() && x.0.is_none() && x.3 == KEYWORD_THIS {
if this_ptr.is_null() { this_ptr
ERR::ErrorUnboundThis(*var_pos).into() .ok_or_else(|| ERR::ErrorUnboundThis(*var_pos).into())
} else { .cloned()
Ok(this_ptr.clone())
}
} else { } else {
self.search_namespace(global, caches, scope, this_ptr, expr) self.search_namespace(global, caches, scope, this_ptr, expr)
.map(Target::take_or_clone) .map(Target::take_or_clone)
@ -264,7 +263,8 @@ impl Engine {
} }
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
let reset = self.run_debugger_with_reset(global, caches, scope, this_ptr, expr)?; let reset =
self.run_debugger_with_reset(global, caches, scope, this_ptr.as_deref_mut(), expr)?;
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
auto_restore!(global if Some(reset) => move |g| g.debugger_mut().reset_status(reset)); auto_restore!(global if Some(reset) => move |g| g.debugger_mut().reset_status(reset));
@ -291,7 +291,7 @@ impl Engine {
x.iter() x.iter()
.try_for_each(|expr| { .try_for_each(|expr| {
let item = self let item = self
.eval_expr(global, caches, scope, this_ptr, expr)? .eval_expr(global, caches, scope, this_ptr.as_deref_mut(), expr)?
.flatten(); .flatten();
op_info.pos = expr.start_position(); op_info.pos = expr.start_position();
@ -312,7 +312,13 @@ impl Engine {
crate::Array::with_capacity(x.len()), crate::Array::with_capacity(x.len()),
|mut array, item_expr| { |mut array, item_expr| {
let value = self let value = self
.eval_expr(global, caches, scope, this_ptr, item_expr)? .eval_expr(
global,
caches,
scope,
this_ptr.as_deref_mut(),
item_expr,
)?
.flatten(); .flatten();
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
@ -344,7 +350,7 @@ impl Engine {
x.0.iter() x.0.iter()
.try_fold(x.1.clone(), |mut map, (key, value_expr)| { .try_fold(x.1.clone(), |mut map, (key, value_expr)| {
let value = self let value = self
.eval_expr(global, caches, scope, this_ptr, value_expr)? .eval_expr(global, caches, scope, this_ptr.as_deref_mut(), value_expr)?
.flatten(); .flatten();
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
@ -367,7 +373,7 @@ impl Engine {
} }
Expr::And(x, ..) => Ok((self Expr::And(x, ..) => Ok((self
.eval_expr(global, caches, scope, this_ptr, &x.lhs)? .eval_expr(global, caches, scope, this_ptr.as_deref_mut(), &x.lhs)?
.as_bool() .as_bool()
.map_err(|typ| self.make_type_mismatch_err::<bool>(typ, x.lhs.position()))? .map_err(|typ| self.make_type_mismatch_err::<bool>(typ, x.lhs.position()))?
&& self && self
@ -377,7 +383,7 @@ impl Engine {
.into()), .into()),
Expr::Or(x, ..) => Ok((self Expr::Or(x, ..) => Ok((self
.eval_expr(global, caches, scope, this_ptr, &x.lhs)? .eval_expr(global, caches, scope, this_ptr.as_deref_mut(), &x.lhs)?
.as_bool() .as_bool()
.map_err(|typ| self.make_type_mismatch_err::<bool>(typ, x.lhs.position()))? .map_err(|typ| self.make_type_mismatch_err::<bool>(typ, x.lhs.position()))?
|| self || self
@ -387,7 +393,8 @@ impl Engine {
.into()), .into()),
Expr::Coalesce(x, ..) => { Expr::Coalesce(x, ..) => {
let value = self.eval_expr(global, caches, scope, this_ptr, &x.lhs)?; let value =
self.eval_expr(global, caches, scope, this_ptr.as_deref_mut(), &x.lhs)?;
if value.is_unit() { if value.is_unit() {
self.eval_expr(global, caches, scope, this_ptr, &x.rhs) self.eval_expr(global, caches, scope, this_ptr, &x.rhs)

View File

@ -32,7 +32,7 @@ impl Engine {
global: &mut GlobalRuntimeState, global: &mut GlobalRuntimeState,
caches: &mut Caches, caches: &mut Caches,
scope: &mut Scope, scope: &mut Scope,
this_ptr: &mut Dynamic, mut this_ptr: Option<&mut Dynamic>,
statements: &[Stmt], statements: &[Stmt],
restore_orig_state: bool, restore_orig_state: bool,
) -> RhaiResult { ) -> RhaiResult {
@ -71,6 +71,8 @@ impl Engine {
// Run the statements // Run the statements
statements.iter().try_fold(Dynamic::UNIT, |_, stmt| { statements.iter().try_fold(Dynamic::UNIT, |_, stmt| {
let this_ptr = this_ptr.as_deref_mut();
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
let imports_len = global.num_imports(); let imports_len = global.num_imports();
@ -198,12 +200,13 @@ impl Engine {
global: &mut GlobalRuntimeState, global: &mut GlobalRuntimeState,
caches: &mut Caches, caches: &mut Caches,
scope: &mut Scope, scope: &mut Scope,
this_ptr: &mut Dynamic, mut this_ptr: Option<&mut Dynamic>,
stmt: &Stmt, stmt: &Stmt,
rewind_scope: bool, rewind_scope: bool,
) -> RhaiResult { ) -> RhaiResult {
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
let reset = self.run_debugger_with_reset(global, caches, scope, this_ptr, stmt)?; let reset =
self.run_debugger_with_reset(global, caches, scope, this_ptr.as_deref_mut(), stmt)?;
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
auto_restore!(global if Some(reset) => move |g| g.debugger_mut().reset_status(reset)); auto_restore!(global if Some(reset) => move |g| g.debugger_mut().reset_status(reset));
@ -227,7 +230,7 @@ impl Engine {
if let Expr::Variable(x, ..) = lhs { if let Expr::Variable(x, ..) = lhs {
let rhs_val = self let rhs_val = self
.eval_expr(global, caches, scope, this_ptr, rhs)? .eval_expr(global, caches, scope, this_ptr.as_deref_mut(), rhs)?
.flatten(); .flatten();
let mut target = self.search_namespace(global, caches, scope, this_ptr, lhs)?; let mut target = self.search_namespace(global, caches, scope, this_ptr, lhs)?;
@ -259,7 +262,7 @@ impl Engine {
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
{ {
let rhs_val = self let rhs_val = self
.eval_expr(global, caches, scope, this_ptr, rhs)? .eval_expr(global, caches, scope, this_ptr.as_deref_mut(), rhs)?
.flatten() .flatten()
.intern_string(self); .intern_string(self);
@ -310,7 +313,7 @@ impl Engine {
let (expr, if_block, else_block) = &**x; let (expr, if_block, else_block) = &**x;
let guard_val = self let guard_val = self
.eval_expr(global, caches, scope, this_ptr, expr)? .eval_expr(global, caches, scope, this_ptr.as_deref_mut(), expr)?
.as_bool() .as_bool()
.map_err(|typ| self.make_type_mismatch_err::<bool>(typ, expr.position()))?; .map_err(|typ| self.make_type_mismatch_err::<bool>(typ, expr.position()))?;
@ -337,7 +340,7 @@ impl Engine {
let mut result = None; let mut result = None;
let value = self.eval_expr(global, caches, scope, this_ptr, expr)?; let value = self.eval_expr(global, caches, scope, this_ptr.as_deref_mut(), expr)?;
if value.is_hashable() { if value.is_hashable() {
let hasher = &mut get_hasher(); let hasher = &mut get_hasher();
@ -354,7 +357,7 @@ impl Engine {
let cond_result = match block.condition { let cond_result = match block.condition {
Expr::BoolConstant(b, ..) => b, Expr::BoolConstant(b, ..) => b,
ref c => self ref c => self
.eval_expr(global, caches, scope, this_ptr, c)? .eval_expr(global, caches, scope, this_ptr.as_deref_mut(), c)?
.as_bool() .as_bool()
.map_err(|typ| { .map_err(|typ| {
self.make_type_mismatch_err::<bool>(typ, c.position()) self.make_type_mismatch_err::<bool>(typ, c.position())
@ -376,7 +379,7 @@ impl Engine {
let cond_result = match block.condition { let cond_result = match block.condition {
Expr::BoolConstant(b, ..) => b, Expr::BoolConstant(b, ..) => b,
ref c => self ref c => self
.eval_expr(global, caches, scope, this_ptr, c)? .eval_expr(global, caches, scope, this_ptr.as_deref_mut(), c)?
.as_bool() .as_bool()
.map_err(|typ| { .map_err(|typ| {
self.make_type_mismatch_err::<bool>(typ, c.position()) self.make_type_mismatch_err::<bool>(typ, c.position())
@ -409,14 +412,15 @@ impl Engine {
} }
loop { loop {
if let Err(err) = let this_ptr = this_ptr.as_deref_mut();
self.eval_stmt_block(global, caches, scope, this_ptr, body, true)
{ match self.eval_stmt_block(global, caches, scope, this_ptr, body, true) {
match *err { Ok(..) => (),
Err(err) => match *err {
ERR::LoopBreak(false, ..) => (), ERR::LoopBreak(false, ..) => (),
ERR::LoopBreak(true, value, ..) => break Ok(value), ERR::LoopBreak(true, value, ..) => break Ok(value),
_ => break Err(err), _ => break Err(err),
} },
} }
} }
} }
@ -427,7 +431,7 @@ impl Engine {
loop { loop {
let condition = self let condition = self
.eval_expr(global, caches, scope, this_ptr, expr)? .eval_expr(global, caches, scope, this_ptr.as_deref_mut(), expr)?
.as_bool() .as_bool()
.map_err(|typ| self.make_type_mismatch_err::<bool>(typ, expr.position()))?; .map_err(|typ| self.make_type_mismatch_err::<bool>(typ, expr.position()))?;
@ -439,14 +443,15 @@ impl Engine {
continue; continue;
} }
if let Err(err) = let this_ptr = this_ptr.as_deref_mut();
self.eval_stmt_block(global, caches, scope, this_ptr, body, true)
{ match self.eval_stmt_block(global, caches, scope, this_ptr, body, true) {
match *err { Ok(..) => (),
Err(err) => match *err {
ERR::LoopBreak(false, ..) => (), ERR::LoopBreak(false, ..) => (),
ERR::LoopBreak(true, value, ..) => break Ok(value), ERR::LoopBreak(true, value, ..) => break Ok(value),
_ => break Err(err), _ => break Err(err),
} },
} }
} }
} }
@ -458,19 +463,20 @@ impl Engine {
loop { loop {
if !body.is_empty() { if !body.is_empty() {
if let Err(err) = let this_ptr = this_ptr.as_deref_mut();
self.eval_stmt_block(global, caches, scope, this_ptr, body, true)
{ match self.eval_stmt_block(global, caches, scope, this_ptr, body, true) {
match *err { Ok(..) => (),
Err(err) => match *err {
ERR::LoopBreak(false, ..) => continue, ERR::LoopBreak(false, ..) => continue,
ERR::LoopBreak(true, value, ..) => break Ok(value), ERR::LoopBreak(true, value, ..) => break Ok(value),
_ => break Err(err), _ => break Err(err),
} },
} }
} }
let condition = self let condition = self
.eval_expr(global, caches, scope, this_ptr, expr)? .eval_expr(global, caches, scope, this_ptr.as_deref_mut(), expr)?
.as_bool() .as_bool()
.map_err(|typ| self.make_type_mismatch_err::<bool>(typ, expr.position()))?; .map_err(|typ| self.make_type_mismatch_err::<bool>(typ, expr.position()))?;
@ -485,7 +491,7 @@ impl Engine {
let (var_name, counter, expr, statements) = &**x; let (var_name, counter, expr, statements) = &**x;
let iter_obj = self let iter_obj = self
.eval_expr(global, caches, scope, this_ptr, expr)? .eval_expr(global, caches, scope, this_ptr.as_deref_mut(), expr)?
.flatten(); .flatten();
let iter_type = iter_obj.type_id(); let iter_type = iter_obj.type_id();
@ -566,6 +572,8 @@ impl Engine {
continue; continue;
} }
let this_ptr = this_ptr.as_deref_mut();
match self.eval_stmt_block(global, caches, scope, this_ptr, statements, true) { match self.eval_stmt_block(global, caches, scope, this_ptr, statements, true) {
Ok(_) => (), Ok(_) => (),
Err(err) => match *err { Err(err) => match *err {
@ -603,7 +611,14 @@ impl Engine {
catch_block, catch_block,
} = &**x; } = &**x;
match self.eval_stmt_block(global, caches, scope, this_ptr, try_block, true) { match self.eval_stmt_block(
global,
caches,
scope,
this_ptr.as_deref_mut(),
try_block,
true,
) {
r @ Ok(_) => r, r @ Ok(_) => r,
Err(err) if err.is_pseudo_error() => Err(err), Err(err) if err.is_pseudo_error() => Err(err),
Err(err) if !err.is_catchable() => Err(err), Err(err) if !err.is_catchable() => Err(err),
@ -650,6 +665,8 @@ impl Engine {
scope.push(catch_var.name.clone(), err_value); scope.push(catch_var.name.clone(), err_value);
} }
let this_ptr = this_ptr.as_deref_mut();
self.eval_stmt_block(global, caches, scope, this_ptr, catch_block, true) self.eval_stmt_block(global, caches, scope, this_ptr, catch_block, true)
.map(|_| Dynamic::UNIT) .map(|_| Dynamic::UNIT)
.map_err(|result_err| match *result_err { .map_err(|result_err| match *result_err {
@ -707,7 +724,8 @@ impl Engine {
nesting_level: global.scope_level, nesting_level: global.scope_level,
will_shadow, will_shadow,
}; };
let context = EvalContext::new(self, global, caches, scope, this_ptr); let context =
EvalContext::new(self, global, caches, scope, this_ptr.as_deref_mut());
if !filter(true, info, context)? { if !filter(true, info, context)? {
return Err(ERR::ErrorForbiddenVariable(var_name.to_string(), *pos).into()); return Err(ERR::ErrorForbiddenVariable(var_name.to_string(), *pos).into());
@ -866,7 +884,7 @@ impl Engine {
/// Evaluate a list of statements with no `this` pointer. /// Evaluate a list of statements with no `this` pointer.
/// This is commonly used to evaluate a list of statements in an [`AST`][crate::AST] or a script function body. /// This is commonly used to evaluate a list of statements in an [`AST`][crate::AST] or a script function body.
#[inline] #[inline(always)]
pub(crate) fn eval_global_statements( pub(crate) fn eval_global_statements(
&self, &self,
global: &mut GlobalRuntimeState, global: &mut GlobalRuntimeState,
@ -874,9 +892,7 @@ impl Engine {
scope: &mut Scope, scope: &mut Scope,
statements: &[Stmt], statements: &[Stmt],
) -> RhaiResult { ) -> RhaiResult {
let mut this_ptr = Dynamic::NULL; self.eval_stmt_block(global, caches, scope, None, statements, false)
self.eval_stmt_block(global, caches, scope, &mut this_ptr, statements, false)
.or_else(|err| match *err { .or_else(|err| match *err {
ERR::Return(out, ..) => Ok(out), ERR::Return(out, ..) => Ok(out),
ERR::LoopBreak(..) => { ERR::LoopBreak(..) => {

View File

@ -438,7 +438,6 @@ impl Engine {
}; };
if trigger { if trigger {
let scope = &mut Scope::new(); let scope = &mut Scope::new();
let mut this_ptr = Dynamic::NULL;
let node = crate::ast::Stmt::Noop(pos); let node = crate::ast::Stmt::Noop(pos);
let node = (&node).into(); let node = (&node).into();
let event = match _result { let event = match _result {
@ -446,10 +445,9 @@ impl Engine {
Err(ref err) => DebuggerEvent::FunctionExitWithError(err), Err(ref err) => DebuggerEvent::FunctionExitWithError(err),
}; };
if let Err(err) = match self.run_debugger_raw(global, caches, scope, None, node, event) {
self.run_debugger_raw(global, caches, scope, &mut this_ptr, node, event) Ok(..) => (),
{ Err(err) => _result = Err(err),
_result = Err(err);
} }
} }
@ -676,7 +674,15 @@ impl Engine {
let (first_arg, rest_args) = _args.split_first_mut().unwrap(); let (first_arg, rest_args) = _args.split_first_mut().unwrap();
self.call_script_fn( self.call_script_fn(
global, caches, scope, first_arg, environ, f, rest_args, true, pos, global,
caches,
scope,
Some(first_arg),
environ,
f,
rest_args,
true,
pos,
) )
} else { } else {
// Normal call of script function // Normal call of script function
@ -691,19 +697,7 @@ impl Engine {
auto_restore!(args = (_args) if swap => move |a| backup.restore_first_arg(a)); auto_restore!(args = (_args) if swap => move |a| backup.restore_first_arg(a));
let mut this_ptr = Dynamic::NULL; self.call_script_fn(global, caches, scope, None, environ, f, args, true, pos)
self.call_script_fn(
global,
caches,
scope,
&mut this_ptr,
environ,
f,
args,
true,
pos,
)
} }
.map(|r| (r, false)); .map(|r| (r, false));
} }
@ -724,7 +718,7 @@ impl Engine {
global: &mut GlobalRuntimeState, global: &mut GlobalRuntimeState,
caches: &mut Caches, caches: &mut Caches,
scope: &mut Scope, scope: &mut Scope,
this_ptr: &mut Dynamic, this_ptr: Option<&mut Dynamic>,
arg_expr: &Expr, arg_expr: &Expr,
) -> RhaiResultOf<(Dynamic, Position)> { ) -> RhaiResultOf<(Dynamic, Position)> {
// Literal values // Literal values
@ -782,14 +776,12 @@ impl Engine {
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
if let Some(fn_def) = fn_ptr.fn_def() { if let Some(fn_def) = fn_ptr.fn_def() {
if fn_def.params.len() == args.len() { if fn_def.params.len() == args.len() {
let mut this_ptr = Dynamic::NULL;
return self return self
.call_script_fn( .call_script_fn(
global, global,
caches, caches,
&mut Scope::new(), &mut Scope::new(),
&mut this_ptr, None,
fn_ptr.encapsulated_environ(), fn_ptr.encapsulated_environ(),
fn_def, fn_def,
args, args,
@ -876,7 +868,7 @@ impl Engine {
global, global,
caches, caches,
&mut Scope::new(), &mut Scope::new(),
target, Some(target),
_environ.as_deref(), _environ.as_deref(),
&fn_def, &fn_def,
args, args,
@ -1018,7 +1010,7 @@ impl Engine {
global: &mut GlobalRuntimeState, global: &mut GlobalRuntimeState,
caches: &mut Caches, caches: &mut Caches,
scope: &mut Scope, scope: &mut Scope,
this_ptr: &mut Dynamic, mut this_ptr: Option<&mut Dynamic>,
fn_name: &str, fn_name: &str,
op_token: Token, op_token: Token,
first_arg: Option<&Expr>, first_arg: Option<&Expr>,
@ -1042,7 +1034,7 @@ impl Engine {
KEYWORD_FN_PTR_CALL if total_args >= 1 => { KEYWORD_FN_PTR_CALL if total_args >= 1 => {
let arg = first_arg.unwrap(); let arg = first_arg.unwrap();
let (arg_value, arg_pos) = let (arg_value, arg_pos) =
self.get_arg_value(global, caches, scope, this_ptr, arg)?; self.get_arg_value(global, caches, scope, this_ptr.as_deref_mut(), arg)?;
if !arg_value.is_fnptr() { if !arg_value.is_fnptr() {
let typ = self.map_type_name(arg_value.type_name()); let typ = self.map_type_name(arg_value.type_name());
@ -1074,23 +1066,17 @@ impl Engine {
.into_iter() .into_iter()
.map(Ok) .map(Ok)
.chain(a_expr.iter().map(|expr| -> Result<_, RhaiError> { .chain(a_expr.iter().map(|expr| -> Result<_, RhaiError> {
let this_ptr = this_ptr.as_deref_mut();
self.get_arg_value(global, caches, scope, this_ptr, expr) self.get_arg_value(global, caches, scope, this_ptr, expr)
.map(|(v, ..)| v) .map(|(v, ..)| v)
})) }))
.collect::<RhaiResultOf<FnArgsVec<_>>>()?; .collect::<RhaiResultOf<FnArgsVec<_>>>()?;
let args = &mut arg_values.iter_mut().collect::<FnArgsVec<_>>(); let args = &mut arg_values.iter_mut().collect::<FnArgsVec<_>>();
let mut this_ptr = Dynamic::NULL; let scope = &mut Scope::new();
let environ = _environ.as_deref();
return self.call_script_fn( return self.call_script_fn(
global, global, caches, scope, None, environ, &fn_def, args, true, pos,
caches,
&mut Scope::new(),
&mut this_ptr,
_environ.as_deref(),
&fn_def,
args,
true,
pos,
); );
} }
} }
@ -1134,7 +1120,7 @@ impl Engine {
KEYWORD_FN_PTR_CURRY if total_args > 1 => { KEYWORD_FN_PTR_CURRY if total_args > 1 => {
let first = first_arg.unwrap(); let first = first_arg.unwrap();
let (arg_value, arg_pos) = let (arg_value, arg_pos) =
self.get_arg_value(global, caches, scope, this_ptr, first)?; self.get_arg_value(global, caches, scope, this_ptr.as_deref_mut(), first)?;
if !arg_value.is_fnptr() { if !arg_value.is_fnptr() {
let typ = self.map_type_name(arg_value.type_name()); let typ = self.map_type_name(arg_value.type_name());
@ -1145,7 +1131,8 @@ impl Engine {
// Append the new curried arguments to the existing list. // Append the new curried arguments to the existing list.
a_expr.iter().try_for_each(|expr| -> Result<_, RhaiError> { a_expr.iter().try_for_each(|expr| -> Result<_, RhaiError> {
let (value, ..) = self.get_arg_value(global, caches, scope, this_ptr, expr)?; let (value, ..) =
self.get_arg_value(global, caches, scope, this_ptr.as_deref_mut(), expr)?;
fn_ptr.add_curry(value); fn_ptr.add_curry(value);
Ok(()) Ok(())
})?; })?;
@ -1157,7 +1144,8 @@ impl Engine {
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
crate::engine::KEYWORD_IS_SHARED if total_args == 1 => { crate::engine::KEYWORD_IS_SHARED if total_args == 1 => {
let arg = first_arg.unwrap(); let arg = first_arg.unwrap();
let (arg_value, ..) = self.get_arg_value(global, caches, scope, this_ptr, arg)?; let (arg_value, ..) =
self.get_arg_value(global, caches, scope, this_ptr.as_deref_mut(), arg)?;
return Ok(arg_value.is_shared().into()); return Ok(arg_value.is_shared().into());
} }
@ -1166,7 +1154,7 @@ impl Engine {
crate::engine::KEYWORD_IS_DEF_FN if total_args == 2 => { crate::engine::KEYWORD_IS_DEF_FN if total_args == 2 => {
let first = first_arg.unwrap(); let first = first_arg.unwrap();
let (arg_value, arg_pos) = let (arg_value, arg_pos) =
self.get_arg_value(global, caches, scope, this_ptr, first)?; self.get_arg_value(global, caches, scope, this_ptr.as_deref_mut(), first)?;
let fn_name = arg_value let fn_name = arg_value
.into_immutable_string() .into_immutable_string()
@ -1258,7 +1246,7 @@ impl Engine {
.copied() .copied()
.chain(a_expr.iter()) .chain(a_expr.iter())
.try_for_each(|expr| { .try_for_each(|expr| {
self.get_arg_value(global, caches, scope, this_ptr, expr) self.get_arg_value(global, caches, scope, this_ptr.as_deref_mut(), expr)
.map(|(value, ..)| arg_values.push(value.flatten())) .map(|(value, ..)| arg_values.push(value.flatten()))
})?; })?;
args.extend(curry.iter_mut()); args.extend(curry.iter_mut());
@ -1286,11 +1274,11 @@ impl Engine {
let first_expr = first_arg.unwrap(); let first_expr = first_arg.unwrap();
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
self.run_debugger(global, caches, scope, this_ptr, first_expr)?; self.run_debugger(global, caches, scope, this_ptr.as_deref_mut(), first_expr)?;
// func(x, ...) -> x.func(...) // func(x, ...) -> x.func(...)
a_expr.iter().try_for_each(|expr| { a_expr.iter().try_for_each(|expr| {
self.get_arg_value(global, caches, scope, this_ptr, expr) self.get_arg_value(global, caches, scope, this_ptr.as_deref_mut(), expr)
.map(|(value, ..)| arg_values.push(value.flatten())) .map(|(value, ..)| arg_values.push(value.flatten()))
})?; })?;
@ -1317,7 +1305,7 @@ impl Engine {
.into_iter() .into_iter()
.chain(a_expr.iter()) .chain(a_expr.iter())
.try_for_each(|expr| { .try_for_each(|expr| {
self.get_arg_value(global, caches, scope, this_ptr, expr) self.get_arg_value(global, caches, scope, this_ptr.as_deref_mut(), expr)
.map(|(value, ..)| arg_values.push(value.flatten())) .map(|(value, ..)| arg_values.push(value.flatten()))
})?; })?;
args.extend(curry.iter_mut()); args.extend(curry.iter_mut());
@ -1339,7 +1327,7 @@ impl Engine {
global: &mut GlobalRuntimeState, global: &mut GlobalRuntimeState,
caches: &mut Caches, caches: &mut Caches,
scope: &mut Scope, scope: &mut Scope,
this_ptr: &mut Dynamic, mut this_ptr: Option<&mut Dynamic>,
namespace: &crate::ast::Namespace, namespace: &crate::ast::Namespace,
fn_name: &str, fn_name: &str,
args_expr: &[Expr], args_expr: &[Expr],
@ -1358,13 +1346,19 @@ impl Engine {
// and avoid cloning the value // and avoid cloning the value
if !args_expr.is_empty() && args_expr[0].is_variable_access(true) { if !args_expr.is_empty() && args_expr[0].is_variable_access(true) {
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
self.run_debugger(global, caches, scope, this_ptr, &args_expr[0])?; self.run_debugger(
global,
caches,
scope,
this_ptr.as_deref_mut(),
&args_expr[0],
)?;
// func(x, ...) -> x.func(...) // func(x, ...) -> x.func(...)
arg_values.push(Dynamic::UNIT); arg_values.push(Dynamic::UNIT);
args_expr.iter().skip(1).try_for_each(|expr| { args_expr.iter().skip(1).try_for_each(|expr| {
self.get_arg_value(global, caches, scope, this_ptr, expr) self.get_arg_value(global, caches, scope, this_ptr.as_deref_mut(), expr)
.map(|(value, ..)| arg_values.push(value.flatten())) .map(|(value, ..)| arg_values.push(value.flatten()))
})?; })?;
@ -1393,7 +1387,7 @@ impl Engine {
} else { } else {
// func(..., ...) or func(mod::x, ...) // func(..., ...) or func(mod::x, ...)
args_expr.iter().try_for_each(|expr| { args_expr.iter().try_for_each(|expr| {
self.get_arg_value(global, caches, scope, this_ptr, expr) self.get_arg_value(global, caches, scope, this_ptr.as_deref_mut(), expr)
.map(|(value, ..)| arg_values.push(value.flatten())) .map(|(value, ..)| arg_values.push(value.flatten()))
})?; })?;
args.extend(arg_values.iter_mut()); args.extend(arg_values.iter_mut());
@ -1466,25 +1460,14 @@ impl Engine {
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
Some(func) if func.is_script() => { Some(func) if func.is_script() => {
let f = func.get_script_fn_def().expect("script-defined function"); let f = func.get_script_fn_def().expect("script-defined function");
let environ = func.get_encapsulated_environ();
let environ = func.get_encapsulated_environ();
let scope = &mut Scope::new(); let scope = &mut Scope::new();
let mut this_ptr = Dynamic::NULL;
let orig_source = mem::replace(&mut global.source, module.id_raw().cloned()); let orig_source = mem::replace(&mut global.source, module.id_raw().cloned());
auto_restore!(global => move |g| g.source = orig_source); auto_restore!(global => move |g| g.source = orig_source);
self.call_script_fn( self.call_script_fn(global, caches, scope, None, environ, f, args, true, pos)
global,
caches,
scope,
&mut this_ptr,
environ,
f,
args,
true,
pos,
)
} }
Some(f) if f.is_plugin_fn() => { Some(f) if f.is_plugin_fn() => {
@ -1581,7 +1564,7 @@ impl Engine {
global: &mut GlobalRuntimeState, global: &mut GlobalRuntimeState,
caches: &mut Caches, caches: &mut Caches,
scope: &mut Scope, scope: &mut Scope,
this_ptr: &mut Dynamic, mut this_ptr: Option<&mut Dynamic>,
expr: &FnCallExpr, expr: &FnCallExpr,
pos: Position, pos: Position,
) -> RhaiResult { ) -> RhaiResult {
@ -1601,7 +1584,7 @@ impl Engine {
// Short-circuit native unary operator call if under Fast Operators mode // Short-circuit native unary operator call if under Fast Operators mode
if op_token == Token::Bang && self.fast_operators() && args.len() == 1 { if op_token == Token::Bang && self.fast_operators() && args.len() == 1 {
let mut value = self let mut value = self
.get_arg_value(global, caches, scope, this_ptr, &args[0])? .get_arg_value(global, caches, scope, this_ptr.as_deref_mut(), &args[0])?
.0 .0
.flatten(); .flatten();
@ -1617,7 +1600,7 @@ impl Engine {
// Short-circuit native binary operator call if under Fast Operators mode // Short-circuit native binary operator call if under Fast Operators mode
if op_token != NO_TOKEN && self.fast_operators() && args.len() == 2 { if op_token != NO_TOKEN && self.fast_operators() && args.len() == 2 {
let mut lhs = self let mut lhs = self
.get_arg_value(global, caches, scope, this_ptr, &args[0])? .get_arg_value(global, caches, scope, this_ptr.as_deref_mut(), &args[0])?
.0 .0
.flatten(); .flatten();

View File

@ -28,7 +28,7 @@ impl Engine {
global: &mut GlobalRuntimeState, global: &mut GlobalRuntimeState,
caches: &mut Caches, caches: &mut Caches,
scope: &mut Scope, scope: &mut Scope,
this_ptr: &mut Dynamic, mut this_ptr: Option<&mut Dynamic>,
_environ: Option<&EncapsulatedEnviron>, _environ: Option<&EncapsulatedEnviron>,
fn_def: &ScriptFnDef, fn_def: &ScriptFnDef,
args: &mut FnCallArgs, args: &mut FnCallArgs,
@ -108,12 +108,19 @@ impl Engine {
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
if self.is_debugger_registered() { if self.is_debugger_registered() {
let node = crate::ast::Stmt::Noop(fn_def.body.position()); let node = crate::ast::Stmt::Noop(fn_def.body.position());
self.run_debugger(global, caches, scope, this_ptr, &node)?; self.run_debugger(global, caches, scope, this_ptr.as_deref_mut(), &node)?;
} }
// Evaluate the function // Evaluate the function
let mut _result: RhaiResult = self let mut _result: RhaiResult = self
.eval_stmt_block(global, caches, scope, this_ptr, &fn_def.body, rewind_scope) .eval_stmt_block(
global,
caches,
scope,
this_ptr.as_deref_mut(),
&fn_def.body,
rewind_scope,
)
.or_else(|err| match *err { .or_else(|err| match *err {
// Convert return statement to return value // Convert return statement to return value
ERR::Return(x, ..) => Ok(x), ERR::Return(x, ..) => Ok(x),

View File

@ -54,7 +54,7 @@ struct OptimizerState<'a> {
/// Has the [`AST`] been changed during this pass? /// Has the [`AST`] been changed during this pass?
changed: bool, changed: bool,
/// Collection of constants to use for eager function evaluations. /// Collection of constants to use for eager function evaluations.
variables: StaticVec<(Identifier, AccessMode, Dynamic)>, variables: StaticVec<(Identifier, AccessMode, Option<Dynamic>)>,
/// Activate constants propagation? /// Activate constants propagation?
propagate_constants: bool, propagate_constants: bool,
/// An [`Engine`] instance for eager function evaluation. /// An [`Engine`] instance for eager function evaluation.
@ -115,7 +115,12 @@ impl<'a> OptimizerState<'a> {
} }
/// Add a new variable to the list. /// Add a new variable to the list.
#[inline(always)] #[inline(always)]
pub fn push_var(&mut self, name: impl Into<Identifier>, access: AccessMode, value: Dynamic) { pub fn push_var(
&mut self,
name: impl Into<Identifier>,
access: AccessMode,
value: Option<Dynamic>,
) {
self.variables.push((name.into(), access, value)); self.variables.push((name.into(), access, value));
} }
/// Look up a constant from the list. /// Look up a constant from the list.
@ -129,8 +134,7 @@ impl<'a> OptimizerState<'a> {
if n == name { if n == name {
return match access { return match access {
AccessMode::ReadWrite => None, AccessMode::ReadWrite => None,
AccessMode::ReadOnly if value.is_null() => None, AccessMode::ReadOnly => value.as_ref(),
AccessMode::ReadOnly => Some(value),
}; };
} }
} }
@ -144,7 +148,7 @@ impl<'a> OptimizerState<'a> {
fn_name: &str, fn_name: &str,
op_token: Token, op_token: Token,
arg_values: &mut [Dynamic], arg_values: &mut [Dynamic],
) -> Dynamic { ) -> Option<Dynamic> {
self.engine self.engine
.exec_native_fn_call( .exec_native_fn_call(
&mut self.global, &mut self.global,
@ -156,7 +160,8 @@ impl<'a> OptimizerState<'a> {
false, false,
Position::NONE, Position::NONE,
) )
.map_or(Dynamic::NULL, |(v, ..)| v) .ok()
.map(|(v, ..)| v)
} }
} }
@ -234,13 +239,13 @@ fn optimize_stmt_block(
state.push_var( state.push_var(
x.0.as_str(), x.0.as_str(),
AccessMode::ReadOnly, AccessMode::ReadOnly,
x.1.get_literal_value().unwrap_or(Dynamic::NULL), x.1.get_literal_value(),
); );
} }
} else { } else {
// Add variables into the state // Add variables into the state
optimize_expr(&mut x.1, state, false); optimize_expr(&mut x.1, state, false);
state.push_var(x.0.as_str(), AccessMode::ReadWrite, Dynamic::NULL); state.push_var(x.0.as_str(), AccessMode::ReadWrite, None);
} }
} }
// Optimize the statement // Optimize the statement
@ -1190,15 +1195,15 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, _chaining: bool) {
let arg_values = &mut x.args.iter().map(Expr::get_literal_value).collect::<Option<StaticVec<_>>>().unwrap(); let arg_values = &mut x.args.iter().map(Expr::get_literal_value).collect::<Option<StaticVec<_>>>().unwrap();
let result = match x.name.as_str() { let result = match x.name.as_str() {
KEYWORD_TYPE_OF if arg_values.len() == 1 => state.engine.map_type_name(arg_values[0].type_name()).into(), KEYWORD_TYPE_OF if arg_values.len() == 1 => Some(state.engine.map_type_name(arg_values[0].type_name()).into()),
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
crate::engine::KEYWORD_IS_SHARED if arg_values.len() == 1 => Dynamic::FALSE, crate::engine::KEYWORD_IS_SHARED if arg_values.len() == 1 => Some(Dynamic::FALSE),
_ => state.call_fn_with_constant_arguments(&x.name, x.op_token.clone(), arg_values) _ => state.call_fn_with_constant_arguments(&x.name, x.op_token.clone(), arg_values)
}; };
if !result.is_null() { if let Some(r) = result {
state.set_dirty(); state.set_dirty();
*expr = Expr::from_dynamic(result, *pos); *expr = Expr::from_dynamic(r, *pos);
return; return;
} }
} }
@ -1303,15 +1308,15 @@ impl Engine {
// Add constants from global modules // Add constants from global modules
for (name, value) in self.global_modules.iter().rev().flat_map(|m| m.iter_var()) { for (name, value) in self.global_modules.iter().rev().flat_map(|m| m.iter_var()) {
state.push_var(name, AccessMode::ReadOnly, value.clone()); state.push_var(name, AccessMode::ReadOnly, Some(value.clone()));
} }
// Add constants and variables from the scope // Add constants and variables from the scope
for (name, constant, value) in scope.iter() { for (name, constant, value) in scope.iter() {
if constant { if constant {
state.push_var(name, AccessMode::ReadOnly, value); state.push_var(name, AccessMode::ReadOnly, Some(value));
} else { } else {
state.push_var(name, AccessMode::ReadWrite, Dynamic::NULL); state.push_var(name, AccessMode::ReadWrite, None);
} }
} }

View File

@ -2890,8 +2890,7 @@ impl Engine {
will_shadow, will_shadow,
}; };
let caches = &mut Caches::new(); let caches = &mut Caches::new();
let mut this_ptr = Dynamic::NULL; let context = EvalContext::new(self, global, caches, stack, None);
let context = EvalContext::new(self, global, caches, stack, &mut this_ptr);
match filter(false, info, context) { match filter(false, info, context) {
Ok(true) => (), Ok(true) => (),

View File

@ -125,8 +125,6 @@ impl<'de> Deserializer<'de> for DynamicDeserializer<'de> {
fn deserialize_any<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> { fn deserialize_any<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
match self.0 .0 { match self.0 .0 {
Union::Null => unreachable!(),
Union::Unit(..) => self.deserialize_unit(visitor), Union::Unit(..) => self.deserialize_unit(visitor),
Union::Bool(..) => self.deserialize_bool(visitor), Union::Bool(..) => self.deserialize_bool(visitor),
Union::Str(..) => self.deserialize_str(visitor), Union::Str(..) => self.deserialize_str(visitor),

View File

@ -15,8 +15,6 @@ use crate::types::dynamic::Variant;
impl Serialize for Dynamic { impl Serialize for Dynamic {
fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> { fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
match self.0 { match self.0 {
Union::Null => unreachable!(),
Union::Unit(..) => ser.serialize_unit(), Union::Unit(..) => ser.serialize_unit(),
Union::Bool(x, ..) => ser.serialize_bool(x), Union::Bool(x, ..) => ser.serialize_bool(x),
Union::Str(ref s, ..) => ser.serialize_str(s.as_str()), Union::Str(ref s, ..) => ser.serialize_str(s.as_str()),

View File

@ -57,9 +57,6 @@ pub struct Dynamic(pub(crate) Union);
/// Most variants are boxed to reduce the size. /// Most variants are boxed to reduce the size.
#[must_use] #[must_use]
pub enum Union { pub enum Union {
/// An error value which should not exist.
Null,
/// The Unit value - (). /// The Unit value - ().
Unit((), Tag, AccessMode), Unit((), Tag, AccessMode),
/// A boolean value. /// A boolean value.
@ -187,8 +184,6 @@ impl Dynamic {
#[must_use] #[must_use]
pub const fn tag(&self) -> Tag { pub const fn tag(&self) -> Tag {
match self.0 { match self.0 {
Union::Null => unreachable!(),
Union::Unit(_, tag, _) Union::Unit(_, tag, _)
| Union::Bool(_, tag, _) | Union::Bool(_, tag, _)
| Union::Str(_, tag, _) | Union::Str(_, tag, _)
@ -214,8 +209,6 @@ impl Dynamic {
/// Attach arbitrary data to this [`Dynamic`]. /// Attach arbitrary data to this [`Dynamic`].
pub fn set_tag(&mut self, value: Tag) -> &mut Self { pub fn set_tag(&mut self, value: Tag) -> &mut Self {
match self.0 { match self.0 {
Union::Null => unreachable!(),
Union::Unit(_, ref mut tag, _) Union::Unit(_, ref mut tag, _)
| Union::Bool(_, ref mut tag, _) | Union::Bool(_, ref mut tag, _)
| Union::Str(_, ref mut tag, _) | Union::Str(_, ref mut tag, _)
@ -239,12 +232,6 @@ impl Dynamic {
} }
self self
} }
/// Is this [`Dynamic`] null?
#[inline(always)]
#[must_use]
pub(crate) const fn is_null(&self) -> bool {
matches!(self.0, Union::Null)
}
/// Does this [`Dynamic`] hold a variant data type instead of one of the supported system /// Does this [`Dynamic`] hold a variant data type instead of one of the supported system
/// primitive types? /// primitive types?
#[inline(always)] #[inline(always)]
@ -334,8 +321,6 @@ impl Dynamic {
#[must_use] #[must_use]
pub fn type_id(&self) -> TypeId { pub fn type_id(&self) -> TypeId {
match self.0 { match self.0 {
Union::Null => unreachable!(),
Union::Unit(..) => TypeId::of::<()>(), Union::Unit(..) => TypeId::of::<()>(),
Union::Bool(..) => TypeId::of::<bool>(), Union::Bool(..) => TypeId::of::<bool>(),
Union::Str(..) => TypeId::of::<ImmutableString>(), Union::Str(..) => TypeId::of::<ImmutableString>(),
@ -370,8 +355,6 @@ impl Dynamic {
#[must_use] #[must_use]
pub fn type_name(&self) -> &'static str { pub fn type_name(&self) -> &'static str {
match self.0 { match self.0 {
Union::Null => unreachable!(),
Union::Unit(..) => "()", Union::Unit(..) => "()",
Union::Bool(..) => "bool", Union::Bool(..) => "bool",
Union::Str(..) => "string", Union::Str(..) => "string",
@ -416,8 +399,6 @@ impl Hash for Dynamic {
mem::discriminant(&self.0).hash(state); mem::discriminant(&self.0).hash(state);
match self.0 { match self.0 {
Union::Null => unreachable!(),
Union::Unit(..) => (), Union::Unit(..) => (),
Union::Bool(ref b, ..) => b.hash(state), Union::Bool(ref b, ..) => b.hash(state),
Union::Str(ref s, ..) => s.hash(state), Union::Str(ref s, ..) => s.hash(state),
@ -449,8 +430,6 @@ impl Hash for Dynamic {
impl fmt::Display for Dynamic { impl fmt::Display for Dynamic {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.0 { match self.0 {
Union::Null => unreachable!(),
Union::Unit(..) => Ok(()), Union::Unit(..) => Ok(()),
Union::Bool(ref v, ..) => fmt::Display::fmt(v, f), Union::Bool(ref v, ..) => fmt::Display::fmt(v, f),
Union::Str(ref v, ..) => fmt::Display::fmt(v, f), Union::Str(ref v, ..) => fmt::Display::fmt(v, f),
@ -544,8 +523,6 @@ impl fmt::Debug for Dynamic {
#[inline(never)] #[inline(never)]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.0 { match self.0 {
Union::Null => unreachable!(),
Union::Unit(ref v, ..) => fmt::Debug::fmt(v, f), Union::Unit(ref v, ..) => fmt::Debug::fmt(v, f),
Union::Bool(ref v, ..) => fmt::Debug::fmt(v, f), Union::Bool(ref v, ..) => fmt::Debug::fmt(v, f),
Union::Str(ref v, ..) => fmt::Debug::fmt(v, f), Union::Str(ref v, ..) => fmt::Debug::fmt(v, f),
@ -657,8 +634,6 @@ impl Clone for Dynamic {
/// The cloned copy is marked read-write even if the original is read-only. /// The cloned copy is marked read-write even if the original is read-only.
fn clone(&self) -> Self { fn clone(&self) -> Self {
match self.0 { match self.0 {
Union::Null => unreachable!(),
Union::Unit(v, tag, ..) => Self(Union::Unit(v, tag, ReadWrite)), Union::Unit(v, tag, ..) => Self(Union::Unit(v, tag, ReadWrite)),
Union::Bool(v, tag, ..) => Self(Union::Bool(v, tag, ReadWrite)), Union::Bool(v, tag, ..) => Self(Union::Bool(v, tag, ReadWrite)),
Union::Str(ref v, tag, ..) => Self(Union::Str(v.clone(), tag, ReadWrite)), Union::Str(ref v, tag, ..) => Self(Union::Str(v.clone(), tag, ReadWrite)),
@ -705,9 +680,6 @@ use std::f32::consts as FloatConstants;
use std::f64::consts as FloatConstants; use std::f64::consts as FloatConstants;
impl Dynamic { impl Dynamic {
/// A [`Dynamic`] containing a `null`.
pub(crate) const NULL: Self = Self(Union::Null);
/// A [`Dynamic`] containing a `()`. /// A [`Dynamic`] containing a `()`.
pub const UNIT: Self = Self(Union::Unit((), DEFAULT_TAG_VALUE, ReadWrite)); pub const UNIT: Self = Self(Union::Unit((), DEFAULT_TAG_VALUE, ReadWrite));
/// A [`Dynamic`] containing a `true`. /// A [`Dynamic`] containing a `true`.
@ -921,8 +893,6 @@ impl Dynamic {
#[must_use] #[must_use]
pub(crate) const fn access_mode(&self) -> AccessMode { pub(crate) const fn access_mode(&self) -> AccessMode {
match self.0 { match self.0 {
Union::Null => unreachable!(),
Union::Unit(.., access) Union::Unit(.., access)
| Union::Bool(.., access) | Union::Bool(.., access)
| Union::Str(.., access) | Union::Str(.., access)
@ -948,8 +918,6 @@ impl Dynamic {
/// Set the [`AccessMode`] for this [`Dynamic`]. /// Set the [`AccessMode`] for this [`Dynamic`].
pub(crate) fn set_access_mode(&mut self, typ: AccessMode) -> &mut Self { pub(crate) fn set_access_mode(&mut self, typ: AccessMode) -> &mut Self {
match self.0 { match self.0 {
Union::Null => unreachable!(),
Union::Unit(.., ref mut access) Union::Unit(.., ref mut access)
| Union::Bool(.., ref mut access) | Union::Bool(.., ref mut access)
| Union::Str(.., ref mut access) | Union::Str(.., ref mut access)
@ -1138,7 +1106,6 @@ impl Dynamic {
let _access = self.access_mode(); let _access = self.access_mode();
match self.0 { match self.0 {
Union::Null => unreachable!(),
Union::Shared(..) => self, Union::Shared(..) => self,
_ => Self(Union::Shared( _ => Self(Union::Shared(
crate::Locked::new(self).into(), crate::Locked::new(self).into(),
@ -1584,7 +1551,6 @@ impl Dynamic {
} }
match self.0 { match self.0 {
Union::Null => unreachable!(),
Union::Variant(ref v, ..) => (***v).as_any().downcast_ref::<T>(), Union::Variant(ref v, ..) => (***v).as_any().downcast_ref::<T>(),
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
Union::Shared(..) => None, Union::Shared(..) => None,
@ -1683,7 +1649,6 @@ impl Dynamic {
} }
match self.0 { match self.0 {
Union::Null => unreachable!(),
Union::Variant(ref mut v, ..) => (***v).as_any_mut().downcast_mut::<T>(), Union::Variant(ref mut v, ..) => (***v).as_any_mut().downcast_mut::<T>(),
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
Union::Shared(..) => None, Union::Shared(..) => None,

View File

@ -298,19 +298,19 @@ impl FnPtr {
// Linked to scripted function? // Linked to scripted function?
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
if let Some(fn_def) = self.fn_def() { if let Some(ref fn_def) = self.fn_def {
if fn_def.params.len() == args.len() { if fn_def.params.len() == args.len() {
let global = &mut context.global_runtime_state().clone(); let global = &mut context.global_runtime_state().clone();
global.level += 1; global.level += 1;
let caches = &mut crate::eval::Caches::new(); let caches = &mut crate::eval::Caches::new();
let mut null_ptr = Dynamic::NULL; let mut this_ptr = this_ptr;
return context.engine().call_script_fn( return context.engine().call_script_fn(
global, global,
caches, caches,
&mut crate::Scope::new(), &mut crate::Scope::new(),
this_ptr.unwrap_or(&mut null_ptr), this_ptr.as_deref_mut(),
self.encapsulated_environ(), self.encapsulated_environ(),
&fn_def, &fn_def,
args, args,
@ -348,8 +348,8 @@ impl FnPtr {
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub(crate) fn fn_def(&self) -> Option<&Shared<crate::ast::ScriptFnDef>> { pub(crate) fn fn_def(&self) -> Option<&crate::ast::ScriptFnDef> {
self.fn_def.as_ref() self.fn_def.as_deref()
} }
/// Set a reference to the linked [`ScriptFnDef`][crate::ast::ScriptFnDef]. /// Set a reference to the linked [`ScriptFnDef`][crate::ast::ScriptFnDef].
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
@ -410,12 +410,11 @@ impl FnPtr {
extras: [Dynamic; E], extras: [Dynamic; E],
) -> RhaiResult { ) -> RhaiResult {
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
{ if let Some(arity) = self.fn_def().map(|f| f.params.len()) {
let arity = self.fn_def().map(|f| f.params.len()).unwrap_or(0);
if arity == N { if arity == N {
return self.call_raw(&ctx, None, items); return self.call_raw(&ctx, None, items);
} else if arity == N + E { }
if arity == N + E {
let mut items2 = FnArgsVec::with_capacity(items.len() + extras.len()); let mut items2 = FnArgsVec::with_capacity(items.len() + extras.len());
items2.extend(IntoIterator::into_iter(items)); items2.extend(IntoIterator::into_iter(items));
items2.extend(IntoIterator::into_iter(extras)); items2.extend(IntoIterator::into_iter(extras));