diff --git a/Cargo.toml b/Cargo.toml index b4b99a8b..4fc4877a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ members = [ [package] name = "rhai" -version = "0.19.4" +version = "0.19.5" edition = "2018" authors = ["Jonathan Turner", "Lukáš Hozda", "Stephen Chung", "jhwgh1968"] description = "Embedded scripting for Rust" diff --git a/RELEASES.md b/RELEASES.md index 9c654cdd..0b9659df 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,6 +1,14 @@ Rhai Release Notes ================== +Version 0.19.5 +============== + +Breaking changes +---------------- + +* Modules imported at global level can now be accessed in functions. + Version 0.19.4 ============== diff --git a/doc/src/context.json b/doc/src/context.json index 7bf82955..597eb0df 100644 --- a/doc/src/context.json +++ b/doc/src/context.json @@ -1,5 +1,5 @@ { - "version": "0.19.4", + "version": "0.19.5", "repoHome": "https://github.com/jonathandturner/rhai/blob/master", "repoTree": "https://github.com/jonathandturner/rhai/tree/master", "rootUrl": "", diff --git a/doc/src/language/fn-namespaces.md b/doc/src/language/fn-namespaces.md index 0e3819b2..f4071421 100644 --- a/doc/src/language/fn-namespaces.md +++ b/doc/src/language/fn-namespaces.md @@ -82,8 +82,9 @@ fn get_message() { "Hello!" } | script.rhai | --------------- +import "message" as msg; + fn say_hello() { - import "message" as msg; print(msg::get_message()); } say_hello(); diff --git a/doc/src/language/fn-ptr.md b/doc/src/language/fn-ptr.md index 71d384c4..d10ff4d4 100644 --- a/doc/src/language/fn-ptr.md +++ b/doc/src/language/fn-ptr.md @@ -77,7 +77,6 @@ f::do_work(); // works! let p = Fn("f::do_work"); // error: invalid function name fn do_work_now() { // call it from a local function - import "foo" as f; f::do_work(); } diff --git a/src/engine.rs b/src/engine.rs index e88cee23..8f6429e1 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -88,10 +88,6 @@ impl Imports { pub fn get(&self, index: usize) -> Option<&Module> { self.0.get(index) } - /// Get a mutable reference to the imported module at a particular index. - pub fn get_mut(&mut self, index: usize) -> Option<&mut Module> { - self.0.get_mut(index) - } /// Get the index of an imported module by name. pub fn find(&self, name: &str) -> Option { self.1 @@ -658,35 +654,6 @@ pub fn search_imports<'s>( }) } -/// Search for a module within an imports stack. -/// Position in `EvalAltResult` is `None` and must be set afterwards. -pub fn search_imports_mut<'s>( - mods: &'s mut Imports, - state: &mut State, - modules: &ModuleRef, -) -> Result<&'s mut Module, Box> { - let Ident { name: root, pos } = &modules[0]; - - // Qualified - check if the root module is directly indexed - let index = if state.always_search { - 0 - } else { - modules.index().map_or(0, NonZeroUsize::get) - }; - - Ok(if index > 0 { - let offset = mods.len() - index; - mods.get_mut(offset).expect("invalid index in Imports") - } else { - if let Some(n) = mods.find(root) { - mods.get_mut(n) - } else { - None - } - .ok_or_else(|| EvalAltResult::ErrorModuleNotFound(root.to_string(), *pos))? - }) -} - impl Engine { /// Create a new `Engine` #[inline(always)] @@ -803,7 +770,7 @@ impl Engine { pub(crate) fn search_namespace<'s, 'a>( &self, scope: &'s mut Scope, - mods: &'s mut Imports, + mods: &mut Imports, state: &mut State, lib: &[&Module], this_ptr: &'s mut Option<&mut Dynamic>, @@ -813,8 +780,8 @@ impl Engine { Expr::Variable(v) => match v.as_ref() { // Qualified variable (_, Some(modules), hash_var, Ident { name, pos }) => { - let module = search_imports_mut(mods, state, modules)?; - let target = module.get_qualified_var_mut(*hash_var).map_err(|mut err| { + let module = search_imports(mods, state, modules)?; + let target = module.get_qualified_var(*hash_var).map_err(|mut err| { match *err { EvalAltResult::ErrorVariableNotFound(ref mut err_name, _) => { *err_name = format!("{}{}", modules, name); @@ -825,7 +792,7 @@ impl Engine { })?; // Module variables are constant - Ok((target.into(), name, ScopeEntryType::Constant, *pos)) + Ok((target.clone().into(), name, ScopeEntryType::Constant, *pos)) } // Normal variable access _ => self.search_scope_only(scope, mods, state, lib, this_ptr, expr), @@ -909,6 +876,7 @@ impl Engine { #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] fn eval_dot_index_chain_helper( &self, + mods: &mut Imports, state: &mut State, lib: &[&Module], this_ptr: &mut Option<&mut Dynamic>, @@ -945,12 +913,12 @@ impl Engine { let idx_pos = x.lhs.position(); let idx_val = idx_val.as_value(); let obj_ptr = &mut self.get_indexed_mut( - state, lib, target, idx_val, idx_pos, false, true, level, + mods, state, lib, target, idx_val, idx_pos, false, true, level, )?; self.eval_dot_index_chain_helper( - state, lib, this_ptr, obj_ptr, &x.rhs, idx_values, next_chain, level, - new_val, + mods, state, lib, this_ptr, obj_ptr, &x.rhs, idx_values, next_chain, + level, new_val, ) .map_err(|err| err.fill_position(*x_pos)) } @@ -960,9 +928,9 @@ impl Engine { let mut idx_val2 = idx_val.clone(); // `call_setter` is introduced to bypass double mutable borrowing of target - let _call_setter = match self - .get_indexed_mut(state, lib, target, idx_val, pos, true, false, level) - { + let _call_setter = match self.get_indexed_mut( + mods, state, lib, target, idx_val, pos, true, false, level, + ) { // Indexed value is a reference - update directly Ok(ref mut obj_ptr) => { obj_ptr.set_value(new_val.unwrap())?; @@ -984,8 +952,8 @@ impl Engine { let args = &mut [val, &mut idx_val2, &mut new_val.0]; self.exec_fn_call( - state, lib, FN_IDX_SET, 0, args, is_ref, true, false, None, None, - level, + mods, state, lib, FN_IDX_SET, 0, args, is_ref, true, false, None, + None, level, ) .map_err(|err| match *err { EvalAltResult::ErrorFunctionNotFound(fn_sig, _) @@ -1005,8 +973,10 @@ impl Engine { // xxx[rhs] _ => { let idx_val = idx_val.as_value(); - self.get_indexed_mut(state, lib, target, idx_val, pos, false, true, level) - .map(|v| (v.take_or_clone(), false)) + self.get_indexed_mut( + mods, state, lib, target, idx_val, pos, false, true, level, + ) + .map(|v| (v.take_or_clone(), false)) } } } @@ -1026,7 +996,8 @@ impl Engine { let def_value = def_value.map(Into::::into); let args = idx_val.as_fn_call_args(); self.make_method_call( - state, lib, name, *hash, target, args, def_value, *native, false, level, + mods, state, lib, name, *hash, target, args, def_value, *native, false, + level, ) .map_err(|err| err.fill_position(*pos)) } @@ -1036,8 +1007,9 @@ impl Engine { Expr::Property(x) if target.is::() && new_val.is_some() => { let IdentX { name, pos } = &x.1; let index = name.clone().into(); - let mut val = self - .get_indexed_mut(state, lib, target, index, *pos, true, false, level)?; + let mut val = self.get_indexed_mut( + mods, state, lib, target, index, *pos, true, false, level, + )?; val.set_value(new_val.unwrap())?; Ok((Default::default(), true)) @@ -1047,7 +1019,7 @@ impl Engine { let IdentX { name, pos } = &x.1; let index = name.clone().into(); let val = self.get_indexed_mut( - state, lib, target, index, *pos, false, false, level, + mods, state, lib, target, index, *pos, false, false, level, )?; Ok((val.take_or_clone(), false)) @@ -1058,8 +1030,8 @@ impl Engine { let mut new_val = new_val; let mut args = [target.as_mut(), &mut new_val.as_mut().unwrap().0]; self.exec_fn_call( - state, lib, setter, 0, &mut args, is_ref, true, false, None, None, - level, + mods, state, lib, setter, 0, &mut args, is_ref, true, false, None, + None, level, ) .map(|(v, _)| (v, true)) .map_err(|err| err.fill_position(*pos)) @@ -1069,8 +1041,8 @@ impl Engine { let ((getter, _), IdentX { pos, .. }) = x.as_ref(); let mut args = [target.as_mut()]; self.exec_fn_call( - state, lib, getter, 0, &mut args, is_ref, true, false, None, None, - level, + mods, state, lib, getter, 0, &mut args, is_ref, true, false, None, + None, level, ) .map(|(v, _)| (v, false)) .map_err(|err| err.fill_position(*pos)) @@ -1082,7 +1054,7 @@ impl Engine { let IdentX { name, pos } = &p.1; let index = name.clone().into(); self.get_indexed_mut( - state, lib, target, index, *pos, false, true, level, + mods, state, lib, target, index, *pos, false, true, level, )? } // {xxx:map}.fn_name(arg_expr_list)[expr] | {xxx:map}.fn_name(arg_expr_list).expr @@ -1098,8 +1070,8 @@ impl Engine { let args = idx_val.as_fn_call_args(); let (val, _) = self .make_method_call( - state, lib, name, *hash, target, args, def_value, *native, - false, level, + mods, state, lib, name, *hash, target, args, def_value, + *native, false, level, ) .map_err(|err| err.fill_position(*pos))?; val.into() @@ -1111,8 +1083,8 @@ impl Engine { }; self.eval_dot_index_chain_helper( - state, lib, this_ptr, &mut val, &x.rhs, idx_values, next_chain, level, - new_val, + mods, state, lib, this_ptr, &mut val, &x.rhs, idx_values, next_chain, + level, new_val, ) .map_err(|err| err.fill_position(*x_pos)) } @@ -1126,8 +1098,8 @@ impl Engine { let args = &mut arg_values[..1]; let (mut val, updated) = self .exec_fn_call( - state, lib, getter, 0, args, is_ref, true, false, None, - None, level, + mods, state, lib, getter, 0, args, is_ref, true, false, + None, None, level, ) .map_err(|err| err.fill_position(*pos))?; @@ -1135,6 +1107,7 @@ impl Engine { let (result, may_be_changed) = self .eval_dot_index_chain_helper( + mods, state, lib, this_ptr, @@ -1152,8 +1125,8 @@ impl Engine { // Re-use args because the first &mut parameter will not be consumed arg_values[1] = val; self.exec_fn_call( - state, lib, setter, 0, arg_values, is_ref, true, false, - None, None, level, + mods, state, lib, setter, 0, arg_values, is_ref, true, + false, None, None, level, ) .or_else( |err| match *err { @@ -1181,16 +1154,16 @@ impl Engine { let args = idx_val.as_fn_call_args(); let (mut val, _) = self .make_method_call( - state, lib, name, *hash, target, args, def_value, *native, - false, level, + mods, state, lib, name, *hash, target, args, def_value, + *native, false, level, ) .map_err(|err| err.fill_position(*pos))?; let val = &mut val; let target = &mut val.into(); self.eval_dot_index_chain_helper( - state, lib, this_ptr, target, &x.rhs, idx_values, next_chain, - level, new_val, + mods, state, lib, this_ptr, target, &x.rhs, idx_values, + next_chain, level, new_val, ) .map_err(|err| err.fill_position(*pos)) } @@ -1275,7 +1248,8 @@ impl Engine { let obj_ptr = &mut target.into(); self.eval_dot_index_chain_helper( - state, lib, &mut None, obj_ptr, dot_rhs, idx_values, chain_type, level, new_val, + mods, state, lib, &mut None, obj_ptr, dot_rhs, idx_values, chain_type, level, + new_val, ) .map(|(v, _)| v) .map_err(|err| err.fill_position(op_pos)) @@ -1287,7 +1261,8 @@ impl Engine { let val = self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?; let obj_ptr = &mut val.into(); self.eval_dot_index_chain_helper( - state, lib, this_ptr, obj_ptr, dot_rhs, idx_values, chain_type, level, new_val, + mods, state, lib, this_ptr, obj_ptr, dot_rhs, idx_values, chain_type, level, + new_val, ) .map(|(v, _)| v) .map_err(|err| err.fill_position(op_pos)) @@ -1375,6 +1350,7 @@ impl Engine { #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] fn get_indexed_mut<'a>( &self, + _mods: &mut Imports, state: &mut State, _lib: &[&Module], target: &'a mut Target, @@ -1457,7 +1433,8 @@ impl Engine { let mut idx = idx; let args = &mut [val, &mut idx]; self.exec_fn_call( - state, _lib, FN_IDX_GET, 0, args, is_ref, true, false, None, None, _level, + _mods, state, _lib, FN_IDX_GET, 0, args, is_ref, true, false, None, None, + _level, ) .map(|(v, _)| v.into()) .map_err(|err| match *err { @@ -1846,8 +1823,8 @@ impl Engine { // Run function let (value, _) = self .exec_fn_call( - state, lib, op, 0, args, false, false, false, None, None, - level, + mods, state, lib, op, 0, args, false, false, false, None, + None, level, ) .map_err(|err| err.fill_position(*op_pos))?; @@ -1884,7 +1861,7 @@ impl Engine { let result = self .exec_fn_call( - state, lib, op, 0, args, false, false, false, None, None, level, + mods, state, lib, op, 0, args, false, false, false, None, None, level, ) .map(|(v, _)| v) .map_err(|err| err.fill_position(*op_pos))?; diff --git a/src/fn_call.rs b/src/fn_call.rs index 18932715..d1fb23d3 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -469,6 +469,7 @@ impl Engine { /// **DO NOT** reuse the argument values unless for the first `&mut` argument - all others are silently replaced by `()`! pub(crate) fn exec_fn_call( &self, + mods: &mut Imports, state: &mut State, lib: &[&Module], fn_name: &str, @@ -535,7 +536,6 @@ impl Engine { let func = func.get_fn_def(); let scope: &mut Scope = &mut Default::default(); - let mods = &mut Default::default(); // Move captured variables into scope #[cfg(not(feature = "no_closure"))] @@ -684,6 +684,7 @@ impl Engine { #[cfg(not(feature = "no_object"))] pub(crate) fn make_method_call( &self, + mods: &mut Imports, state: &mut State, lib: &[&Module], name: &str, @@ -723,7 +724,7 @@ impl Engine { // Map it to name(args) in function-call style self.exec_fn_call( - state, lib, fn_name, hash, args, false, false, pub_only, None, def_val, level, + mods, state, lib, fn_name, hash, args, false, false, pub_only, None, def_val, level, ) } else if _fn_name == KEYWORD_FN_PTR_CALL && call_args.len() > 0 @@ -750,7 +751,7 @@ impl Engine { // Map it to name(args) in function-call style self.exec_fn_call( - state, lib, fn_name, hash, args, is_ref, true, pub_only, None, def_val, level, + mods, state, lib, fn_name, hash, args, is_ref, true, pub_only, None, def_val, level, ) } else if _fn_name == KEYWORD_FN_PTR_CURRY && obj.is::() { // Curry call @@ -818,7 +819,8 @@ impl Engine { let args = arg_values.as_mut(); self.exec_fn_call( - state, lib, _fn_name, hash, args, is_ref, true, pub_only, None, def_val, level, + mods, state, lib, _fn_name, hash, args, is_ref, true, pub_only, None, def_val, + level, ) }?; @@ -1064,7 +1066,7 @@ impl Engine { let args = args.as_mut(); self.exec_fn_call( - state, lib, name, hash, args, is_ref, false, pub_only, capture, def_val, level, + mods, state, lib, name, hash, args, is_ref, false, pub_only, capture, def_val, level, ) .map(|(v, _)| v) } @@ -1176,12 +1178,11 @@ impl Engine { } let args = args.as_mut(); - let fn_def = f.get_fn_def(); + let fn_def = f.get_shared_fn_def().clone(); let new_scope = &mut Default::default(); - let mods = &mut Default::default(); - self.call_script_fn(new_scope, mods, state, lib, &mut None, fn_def, args, level) + self.call_script_fn(new_scope, mods, state, lib, &mut None, &fn_def, args, level) } Some(f) if f.is_plugin_fn() => { f.get_plugin_fn().call((self, lib).into(), args.as_mut()) diff --git a/src/fn_native.rs b/src/fn_native.rs index ef30149c..9b80d59a 100644 --- a/src/fn_native.rs +++ b/src/fn_native.rs @@ -183,6 +183,7 @@ impl FnPtr { ctx.engine() .exec_fn_call( + &mut Default::default(), &mut Default::default(), ctx.lib, fn_name, diff --git a/src/module/mod.rs b/src/module/mod.rs index c4853cf3..b0226d37 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -268,20 +268,17 @@ impl Module { self } - /// Get a mutable reference to a modules-qualified variable. + /// Get a reference to a modules-qualified variable. /// Name and Position in `EvalAltResult` are None and must be set afterwards. /// /// The `u64` hash is calculated by the function `crate::calc_native_fn_hash`. #[inline(always)] - pub(crate) fn get_qualified_var_mut( - &mut self, - hash_var: u64, - ) -> Result<&mut Dynamic, Box> { + pub(crate) fn get_qualified_var(&self, hash_var: u64) -> Result<&Dynamic, Box> { if hash_var == 0 { Err(EvalAltResult::ErrorVariableNotFound(String::new(), NO_POS).into()) } else { self.all_variables - .get_mut(&hash_var) + .get(&hash_var) .ok_or_else(|| EvalAltResult::ErrorVariableNotFound(String::new(), NO_POS).into()) } }