From 3a028f2642f7da8b1ecaecd843cf505362b16fa3 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Thu, 10 Nov 2022 11:49:10 +0800 Subject: [PATCH] Move lib into global. --- src/api/call_fn.rs | 43 +++++----- src/api/eval.rs | 58 ++++++------- src/api/optimize.rs | 4 +- src/api/run.rs | 23 ++---- src/ast/ast.rs | 17 ++++ src/eval/chaining.rs | 173 +++++++++++++++++---------------------- src/eval/debugger.rs | 16 ++-- src/eval/eval_context.rs | 22 ++--- src/eval/expr.rs | 52 ++++++------ src/eval/global_state.rs | 60 ++++---------- src/eval/stmt.rs | 130 +++++++++++++---------------- src/func/call.rs | 121 ++++++++++++--------------- src/func/native.rs | 21 +---- src/func/script.rs | 53 ++++-------- src/module/mod.rs | 2 + src/optimizer.rs | 25 ++---- src/parser.rs | 10 +-- src/tests.rs | 4 +- src/types/fn_ptr.rs | 19 ++--- 19 files changed, 353 insertions(+), 500 deletions(-) diff --git a/src/api/call_fn.rs b/src/api/call_fn.rs index 1a78cae1..f7e5bfee 100644 --- a/src/api/call_fn.rs +++ b/src/api/call_fn.rs @@ -3,9 +3,10 @@ use crate::eval::{Caches, GlobalRuntimeState}; use crate::types::dynamic::Variant; +use crate::types::RestoreOnDrop; use crate::{ - reify, Dynamic, Engine, FuncArgs, Position, RhaiResult, RhaiResultOf, Scope, SharedModule, - StaticVec, AST, ERR, + reify, Dynamic, Engine, FuncArgs, Position, RhaiResult, RhaiResultOf, Scope, StaticVec, AST, + ERR, }; use std::any::{type_name, TypeId}; #[cfg(feature = "no_std")] @@ -248,31 +249,30 @@ impl Engine { arg_values: &mut [Dynamic], ) -> RhaiResult { let statements = ast.statements(); - let lib = &[AsRef::::as_ref(ast).clone()]; + + let orig_lib_len = global.lib.len(); + + #[cfg(not(feature = "no_function"))] + if !ast.functions().is_empty() { + global.lib.push(ast.functions().clone()); + } let mut no_this_ptr = Dynamic::NULL; let this_ptr = this_ptr.unwrap_or(&mut no_this_ptr); - let orig_scope_len = scope.len(); - #[cfg(not(feature = "no_module"))] let orig_embedded_module_resolver = std::mem::replace( &mut global.embedded_module_resolver, ast.resolver().cloned(), ); - #[cfg(not(feature = "no_module"))] - let global = &mut *crate::types::RestoreOnDrop::lock(global, move |g| { - g.embedded_module_resolver = orig_embedded_module_resolver - }); let result = if eval_ast && !statements.is_empty() { - let r = self.eval_global_statements(global, caches, lib, scope, statements); + let orig_scope_len = scope.len(); + let scope = &mut *RestoreOnDrop::lock_if(rewind_scope, scope, move |s| { + s.rewind(orig_scope_len); + }); - if rewind_scope { - scope.rewind(orig_scope_len); - } - - r + self.eval_global_statements(global, caches, scope, statements) } else { Ok(Dynamic::UNIT) } @@ -287,7 +287,6 @@ impl Engine { self.call_script_fn( global, caches, - lib, scope, this_ptr, fn_def, @@ -298,15 +297,21 @@ impl Engine { } else { Err(ERR::ErrorFunctionNotFound(name.into(), Position::NONE).into()) } - })?; + }); #[cfg(feature = "debugging")] if self.debugger.is_some() { global.debugger.status = crate::eval::DebuggerStatus::Terminate; let node = &crate::ast::Stmt::Noop(Position::NONE); - self.run_debugger(global, caches, lib, scope, this_ptr, node)?; + self.run_debugger(global, caches, scope, this_ptr, node)?; } - Ok(result) + #[cfg(not(feature = "no_module"))] + { + global.embedded_module_resolver = orig_embedded_module_resolver; + } + global.lib.truncate(orig_lib_len); + + result } } diff --git a/src/api/eval.rs b/src/api/eval.rs index 10cf9040..111e2828 100644 --- a/src/api/eval.rs +++ b/src/api/eval.rs @@ -6,9 +6,9 @@ use crate::types::dynamic::Variant; use crate::{ Dynamic, Engine, OptimizationLevel, Position, RhaiResult, RhaiResultOf, Scope, AST, ERR, }; -use std::any::type_name; #[cfg(feature = "no_std")] use std::prelude::v1::*; +use std::{any::type_name, mem}; impl Engine { /// Evaluate a string as a script, returning the result value or an error. @@ -190,19 +190,6 @@ impl Engine { let result = self.eval_ast_with_scope_raw(global, caches, scope, ast)?; - #[cfg(feature = "debugging")] - if self.debugger.is_some() { - global.debugger.status = crate::eval::DebuggerStatus::Terminate; - let lib = &[ - #[cfg(not(feature = "no_function"))] - AsRef::::as_ref(ast).clone(), - ]; - let mut this = Dynamic::NULL; - let node = &crate::ast::Stmt::Noop(Position::NONE); - - self.run_debugger(global, caches, lib, scope, &mut this, node)?; - } - let typ = self.map_type_name(result.type_name()); result.try_cast::().ok_or_else(|| { @@ -216,21 +203,22 @@ impl Engine { &self, global: &mut GlobalRuntimeState, caches: &mut Caches, - scope: &mut Scope, ast: &'a AST, ) -> RhaiResult { - global.source = ast.source_raw().cloned(); + let orig_source = mem::replace(&mut global.source, ast.source_raw().cloned()); + let orig_lib_len = global.lib.len(); + + #[cfg(not(feature = "no_function"))] + if !ast.functions().is_empty() { + global.lib.push(ast.functions().clone()); + } #[cfg(not(feature = "no_module"))] - let orig_embedded_module_resolver = std::mem::replace( + let orig_embedded_module_resolver = mem::replace( &mut global.embedded_module_resolver, ast.resolver().cloned(), ); - #[cfg(not(feature = "no_module"))] - let global = &mut *crate::types::RestoreOnDrop::lock(global, move |g| { - g.embedded_module_resolver = orig_embedded_module_resolver - }); let statements = ast.statements(); @@ -238,12 +226,26 @@ impl Engine { return Ok(Dynamic::UNIT); } - let lib = &[ - #[cfg(not(feature = "no_function"))] - AsRef::::as_ref(ast).clone(), - ]; + let result = self.eval_global_statements(global, caches, scope, statements); - self.eval_global_statements(global, caches, lib, scope, statements) + #[cfg(feature = "debugging")] + if self.debugger.is_some() { + global.debugger.status = crate::eval::DebuggerStatus::Terminate; + let mut this = Dynamic::NULL; + let node = &crate::ast::Stmt::Noop(Position::NONE); + + self.run_debugger(global, caches, scope, &mut this, node)?; + } + + #[cfg(not(feature = "no_module"))] + { + global.embedded_module_resolver = orig_embedded_module_resolver; + } + + global.lib.truncate(orig_lib_len); + global.source = orig_source; + + result } /// _(internals)_ Evaluate a list of statements with no `this` pointer. /// Exported under the `internals` feature only. @@ -259,12 +261,10 @@ impl Engine { &self, global: &mut GlobalRuntimeState, caches: &mut Caches, - lib: &[crate::SharedModule], - scope: &mut Scope, statements: &[crate::ast::Stmt], ) -> RhaiResult { - self.eval_global_statements(global, caches, lib, scope, statements) + self.eval_global_statements(global, caches, scope, statements) } } diff --git a/src/api/optimize.rs b/src/api/optimize.rs index f790a803..0baccba6 100644 --- a/src/api/optimize.rs +++ b/src/api/optimize.rs @@ -52,7 +52,7 @@ impl Engine { let mut ast = ast; #[cfg(not(feature = "no_function"))] - let lib = ast + let functions = ast .shared_lib() .iter_fn() .filter(|f| f.func.is_script()) @@ -64,7 +64,7 @@ impl Engine { scope, ast.take_statements(), #[cfg(not(feature = "no_function"))] - lib, + functions, optimization_level, ); diff --git a/src/api/run.rs b/src/api/run.rs index 551b5e98..08206088 100644 --- a/src/api/run.rs +++ b/src/api/run.rs @@ -2,7 +2,7 @@ use crate::eval::{Caches, GlobalRuntimeState}; use crate::parser::ParseState; -use crate::{Engine, RhaiResultOf, Scope, SharedModule, AST}; +use crate::{Engine, RhaiResultOf, Scope, AST}; #[cfg(feature = "no_std")] use std::prelude::v1::*; @@ -115,6 +115,10 @@ impl Engine { let global = &mut GlobalRuntimeState::new(self); global.source = ast.source_raw().cloned(); + #[cfg(not(feature = "no_function"))] + if !ast.functions().is_empty() { + global.lib.push(ast.functions().clone()); + } #[cfg(not(feature = "no_module"))] { global.embedded_module_resolver = ast.resolver().cloned(); @@ -122,28 +126,15 @@ impl Engine { let statements = ast.statements(); if !statements.is_empty() { - let lib: &[SharedModule] = &[ - #[cfg(not(feature = "no_function"))] - AsRef::::as_ref(ast).clone(), - ]; - let lib = if lib.first().map_or(true, |m| m.is_empty()) { - &[][..] - } else { - &lib - }; - self.eval_global_statements(global, caches, lib, scope, statements)?; + self.eval_global_statements(global, caches, scope, statements)?; } #[cfg(feature = "debugging")] if self.debugger.is_some() { global.debugger.status = crate::eval::DebuggerStatus::Terminate; - let lib = &[ - #[cfg(not(feature = "no_function"))] - AsRef::::as_ref(ast).clone(), - ]; let mut this = crate::Dynamic::NULL; let node = &crate::ast::Stmt::Noop(crate::Position::NONE); - self.run_debugger(global, caches, lib, scope, &mut this, node)?; + self.run_debugger(global, caches, scope, &mut this, node)?; } Ok(()) diff --git a/src/ast/ast.rs b/src/ast/ast.rs index c1cfbaed..26226f6e 100644 --- a/src/ast/ast.rs +++ b/src/ast/ast.rs @@ -231,6 +231,23 @@ impl AST { pub(crate) fn set_doc(&mut self, doc: impl Into) { self.doc = doc.into(); } + /// Get the shared [module][crate::Module] containing script-defined functions. + #[cfg(not(feature = "no_function"))] + #[cfg(not(feature = "internals"))] + #[inline(always)] + #[must_use] + pub(crate) fn functions(&self) -> &crate::SharedModule { + &self.lib + } + /// _(internals)_ Get the shared [module][crate::Module] containing script-defined functions. + /// Exported under the `internals` feature only. + #[cfg(not(feature = "no_function"))] + #[cfg(feature = "internals")] + #[inline(always)] + #[must_use] + pub fn functions(&self) -> &crate::SharedModule { + &self.lib + } /// Get the statements. #[cfg(not(feature = "internals"))] #[inline(always)] diff --git a/src/eval/chaining.rs b/src/eval/chaining.rs index 231e915a..339afd8d 100644 --- a/src/eval/chaining.rs +++ b/src/eval/chaining.rs @@ -5,9 +5,7 @@ use super::{Caches, GlobalRuntimeState, Target}; use crate::ast::{ASTFlags, Expr, OpAssignment}; use crate::types::dynamic::Union; use crate::types::RestoreOnDrop; -use crate::{ - Dynamic, Engine, FnArgsVec, Position, RhaiResult, RhaiResultOf, Scope, SharedModule, ERR, -}; +use crate::{Dynamic, Engine, FnArgsVec, Position, RhaiResult, RhaiResultOf, Scope, ERR}; use std::hash::Hash; #[cfg(feature = "no_std")] use std::prelude::v1::*; @@ -43,7 +41,6 @@ impl Engine { &self, global: &mut GlobalRuntimeState, caches: &mut Caches, - lib: &[SharedModule], this_ptr: &mut Dynamic, target: &mut Target, root: (&str, Position), @@ -75,7 +72,7 @@ impl Engine { if !parent_options.contains(ASTFlags::BREAK) => { #[cfg(feature = "debugging")] - self.run_debugger(global, caches, lib, scope, this_ptr, _parent)?; + self.run_debugger(global, caches, scope, this_ptr, _parent)?; let idx_val = &mut idx_values.pop().unwrap(); let mut idx_val_for_setter = idx_val.clone(); @@ -84,14 +81,14 @@ impl Engine { let (try_setter, result) = { let mut obj = self.get_indexed_mut( - global, caches, lib, target, idx_val, idx_pos, false, true, + global, caches, target, idx_val, idx_pos, false, true, )?; let is_obj_temp_val = obj.is_temp_value(); let obj_ptr = &mut obj; match self.eval_dot_index_chain_helper( - global, caches, lib, this_ptr, obj_ptr, root, rhs, *options, - &x.rhs, idx_values, rhs_chain, new_val, + global, caches, this_ptr, obj_ptr, root, rhs, *options, &x.rhs, + idx_values, rhs_chain, new_val, ) { Ok((result, true)) if is_obj_temp_val => { (Some(obj.take_or_clone()), (result, true)) @@ -105,13 +102,11 @@ impl Engine { // Try to call index setter if value is changed let idx = &mut idx_val_for_setter; let new_val = &mut new_val; - self.call_indexer_set( - global, caches, lib, target, idx, new_val, is_ref_mut, - ) - .or_else(|e| match *e { - ERR::ErrorIndexingType(..) => Ok((Dynamic::UNIT, false)), - _ => Err(e), - })?; + self.call_indexer_set(global, caches, target, idx, new_val, is_ref_mut) + .or_else(|e| match *e { + ERR::ErrorIndexingType(..) => Ok((Dynamic::UNIT, false)), + _ => Err(e), + })?; } Ok(result) @@ -119,19 +114,19 @@ impl Engine { // xxx[rhs] op= new_val _ if new_val.is_some() => { #[cfg(feature = "debugging")] - self.run_debugger(global, caches, lib, scope, this_ptr, _parent)?; + self.run_debugger(global, caches, scope, this_ptr, _parent)?; let (new_val, op_info) = new_val.take().expect("`Some`"); let idx_val = &mut idx_values.pop().unwrap(); let idx = &mut idx_val.clone(); let try_setter = match self - .get_indexed_mut(global, caches, lib, target, idx, pos, true, false) + .get_indexed_mut(global, caches, target, idx, pos, true, false) { // Indexed value is not a temp value - update directly Ok(ref mut obj_ptr) => { self.eval_op_assignment( - global, caches, lib, op_info, obj_ptr, root, new_val, + global, caches, op_info, obj_ptr, root, new_val, )?; self.check_data_size(obj_ptr, op_info.pos)?; None @@ -149,13 +144,12 @@ impl Engine { let idx = &mut idx_val.clone(); // Call the index getter to get the current value - if let Ok(val) = - self.call_indexer_get(global, caches, lib, target, idx) + if let Ok(val) = self.call_indexer_get(global, caches, target, idx) { let mut val = val.into(); // Run the op-assignment self.eval_op_assignment( - global, caches, lib, op_info, &mut val, root, new_val, + global, caches, op_info, &mut val, root, new_val, )?; // Replace new value new_val = val.take_or_clone(); @@ -167,7 +161,7 @@ impl Engine { let new_val = &mut new_val; self.call_indexer_set( - global, caches, lib, target, idx_val, new_val, is_ref_mut, + global, caches, target, idx_val, new_val, is_ref_mut, )?; } @@ -176,11 +170,11 @@ impl Engine { // xxx[rhs] _ => { #[cfg(feature = "debugging")] - self.run_debugger(global, caches, lib, scope, this_ptr, _parent)?; + self.run_debugger(global, caches, scope, this_ptr, _parent)?; let idx_val = &mut idx_values.pop().unwrap(); - self.get_indexed_mut(global, caches, lib, target, idx_val, pos, false, true) + self.get_indexed_mut(global, caches, target, idx_val, pos, false, true) .map(|v| (v.take_or_clone(), false)) } } @@ -197,8 +191,8 @@ impl Engine { // xxx.fn_name(arg_expr_list) Expr::MethodCall(x, pos) if !x.is_qualified() && new_val.is_none() => { #[cfg(feature = "debugging")] - let reset = self - .run_debugger_with_reset(global, caches, lib, scope, this_ptr, rhs)?; + let reset = + self.run_debugger_with_reset(global, caches, scope, this_ptr, rhs)?; #[cfg(feature = "debugging")] let global = &mut *RestoreOnDrop::lock(global, move |g| { g.debugger.reset_status(reset) @@ -217,7 +211,7 @@ impl Engine { let pos1 = args.get(0).map_or(Position::NONE, Expr::position); self.make_method_call( - global, caches, lib, name, *hashes, target, call_args, pos1, *pos, + global, caches, name, *hashes, target, call_args, pos1, *pos, ) } // xxx.fn_name(...) = ??? @@ -231,16 +225,16 @@ impl Engine { // {xxx:map}.id op= ??? Expr::Property(x, pos) if target.is_map() && new_val.is_some() => { #[cfg(feature = "debugging")] - self.run_debugger(global, caches, lib, scope, this_ptr, rhs)?; + self.run_debugger(global, caches, scope, this_ptr, rhs)?; let index = &mut x.2.clone().into(); let (new_val, op_info) = new_val.take().expect("`Some`"); { let val_target = &mut self.get_indexed_mut( - global, caches, lib, target, index, *pos, true, false, + global, caches, target, index, *pos, true, false, )?; self.eval_op_assignment( - global, caches, lib, op_info, val_target, root, new_val, + global, caches, op_info, val_target, root, new_val, )?; } self.check_data_size(target.source(), op_info.pos)?; @@ -249,18 +243,17 @@ impl Engine { // {xxx:map}.id Expr::Property(x, pos) if target.is_map() => { #[cfg(feature = "debugging")] - self.run_debugger(global, caches, lib, scope, this_ptr, rhs)?; + self.run_debugger(global, caches, scope, this_ptr, rhs)?; let index = &mut x.2.clone().into(); - let val = self.get_indexed_mut( - global, caches, lib, target, index, *pos, false, false, - )?; + let val = self + .get_indexed_mut(global, caches, target, index, *pos, false, false)?; Ok((val.take_or_clone(), false)) } // xxx.id op= ??? Expr::Property(x, pos) if new_val.is_some() => { #[cfg(feature = "debugging")] - self.run_debugger(global, caches, lib, scope, this_ptr, rhs)?; + self.run_debugger(global, caches, scope, this_ptr, rhs)?; let ((getter, hash_get), (setter, hash_set), name) = &**x; let (mut new_val, op_info) = new_val.take().expect("`Some`"); @@ -269,23 +262,18 @@ impl Engine { let args = &mut [target.as_mut()]; let (mut orig_val, ..) = self .exec_native_fn_call( - global, caches, lib, getter, None, *hash_get, args, is_ref_mut, - *pos, + global, caches, getter, None, *hash_get, args, is_ref_mut, *pos, ) .or_else(|err| match *err { // Try an indexer if property does not exist ERR::ErrorDotExpr(..) => { let mut prop = name.into(); - self.call_indexer_get( - global, caches, lib, target, &mut prop, - ) - .map(|r| (r, false)) - .map_err(|e| { - match *e { + self.call_indexer_get(global, caches, target, &mut prop) + .map(|r| (r, false)) + .map_err(|e| match *e { ERR::ErrorIndexingType(..) => err, _ => e, - } - }) + }) } _ => Err(err), })?; @@ -294,7 +282,7 @@ impl Engine { let orig_val = &mut (&mut orig_val).into(); self.eval_op_assignment( - global, caches, lib, op_info, orig_val, root, new_val, + global, caches, op_info, orig_val, root, new_val, )?; } @@ -303,7 +291,7 @@ impl Engine { let args = &mut [target.as_mut(), &mut new_val]; self.exec_native_fn_call( - global, caches, lib, setter, None, *hash_set, args, is_ref_mut, *pos, + global, caches, setter, None, *hash_set, args, is_ref_mut, *pos, ) .or_else(|err| match *err { // Try an indexer if property does not exist @@ -311,7 +299,7 @@ impl Engine { let idx = &mut name.into(); let new_val = &mut new_val; self.call_indexer_set( - global, caches, lib, target, idx, new_val, is_ref_mut, + global, caches, target, idx, new_val, is_ref_mut, ) .map_err(|e| match *e { ERR::ErrorIndexingType(..) => err, @@ -324,19 +312,19 @@ impl Engine { // xxx.id Expr::Property(x, pos) => { #[cfg(feature = "debugging")] - self.run_debugger(global, caches, lib, scope, this_ptr, rhs)?; + self.run_debugger(global, caches, scope, this_ptr, rhs)?; let ((getter, hash_get), _, name) = &**x; let args = &mut [target.as_mut()]; self.exec_native_fn_call( - global, caches, lib, getter, None, *hash_get, args, is_ref_mut, *pos, + global, caches, getter, None, *hash_get, args, is_ref_mut, *pos, ) .map_or_else( |err| match *err { // Try an indexer if property does not exist ERR::ErrorDotExpr(..) => { let mut prop = name.into(); - self.call_indexer_get(global, caches, lib, target, &mut prop) + self.call_indexer_get(global, caches, target, &mut prop) .map(|r| (r, false)) .map_err(|e| match *e { ERR::ErrorIndexingType(..) => err, @@ -358,18 +346,18 @@ impl Engine { let val_target = &mut match x.lhs { Expr::Property(ref p, pos) => { #[cfg(feature = "debugging")] - self.run_debugger(global, caches, lib, scope, this_ptr, _node)?; + self.run_debugger(global, caches, scope, this_ptr, _node)?; let index = &mut p.2.clone().into(); self.get_indexed_mut( - global, caches, lib, target, index, pos, false, true, + global, caches, target, index, pos, false, true, )? } // {xxx:map}.fn_name(arg_expr_list)[expr] | {xxx:map}.fn_name(arg_expr_list).expr Expr::MethodCall(ref x, pos) if !x.is_qualified() => { #[cfg(feature = "debugging")] let reset = self.run_debugger_with_reset( - global, caches, lib, scope, this_ptr, _node, + global, caches, scope, this_ptr, _node, )?; #[cfg(feature = "debugging")] let global = &mut *RestoreOnDrop::lock(global, move |g| { @@ -390,8 +378,7 @@ impl Engine { let pos1 = args.get(0).map_or(Position::NONE, Expr::position); self.make_method_call( - global, caches, lib, name, *hashes, target, call_args, pos1, - pos, + global, caches, name, *hashes, target, call_args, pos1, pos, )? .0 .into() @@ -406,7 +393,7 @@ impl Engine { let rhs_chain = rhs.into(); self.eval_dot_index_chain_helper( - global, caches, lib, this_ptr, val_target, root, rhs, *options, &x.rhs, + global, caches, this_ptr, val_target, root, rhs, *options, &x.rhs, idx_values, rhs_chain, new_val, ) .map_err(|err| err.fill_position(*x_pos)) @@ -419,7 +406,7 @@ impl Engine { // xxx.prop[expr] | xxx.prop.expr Expr::Property(ref p, pos) => { #[cfg(feature = "debugging")] - self.run_debugger(global, caches, lib, scope, this_ptr, _node)?; + self.run_debugger(global, caches, scope, this_ptr, _node)?; let ((getter, hash_get), (setter, hash_set), name) = &**p; let rhs_chain = rhs.into(); @@ -429,23 +416,19 @@ impl Engine { // Assume getters are always pure let (mut val, ..) = self .exec_native_fn_call( - global, caches, lib, getter, None, *hash_get, args, - is_ref_mut, pos, + global, caches, getter, None, *hash_get, args, is_ref_mut, + pos, ) .or_else(|err| match *err { // Try an indexer if property does not exist ERR::ErrorDotExpr(..) => { let mut prop = name.into(); - self.call_indexer_get( - global, caches, lib, target, &mut prop, - ) - .map(|r| (r, false)) - .map_err( - |e| match *e { + self.call_indexer_get(global, caches, target, &mut prop) + .map(|r| (r, false)) + .map_err(|e| match *e { ERR::ErrorIndexingType(..) => err, _ => e, - }, - ) + }) } _ => Err(err), })?; @@ -454,8 +437,8 @@ impl Engine { let (result, may_be_changed) = self .eval_dot_index_chain_helper( - global, caches, lib, this_ptr, val, root, rhs, *options, - &x.rhs, idx_values, rhs_chain, new_val, + global, caches, this_ptr, val, root, rhs, *options, &x.rhs, + idx_values, rhs_chain, new_val, ) .map_err(|err| err.fill_position(*x_pos))?; @@ -465,8 +448,8 @@ impl Engine { let mut arg_values = [target.as_mut(), val.as_mut()]; let args = &mut arg_values; self.exec_native_fn_call( - global, caches, lib, setter, None, *hash_set, args, - is_ref_mut, pos, + global, caches, setter, None, *hash_set, args, is_ref_mut, + pos, ) .or_else( |err| match *err { @@ -475,7 +458,7 @@ impl Engine { let idx = &mut name.into(); let new_val = val; self.call_indexer_set( - global, caches, lib, target, idx, new_val, + global, caches, target, idx, new_val, is_ref_mut, ) .or_else(|e| match *e { @@ -499,7 +482,7 @@ impl Engine { let val = { #[cfg(feature = "debugging")] let reset = self.run_debugger_with_reset( - global, caches, lib, scope, this_ptr, _node, + global, caches, scope, this_ptr, _node, )?; #[cfg(feature = "debugging")] let global = &mut *RestoreOnDrop::lock(global, move |g| { @@ -521,8 +504,7 @@ impl Engine { let pos1 = args.get(0).map_or(Position::NONE, Expr::position); self.make_method_call( - global, caches, lib, name, *hashes, target, call_args, - pos1, pos, + global, caches, name, *hashes, target, call_args, pos1, pos, )? .0 }; @@ -531,8 +513,8 @@ impl Engine { let rhs_chain = rhs.into(); self.eval_dot_index_chain_helper( - global, caches, lib, this_ptr, val, root, rhs, *options, - &x.rhs, idx_values, rhs_chain, new_val, + global, caches, this_ptr, val, root, rhs, *options, &x.rhs, + idx_values, rhs_chain, new_val, ) .map_err(|err| err.fill_position(pos)) } @@ -556,7 +538,6 @@ impl Engine { &self, global: &mut GlobalRuntimeState, caches: &mut Caches, - lib: &[SharedModule], scope: &mut Scope, this_ptr: &mut Dynamic, expr: &Expr, @@ -597,7 +578,7 @@ impl Engine { // All other patterns - evaluate the arguments chain _ => { self.eval_dot_index_chain_arguments( - global, caches, lib, scope, this_ptr, rhs, options, chain_type, idx_values, + global, caches, scope, this_ptr, rhs, options, chain_type, idx_values, )?; } } @@ -606,18 +587,18 @@ impl Engine { // id.??? or id[???] Expr::Variable(x, .., var_pos) => { #[cfg(feature = "debugging")] - self.run_debugger(global, caches, lib, scope, this_ptr, lhs)?; + self.run_debugger(global, caches, scope, this_ptr, lhs)?; self.track_operation(global, *var_pos)?; let (mut target, ..) = - self.search_namespace(global, caches, lib, scope, this_ptr, lhs)?; + self.search_namespace(global, caches, scope, this_ptr, lhs)?; let obj_ptr = &mut target; let root = (x.3.as_str(), *var_pos); let mut this = Dynamic::NULL; self.eval_dot_index_chain_helper( - global, caches, lib, &mut this, obj_ptr, root, expr, options, rhs, idx_values, + global, caches, &mut this, obj_ptr, root, expr, options, rhs, idx_values, chain_type, new_val, ) } @@ -626,13 +607,13 @@ impl Engine { // {expr}.??? or {expr}[???] expr => { let value = self - .eval_expr(global, caches, lib, scope, this_ptr, expr)? + .eval_expr(global, caches, scope, this_ptr, expr)? .flatten(); let obj_ptr = &mut value.into(); let root = ("", expr.start_position()); self.eval_dot_index_chain_helper( - global, caches, lib, this_ptr, obj_ptr, root, expr, options, rhs, idx_values, + global, caches, this_ptr, obj_ptr, root, expr, options, rhs, idx_values, chain_type, new_val, ) } @@ -646,7 +627,6 @@ impl Engine { &self, global: &mut GlobalRuntimeState, caches: &mut Caches, - lib: &[SharedModule], scope: &mut Scope, this_ptr: &mut Dynamic, expr: &Expr, @@ -663,7 +643,7 @@ impl Engine { { for arg_expr in &x.args { idx_values.push( - self.get_arg_value(global, caches, lib, scope, this_ptr, arg_expr)? + self.get_arg_value(global, caches, scope, this_ptr, arg_expr)? .0 .flatten(), ); @@ -697,7 +677,7 @@ impl Engine { { for arg_expr in &x.args { _arg_values.push( - self.get_arg_value(global, caches, lib, scope, this_ptr, arg_expr)? + self.get_arg_value(global, caches, scope, this_ptr, arg_expr)? .0 .flatten(), ); @@ -714,7 +694,7 @@ impl Engine { #[cfg(not(feature = "no_index"))] _ if parent_chain_type == ChainType::Indexing => { _arg_values.push( - self.eval_expr(global, caches, lib, scope, this_ptr, lhs)? + self.eval_expr(global, caches, scope, this_ptr, lhs)? .flatten(), ); } @@ -725,7 +705,7 @@ impl Engine { let chain_type = expr.into(); self.eval_dot_index_chain_arguments( - global, caches, lib, scope, this_ptr, rhs, *options, chain_type, idx_values, + global, caches, scope, this_ptr, rhs, *options, chain_type, idx_values, )?; if !_arg_values.is_empty() { @@ -739,7 +719,7 @@ impl Engine { } #[cfg(not(feature = "no_index"))] _ if parent_chain_type == ChainType::Indexing => idx_values.push( - self.eval_expr(global, caches, lib, scope, this_ptr, expr)? + self.eval_expr(global, caches, scope, this_ptr, expr)? .flatten(), ), _ => unreachable!("unknown chained expression: {:?}", expr), @@ -754,7 +734,6 @@ impl Engine { &self, global: &mut GlobalRuntimeState, caches: &mut Caches, - lib: &[SharedModule], target: &mut Dynamic, idx: &mut Dynamic, ) -> RhaiResultOf { @@ -766,7 +745,7 @@ impl Engine { global.level += 1; let global = &mut *RestoreOnDrop::lock(global, move |g| g.level -= 1); - self.exec_native_fn_call(global, caches, lib, fn_name, None, hash, args, true, pos) + self.exec_native_fn_call(global, caches, fn_name, None, hash, args, true, pos) .map(|(r, ..)| r) } @@ -776,7 +755,6 @@ impl Engine { &self, global: &mut GlobalRuntimeState, caches: &mut Caches, - lib: &[SharedModule], target: &mut Dynamic, idx: &mut Dynamic, new_val: &mut Dynamic, @@ -790,9 +768,7 @@ impl Engine { global.level += 1; let global = &mut *RestoreOnDrop::lock(global, move |g| g.level -= 1); - self.exec_native_fn_call( - global, caches, lib, fn_name, None, hash, args, is_ref_mut, pos, - ) + self.exec_native_fn_call(global, caches, fn_name, None, hash, args, is_ref_mut, pos) } /// Get the value at the indexed position of a base type. @@ -801,7 +777,6 @@ impl Engine { &self, global: &mut GlobalRuntimeState, caches: &mut Caches, - lib: &[SharedModule], target: &'t mut Dynamic, idx: &mut Dynamic, idx_pos: Position, @@ -1010,7 +985,7 @@ impl Engine { } _ if use_indexers => self - .call_indexer_get(global, caches, lib, target, idx) + .call_indexer_get(global, caches, target, idx) .map(Into::into), _ => Err(ERR::ErrorIndexingType( diff --git a/src/eval/debugger.rs b/src/eval/debugger.rs index 6eed7279..bf74af3d 100644 --- a/src/eval/debugger.rs +++ b/src/eval/debugger.rs @@ -3,9 +3,7 @@ use super::{Caches, EvalContext, GlobalRuntimeState}; use crate::ast::{ASTNode, Expr, Stmt}; -use crate::{ - Dynamic, Engine, EvalAltResult, ImmutableString, Position, RhaiResultOf, Scope, SharedModule, -}; +use crate::{Dynamic, Engine, EvalAltResult, ImmutableString, Position, RhaiResultOf, Scope}; #[cfg(feature = "no_std")] use std::prelude::v1::*; use std::{fmt, iter::repeat, mem}; @@ -413,14 +411,13 @@ impl Engine { &self, global: &mut GlobalRuntimeState, caches: &mut Caches, - lib: &[SharedModule], scope: &mut Scope, this_ptr: &mut Dynamic, node: impl Into>, ) -> RhaiResultOf<()> { if self.debugger.is_some() { if let Some(cmd) = - self.run_debugger_with_reset_raw(global, caches, lib, scope, this_ptr, node)? + self.run_debugger_with_reset_raw(global, caches, scope, this_ptr, node)? { global.debugger.status = cmd; } @@ -439,13 +436,12 @@ impl Engine { &self, global: &mut GlobalRuntimeState, caches: &mut Caches, - lib: &[SharedModule], scope: &mut Scope, this_ptr: &mut Dynamic, node: impl Into>, ) -> RhaiResultOf> { if self.debugger.is_some() { - self.run_debugger_with_reset_raw(global, caches, lib, scope, this_ptr, node) + self.run_debugger_with_reset_raw(global, caches, scope, this_ptr, node) } else { Ok(None) } @@ -461,7 +457,6 @@ impl Engine { &self, global: &mut GlobalRuntimeState, caches: &mut Caches, - lib: &[SharedModule], scope: &mut Scope, this_ptr: &mut Dynamic, node: impl Into>, @@ -494,7 +489,7 @@ impl Engine { }, }; - self.run_debugger_raw(global, caches, lib, scope, this_ptr, node, event) + self.run_debugger_raw(global, caches, scope, this_ptr, node, event) } /// Run the debugger callback unconditionally. /// @@ -507,7 +502,6 @@ impl Engine { &self, global: &mut GlobalRuntimeState, caches: &mut Caches, - lib: &[SharedModule], scope: &mut Scope, this_ptr: &mut Dynamic, node: ASTNode<'a>, @@ -515,7 +509,7 @@ impl Engine { ) -> Result, Box> { let src = global.source_raw().cloned(); let src = src.as_ref().map(|s| s.as_str()); - let context = crate::EvalContext::new(self, global, caches, lib, scope, this_ptr); + let context = crate::EvalContext::new(self, global, caches, scope, this_ptr); if let Some((.., ref on_debugger)) = self.debugger { let command = on_debugger(context, event, node, src, node.position())?; diff --git a/src/eval/eval_context.rs b/src/eval/eval_context.rs index f8f2fd1a..8a4b3df6 100644 --- a/src/eval/eval_context.rs +++ b/src/eval/eval_context.rs @@ -17,8 +17,6 @@ pub struct EvalContext<'a, 's, 'ps, 'g, 'c, 't> { global: &'g mut GlobalRuntimeState, /// The current [caches][Caches], if available. caches: &'c mut Caches, - /// The current stack of imported [modules][Module]. - lib: &'a [SharedModule], /// The current bound `this` pointer, if any. this_ptr: &'t mut Dynamic, } @@ -31,7 +29,6 @@ impl<'a, 's, 'ps, 'g, 'c, 't> EvalContext<'a, 's, 'ps, 'g, 'c, 't> { engine: &'a Engine, global: &'g mut GlobalRuntimeState, caches: &'c mut Caches, - lib: &'a [SharedModule], scope: &'s mut Scope<'ps>, this_ptr: &'t mut Dynamic, ) -> Self { @@ -40,7 +37,6 @@ impl<'a, 's, 'ps, 'g, 'c, 't> EvalContext<'a, 's, 'ps, 'g, 'c, 't> { scope, global, caches, - lib, this_ptr, } } @@ -106,15 +102,15 @@ impl<'a, 's, 'ps, 'g, 'c, 't> EvalContext<'a, 's, 'ps, 'g, 'c, 't> { /// Get an iterator over the namespaces containing definition of all script-defined functions. #[inline] pub fn iter_namespaces(&self) -> impl Iterator { - self.lib.iter().map(|m| m.as_ref()) + self.global.lib.iter().map(|m| m.as_ref()) } /// _(internals)_ The current set of namespaces containing definitions of all script-defined functions. /// Exported under the `internals` feature only. #[cfg(feature = "internals")] #[inline(always)] #[must_use] - pub const fn namespaces(&self) -> &[SharedModule] { - self.lib + pub fn namespaces(&self) -> &[SharedModule] { + &self.global.lib } /// The current bound `this` pointer, if any. #[inline] @@ -181,20 +177,14 @@ impl<'a, 's, 'ps, 'g, 'c, 't> EvalContext<'a, 's, 'ps, 'g, 'c, 't> { crate::ast::Expr::Stmt(statements) => self.engine.eval_stmt_block( self.global, self.caches, - self.lib, self.scope, self.this_ptr, statements, rewind_scope, ), - _ => self.engine.eval_expr( - self.global, - self.caches, - self.lib, - self.scope, - self.this_ptr, - expr, - ), + _ => self + .engine + .eval_expr(self.global, self.caches, self.scope, self.this_ptr, expr), } } } diff --git a/src/eval/expr.rs b/src/eval/expr.rs index 92d392bd..58e45d8a 100644 --- a/src/eval/expr.rs +++ b/src/eval/expr.rs @@ -51,23 +51,22 @@ impl Engine { &self, global: &mut GlobalRuntimeState, caches: &mut Caches, - lib: &[SharedModule], scope: &'s mut Scope, this_ptr: &'s mut Dynamic, expr: &Expr, ) -> RhaiResultOf<(Target<'s>, Position)> { match expr { Expr::Variable(_, Some(_), _) => { - self.search_scope_only(global, caches, lib, scope, this_ptr, expr) + self.search_scope_only(global, caches, scope, this_ptr, expr) } Expr::Variable(v, None, _var_pos) => match &**v { // Normal variable access #[cfg(not(feature = "no_module"))] (_, ns, ..) if ns.is_empty() => { - self.search_scope_only(global, caches, lib, scope, this_ptr, expr) + self.search_scope_only(global, caches, scope, this_ptr, expr) } #[cfg(feature = "no_module")] - (_, (), ..) => self.search_scope_only(global, caches, lib, scope, this_ptr, expr), + (_, (), ..) => self.search_scope_only(global, caches, scope, this_ptr, expr), // Qualified variable access #[cfg(not(feature = "no_module"))] @@ -134,7 +133,6 @@ impl Engine { &self, global: &mut GlobalRuntimeState, caches: &mut Caches, - lib: &[SharedModule], scope: &'s mut Scope, this_ptr: &'s mut Dynamic, expr: &Expr, @@ -155,7 +153,8 @@ impl Engine { // Scripted function with the same name #[cfg(not(feature = "no_function"))] Expr::Variable(v, None, pos) - if lib + if global + .lib .iter() .flat_map(|m| m.iter_script_fn()) .any(|(_, _, f, ..)| f == v.3.as_str()) => @@ -170,7 +169,7 @@ impl Engine { // Check the variable resolver, if any if let Some(ref resolve_var) = self.resolve_var { - let context = EvalContext::new(self, global, caches, lib, scope, this_ptr); + let context = EvalContext::new(self, global, caches, scope, this_ptr); let var_name = expr.get_variable_name(true).expect("`Expr::Variable`"); match resolve_var(var_name, index, context) { Ok(Some(mut result)) => { @@ -218,7 +217,6 @@ impl Engine { &self, global: &mut GlobalRuntimeState, caches: &mut Caches, - lib: &[SharedModule], scope: &mut Scope, this_ptr: &mut Dynamic, expr: &Expr, @@ -230,7 +228,7 @@ impl Engine { // binary operators are also function calls. if let Expr::FnCall(x, pos) = expr { #[cfg(feature = "debugging")] - let reset = self.run_debugger_with_reset(global, caches, lib, scope, this_ptr, expr)?; + let reset = self.run_debugger_with_reset(global, caches, scope, this_ptr, expr)?; #[cfg(feature = "debugging")] let global = &mut *crate::types::RestoreOnDrop::lock(global, move |g| { g.debugger.reset_status(reset) @@ -238,7 +236,7 @@ impl Engine { self.track_operation(global, expr.position())?; - return self.eval_fn_call_expr(global, caches, lib, scope, this_ptr, x, *pos); + return self.eval_fn_call_expr(global, caches, scope, this_ptr, x, *pos); } // Then variable access. @@ -246,7 +244,7 @@ impl Engine { // will cost more than the mis-predicted `match` branch. if let Expr::Variable(x, index, var_pos) = expr { #[cfg(feature = "debugging")] - self.run_debugger(global, caches, lib, scope, this_ptr, expr)?; + self.run_debugger(global, caches, scope, this_ptr, expr)?; self.track_operation(global, expr.position())?; @@ -257,13 +255,13 @@ impl Engine { Ok(this_ptr.clone()) } } else { - self.search_namespace(global, caches, lib, scope, this_ptr, expr) + self.search_namespace(global, caches, scope, this_ptr, expr) .map(|(val, ..)| val.take_or_clone()) }; } #[cfg(feature = "debugging")] - let reset = self.run_debugger_with_reset(global, caches, lib, scope, this_ptr, expr)?; + let reset = self.run_debugger_with_reset(global, caches, scope, this_ptr, expr)?; #[cfg(feature = "debugging")] let global = &mut *crate::types::RestoreOnDrop::lock(global, move |g| { g.debugger.reset_status(reset) @@ -294,12 +292,12 @@ impl Engine { .iter() .try_for_each(|expr| { let item = self - .eval_expr(global, caches, lib, scope, this_ptr, expr)? + .eval_expr(global, caches, scope, this_ptr, expr)? .flatten(); op_info.pos = expr.start_position(); - self.eval_op_assignment(global, caches, lib, &op_info, target, root, item) + self.eval_op_assignment(global, caches, &op_info, target, root, item) }) .map(|_| concat.take_or_clone()); @@ -316,7 +314,7 @@ impl Engine { crate::Array::with_capacity(x.len()), |mut array, item_expr| { let value = self - .eval_expr(global, caches, lib, scope, this_ptr, item_expr)? + .eval_expr(global, caches, scope, this_ptr, item_expr)? .flatten(); #[cfg(not(feature = "unchecked"))] @@ -348,7 +346,7 @@ impl Engine { x.0.iter() .try_fold(x.1.clone(), |mut map, (key, value_expr)| { let value = self - .eval_expr(global, caches, lib, scope, this_ptr, value_expr)? + .eval_expr(global, caches, scope, this_ptr, value_expr)? .flatten(); #[cfg(not(feature = "unchecked"))] @@ -371,30 +369,30 @@ impl Engine { } Expr::And(x, ..) => Ok((self - .eval_expr(global, caches, lib, scope, this_ptr, &x.lhs)? + .eval_expr(global, caches, scope, this_ptr, &x.lhs)? .as_bool() .map_err(|typ| self.make_type_mismatch_err::(typ, x.lhs.position()))? && self - .eval_expr(global, caches, lib, scope, this_ptr, &x.rhs)? + .eval_expr(global, caches, scope, this_ptr, &x.rhs)? .as_bool() .map_err(|typ| self.make_type_mismatch_err::(typ, x.rhs.position()))?) .into()), Expr::Or(x, ..) => Ok((self - .eval_expr(global, caches, lib, scope, this_ptr, &x.lhs)? + .eval_expr(global, caches, scope, this_ptr, &x.lhs)? .as_bool() .map_err(|typ| self.make_type_mismatch_err::(typ, x.lhs.position()))? || self - .eval_expr(global, caches, lib, scope, this_ptr, &x.rhs)? + .eval_expr(global, caches, scope, this_ptr, &x.rhs)? .as_bool() .map_err(|typ| self.make_type_mismatch_err::(typ, x.rhs.position()))?) .into()), Expr::Coalesce(x, ..) => { - let value = self.eval_expr(global, caches, lib, scope, this_ptr, &x.lhs)?; + let value = self.eval_expr(global, caches, scope, this_ptr, &x.lhs)?; if value.is_unit() { - self.eval_expr(global, caches, lib, scope, this_ptr, &x.rhs) + self.eval_expr(global, caches, scope, this_ptr, &x.rhs) } else { Ok(value) } @@ -414,7 +412,7 @@ impl Engine { *pos, )) })?; - let mut context = EvalContext::new(self, global, caches, lib, scope, this_ptr); + let mut context = EvalContext::new(self, global, caches, scope, this_ptr); let result = (custom_def.func)(&mut context, &expressions, &custom.state); @@ -422,16 +420,16 @@ impl Engine { } Expr::Stmt(x) if x.is_empty() => Ok(Dynamic::UNIT), - Expr::Stmt(x) => self.eval_stmt_block(global, caches, lib, scope, this_ptr, x, true), + Expr::Stmt(x) => self.eval_stmt_block(global, caches, scope, this_ptr, x, true), #[cfg(not(feature = "no_index"))] Expr::Index(..) => { - self.eval_dot_index_chain(global, caches, lib, scope, this_ptr, expr, &mut None) + self.eval_dot_index_chain(global, caches, scope, this_ptr, expr, &mut None) } #[cfg(not(feature = "no_object"))] Expr::Dot(..) => { - self.eval_dot_index_chain(global, caches, lib, scope, this_ptr, expr, &mut None) + self.eval_dot_index_chain(global, caches, scope, this_ptr, expr, &mut None) } _ => unreachable!("expression cannot be evaluated: {:?}", expr), diff --git a/src/eval/global_state.rs b/src/eval/global_state.rs index 94dcb837..179812c0 100644 --- a/src/eval/global_state.rs +++ b/src/eval/global_state.rs @@ -1,6 +1,6 @@ //! Global runtime state. -use crate::{Dynamic, Engine, ImmutableString}; +use crate::{Dynamic, Engine, ImmutableString, SharedModule, StaticVec}; use std::fmt; #[cfg(feature = "no_std")] use std::prelude::v1::*; @@ -25,10 +25,12 @@ pub type GlobalConstants = pub struct GlobalRuntimeState { /// Names of imported [modules][crate::Module]. #[cfg(not(feature = "no_module"))] - imports: crate::StaticVec, + imports: StaticVec, /// Stack of imported [modules][crate::Module]. #[cfg(not(feature = "no_module"))] - modules: crate::StaticVec, + modules: StaticVec, + /// The current stack of loaded [modules][Module]. + pub lib: StaticVec, /// Source of the current context. /// /// No source if the string is empty. @@ -81,9 +83,10 @@ impl GlobalRuntimeState { pub fn new(engine: &Engine) -> Self { Self { #[cfg(not(feature = "no_module"))] - imports: crate::StaticVec::new_const(), + imports: StaticVec::new_const(), #[cfg(not(feature = "no_module"))] - modules: crate::StaticVec::new_const(), + modules: StaticVec::new_const(), + lib: StaticVec::new_const(), source: None, num_operations: 0, #[cfg(not(feature = "no_module"))] @@ -130,7 +133,7 @@ impl GlobalRuntimeState { #[cfg(not(feature = "no_module"))] #[inline(always)] #[must_use] - pub fn get_shared_import(&self, index: usize) -> Option { + pub fn get_shared_import(&self, index: usize) -> Option { self.modules.get(index).cloned() } /// Get a mutable reference to the globally-imported [module][crate::Module] at a @@ -141,10 +144,7 @@ impl GlobalRuntimeState { #[allow(dead_code)] #[inline(always)] #[must_use] - pub(crate) fn get_shared_import_mut( - &mut self, - index: usize, - ) -> Option<&mut crate::SharedModule> { + pub(crate) fn get_shared_import_mut(&mut self, index: usize) -> Option<&mut SharedModule> { self.modules.get_mut(index) } /// Get the index of a globally-imported [module][crate::Module] by name. @@ -168,7 +168,7 @@ impl GlobalRuntimeState { pub fn push_import( &mut self, name: impl Into, - module: impl Into, + module: impl Into, ) { self.imports.push(name.into()); self.modules.push(module.into()); @@ -201,7 +201,7 @@ impl GlobalRuntimeState { #[inline] pub(crate) fn iter_imports_raw( &self, - ) -> impl Iterator { + ) -> impl Iterator { self.imports.iter().zip(self.modules.iter()).rev() } /// Get an iterator to the stack of globally-imported [modules][crate::Module] in forward order. @@ -209,9 +209,7 @@ impl GlobalRuntimeState { /// Not available under `no_module`. #[cfg(not(feature = "no_module"))] #[inline] - pub fn scan_imports_raw( - &self, - ) -> impl Iterator { + pub fn scan_imports_raw(&self) -> impl Iterator { self.imports.iter().zip(self.modules.iter()) } /// Can the particular function with [`Dynamic`] parameter(s) exist in the stack of @@ -318,37 +316,7 @@ impl GlobalRuntimeState { } #[cfg(not(feature = "no_module"))] -impl IntoIterator for GlobalRuntimeState { - type Item = (ImmutableString, crate::SharedModule); - type IntoIter = std::iter::Rev< - std::iter::Zip< - smallvec::IntoIter<[ImmutableString; crate::STATIC_VEC_INLINE_SIZE]>, - smallvec::IntoIter<[crate::SharedModule; crate::STATIC_VEC_INLINE_SIZE]>, - >, - >; - - fn into_iter(self) -> Self::IntoIter { - self.imports.into_iter().zip(self.modules.into_iter()).rev() - } -} - -#[cfg(not(feature = "no_module"))] -impl<'a> IntoIterator for &'a GlobalRuntimeState { - type Item = (&'a ImmutableString, &'a crate::SharedModule); - type IntoIter = std::iter::Rev< - std::iter::Zip< - std::slice::Iter<'a, ImmutableString>, - std::slice::Iter<'a, crate::SharedModule>, - >, - >; - - fn into_iter(self) -> Self::IntoIter { - self.imports.iter().zip(self.modules.iter()).rev() - } -} - -#[cfg(not(feature = "no_module"))] -impl, M: Into> Extend<(K, M)> for GlobalRuntimeState { +impl, M: Into> Extend<(K, M)> for GlobalRuntimeState { #[inline] fn extend>(&mut self, iter: T) { for (k, m) in iter { diff --git a/src/eval/stmt.rs b/src/eval/stmt.rs index 7aedeb59..c6a497d6 100644 --- a/src/eval/stmt.rs +++ b/src/eval/stmt.rs @@ -9,8 +9,7 @@ use crate::func::{get_builtin_op_assignment_fn, get_hasher}; use crate::types::dynamic::AccessMode; use crate::types::RestoreOnDrop; use crate::{ - Dynamic, Engine, ImmutableString, Position, RhaiResult, RhaiResultOf, Scope, SharedModule, ERR, - INT, + Dynamic, Engine, ImmutableString, Position, RhaiResult, RhaiResultOf, Scope, ERR, INT, }; use std::hash::{Hash, Hasher}; #[cfg(feature = "no_std")] @@ -29,7 +28,6 @@ impl Engine { &self, global: &mut GlobalRuntimeState, caches: &mut Caches, - lib: &[SharedModule], scope: &mut Scope, this_ptr: &mut Dynamic, statements: &[Stmt], @@ -76,15 +74,8 @@ impl Engine { #[cfg(not(feature = "no_module"))] let imports_len = global.num_imports(); - let result = self.eval_stmt( - global, - caches, - lib, - scope, - this_ptr, - stmt, - restore_orig_state, - )?; + let result = + self.eval_stmt(global, caches, scope, this_ptr, stmt, restore_orig_state)?; #[cfg(not(feature = "no_module"))] if matches!(stmt, Stmt::Import(..)) { @@ -120,7 +111,6 @@ impl Engine { &self, global: &mut GlobalRuntimeState, caches: &mut Caches, - lib: &[SharedModule], op_info: &OpAssignment, target: &mut Target, root: (&str, Position), @@ -154,7 +144,7 @@ impl Engine { global.level += 1; let global = &*RestoreOnDrop::lock(global, move |g| g.level -= 1); - let context = (self, op, None, global, lib, *op_pos).into(); + let context = (self, op, None, global, *op_pos).into(); return func(context, args).map(|_| ()); } } @@ -163,9 +153,9 @@ impl Engine { let op = op_token.literal_syntax(); let token = Some(op_assign_token); - match self.exec_native_fn_call( - global, caches, lib, op_assign, token, hash, args, true, *op_pos, - ) { + match self + .exec_native_fn_call(global, caches, op_assign, token, hash, args, true, *op_pos) + { Ok(_) => (), Err(err) if matches!(*err, ERR::ErrorFunctionNotFound(ref f, ..) if f.starts_with(op_assign)) => { @@ -174,7 +164,7 @@ impl Engine { *args[0] = self .exec_native_fn_call( - global, caches, lib, op, token, *hash_op, args, true, *op_pos, + global, caches, op, token, *hash_op, args, true, *op_pos, ) .map_err(|err| err.fill_position(op_info.pos))? .0; @@ -210,14 +200,13 @@ impl Engine { &self, global: &mut GlobalRuntimeState, caches: &mut Caches, - lib: &[SharedModule], scope: &mut Scope, this_ptr: &mut Dynamic, stmt: &Stmt, rewind_scope: bool, ) -> RhaiResult { #[cfg(feature = "debugging")] - let reset = self.run_debugger_with_reset(global, caches, lib, scope, this_ptr, stmt)?; + let reset = self.run_debugger_with_reset(global, caches, scope, this_ptr, stmt)?; #[cfg(feature = "debugging")] let global = &mut *RestoreOnDrop::lock(global, move |g| g.debugger.reset_status(reset)); @@ -228,7 +217,7 @@ impl Engine { if let Stmt::FnCall(x, pos) = stmt { self.track_operation(global, stmt.position())?; - return self.eval_fn_call_expr(global, caches, lib, scope, this_ptr, x, *pos); + return self.eval_fn_call_expr(global, caches, scope, this_ptr, x, *pos); } // Then assignments. @@ -241,11 +230,11 @@ impl Engine { if let Expr::Variable(x, ..) = lhs { let rhs_val = self - .eval_expr(global, caches, lib, scope, this_ptr, rhs)? + .eval_expr(global, caches, scope, this_ptr, rhs)? .flatten(); let (mut lhs_ptr, pos) = - self.search_namespace(global, caches, lib, scope, this_ptr, lhs)?; + self.search_namespace(global, caches, scope, this_ptr, lhs)?; let var_name = x.3.as_str(); @@ -266,7 +255,7 @@ impl Engine { let root = (var_name, pos); let lhs_ptr = &mut lhs_ptr; - self.eval_op_assignment(global, caches, lib, op_info, lhs_ptr, root, rhs_val)?; + self.eval_op_assignment(global, caches, op_info, lhs_ptr, root, rhs_val)?; return Ok(Dynamic::UNIT); } @@ -274,7 +263,7 @@ impl Engine { #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] { let mut rhs_val = self - .eval_expr(global, caches, lib, scope, this_ptr, rhs)? + .eval_expr(global, caches, scope, this_ptr, rhs)? .flatten(); // If value is a string, intern it @@ -293,12 +282,14 @@ impl Engine { } // idx_lhs[idx_expr] op= rhs #[cfg(not(feature = "no_index"))] - Expr::Index(..) => self - .eval_dot_index_chain(global, caches, lib, scope, this_ptr, lhs, _new_val), + Expr::Index(..) => { + self.eval_dot_index_chain(global, caches, scope, this_ptr, lhs, _new_val) + } // dot_lhs.dot_rhs op= rhs #[cfg(not(feature = "no_object"))] - Expr::Dot(..) => self - .eval_dot_index_chain(global, caches, lib, scope, this_ptr, lhs, _new_val), + Expr::Dot(..) => { + self.eval_dot_index_chain(global, caches, scope, this_ptr, lhs, _new_val) + } _ => unreachable!("cannot assign to expression: {:?}", lhs), }?; @@ -314,13 +305,13 @@ impl Engine { // Expression as statement Stmt::Expr(expr) => self - .eval_expr(global, caches, lib, scope, this_ptr, expr) + .eval_expr(global, caches, scope, this_ptr, expr) .map(Dynamic::flatten), // Block scope Stmt::Block(statements, ..) if statements.is_empty() => Ok(Dynamic::UNIT), Stmt::Block(statements, ..) => { - self.eval_stmt_block(global, caches, lib, scope, this_ptr, statements, true) + self.eval_stmt_block(global, caches, scope, this_ptr, statements, true) } // If statement @@ -328,14 +319,14 @@ impl Engine { let (expr, if_block, else_block) = &**x; let guard_val = self - .eval_expr(global, caches, lib, scope, this_ptr, expr)? + .eval_expr(global, caches, scope, this_ptr, expr)? .as_bool() .map_err(|typ| self.make_type_mismatch_err::(typ, expr.position()))?; if guard_val && !if_block.is_empty() { - self.eval_stmt_block(global, caches, lib, scope, this_ptr, if_block, true) + self.eval_stmt_block(global, caches, scope, this_ptr, if_block, true) } else if !guard_val && !else_block.is_empty() { - self.eval_stmt_block(global, caches, lib, scope, this_ptr, else_block, true) + self.eval_stmt_block(global, caches, scope, this_ptr, else_block, true) } else { Ok(Dynamic::UNIT) } @@ -355,7 +346,7 @@ impl Engine { let mut result = None; - let value = self.eval_expr(global, caches, lib, scope, this_ptr, expr)?; + let value = self.eval_expr(global, caches, scope, this_ptr, expr)?; if value.is_hashable() { let hasher = &mut get_hasher(); @@ -372,7 +363,7 @@ impl Engine { let cond_result = match block.condition { Expr::BoolConstant(b, ..) => b, ref c => self - .eval_expr(global, caches, lib, scope, this_ptr, c)? + .eval_expr(global, caches, scope, this_ptr, c)? .as_bool() .map_err(|typ| { self.make_type_mismatch_err::(typ, c.position()) @@ -394,7 +385,7 @@ impl Engine { let cond_result = match block.condition { Expr::BoolConstant(b, ..) => b, ref c => self - .eval_expr(global, caches, lib, scope, this_ptr, c)? + .eval_expr(global, caches, scope, this_ptr, c)? .as_bool() .map_err(|typ| { self.make_type_mismatch_err::(typ, c.position()) @@ -412,7 +403,7 @@ impl Engine { result .or_else(|| def_case.as_ref().map(|&index| &expressions[index].expr)) .map_or(Ok(Dynamic::UNIT), |expr| { - self.eval_expr(global, caches, lib, scope, this_ptr, expr) + self.eval_expr(global, caches, scope, this_ptr, expr) }) } @@ -428,7 +419,7 @@ impl Engine { loop { if let Err(err) = - self.eval_stmt_block(global, caches, lib, scope, this_ptr, body, true) + self.eval_stmt_block(global, caches, scope, this_ptr, body, true) { match *err { ERR::LoopBreak(false, ..) => (), @@ -445,7 +436,7 @@ impl Engine { loop { let condition = self - .eval_expr(global, caches, lib, scope, this_ptr, expr)? + .eval_expr(global, caches, scope, this_ptr, expr)? .as_bool() .map_err(|typ| self.make_type_mismatch_err::(typ, expr.position()))?; @@ -458,7 +449,7 @@ impl Engine { } if let Err(err) = - self.eval_stmt_block(global, caches, lib, scope, this_ptr, body, true) + self.eval_stmt_block(global, caches, scope, this_ptr, body, true) { match *err { ERR::LoopBreak(false, ..) => (), @@ -477,7 +468,7 @@ impl Engine { loop { if !body.is_empty() { if let Err(err) = - self.eval_stmt_block(global, caches, lib, scope, this_ptr, body, true) + self.eval_stmt_block(global, caches, scope, this_ptr, body, true) { match *err { ERR::LoopBreak(false, ..) => continue, @@ -488,7 +479,7 @@ impl Engine { } let condition = self - .eval_expr(global, caches, lib, scope, this_ptr, expr)? + .eval_expr(global, caches, scope, this_ptr, expr)? .as_bool() .map_err(|typ| self.make_type_mismatch_err::(typ, expr.position()))?; @@ -503,7 +494,7 @@ impl Engine { let (var_name, counter, expr, statements) = &**x; let iter_obj = self - .eval_expr(global, caches, lib, scope, this_ptr, expr)? + .eval_expr(global, caches, scope, this_ptr, expr)? .flatten(); let iter_type = iter_obj.type_id(); @@ -582,9 +573,7 @@ impl Engine { continue; } - match self - .eval_stmt_block(global, caches, lib, scope, this_ptr, statements, true) - { + match self.eval_stmt_block(global, caches, scope, this_ptr, statements, true) { Ok(_) => (), Err(err) => match *err { ERR::LoopBreak(false, ..) => (), @@ -605,7 +594,7 @@ impl Engine { let is_break = options.contains(ASTFlags::BREAK); let value = if let Some(ref expr) = expr { - self.eval_expr(global, caches, lib, scope, this_ptr, expr)? + self.eval_expr(global, caches, scope, this_ptr, expr)? } else { Dynamic::UNIT }; @@ -624,7 +613,7 @@ impl Engine { catch_block, } = &**x; - match self.eval_stmt_block(global, caches, lib, scope, this_ptr, try_block, true) { + match self.eval_stmt_block(global, caches, scope, this_ptr, try_block, true) { r @ Ok(_) => r, Err(err) if err.is_pseudo_error() => Err(err), Err(err) if !err.is_catchable() => Err(err), @@ -675,31 +664,23 @@ impl Engine { scope.push(catch_var.clone(), err_value); } - self.eval_stmt_block( - global, - caches, - lib, - scope, - this_ptr, - catch_block, - true, - ) - .map(|_| Dynamic::UNIT) - .map_err(|result_err| match *result_err { - // Re-throw exception - ERR::ErrorRuntime(v, pos) if v.is_unit() => { - err.set_position(pos); - err - } - _ => result_err, - }) + self.eval_stmt_block(global, caches, scope, this_ptr, catch_block, true) + .map(|_| Dynamic::UNIT) + .map_err(|result_err| match *result_err { + // Re-throw exception + ERR::ErrorRuntime(v, pos) if v.is_unit() => { + err.set_position(pos); + err + } + _ => result_err, + }) } } } // Throw value Stmt::Return(Some(expr), options, pos) if options.contains(ASTFlags::BREAK) => self - .eval_expr(global, caches, lib, scope, this_ptr, expr) + .eval_expr(global, caches, scope, this_ptr, expr) .and_then(|v| Err(ERR::ErrorRuntime(v.flatten(), *pos).into())), // Empty throw @@ -709,7 +690,7 @@ impl Engine { // Return value Stmt::Return(Some(expr), .., pos) => self - .eval_expr(global, caches, lib, scope, this_ptr, expr) + .eval_expr(global, caches, scope, this_ptr, expr) .and_then(|v| Err(ERR::Return(v.flatten(), *pos).into())), // Empty return @@ -740,7 +721,7 @@ impl Engine { nesting_level: global.scope_level, will_shadow, }; - let context = EvalContext::new(self, global, caches, lib, scope, this_ptr); + let context = EvalContext::new(self, global, caches, scope, this_ptr); if !filter(true, info, context)? { return Err(ERR::ErrorForbiddenVariable(var_name.to_string(), *pos).into()); @@ -749,7 +730,7 @@ impl Engine { // Evaluate initial value let mut value = self - .eval_expr(global, caches, lib, scope, this_ptr, expr)? + .eval_expr(global, caches, scope, this_ptr, expr)? .flatten(); let _alias = if !rewind_scope { @@ -758,7 +739,7 @@ impl Engine { #[cfg(not(feature = "no_module"))] if global.scope_level == 0 && access == AccessMode::ReadOnly - && lib.iter().any(|m| !m.is_empty()) + && global.lib.iter().any(|m| !m.is_empty()) { crate::func::locked_write(global.constants.get_or_insert_with(|| { crate::Shared::new( @@ -804,7 +785,7 @@ impl Engine { return Err(ERR::ErrorTooManyModules(*_pos).into()); } - let v = self.eval_expr(global, caches, lib, scope, this_ptr, expr)?; + let v = self.eval_expr(global, caches, scope, this_ptr, expr)?; let typ = v.type_name(); let path = v.try_cast::().ok_or_else(|| { self.make_type_mismatch_err::(typ, expr.position()) @@ -900,13 +881,12 @@ impl Engine { &self, global: &mut GlobalRuntimeState, caches: &mut Caches, - lib: &[SharedModule], scope: &mut Scope, statements: &[Stmt], ) -> RhaiResult { let mut this = Dynamic::NULL; - self.eval_stmt_block(global, caches, lib, scope, &mut this, statements, false) + self.eval_stmt_block(global, caches, scope, &mut this, statements, false) .or_else(|err| match *err { ERR::Return(out, ..) => Ok(out), ERR::LoopBreak(..) => { diff --git a/src/func/call.rs b/src/func/call.rs index 5f209345..58f4d656 100644 --- a/src/func/call.rs +++ b/src/func/call.rs @@ -12,7 +12,7 @@ use crate::tokenizer::{is_valid_function_name, Token}; use crate::types::RestoreOnDrop; use crate::{ calc_fn_hash, calc_fn_hash_full, Dynamic, Engine, FnArgsVec, FnPtr, ImmutableString, - OptimizationLevel, Position, RhaiError, RhaiResult, RhaiResultOf, Scope, SharedModule, ERR, + OptimizationLevel, Position, RhaiError, RhaiResult, RhaiResultOf, Scope, ERR, }; #[cfg(feature = "no_std")] use hashbrown::hash_map::Entry; @@ -166,10 +166,9 @@ impl Engine { #[must_use] fn resolve_fn<'s>( &self, - _global: &GlobalRuntimeState, + global: &GlobalRuntimeState, caches: &'s mut Caches, local_entry: &'s mut Option, - lib: &[SharedModule], op_token: Option<&Token>, hash_base: u64, args: Option<&mut FnCallArgs>, @@ -194,8 +193,10 @@ impl Engine { let mut bitmask = 1usize; // Bitmask of which parameter to replace with `Dynamic` loop { - let func = lib + let func = global + .lib .iter() + .rev() .chain(self.global_modules.iter()) .find_map(|m| m.get_fn(hash).map(|f| (f, m.id_raw()))); @@ -204,7 +205,7 @@ impl Engine { // Scripted functions are not exposed globally func } else { - func.or_else(|| _global.get_qualified_fn(hash)).or_else(|| { + func.or_else(|| global.get_qualified_fn(hash)).or_else(|| { self.global_sub_modules .values() .find_map(|m| m.get_qualified_fn(hash).map(|f| (f, m.id_raw()))) @@ -229,7 +230,10 @@ impl Engine { // Check `Dynamic` parameters for functions with parameters if allow_dynamic && max_bitmask == 0 && num_args > 0 { - let is_dynamic = lib.iter().any(|m| m.may_contain_dynamic_fn(hash_base)) + let is_dynamic = global + .lib + .iter() + .any(|m| m.may_contain_dynamic_fn(hash_base)) || self .global_modules .iter() @@ -237,7 +241,7 @@ impl Engine { #[cfg(not(feature = "no_module"))] let is_dynamic = is_dynamic - || _global.may_contain_dynamic_fn(hash_base) + || global.may_contain_dynamic_fn(hash_base) || self .global_sub_modules .values() @@ -325,7 +329,6 @@ impl Engine { &self, global: &mut GlobalRuntimeState, caches: &mut Caches, - lib: &[SharedModule], name: &str, op_token: Option<&Token>, hash: u64, @@ -342,7 +345,6 @@ impl Engine { global, caches, local_entry, - lib, op_token, hash, Some(args), @@ -384,7 +386,7 @@ impl Engine { // Run external function let src = source.as_ref().map(|s| s.as_str()); - let context = (self, name, src, &*global, lib, pos).into(); + let context = (self, name, src, &*global, pos).into(); let mut _result = if func.is_plugin_fn() { let f = func.get_plugin_fn().unwrap(); @@ -415,7 +417,7 @@ impl Engine { }; if let Err(err) = - self.run_debugger_raw(global, caches, lib, scope, &mut this, node, event) + self.run_debugger_raw(global, caches, scope, &mut this, node, event) { _result = Err(err); } @@ -537,7 +539,6 @@ impl Engine { &self, global: &mut GlobalRuntimeState, caches: &mut Caches, - lib: &[SharedModule], _scope: Option<&mut Scope>, fn_name: &str, op_token: Option<&Token>, @@ -585,7 +586,7 @@ impl Engine { } else { let hash_script = calc_fn_hash(None, fn_name.as_str(), num_params as usize); - self.has_script_fn(global, caches, lib, hash_script) + self.has_script_fn(global, caches, hash_script) } .into(), false, @@ -617,7 +618,7 @@ impl Engine { let local_entry = &mut None; if let Some(FnResolutionCacheEntry { func, ref source }) = self - .resolve_fn(global, caches, local_entry, lib, None, hash, None, false) + .resolve_fn(global, caches, local_entry, None, hash, None, false) .cloned() { // Script function call @@ -646,7 +647,7 @@ impl Engine { let (first_arg, rest_args) = args.split_first_mut().unwrap(); self.call_script_fn( - global, caches, lib, scope, first_arg, func, rest_args, true, pos, + global, caches, scope, first_arg, func, rest_args, true, pos, ) } else { // Normal call of script function @@ -665,9 +666,7 @@ impl Engine { let mut this = Dynamic::NULL; - self.call_script_fn( - global, caches, lib, scope, &mut this, func, args, true, pos, - ) + self.call_script_fn(global, caches, scope, &mut this, func, args, true, pos) } .map(|r| (r, false)); } @@ -677,7 +676,7 @@ impl Engine { let hash = hashes.native(); self.exec_native_fn_call( - global, caches, lib, fn_name, op_token, hash, args, is_ref_mut, pos, + global, caches, fn_name, op_token, hash, args, is_ref_mut, pos, ) } @@ -687,7 +686,6 @@ impl Engine { &self, global: &mut GlobalRuntimeState, caches: &mut Caches, - lib: &[SharedModule], scope: &mut Scope, this_ptr: &mut Dynamic, arg_expr: &Expr, @@ -697,7 +695,7 @@ impl Engine { self.track_operation(global, arg_expr.start_position())?; #[cfg(feature = "debugging")] - self.run_debugger(global, caches, lib, scope, this_ptr, arg_expr)?; + self.run_debugger(global, caches, scope, this_ptr, arg_expr)?; return Ok((value, arg_expr.start_position())); } @@ -710,7 +708,7 @@ impl Engine { #[cfg(feature = "debugging")] let global = &mut *RestoreOnDrop::lock(global, move |g| g.debugger.reset_status(reset)); - self.eval_expr(global, caches, lib, scope, this_ptr, arg_expr) + self.eval_expr(global, caches, scope, this_ptr, arg_expr) .map(|r| (r, arg_expr.start_position())) } @@ -720,7 +718,6 @@ impl Engine { &self, global: &mut GlobalRuntimeState, caches: &mut Caches, - lib: &[SharedModule], fn_name: &str, mut hash: FnCallHashes, target: &mut crate::eval::Target, @@ -760,7 +757,6 @@ impl Engine { self.exec_fn_call( global, caches, - lib, None, fn_name, None, @@ -815,7 +811,6 @@ impl Engine { self.exec_fn_call( global, caches, - lib, None, &fn_name, None, @@ -915,7 +910,6 @@ impl Engine { self.exec_fn_call( global, caches, - lib, None, fn_name, None, @@ -941,7 +935,6 @@ impl Engine { &self, global: &mut GlobalRuntimeState, caches: &mut Caches, - lib: &[SharedModule], scope: &mut Scope, this_ptr: &mut Dynamic, fn_name: &str, @@ -967,7 +960,7 @@ impl Engine { KEYWORD_FN_PTR_CALL if total_args >= 1 => { let arg = first_arg.unwrap(); let (arg_value, arg_pos) = - self.get_arg_value(global, caches, lib, scope, this_ptr, arg)?; + self.get_arg_value(global, caches, scope, this_ptr, arg)?; if !arg_value.is_fnptr() { let typ = self.map_type_name(arg_value.type_name()); @@ -1008,7 +1001,7 @@ impl Engine { KEYWORD_FN_PTR if total_args == 1 => { let arg = first_arg.unwrap(); let (arg_value, arg_pos) = - self.get_arg_value(global, caches, lib, scope, this_ptr, arg)?; + self.get_arg_value(global, caches, scope, this_ptr, arg)?; // Fn - only in function call style return arg_value @@ -1023,7 +1016,7 @@ impl Engine { KEYWORD_FN_PTR_CURRY if total_args > 1 => { let first = first_arg.unwrap(); let (arg_value, arg_pos) = - self.get_arg_value(global, caches, lib, scope, this_ptr, first)?; + self.get_arg_value(global, caches, scope, this_ptr, first)?; if !arg_value.is_fnptr() { let typ = self.map_type_name(arg_value.type_name()); @@ -1034,8 +1027,7 @@ impl Engine { // Append the new curried arguments to the existing list. let fn_curry = a_expr.iter().try_fold(fn_curry, |mut curried, expr| { - let (value, ..) = - self.get_arg_value(global, caches, lib, scope, this_ptr, expr)?; + let (value, ..) = self.get_arg_value(global, caches, scope, this_ptr, expr)?; curried.push(value); Ok::<_, RhaiError>(curried) })?; @@ -1047,8 +1039,7 @@ impl Engine { #[cfg(not(feature = "no_closure"))] crate::engine::KEYWORD_IS_SHARED if total_args == 1 => { let arg = first_arg.unwrap(); - let (arg_value, ..) = - self.get_arg_value(global, caches, lib, scope, this_ptr, arg)?; + let (arg_value, ..) = self.get_arg_value(global, caches, scope, this_ptr, arg)?; return Ok(arg_value.is_shared().into()); } @@ -1057,14 +1048,14 @@ impl Engine { crate::engine::KEYWORD_IS_DEF_FN if total_args == 2 => { let first = first_arg.unwrap(); let (arg_value, arg_pos) = - self.get_arg_value(global, caches, lib, scope, this_ptr, first)?; + self.get_arg_value(global, caches, scope, this_ptr, first)?; let fn_name = arg_value .into_immutable_string() .map_err(|typ| self.make_type_mismatch_err::(typ, arg_pos))?; let (arg_value, arg_pos) = - self.get_arg_value(global, caches, lib, scope, this_ptr, &a_expr[0])?; + self.get_arg_value(global, caches, scope, this_ptr, &a_expr[0])?; let num_params = arg_value .as_int() @@ -1074,7 +1065,7 @@ impl Engine { false } else { let hash_script = calc_fn_hash(None, &fn_name, num_params as usize); - self.has_script_fn(global, caches, lib, hash_script) + self.has_script_fn(global, caches, hash_script) } .into()); } @@ -1083,7 +1074,7 @@ impl Engine { KEYWORD_IS_DEF_VAR if total_args == 1 => { let arg = first_arg.unwrap(); let (arg_value, arg_pos) = - self.get_arg_value(global, caches, lib, scope, this_ptr, arg)?; + self.get_arg_value(global, caches, scope, this_ptr, arg)?; let var_name = arg_value .into_immutable_string() .map_err(|typ| self.make_type_mismatch_err::(typ, arg_pos))?; @@ -1097,8 +1088,7 @@ impl Engine { #[cfg(not(feature = "no_module"))] let orig_imports_len = global.num_imports(); let arg = first_arg.unwrap(); - let (arg_value, pos) = - self.get_arg_value(global, caches, lib, scope, this_ptr, arg)?; + let (arg_value, pos) = self.get_arg_value(global, caches, scope, this_ptr, arg)?; let s = &arg_value .into_immutable_string() .map_err(|typ| self.make_type_mismatch_err::(typ, pos))?; @@ -1106,7 +1096,7 @@ impl Engine { global.level += 1; let global = &mut *RestoreOnDrop::lock(global, move |g| g.level -= 1); - let result = self.eval_script_expr_in_place(global, caches, lib, scope, s, pos); + let result = self.eval_script_expr_in_place(global, caches, scope, s, pos); // IMPORTANT! If the eval defines new variables in the current scope, // all variable offsets from this point on will be mis-aligned. @@ -1148,7 +1138,7 @@ impl Engine { .copied() .chain(a_expr.iter()) .try_for_each(|expr| { - self.get_arg_value(global, caches, lib, scope, this_ptr, expr) + self.get_arg_value(global, caches, scope, this_ptr, expr) .map(|(value, ..)| arg_values.push(value.flatten())) })?; args.extend(curry.iter_mut()); @@ -1159,8 +1149,8 @@ impl Engine { return self .exec_fn_call( - global, caches, lib, scope, name, op_token, hashes, &mut args, is_ref_mut, - false, pos, + global, caches, scope, name, op_token, hashes, &mut args, is_ref_mut, false, + pos, ) .map(|(v, ..)| v); } @@ -1176,16 +1166,16 @@ impl Engine { let first_expr = first_arg.unwrap(); #[cfg(feature = "debugging")] - self.run_debugger(global, caches, lib, scope, this_ptr, first_expr)?; + self.run_debugger(global, caches, scope, this_ptr, first_expr)?; // func(x, ...) -> x.func(...) a_expr.iter().try_for_each(|expr| { - self.get_arg_value(global, caches, lib, scope, this_ptr, expr) + self.get_arg_value(global, caches, scope, this_ptr, expr) .map(|(value, ..)| arg_values.push(value.flatten())) })?; let (mut target, _pos) = - self.search_namespace(global, caches, lib, scope, this_ptr, first_expr)?; + self.search_namespace(global, caches, scope, this_ptr, first_expr)?; if target.is_read_only() { target = target.into_owned(); @@ -1212,7 +1202,7 @@ impl Engine { .into_iter() .chain(a_expr.iter()) .try_for_each(|expr| { - self.get_arg_value(global, caches, lib, scope, this_ptr, expr) + self.get_arg_value(global, caches, scope, this_ptr, expr) .map(|(value, ..)| arg_values.push(value.flatten())) })?; args.extend(curry.iter_mut()); @@ -1222,7 +1212,7 @@ impl Engine { } self.exec_fn_call( - global, caches, lib, None, name, op_token, hashes, &mut args, is_ref_mut, false, pos, + global, caches, None, name, op_token, hashes, &mut args, is_ref_mut, false, pos, ) .map(|(v, ..)| v) } @@ -1233,7 +1223,6 @@ impl Engine { &self, global: &mut GlobalRuntimeState, caches: &mut Caches, - lib: &[SharedModule], scope: &mut Scope, this_ptr: &mut Dynamic, namespace: &crate::ast::Namespace, @@ -1254,20 +1243,20 @@ impl Engine { // and avoid cloning the value if !args_expr.is_empty() && args_expr[0].is_variable_access(true) { #[cfg(feature = "debugging")] - self.run_debugger(global, caches, lib, scope, this_ptr, &args_expr[0])?; + self.run_debugger(global, caches, scope, this_ptr, &args_expr[0])?; // func(x, ...) -> x.func(...) arg_values.push(Dynamic::UNIT); args_expr.iter().skip(1).try_for_each(|expr| { - self.get_arg_value(global, caches, lib, scope, this_ptr, expr) + self.get_arg_value(global, caches, scope, this_ptr, expr) .map(|(value, ..)| arg_values.push(value.flatten())) })?; // Get target reference to first argument let first_arg = &args_expr[0]; let (target, _pos) = - self.search_scope_only(global, caches, lib, scope, this_ptr, first_arg)?; + self.search_scope_only(global, caches, scope, this_ptr, first_arg)?; self.track_operation(global, _pos)?; @@ -1290,7 +1279,7 @@ impl Engine { } else { // func(..., ...) or func(mod::x, ...) args_expr.iter().try_for_each(|expr| { - self.get_arg_value(global, caches, lib, scope, this_ptr, expr) + self.get_arg_value(global, caches, scope, this_ptr, expr) .map(|(value, ..)| arg_values.push(value.flatten())) })?; args.extend(arg_values.iter_mut()); @@ -1371,12 +1360,12 @@ impl Engine { let global = &mut *RestoreOnDrop::lock(global, move |g| g.source = orig_source); self.call_script_fn( - global, caches, lib, new_scope, &mut this, fn_def, &mut args, true, pos, + global, caches, new_scope, &mut this, fn_def, &mut args, true, pos, ) } Some(f) if f.is_plugin_fn() => { - let context = (self, fn_name, module.id(), &*global, lib, pos).into(); + let context = (self, fn_name, module.id(), &*global, pos).into(); let f = f.get_plugin_fn().expect("plugin function"); let result = if !f.is_pure() && !args.is_empty() && args[0].is_read_only() { Err(ERR::ErrorNonPureMethodCallOnConstant(fn_name.to_string(), pos).into()) @@ -1388,7 +1377,7 @@ impl Engine { Some(f) if f.is_native() => { let func = f.get_native_fn().expect("native function"); - let context = (self, fn_name, module.id(), &*global, lib, pos).into(); + let context = (self, fn_name, module.id(), &*global, pos).into(); let result = func(context, &mut args); self.check_return_value(result, pos) } @@ -1416,7 +1405,6 @@ impl Engine { &self, global: &mut GlobalRuntimeState, caches: &mut Caches, - lib: &[SharedModule], scope: &mut Scope, script: &str, _pos: Position, @@ -1452,7 +1440,7 @@ impl Engine { } // Evaluate the AST - self.eval_global_statements(global, caches, lib, scope, statements) + self.eval_global_statements(global, caches, scope, statements) } /// Evaluate a function call expression. @@ -1460,7 +1448,6 @@ impl Engine { &self, global: &mut GlobalRuntimeState, caches: &mut Caches, - lib: &[SharedModule], scope: &mut Scope, this_ptr: &mut Dynamic, expr: &FnCallExpr, @@ -1482,12 +1469,12 @@ impl Engine { // Short-circuit native binary operator call if under Fast Operators mode if op_token.is_some() && self.fast_operators() && args.len() == 2 { let mut lhs = self - .get_arg_value(global, caches, lib, scope, this_ptr, &args[0])? + .get_arg_value(global, caches, scope, this_ptr, &args[0])? .0 .flatten(); let mut rhs = self - .get_arg_value(global, caches, lib, scope, this_ptr, &args[1])? + .get_arg_value(global, caches, scope, this_ptr, &args[1])? .0 .flatten(); @@ -1500,13 +1487,13 @@ impl Engine { global.level += 1; let global = &*RestoreOnDrop::lock(global, move |g| g.level -= 1); - let context = (self, name.as_str(), None, global, lib, pos).into(); + let context = (self, name.as_str(), None, global, pos).into(); return func(context, operands); } return self .exec_fn_call( - global, caches, lib, None, name, op_token, *hashes, operands, false, false, pos, + global, caches, None, name, op_token, *hashes, operands, false, false, pos, ) .map(|(v, ..)| v); } @@ -1517,7 +1504,7 @@ impl Engine { let hash = hashes.native(); return self.make_qualified_function_call( - global, caches, lib, scope, this_ptr, namespace, name, args, hash, pos, + global, caches, scope, this_ptr, namespace, name, args, hash, pos, ); } @@ -1528,8 +1515,8 @@ impl Engine { ); self.make_function_call( - global, caches, lib, scope, this_ptr, name, op_token, first_arg, args, *hashes, - *capture, pos, + global, caches, scope, this_ptr, name, op_token, first_arg, args, *hashes, *capture, + pos, ) } } diff --git a/src/func/native.rs b/src/func/native.rs index a6501803..ab56cb59 100644 --- a/src/func/native.rs +++ b/src/func/native.rs @@ -73,8 +73,6 @@ pub struct NativeCallContext<'a> { source: Option<&'a str>, /// The current [`GlobalRuntimeState`], if any. global: &'a GlobalRuntimeState, - /// The current stack of loaded [modules][Module]. - lib: &'a [SharedModule], /// [Position] of the function call. pos: Position, } @@ -95,8 +93,6 @@ pub struct NativeCallContextStore { pub source: Option, /// The current [`GlobalRuntimeState`], if any. pub global: GlobalRuntimeState, - /// The current stack of loaded [modules][Module]. - pub lib: StaticVec, /// [Position] of the function call. pub pos: Position, } @@ -123,7 +119,6 @@ impl<'a> &'a str, Option<&'a str>, &'a GlobalRuntimeState, - &'a [SharedModule], Position, )> for NativeCallContext<'a> { @@ -134,7 +129,6 @@ impl<'a> &'a str, Option<&'a str>, &'a GlobalRuntimeState, - &'a [SharedModule], Position, ), ) -> Self { @@ -143,8 +137,7 @@ impl<'a> fn_name: value.1, source: value.2, global: value.3, - lib: value.4, - pos: value.5, + pos: value.4, } } } @@ -163,7 +156,6 @@ impl<'a> NativeCallContext<'a> { fn_name: &'a str, source: Option<&'a str>, global: &'a GlobalRuntimeState, - lib: &'a [SharedModule], pos: Position, ) -> Self { Self { @@ -171,7 +163,6 @@ impl<'a> NativeCallContext<'a> { fn_name, source, global, - lib, pos, } } @@ -193,7 +184,6 @@ impl<'a> NativeCallContext<'a> { fn_name: &context.fn_name, source: context.source.as_ref().map(String::as_str), global: &context.global, - lib: &context.lib, pos: context.pos, } } @@ -213,7 +203,6 @@ impl<'a> NativeCallContext<'a> { fn_name: self.fn_name.to_string(), source: self.source.map(|s| s.to_string()), global: self.global.clone(), - lib: self.lib.iter().cloned().collect(), pos: self.pos, } } @@ -286,15 +275,15 @@ impl<'a> NativeCallContext<'a> { /// in reverse order (i.e. parent namespaces are iterated after child namespaces). #[inline] pub fn iter_namespaces(&self) -> impl Iterator { - self.lib.iter().map(|m| m.as_ref()) + self.global.lib.iter().map(|m| m.as_ref()) } /// _(internals)_ The current stack of namespaces containing definitions of all script-defined functions. /// Exported under the `internals` feature only. #[cfg(feature = "internals")] #[inline(always)] #[must_use] - pub const fn namespaces(&self) -> &[SharedModule] { - self.lib + pub fn namespaces(&self) -> &[SharedModule] { + &self.global.lib } /// Call a function inside the call context with the provided arguments. #[inline] @@ -431,7 +420,6 @@ impl<'a> NativeCallContext<'a> { .exec_native_fn_call( global, caches, - self.lib, fn_name, op_token, calc_fn_hash(None, fn_name, args_len), @@ -458,7 +446,6 @@ impl<'a> NativeCallContext<'a> { .exec_fn_call( global, caches, - self.lib, None, fn_name, op_token, diff --git a/src/func/script.rs b/src/func/script.rs index 734acace..cc733691 100644 --- a/src/func/script.rs +++ b/src/func/script.rs @@ -4,7 +4,7 @@ use super::call::FnCallArgs; use crate::ast::ScriptFnDef; use crate::eval::{Caches, GlobalRuntimeState}; -use crate::{Dynamic, Engine, Position, RhaiError, RhaiResult, Scope, SharedModule, ERR}; +use crate::{Dynamic, Engine, Position, RhaiError, RhaiResult, Scope, ERR}; use std::mem; #[cfg(feature = "no_std")] use std::prelude::v1::*; @@ -26,7 +26,6 @@ impl Engine { &self, global: &mut GlobalRuntimeState, caches: &mut Caches, - lib: &[SharedModule], scope: &mut Scope, this_ptr: &mut Dynamic, fn_def: &ScriptFnDef, @@ -79,6 +78,7 @@ impl Engine { } let orig_scope_len = scope.len(); + let orig_lib_len = global.lib.len(); #[cfg(not(feature = "no_module"))] let orig_imports_len = global.num_imports(); @@ -106,12 +106,9 @@ impl Engine { let orig_fn_resolution_caches_len = caches.fn_resolution_caches_len(); #[cfg(not(feature = "no_module"))] - let mut lib_merged = crate::StaticVec::with_capacity(lib.len() + 1); - - #[cfg(not(feature = "no_module"))] - let (lib, constants) = if let Some(ref environ) = fn_def.environ { + let orig_constants = if let Some(ref environ) = fn_def.environ { let crate::ast::EncapsulatedEnviron { - lib: ref fn_lib, + ref lib, ref imports, ref constants, } = **environ; @@ -121,38 +118,24 @@ impl Engine { .cloned() .for_each(|(n, m)| global.push_import(n, m)); - ( - if fn_lib.is_empty() { - lib - } else { - caches.push_fn_resolution_cache(); - lib_merged.push(fn_lib.clone()); - lib_merged.extend(lib.iter().cloned()); - &lib_merged - }, - Some(mem::replace(&mut global.constants, constants.clone())), - ) + if !lib.is_empty() { + global.lib.push(lib.clone()); + } + + Some(mem::replace(&mut global.constants, constants.clone())) } else { - (lib, None) + None }; #[cfg(feature = "debugging")] { let node = crate::ast::Stmt::Noop(fn_def.body.position()); - self.run_debugger(global, caches, lib, scope, this_ptr, &node)?; + self.run_debugger(global, caches, scope, this_ptr, &node)?; } // Evaluate the function let mut _result = self - .eval_stmt_block( - global, - caches, - lib, - scope, - this_ptr, - &fn_def.body, - rewind_scope, - ) + .eval_stmt_block(global, caches, scope, this_ptr, &fn_def.body, rewind_scope) .or_else(|err| match *err { // Convert return statement to return value ERR::Return(x, ..) => Ok(x), @@ -188,7 +171,7 @@ impl Engine { Ok(ref r) => crate::eval::DebuggerEvent::FunctionExitWithValue(r), Err(ref err) => crate::eval::DebuggerEvent::FunctionExitWithError(err), }; - match self.run_debugger_raw(global, caches, lib, scope, this_ptr, node, event) { + match self.run_debugger_raw(global, caches, scope, this_ptr, node, event) { Ok(_) => (), Err(err) => _result = Err(err), } @@ -205,12 +188,13 @@ impl Engine { // Remove arguments only, leaving new variables in the scope scope.remove_range(orig_scope_len, args.len()); } + global.lib.truncate(orig_lib_len); #[cfg(not(feature = "no_module"))] global.truncate_imports(orig_imports_len); // Restore constants #[cfg(not(feature = "no_module"))] - if let Some(constants) = constants { + if let Some(constants) = orig_constants { global.constants = constants; } @@ -224,9 +208,8 @@ impl Engine { #[must_use] pub(crate) fn has_script_fn( &self, - _global: &GlobalRuntimeState, + global: &GlobalRuntimeState, caches: &mut Caches, - lib: &[SharedModule], hash_script: u64, ) -> bool { let cache = caches.fn_resolution_cache_mut(); @@ -236,14 +219,14 @@ impl Engine { } // First check script-defined functions - let result = lib.iter().any(|m| m.contains_fn(hash_script)) + let result = global.lib.iter().any(|m| m.contains_fn(hash_script)) // Then check the global namespace and packages || self.global_modules.iter().any(|m| m.contains_fn(hash_script)); #[cfg(not(feature = "no_module"))] let result = result || // Then check imported modules - _global.contains_qualified_fn(hash_script) + global.contains_qualified_fn(hash_script) // Then check sub-modules || self.global_sub_modules.values().any(|m| m.contains_qualified_fn(hash_script)); diff --git a/src/module/mod.rs b/src/module/mod.rs index a8676655..78e7bc58 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -1980,6 +1980,7 @@ impl Module { // Save global state let orig_imports_len = global.num_imports(); let orig_source = global.source.clone(); + let orig_lib_len = global.lib.len(); #[cfg(not(feature = "no_function"))] let orig_constants = std::mem::take(&mut global.constants); @@ -2008,6 +2009,7 @@ impl Module { #[cfg(not(feature = "no_function"))] let constants = std::mem::replace(&mut global.constants, orig_constants); global.truncate_imports(orig_imports_len); + global.lib.truncate(orig_lib_len); global.source = orig_source; result?; diff --git a/src/optimizer.rs b/src/optimizer.rs index 8812db59..789a7bea 100644 --- a/src/optimizer.rs +++ b/src/optimizer.rs @@ -59,9 +59,6 @@ struct OptimizerState<'a> { global: GlobalRuntimeState, /// Function resolution caches. caches: Caches, - /// [Module][crate::Module] containing script-defined functions. - #[cfg(not(feature = "no_function"))] - lib: &'a [crate::SharedModule], /// Optimization level. optimization_level: OptimizationLevel, } @@ -74,15 +71,16 @@ impl<'a> OptimizerState<'a> { #[cfg(not(feature = "no_function"))] lib: &'a [crate::SharedModule], optimization_level: OptimizationLevel, ) -> Self { + let mut global = GlobalRuntimeState::new(engine); + global.lib = lib.iter().cloned().collect(); + Self { changed: false, variables: StaticVec::new_const(), propagate_constants: true, engine, - global: GlobalRuntimeState::new(engine), + global, caches: Caches::new(), - #[cfg(not(feature = "no_function"))] - lib, optimization_level, } } @@ -138,16 +136,10 @@ impl<'a> OptimizerState<'a> { op_token: Option<&Token>, arg_values: &mut [Dynamic], ) -> Dynamic { - #[cfg(not(feature = "no_function"))] - let lib = self.lib; - #[cfg(feature = "no_function")] - let lib = &[]; - self.engine .exec_native_fn_call( &mut self.global, &mut self.caches, - lib, fn_name, op_token, calc_fn_hash(None, fn_name, arg_values.len()), @@ -1138,12 +1130,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, _chaining: bool) { _ if x.args.len() == 2 && x.op_token.is_some() && (state.engine.fast_operators() || !has_native_fn_override(state.engine, x.hashes.native(), &arg_types)) => { if let Some(result) = get_builtin_binary_op_fn(x.op_token.as_ref().unwrap(), &arg_values[0], &arg_values[1]) .and_then(|f| { - #[cfg(not(feature = "no_function"))] - let lib = state.lib; - #[cfg(feature = "no_function")] - let lib = &[][..]; - - let context = (state.engine, x.name.as_str(),None, &state.global, lib, *pos).into(); + let context = (state.engine, x.name.as_str(),None, &state.global, *pos).into(); let (first, second) = arg_values.split_first_mut().unwrap(); (f)(context, &mut [ first, &mut second[0] ]).ok() }) { @@ -1183,7 +1170,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, _chaining: bool) { => { // First search for script-defined functions (can override built-in) #[cfg(not(feature = "no_function"))] - let has_script_fn = !x.hashes.is_native_only() && state.lib.iter().find_map(|m| m.get_script_fn(&x.name, x.args.len())).is_some(); + let has_script_fn = !x.hashes.is_native_only() && state.global.lib.iter().find_map(|m| m.get_script_fn(&x.name, x.args.len())).is_some(); #[cfg(feature = "no_function")] let has_script_fn = false; diff --git a/src/parser.rs b/src/parser.rs index b57da9c3..38f357bf 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -2909,14 +2909,8 @@ impl Engine { let caches = &mut Caches::new(); let mut this = Dynamic::NULL; - let context = EvalContext::new( - self, - &mut state.global, - caches, - &[], - &mut state.stack, - &mut this, - ); + let context = + EvalContext::new(self, &mut state.global, caches, &mut state.stack, &mut this); match filter(false, info, context) { Ok(true) => (), diff --git a/src/tests.rs b/src/tests.rs index 6e36c977..01a0e8e7 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -45,9 +45,9 @@ fn check_struct_sizes() { assert_eq!( size_of::(), if cfg!(feature = "no_position") { - 64 + 48 } else { - 72 + 56 } ); } diff --git a/src/types/fn_ptr.rs b/src/types/fn_ptr.rs index 5d087ef2..7d11ecd7 100644 --- a/src/types/fn_ptr.rs +++ b/src/types/fn_ptr.rs @@ -5,7 +5,7 @@ use crate::tokenizer::is_valid_function_name; use crate::types::dynamic::Variant; use crate::{ Dynamic, Engine, FuncArgs, ImmutableString, NativeCallContext, Position, RhaiError, RhaiResult, - RhaiResultOf, SharedModule, StaticVec, AST, ERR, + RhaiResultOf, StaticVec, AST, ERR, }; #[cfg(feature = "no_std")] use std::prelude::v1::*; @@ -151,19 +151,14 @@ impl FnPtr { let mut arg_values = crate::StaticVec::new_const(); args.parse(&mut arg_values); - let lib: &[SharedModule] = &[ - #[cfg(not(feature = "no_function"))] - AsRef::::as_ref(ast).clone(), - ]; - let lib = if lib.first().map_or(true, |m| m.is_empty()) { - &[][..] - } else { - &lib - }; + let global = &mut GlobalRuntimeState::new(engine); - let global = &GlobalRuntimeState::new(engine); + #[cfg(not(feature = "no_function"))] + if !_ast.functions().is_empty() { + global.lib.push(_ast.functions().clone()); + } - let ctx = (engine, self.fn_name(), None, global, lib, Position::NONE).into(); + let ctx = (engine, self.fn_name(), None, &*global, Position::NONE).into(); let result = self.call_raw(&ctx, None, arg_values)?;