Enable functions to use global imports.
This commit is contained in:
parent
07a8a43298
commit
6bc5ba6668
@ -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"
|
||||
|
@ -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
|
||||
==============
|
||||
|
@ -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": "",
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
123
src/engine.rs
123
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<usize> {
|
||||
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<EvalAltResult>> {
|
||||
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,7 +973,9 @@ impl Engine {
|
||||
// xxx[rhs]
|
||||
_ => {
|
||||
let idx_val = idx_val.as_value();
|
||||
self.get_indexed_mut(state, lib, target, idx_val, pos, false, true, level)
|
||||
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::<Dynamic>::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::<Map>() && 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))?;
|
||||
|
@ -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::<FnPtr>() {
|
||||
// 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())
|
||||
|
@ -183,6 +183,7 @@ impl FnPtr {
|
||||
|
||||
ctx.engine()
|
||||
.exec_fn_call(
|
||||
&mut Default::default(),
|
||||
&mut Default::default(),
|
||||
ctx.lib,
|
||||
fn_name,
|
||||
|
@ -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<EvalAltResult>> {
|
||||
pub(crate) fn get_qualified_var(&self, hash_var: u64) -> Result<&Dynamic, Box<EvalAltResult>> {
|
||||
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())
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user