Remove Dynamic::NULL, use .as_deref_mut() for this_ptr.
This commit is contained in:
parent
99080be91d
commit
babc0b5466
@ -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"))]
|
||||||
|
@ -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)
|
||||||
})
|
})
|
||||||
|
@ -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(())
|
||||||
})
|
})
|
||||||
|
@ -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));
|
||||||
|
@ -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>> {
|
||||||
|
@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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(..) => {
|
||||||
|
111
src/func/call.rs
111
src/func/call.rs
@ -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();
|
||||||
|
|
||||||
|
@ -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),
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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) => (),
|
||||||
|
@ -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),
|
||||||
|
@ -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()),
|
||||||
|
@ -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,
|
||||||
|
@ -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));
|
||||||
|
Loading…
Reference in New Issue
Block a user