Code enhancements.
This commit is contained in:
parent
e1ac6cc90e
commit
dc4e52e795
@ -13,11 +13,13 @@ Breaking changes
|
||||
* `Engine::load_package` is renamed `Engine::register_global_module` and now must explicitly pass a shared [`Module`].
|
||||
* `Engine::register_module` is renamed `Engine::register_static_module` and now must explicitly pass a shared [`Module`].
|
||||
* `Package::get` is renamed `Package::as_shared_module`.
|
||||
* `Engine::set_module_resolver` now takes a straight module resolver instead of an `Option`. To disable module resolving, use the new `DummyModuleResolver`.
|
||||
|
||||
Enhancements
|
||||
------------
|
||||
|
||||
* `Scope` is now `Clone + Hash`.
|
||||
* `Engine::register_static_module` now supports sub-module paths (e.g. `foo::bar::baz`).
|
||||
|
||||
|
||||
Version 0.19.8
|
||||
|
@ -21,7 +21,7 @@
|
||||
//! let m = exported_module!(advanced_math);
|
||||
//! let mut r = StaticModuleResolver::new();
|
||||
//! r.insert("Math::Advanced", m);
|
||||
//! engine.set_module_resolver(Some(r));
|
||||
//! engine.set_module_resolver(r);
|
||||
//!
|
||||
//! assert_eq!(engine.eval::<FLOAT>(
|
||||
//! r#"
|
||||
@ -51,7 +51,7 @@
|
||||
//! set_exported_fn!(m, "euclidean_distance", distance_function);
|
||||
//! let mut r = StaticModuleResolver::new();
|
||||
//! r.insert("Math::Advanced", m);
|
||||
//! engine.set_module_resolver(Some(r));
|
||||
//! engine.set_module_resolver(r);
|
||||
//!
|
||||
//! assert_eq!(engine.eval::<FLOAT>(
|
||||
//! r#"
|
||||
|
@ -18,14 +18,11 @@ fn raw_fn_test() -> Result<(), Box<EvalAltResult>> {
|
||||
engine.register_fn("get_mystic_number", || 42 as FLOAT);
|
||||
let mut m = Module::new();
|
||||
rhai::set_exported_fn!(m, "euclidean_distance", raw_fn::distance_function);
|
||||
let mut r = StaticModuleResolver::new();
|
||||
r.insert("Math::Advanced", m);
|
||||
engine.set_module_resolver(Some(r));
|
||||
engine.register_static_module("Math::Advanced", m.into());
|
||||
|
||||
assert_eq!(
|
||||
engine.eval::<FLOAT>(
|
||||
r#"import "Math::Advanced" as math;
|
||||
let x = math::euclidean_distance(0.0, 1.0, 0.0, get_mystic_number()); x"#
|
||||
r#"let x = Math::Advanced::euclidean_distance(0.0, 1.0, 0.0, get_mystic_number()); x"#
|
||||
)?,
|
||||
41.0
|
||||
);
|
||||
@ -48,16 +45,13 @@ fn raw_fn_mut_test() -> Result<(), Box<EvalAltResult>> {
|
||||
engine.register_fn("get_mystic_number", || 42 as FLOAT);
|
||||
let mut m = Module::new();
|
||||
rhai::set_exported_fn!(m, "add_in_place", raw_fn_mut::add_in_place);
|
||||
let mut r = StaticModuleResolver::new();
|
||||
r.insert("Math::Advanced", m);
|
||||
engine.set_module_resolver(Some(r));
|
||||
engine.register_static_module("Math::Advanced", m.into());
|
||||
|
||||
assert_eq!(
|
||||
engine.eval::<FLOAT>(
|
||||
r#"import "Math::Advanced" as math;
|
||||
let x = get_mystic_number();
|
||||
math::add_in_place(x, 1.0);
|
||||
x"#
|
||||
r#"let x = get_mystic_number();
|
||||
Math::Advanced::add_in_place(x, 1.0);
|
||||
x"#
|
||||
)?,
|
||||
43.0
|
||||
);
|
||||
@ -80,16 +74,10 @@ fn raw_fn_str_test() -> Result<(), Box<EvalAltResult>> {
|
||||
engine.register_fn("get_mystic_number", || 42 as FLOAT);
|
||||
let mut m = Module::new();
|
||||
rhai::set_exported_fn!(m, "write_out_str", raw_fn_str::write_out_str);
|
||||
let mut r = StaticModuleResolver::new();
|
||||
r.insert("Host::IO", m);
|
||||
engine.set_module_resolver(Some(r));
|
||||
engine.register_static_module("Host::IO", m.into());
|
||||
|
||||
assert_eq!(
|
||||
engine.eval::<bool>(
|
||||
r#"import "Host::IO" as io;
|
||||
let x = io::write_out_str("hello world!");
|
||||
x"#
|
||||
)?,
|
||||
engine.eval::<bool>(r#"let x = Host::IO::write_out_str("hello world!"); x"#)?,
|
||||
true
|
||||
);
|
||||
Ok(())
|
||||
@ -138,18 +126,16 @@ fn mut_opaque_ref_test() -> Result<(), Box<EvalAltResult>> {
|
||||
rhai::set_exported_fn!(m, "new_message", mut_opaque_ref::new_message);
|
||||
rhai::set_exported_fn!(m, "new_os_message", mut_opaque_ref::new_os_message);
|
||||
rhai::set_exported_fn!(m, "write_out_message", mut_opaque_ref::write_out_message);
|
||||
let mut r = StaticModuleResolver::new();
|
||||
r.insert("Host::Msg", m);
|
||||
engine.set_module_resolver(Some(r));
|
||||
engine.register_static_module("Host::Msg", m.into());
|
||||
|
||||
assert_eq!(
|
||||
engine.eval::<bool>(
|
||||
r#"import "Host::Msg" as msg;
|
||||
let message1 = msg::new_message(true, "it worked");
|
||||
let ok1 = msg::write_out_message(message1);
|
||||
let message2 = msg::new_os_message(true, 0);
|
||||
let ok2 = msg::write_out_message(message2);
|
||||
ok1 && ok2"#
|
||||
r#"
|
||||
let message1 = Host::Msg::new_message(true, "it worked");
|
||||
let ok1 = Host::Msg::write_out_message(message1);
|
||||
let message2 = Host::Msg::new_os_message(true, 0);
|
||||
let ok2 = Host::Msg::write_out_message(message2);
|
||||
ok1 && ok2"#
|
||||
)?,
|
||||
true
|
||||
);
|
||||
@ -179,14 +165,11 @@ fn raw_returning_fn_test() -> Result<(), Box<EvalAltResult>> {
|
||||
engine.register_fn("get_mystic_number", || 42 as FLOAT);
|
||||
let mut m = Module::new();
|
||||
rhai::set_exported_fn!(m, "euclidean_distance", raw_returning_fn::distance_function);
|
||||
let mut r = StaticModuleResolver::new();
|
||||
r.insert("Math::Advanced", m);
|
||||
engine.set_module_resolver(Some(r));
|
||||
engine.register_static_module("Math::Advanced", m.into());
|
||||
|
||||
assert_eq!(
|
||||
engine.eval::<FLOAT>(
|
||||
r#"import "Math::Advanced" as math;
|
||||
let x = math::euclidean_distance(0.0, 1.0, 0.0, get_mystic_number()); x"#
|
||||
r#"let x = Math::Advanced::euclidean_distance(0.0, 1.0, 0.0, get_mystic_number()); x"#
|
||||
)?,
|
||||
41.0
|
||||
);
|
||||
|
@ -12,14 +12,8 @@ pub mod empty_module {
|
||||
fn empty_module_test() -> Result<(), Box<EvalAltResult>> {
|
||||
let mut engine = Engine::new();
|
||||
let m = rhai::exported_module!(crate::empty_module::EmptyModule);
|
||||
let mut r = StaticModuleResolver::new();
|
||||
r.insert("Module::Empty", m);
|
||||
engine.set_module_resolver(Some(r));
|
||||
engine.register_static_module("Module::Empty", m.into());
|
||||
|
||||
assert_eq!(
|
||||
engine.eval::<INT>(r#"import "Module::Empty" as m; 42"#)?,
|
||||
42
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -39,16 +33,10 @@ pub mod one_fn_module {
|
||||
fn one_fn_module_test() -> Result<(), Box<EvalAltResult>> {
|
||||
let mut engine = Engine::new();
|
||||
let m = rhai::exported_module!(crate::one_fn_module::advanced_math);
|
||||
let mut r = StaticModuleResolver::new();
|
||||
r.insert("Math::Advanced", m);
|
||||
engine.set_module_resolver(Some(r));
|
||||
engine.register_static_module("Math::Advanced", m.into());
|
||||
|
||||
assert_eq!(
|
||||
engine.eval::<FLOAT>(
|
||||
r#"import "Math::Advanced" as math;
|
||||
let m = math::get_mystic_number();
|
||||
m"#
|
||||
)?,
|
||||
engine.eval::<FLOAT>(r#"let m = Math::Advanced::get_mystic_number();m"#)?,
|
||||
42.0
|
||||
);
|
||||
Ok(())
|
||||
@ -73,16 +61,14 @@ pub mod one_fn_and_const_module {
|
||||
fn one_fn_and_const_module_test() -> Result<(), Box<EvalAltResult>> {
|
||||
let mut engine = Engine::new();
|
||||
let m = rhai::exported_module!(crate::one_fn_and_const_module::advanced_math);
|
||||
let mut r = StaticModuleResolver::new();
|
||||
r.insert("Math::Advanced", m);
|
||||
engine.set_module_resolver(Some(r));
|
||||
engine.register_static_module("Math::Advanced", m.into());
|
||||
|
||||
assert_eq!(
|
||||
engine.eval::<FLOAT>(
|
||||
r#"import "Math::Advanced" as math;
|
||||
let m = math::MYSTIC_NUMBER;
|
||||
let x = math::euclidean_distance(0.0, 1.0, 0.0, m);
|
||||
x"#
|
||||
r#"
|
||||
let m = Math::Advanced::MYSTIC_NUMBER;
|
||||
let x = Math::Advanced::euclidean_distance(0.0, 1.0, 0.0, m);
|
||||
x"#
|
||||
)?,
|
||||
41.0
|
||||
);
|
||||
@ -105,16 +91,10 @@ pub mod raw_fn_str_module {
|
||||
fn raw_fn_str_module_test() -> Result<(), Box<EvalAltResult>> {
|
||||
let mut engine = Engine::new();
|
||||
let m = rhai::exported_module!(crate::raw_fn_str_module::host_io);
|
||||
let mut r = StaticModuleResolver::new();
|
||||
r.insert("Host::IO", m);
|
||||
engine.set_module_resolver(Some(r));
|
||||
engine.register_static_module("Host::IO", m.into());
|
||||
|
||||
assert_eq!(
|
||||
engine.eval::<bool>(
|
||||
r#"import "Host::IO" as io;
|
||||
let x = io::write_out_str("hello world!");
|
||||
x"#
|
||||
)?,
|
||||
engine.eval::<bool>(r#"let x = Host::IO::write_out_str("hello world!"); x"#)?,
|
||||
true
|
||||
);
|
||||
Ok(())
|
||||
@ -162,19 +142,17 @@ pub mod mut_opaque_ref_module {
|
||||
fn mut_opaque_ref_test() -> Result<(), Box<EvalAltResult>> {
|
||||
let mut engine = Engine::new();
|
||||
let m = rhai::exported_module!(crate::mut_opaque_ref_module::host_msg);
|
||||
let mut r = StaticModuleResolver::new();
|
||||
r.insert("Host::Msg", m);
|
||||
engine.set_module_resolver(Some(r));
|
||||
engine.register_static_module("Host::Msg", m.into());
|
||||
|
||||
assert_eq!(
|
||||
engine.eval::<bool>(
|
||||
r#"import "Host::Msg" as msg;
|
||||
let success = "it worked";
|
||||
let message1 = msg::new_message(true, success);
|
||||
let ok1 = msg::write_out_message(message1);
|
||||
let message2 = msg::new_os_message(true, 0);
|
||||
let ok2 = msg::write_out_message(message2);
|
||||
ok1 && ok2"#
|
||||
r#"
|
||||
let success = "it worked";
|
||||
let message1 = Host::Msg::new_message(true, success);
|
||||
let ok1 = Host::Msg::write_out_message(message1);
|
||||
let message2 = Host::Msg::new_os_message(true, 0);
|
||||
let ok2 = Host::Msg::write_out_message(message2);
|
||||
ok1 && ok2"#
|
||||
)?,
|
||||
true
|
||||
);
|
||||
@ -204,18 +182,16 @@ fn duplicate_fn_rename_test() -> Result<(), Box<EvalAltResult>> {
|
||||
let mut engine = Engine::new();
|
||||
engine.register_fn("get_mystic_number", || 42 as FLOAT);
|
||||
let m = rhai::exported_module!(crate::duplicate_fn_rename::my_adds);
|
||||
let mut r = StaticModuleResolver::new();
|
||||
r.insert("Math::Advanced", m);
|
||||
engine.set_module_resolver(Some(r));
|
||||
engine.register_static_module("Math::Advanced", m.into());
|
||||
|
||||
let output_array = engine.eval::<Array>(
|
||||
r#"import "Math::Advanced" as math;
|
||||
let fx = get_mystic_number();
|
||||
let fy = math::add(fx, 1.0);
|
||||
let ix = 42;
|
||||
let iy = math::add(ix, 1);
|
||||
[fy, iy]
|
||||
"#,
|
||||
r#"
|
||||
let fx = get_mystic_number();
|
||||
let fy = Math::Advanced::add(fx, 1.0);
|
||||
let ix = 42;
|
||||
let iy = Math::Advanced::add(ix, 1);
|
||||
[fy, iy]
|
||||
"#,
|
||||
)?;
|
||||
assert_eq!(&output_array[0].as_float().unwrap(), &43.0);
|
||||
assert_eq!(&output_array[1].as_int().unwrap(), &43);
|
||||
@ -329,20 +305,18 @@ mod export_by_prefix {
|
||||
fn export_by_prefix_test() -> Result<(), Box<EvalAltResult>> {
|
||||
let mut engine = Engine::new();
|
||||
let m = rhai::exported_module!(crate::export_by_prefix::my_adds);
|
||||
let mut r = StaticModuleResolver::new();
|
||||
r.insert("Math::Advanced", m);
|
||||
engine.set_module_resolver(Some(r));
|
||||
engine.register_static_module("Math::Advanced", m.into());
|
||||
|
||||
let output_array = engine.eval::<Array>(
|
||||
r#"import "Math::Advanced" as math;
|
||||
let ex = 41.0;
|
||||
let fx = math::foo_add_f(ex, 1.0);
|
||||
let gx = math::foo_m(41.0, 1.0);
|
||||
let ei = 41;
|
||||
let fi = math::bar_add_i(ei, 1);
|
||||
let gi = math::foo_n(41, 1);
|
||||
[fx, gx, fi, gi]
|
||||
"#,
|
||||
r#"
|
||||
let ex = 41.0;
|
||||
let fx = Math::Advanced::foo_add_f(ex, 1.0);
|
||||
let gx = Math::Advanced::foo_m(41.0, 1.0);
|
||||
let ei = 41;
|
||||
let fi = Math::Advanced::bar_add_i(ei, 1);
|
||||
let gi = Math::Advanced::foo_n(41, 1);
|
||||
[fx, gx, fi, gi]
|
||||
"#,
|
||||
)?;
|
||||
assert_eq!(&output_array[0].as_float().unwrap(), &42.0);
|
||||
assert_eq!(&output_array[1].as_float().unwrap(), &42.0);
|
||||
@ -350,24 +324,24 @@ fn export_by_prefix_test() -> Result<(), Box<EvalAltResult>> {
|
||||
assert_eq!(&output_array[3].as_int().unwrap(), &42);
|
||||
|
||||
assert!(matches!(*engine.eval::<FLOAT>(
|
||||
r#"import "Math::Advanced" as math;
|
||||
let ex = 41.0;
|
||||
let fx = math::foo_add_float2(ex, 1.0);
|
||||
fx
|
||||
"#).unwrap_err(),
|
||||
EvalAltResult::ErrorFunctionNotFound(s, p)
|
||||
if s == "math::foo_add_float2 (f64, f64)"
|
||||
&& p == rhai::Position::new(3, 23)));
|
||||
r#"
|
||||
let ex = 41.0;
|
||||
let fx = Math::Advanced::foo_add_float2(ex, 1.0);
|
||||
fx
|
||||
"#).unwrap_err(),
|
||||
EvalAltResult::ErrorFunctionNotFound(s, p)
|
||||
if s == "Math::Advanced::foo_add_float2 (f64, f64)"
|
||||
&& p == rhai::Position::new(3, 34)));
|
||||
|
||||
assert!(matches!(*engine.eval::<FLOAT>(
|
||||
r#"import "Math::Advanced" as math;
|
||||
let ex = 41.0;
|
||||
let fx = math::bar_m(ex, 1.0);
|
||||
fx
|
||||
"#).unwrap_err(),
|
||||
EvalAltResult::ErrorFunctionNotFound(s, p)
|
||||
if s == "math::bar_m (f64, f64)"
|
||||
&& p == rhai::Position::new(3, 23)));
|
||||
r#"
|
||||
let ex = 41.0;
|
||||
let fx = Math::Advanced::bar_m(ex, 1.0);
|
||||
fx
|
||||
"#).unwrap_err(),
|
||||
EvalAltResult::ErrorFunctionNotFound(s, p)
|
||||
if s == "Math::Advanced::bar_m (f64, f64)"
|
||||
&& p == rhai::Position::new(3, 34)));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -413,20 +387,18 @@ mod export_all {
|
||||
fn export_all_test() -> Result<(), Box<EvalAltResult>> {
|
||||
let mut engine = Engine::new();
|
||||
let m = rhai::exported_module!(crate::export_all::my_adds);
|
||||
let mut r = StaticModuleResolver::new();
|
||||
r.insert("Math::Advanced", m);
|
||||
engine.set_module_resolver(Some(r));
|
||||
engine.register_static_module("Math::Advanced", m.into());
|
||||
|
||||
let output_array = engine.eval::<Array>(
|
||||
r#"import "Math::Advanced" as math;
|
||||
let ex = 41.0;
|
||||
let fx = math::foo_add_f(ex, 1.0);
|
||||
let gx = math::foo_m(41.0, 1.0);
|
||||
let ei = 41;
|
||||
let fi = math::foo_add_i(ei, 1);
|
||||
let gi = math::foo_n(41, 1);
|
||||
[fx, gx, fi, gi]
|
||||
"#,
|
||||
r#"
|
||||
let ex = 41.0;
|
||||
let fx = Math::Advanced::foo_add_f(ex, 1.0);
|
||||
let gx = Math::Advanced::foo_m(41.0, 1.0);
|
||||
let ei = 41;
|
||||
let fi = Math::Advanced::foo_add_i(ei, 1);
|
||||
let gi = Math::Advanced::foo_n(41, 1);
|
||||
[fx, gx, fi, gi]
|
||||
"#,
|
||||
)?;
|
||||
assert_eq!(&output_array[0].as_float().unwrap(), &42.0);
|
||||
assert_eq!(&output_array[1].as_float().unwrap(), &42.0);
|
||||
@ -434,14 +406,14 @@ fn export_all_test() -> Result<(), Box<EvalAltResult>> {
|
||||
assert_eq!(&output_array[3].as_int().unwrap(), &42);
|
||||
|
||||
assert!(matches!(*engine.eval::<INT>(
|
||||
r#"import "Math::Advanced" as math;
|
||||
let ex = 41;
|
||||
let fx = math::foo_p(ex, 1);
|
||||
fx
|
||||
"#).unwrap_err(),
|
||||
EvalAltResult::ErrorFunctionNotFound(s, p)
|
||||
if s == "math::foo_p (i64, i64)"
|
||||
&& p == rhai::Position::new(3, 23)));
|
||||
r#"
|
||||
let ex = 41;
|
||||
let fx = Math::Advanced::foo_p(ex, 1);
|
||||
fx
|
||||
"#).unwrap_err(),
|
||||
EvalAltResult::ErrorFunctionNotFound(s, p)
|
||||
if s == "Math::Advanced::foo_p (i64, i64)"
|
||||
&& p == rhai::Position::new(3, 34)));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -20,16 +20,10 @@ pub mod one_fn_module_nested_attr {
|
||||
fn one_fn_module_nested_attr_test() -> Result<(), Box<EvalAltResult>> {
|
||||
let mut engine = Engine::new();
|
||||
let m = rhai::exported_module!(crate::one_fn_module_nested_attr::advanced_math);
|
||||
let mut r = StaticModuleResolver::new();
|
||||
r.insert("Math::Advanced", m);
|
||||
engine.set_module_resolver(Some(r));
|
||||
engine.register_static_module("Math::Advanced", m.into());
|
||||
|
||||
assert_eq!(
|
||||
engine.eval::<FLOAT>(
|
||||
r#"import "Math::Advanced" as math;
|
||||
let m = math::get_mystic_number();
|
||||
m"#
|
||||
)?,
|
||||
engine.eval::<FLOAT>(r#"let m = Math::Advanced::get_mystic_number(); m"#)?,
|
||||
42.0
|
||||
);
|
||||
Ok(())
|
||||
@ -56,16 +50,10 @@ pub mod one_fn_submodule_nested_attr {
|
||||
fn one_fn_submodule_nested_attr_test() -> Result<(), Box<EvalAltResult>> {
|
||||
let mut engine = Engine::new();
|
||||
let m = rhai::exported_module!(crate::one_fn_submodule_nested_attr::advanced_math);
|
||||
let mut r = StaticModuleResolver::new();
|
||||
r.insert("Math::Advanced", m);
|
||||
engine.set_module_resolver(Some(r));
|
||||
engine.register_static_module("Math::Advanced", m.into());
|
||||
|
||||
assert_eq!(
|
||||
engine.eval::<FLOAT>(
|
||||
r#"import "Math::Advanced" as math;
|
||||
let m = math::constants::get_mystic_number();
|
||||
m"#
|
||||
)?,
|
||||
engine.eval::<FLOAT>(r#"let m = Math::Advanced::constants::get_mystic_number(); m"#)?,
|
||||
42.0
|
||||
);
|
||||
Ok(())
|
||||
@ -131,26 +119,24 @@ mod export_nested_by_prefix {
|
||||
fn export_nested_by_prefix_test() -> Result<(), Box<EvalAltResult>> {
|
||||
let mut engine = Engine::new();
|
||||
let m = rhai::exported_module!(crate::export_nested_by_prefix::my_adds);
|
||||
let mut r = StaticModuleResolver::new();
|
||||
r.insert("Math::Advanced", m);
|
||||
engine.set_module_resolver(Some(r));
|
||||
engine.register_static_module("Math::Advanced", m.into());
|
||||
|
||||
let output_array = engine.eval::<Array>(
|
||||
r#"import "Math::Advanced" as math;
|
||||
let ex = 41.0;
|
||||
let fx = math::foo_first_adders::add_float(ex, 1.0);
|
||||
r#"
|
||||
let ex = 41.0;
|
||||
let fx = Math::Advanced::foo_first_adders::add_float(ex, 1.0);
|
||||
|
||||
let ei = 41;
|
||||
let fi = math::foo_first_adders::add_int(ei, 1);
|
||||
let ei = 41;
|
||||
let fi = Math::Advanced::foo_first_adders::add_int(ei, 1);
|
||||
|
||||
let gx = 41.0;
|
||||
let hx = math::foo_second_adders::add_float(gx, 1.0);
|
||||
let gx = 41.0;
|
||||
let hx = Math::Advanced::foo_second_adders::add_float(gx, 1.0);
|
||||
|
||||
let gi = 41;
|
||||
let hi = math::foo_second_adders::add_int(gi, 1);
|
||||
let gi = 41;
|
||||
let hi = Math::Advanced::foo_second_adders::add_int(gi, 1);
|
||||
|
||||
[fx, hx, fi, hi]
|
||||
"#,
|
||||
[fx, hx, fi, hi]
|
||||
"#,
|
||||
)?;
|
||||
assert_eq!(&output_array[0].as_float().unwrap(), &42.0);
|
||||
assert_eq!(&output_array[1].as_float().unwrap(), &42.0);
|
||||
@ -158,44 +144,44 @@ fn export_nested_by_prefix_test() -> Result<(), Box<EvalAltResult>> {
|
||||
assert_eq!(&output_array[3].as_int().unwrap(), &42);
|
||||
|
||||
assert!(matches!(*engine.eval::<FLOAT>(
|
||||
r#"import "Math::Advanced" as math;
|
||||
let ex = 41.0;
|
||||
let fx = math::foo_third_adders::add_float(ex, 1.0);
|
||||
fx
|
||||
"#).unwrap_err(),
|
||||
EvalAltResult::ErrorFunctionNotFound(s, p)
|
||||
if s == "math::foo_third_adders::add_float (f64, f64)"
|
||||
&& p == rhai::Position::new(3, 41)));
|
||||
r#"
|
||||
let ex = 41.0;
|
||||
let fx = Math::Advanced::foo_third_adders::add_float(ex, 1.0);
|
||||
fx
|
||||
"#).unwrap_err(),
|
||||
EvalAltResult::ErrorFunctionNotFound(s, p)
|
||||
if s == "Math::Advanced::foo_third_adders::add_float (f64, f64)"
|
||||
&& p == rhai::Position::new(3, 52)));
|
||||
|
||||
assert!(matches!(*engine.eval::<FLOAT>(
|
||||
r#"import "Math::Advanced" as math;
|
||||
let ex = 41;
|
||||
let fx = math::foo_third_adders::add_int(ex, 1);
|
||||
fx
|
||||
"#).unwrap_err(),
|
||||
EvalAltResult::ErrorFunctionNotFound(s, p)
|
||||
if s == "math::foo_third_adders::add_int (i64, i64)"
|
||||
&& p == rhai::Position::new(3, 41)));
|
||||
r#"
|
||||
let ex = 41;
|
||||
let fx = Math::Advanced::foo_third_adders::add_int(ex, 1);
|
||||
fx
|
||||
"#).unwrap_err(),
|
||||
EvalAltResult::ErrorFunctionNotFound(s, p)
|
||||
if s == "Math::Advanced::foo_third_adders::add_int (i64, i64)"
|
||||
&& p == rhai::Position::new(3, 52)));
|
||||
|
||||
assert!(matches!(*engine.eval::<FLOAT>(
|
||||
r#"import "Math::Advanced" as math;
|
||||
let ex = 41;
|
||||
let fx = math::bar_fourth_adders::add_int(ex, 1);
|
||||
fx
|
||||
"#).unwrap_err(),
|
||||
EvalAltResult::ErrorFunctionNotFound(s, p)
|
||||
if s == "math::bar_fourth_adders::add_int (i64, i64)"
|
||||
&& p == rhai::Position::new(3, 42)));
|
||||
r#"
|
||||
let ex = 41;
|
||||
let fx = Math::Advanced::bar_fourth_adders::add_int(ex, 1);
|
||||
fx
|
||||
"#).unwrap_err(),
|
||||
EvalAltResult::ErrorFunctionNotFound(s, p)
|
||||
if s == "Math::Advanced::bar_fourth_adders::add_int (i64, i64)"
|
||||
&& p == rhai::Position::new(3, 53)));
|
||||
|
||||
assert!(matches!(*engine.eval::<FLOAT>(
|
||||
r#"import "Math::Advanced" as math;
|
||||
let ex = 41.0;
|
||||
let fx = math::bar_fourth_adders::add_float(ex, 1.0);
|
||||
fx
|
||||
"#).unwrap_err(),
|
||||
EvalAltResult::ErrorFunctionNotFound(s, p)
|
||||
if s == "math::bar_fourth_adders::add_float (f64, f64)"
|
||||
&& p == rhai::Position::new(3, 42)));
|
||||
r#"
|
||||
let ex = 41.0;
|
||||
let fx = Math::Advanced::bar_fourth_adders::add_float(ex, 1.0);
|
||||
fx
|
||||
"#).unwrap_err(),
|
||||
EvalAltResult::ErrorFunctionNotFound(s, p)
|
||||
if s == "Math::Advanced::bar_fourth_adders::add_float (f64, f64)"
|
||||
&& p == rhai::Position::new(3, 53)));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -25,7 +25,6 @@ Use Case 1 - Make the `Module` Globally Available
|
||||
`Engine::register_global_module` registers a shared [module] into the _global_ namespace.
|
||||
|
||||
All [functions] and [type iterators] can be accessed without _namespace qualifiers_.
|
||||
|
||||
Variables and sub-modules are **ignored**.
|
||||
|
||||
This is by far the easiest way to expose a module's functionalities to Rhai.
|
||||
@ -35,11 +34,11 @@ use rhai::{Engine, Module};
|
||||
|
||||
let mut module = Module::new(); // new module
|
||||
|
||||
// Use the 'set_fn_XXX' API to add functions.
|
||||
let hash = module.set_fn_1("inc", |x: i64| Ok(x+1));
|
||||
// Use the 'Module::set_fn_XXX' API to add functions.
|
||||
let hash = module.set_fn_1("inc", |x: i64| Ok(x + 1));
|
||||
|
||||
// Remember to update the parameter names/types and return type metadata.
|
||||
// 'set_fn_XXX' by default does not set function metadata.
|
||||
// 'Module::set_fn_XXX' by default does not set function metadata.
|
||||
module.update_fn_metadata(hash, ["x: i64", "i64"]);
|
||||
|
||||
// Register the module into the global namespace of the Engine.
|
||||
@ -49,6 +48,19 @@ engine.register_global_module(module.into());
|
||||
engine.eval::<i64>("inc(41)")? == 42; // no need to import module
|
||||
```
|
||||
|
||||
Registering a [module] via `Engine::register_global_module` is essentially the _same_
|
||||
as calling `Engine::register_fn` (or any of the `Engine::register_XXX` API) individually
|
||||
on each top-level function within that [module]. In fact, the actual implementation of
|
||||
`Engine::register_fn` etc. simply adds the function to an internal [module]!
|
||||
|
||||
```rust
|
||||
// The above is essentially the same as:
|
||||
let mut engine = Engine::new();
|
||||
|
||||
engine.register_fn("inc", |x: i64| x + 1);
|
||||
|
||||
engine.eval::<i64>("inc(41)")? == 42; // no need to import module
|
||||
```
|
||||
|
||||
Use Case 2 - Make the `Module` a Static Module
|
||||
---------------------------------------------
|
||||
@ -60,25 +72,27 @@ use rhai::{Engine, Module};
|
||||
|
||||
let mut module = Module::new(); // new module
|
||||
|
||||
// Use the 'set_fn_XXX' API to add functions.
|
||||
let hash = module.set_fn_1("inc", |x: i64| Ok(x+1));
|
||||
// Use the 'Module::set_fn_XXX' API to add functions.
|
||||
let hash = module.set_fn_1("inc", |x: i64| Ok(x + 1));
|
||||
|
||||
// Remember to update the parameter names/types and return type metadata.
|
||||
// 'set_fn_XXX' by default does not set function metadata.
|
||||
// 'Module::set_fn_XXX' by default does not set function metadata.
|
||||
module.update_fn_metadata(hash, ["x: i64", "i64"]);
|
||||
|
||||
// Register the module into the Engine as a static module namespace 'calc'
|
||||
// Register the module into the Engine as the static module namespace path
|
||||
// 'services::calc'
|
||||
let mut engine = Engine::new();
|
||||
engine.register_static_module("calc", module.into());
|
||||
engine.register_static_module("services::calc", module.into());
|
||||
|
||||
engine.eval::<i64>("calc::inc(41)")? == 42; // refer to the 'Calc' module
|
||||
// refer to the 'services::calc' module
|
||||
engine.eval::<i64>("services::calc::inc(41)")? == 42;
|
||||
```
|
||||
|
||||
### Expose Functions to the Global Namespace
|
||||
|
||||
`Module::set_fn_mut` and `Module::set_fn_XXX_mut` can optionally expose functions (usually _methods_)
|
||||
in the module to the _global_ namespace, so [getters/setters] and [indexers] for [custom types]
|
||||
can work as expected.
|
||||
The `Module::set_fn_XXX_mut` API methods can optionally expose functions in the [module]
|
||||
to the _global_ namespace by setting the `namespace` parameter to `FnNamespace::Global`,
|
||||
so [getters/setters] and [indexers] for [custom types] can work as expected.
|
||||
|
||||
[Type iterators], because of their special nature, are _always_ exposed to the _global_ namespace.
|
||||
|
||||
@ -87,19 +101,24 @@ use rhai::{Engine, Module, FnNamespace};
|
||||
|
||||
let mut module = Module::new(); // new module
|
||||
|
||||
// Expose method 'inc' to the global namespace (default is 'Internal')
|
||||
let hash = module.set_fn_1_mut("inc", FnNamespace::Global, |x: &mut i64| Ok(x+1));
|
||||
// Expose method 'inc' to the global namespace (default is 'FnNamespace::Internal')
|
||||
let hash = module.set_fn_1_mut("inc", FnNamespace::Global, |x: &mut i64| Ok(x + 1));
|
||||
|
||||
// Remember to update the parameter names/types and return type metadata.
|
||||
// 'set_fn_XXX' by default does not set function metadata.
|
||||
// 'Module::set_fn_XXX_mut' by default does not set function metadata.
|
||||
module.update_fn_metadata(hash, ["x: &mut i64", "i64"]);
|
||||
|
||||
// Register the module into the Engine as a static module namespace 'calc'
|
||||
let mut engine = Engine::new();
|
||||
engine.register_static_module("calc", module.into());
|
||||
|
||||
// The method 'inc' works as expected because it is exposed to the global namespace
|
||||
// 'inc' works when qualified by the namespace
|
||||
engine.eval::<i64>("calc::inc(41)")? == 42;
|
||||
|
||||
// 'inc' also works without a namespace qualifier
|
||||
// because it is exposed to the global namespace
|
||||
engine.eval::<i64>("let x = 41; x.inc()")? == 42;
|
||||
engine.eval::<i64>("let x = 41; inc(x)")? == 42;
|
||||
```
|
||||
|
||||
|
||||
@ -118,7 +137,7 @@ use rhai::module_resolvers::StaticModuleResolver;
|
||||
|
||||
let mut module = Module::new(); // new module
|
||||
module.set_var("answer", 41_i64); // variable 'answer' under module
|
||||
module.set_fn_1("inc", |x: i64| Ok(x+1)); // use the 'set_fn_XXX' API to add functions
|
||||
module.set_fn_1("inc", |x: i64| Ok(x + 1)); // use the 'set_fn_XXX' API to add functions
|
||||
|
||||
// Create the module resolver
|
||||
let mut resolver = StaticModuleResolver::new();
|
||||
@ -129,7 +148,7 @@ resolver.insert("question", module);
|
||||
|
||||
// Set the module resolver into the 'Engine'
|
||||
let mut engine = Engine::new();
|
||||
engine.set_module_resolver(Some(resolver));
|
||||
engine.set_module_resolver(resolver);
|
||||
|
||||
// Use namespace-qualified variables
|
||||
engine.eval::<i64>(r#"import "question" as q; q::answer + 1"#)? == 42;
|
||||
|
@ -62,7 +62,7 @@ impl ModuleResolver for MyModuleResolver {
|
||||
let mut engine = Engine::new();
|
||||
|
||||
// Set the custom module resolver into the 'Engine'.
|
||||
engine.set_module_resolver(Some(MyModuleResolver {}));
|
||||
engine.set_module_resolver(MyModuleResolver {});
|
||||
|
||||
engine.consume(r#"
|
||||
import "hello" as foo; // this 'import' statement will call
|
||||
|
@ -153,13 +153,19 @@ A collection of module resolvers. Modules will be resolved from each resolver in
|
||||
This is useful when multiple types of modules are needed simultaneously.
|
||||
|
||||
|
||||
`DummyResolversCollection`
|
||||
-------------------------
|
||||
|
||||
This module resolver acts as a _dummy_ and always fails all module resolution calls.
|
||||
|
||||
|
||||
Set into `Engine`
|
||||
-----------------
|
||||
|
||||
An [`Engine`]'s module resolver is set via a call to `Engine::set_module_resolver`:
|
||||
|
||||
```rust
|
||||
use rhai::module_resolvers::StaticModuleResolver;
|
||||
use rhai::module_resolvers::{DummyModuleResolver, StaticModuleResolver};
|
||||
|
||||
// Create a module resolver
|
||||
let resolver = StaticModuleResolver::new();
|
||||
@ -167,8 +173,9 @@ let resolver = StaticModuleResolver::new();
|
||||
// Register functions into 'resolver'...
|
||||
|
||||
// Use the module resolver
|
||||
engine.set_module_resolver(Some(resolver));
|
||||
engine.set_module_resolver(resolver);
|
||||
|
||||
// Effectively disable 'import' statements by setting module resolver to 'None'
|
||||
engine.set_module_resolver(None);
|
||||
// Effectively disable 'import' statements by setting module resolver to
|
||||
// the 'DummyModuleResolver' which acts as... well... a dummy.
|
||||
engine.set_module_resolver(DummyModuleResolver::new());
|
||||
```
|
||||
|
@ -748,13 +748,16 @@ impl Dynamic {
|
||||
|
||||
Self(Union::Variant(Box::new(boxed), AccessMode::ReadWrite))
|
||||
}
|
||||
/// Turn the [`Dynamic`] value into a shared [`Dynamic`] value backed by an [`Rc`][std::rc::Rc]`<`[`RefCell`][std::cell::RefCell]`<`[`Dynamic`]`>>`
|
||||
/// or [`Arc`][std::sync::Arc]`<`[`RwLock`][std::sync::RwLock]`<`[`Dynamic`]`>>` depending on the `sync` feature.
|
||||
/// Turn the [`Dynamic`] value into a shared [`Dynamic`] value backed by an
|
||||
/// [`Rc`][std::rc::Rc]`<`[`RefCell`][std::cell::RefCell]`<`[`Dynamic`]`>>` or
|
||||
/// [`Arc`][std::sync::Arc]`<`[`RwLock`][std::sync::RwLock]`<`[`Dynamic`]`>>`
|
||||
/// depending on the `sync` feature.
|
||||
///
|
||||
/// Shared [`Dynamic`] values are relatively cheap to clone as they simply increment the
|
||||
/// reference counts.
|
||||
///
|
||||
/// Shared [`Dynamic`] values can be converted seamlessly to and from ordinary [`Dynamic`] values.
|
||||
/// Shared [`Dynamic`] values can be converted seamlessly to and from ordinary [`Dynamic`]
|
||||
/// values.
|
||||
///
|
||||
/// If the [`Dynamic`] value is already shared, this method returns itself.
|
||||
///
|
||||
@ -970,8 +973,8 @@ impl Dynamic {
|
||||
///
|
||||
/// If the [`Dynamic`] is not a shared value, it returns itself.
|
||||
///
|
||||
/// If the [`Dynamic`] is a shared value, it returns the shared value if there are
|
||||
/// no outstanding references, or a cloned copy.
|
||||
/// If the [`Dynamic`] is a shared value, it returns the shared value if there are no
|
||||
/// outstanding references, or a cloned copy.
|
||||
#[inline(always)]
|
||||
pub fn flatten(self) -> Self {
|
||||
match self.0 {
|
||||
|
105
src/engine.rs
105
src/engine.rs
@ -18,7 +18,7 @@ use crate::stdlib::{
|
||||
collections::{HashMap, HashSet},
|
||||
fmt, format,
|
||||
hash::{Hash, Hasher},
|
||||
iter::{empty, once},
|
||||
iter::{empty, once, FromIterator},
|
||||
num::NonZeroU64,
|
||||
num::NonZeroUsize,
|
||||
ops::DerefMut,
|
||||
@ -137,6 +137,22 @@ impl Imports {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: IntoIterator<Item = (&'a ImmutableString, &'a Shared<Module>)>> From<T> for Imports {
|
||||
fn from(value: T) -> Self {
|
||||
Self(
|
||||
value
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k.clone(), v.clone()))
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
}
|
||||
impl FromIterator<(ImmutableString, Shared<Module>)> for Imports {
|
||||
fn from_iter<T: IntoIterator<Item = (ImmutableString, Shared<Module>)>>(iter: T) -> Self {
|
||||
Self(iter.into_iter().collect())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
#[cfg(debug_assertions)]
|
||||
pub const MAX_CALL_STACK_DEPTH: usize = 8;
|
||||
@ -609,11 +625,11 @@ pub struct Engine {
|
||||
/// A collection of all modules loaded into the global namespace of the Engine.
|
||||
pub(crate) global_modules: StaticVec<Shared<Module>>,
|
||||
/// A collection of all sub-modules directly loaded into the Engine.
|
||||
pub(crate) global_sub_modules: Imports,
|
||||
pub(crate) global_sub_modules: HashMap<ImmutableString, Shared<Module>>,
|
||||
|
||||
/// A module resolution service.
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
pub(crate) module_resolver: Option<Box<dyn crate::ModuleResolver>>,
|
||||
pub(crate) module_resolver: Box<dyn crate::ModuleResolver>,
|
||||
|
||||
/// A hashmap mapping type names to pretty-print names.
|
||||
pub(crate) type_names: HashMap<String, String>,
|
||||
@ -745,7 +761,7 @@ impl Engine {
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
#[cfg(not(feature = "no_std"))]
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
module_resolver: Some(Box::new(crate::module::resolvers::FileModuleResolver::new())),
|
||||
module_resolver: Box::new(crate::module::resolvers::FileModuleResolver::new()),
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
#[cfg(any(feature = "no_std", target_arch = "wasm32",))]
|
||||
module_resolver: None,
|
||||
@ -808,7 +824,7 @@ impl Engine {
|
||||
global_sub_modules: Default::default(),
|
||||
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
module_resolver: None,
|
||||
module_resolver: Box::new(crate::module::resolvers::DummyModuleResolver::new()),
|
||||
|
||||
type_names: Default::default(),
|
||||
disabled_symbols: Default::default(),
|
||||
@ -849,15 +865,15 @@ impl Engine {
|
||||
|
||||
/// Search for a variable within the scope or within imports,
|
||||
/// depending on whether the variable name is namespace-qualified.
|
||||
pub(crate) fn search_namespace<'s, 'a>(
|
||||
pub(crate) fn search_namespace<'s>(
|
||||
&self,
|
||||
scope: &'s mut Scope,
|
||||
mods: &mut Imports,
|
||||
state: &mut State,
|
||||
lib: &[&Module],
|
||||
this_ptr: &'s mut Option<&mut Dynamic>,
|
||||
expr: &'a Expr,
|
||||
) -> Result<(Target<'s>, &'a str, Position), Box<EvalAltResult>> {
|
||||
expr: &Expr,
|
||||
) -> Result<(Target<'s>, Position), Box<EvalAltResult>> {
|
||||
match expr {
|
||||
Expr::Variable(v) => match v.as_ref() {
|
||||
// Qualified variable
|
||||
@ -876,7 +892,7 @@ impl Engine {
|
||||
// Module variables are constant
|
||||
let mut target = target.clone();
|
||||
target.set_access_mode(AccessMode::ReadOnly);
|
||||
Ok((target.into(), name, *pos))
|
||||
Ok((target.into(), *pos))
|
||||
}
|
||||
// Normal variable access
|
||||
_ => self.search_scope_only(scope, mods, state, lib, this_ptr, expr),
|
||||
@ -886,15 +902,15 @@ impl Engine {
|
||||
}
|
||||
|
||||
/// Search for a variable within the scope
|
||||
pub(crate) fn search_scope_only<'s, 'a>(
|
||||
pub(crate) fn search_scope_only<'s>(
|
||||
&self,
|
||||
scope: &'s mut Scope,
|
||||
mods: &mut Imports,
|
||||
state: &mut State,
|
||||
lib: &[&Module],
|
||||
this_ptr: &'s mut Option<&mut Dynamic>,
|
||||
expr: &'a Expr,
|
||||
) -> Result<(Target<'s>, &'a str, Position), Box<EvalAltResult>> {
|
||||
expr: &Expr,
|
||||
) -> Result<(Target<'s>, Position), Box<EvalAltResult>> {
|
||||
let (index, _, Ident { name, pos }) = match expr {
|
||||
Expr::Variable(v) => v.as_ref(),
|
||||
_ => unreachable!(),
|
||||
@ -903,7 +919,7 @@ impl Engine {
|
||||
// Check if the variable is `this`
|
||||
if name.as_str() == KEYWORD_THIS {
|
||||
if let Some(val) = this_ptr {
|
||||
return Ok(((*val).into(), KEYWORD_THIS, *pos));
|
||||
return Ok(((*val).into(), *pos));
|
||||
} else {
|
||||
return EvalAltResult::ErrorUnboundThis(*pos).into();
|
||||
}
|
||||
@ -931,7 +947,7 @@ impl Engine {
|
||||
resolve_var(name, index, &context).map_err(|err| err.fill_position(*pos))?
|
||||
{
|
||||
result.set_access_mode(AccessMode::ReadOnly);
|
||||
return Ok((result.into(), name, *pos));
|
||||
return Ok((result.into(), *pos));
|
||||
}
|
||||
}
|
||||
|
||||
@ -945,7 +961,7 @@ impl Engine {
|
||||
.0
|
||||
};
|
||||
|
||||
let val = scope.get_mut(index);
|
||||
let val = scope.get_mut_by_index(index);
|
||||
|
||||
// Check for data race - probably not necessary because the only place it should conflict is in a method call
|
||||
// when the object variable is also used as a parameter.
|
||||
@ -953,7 +969,7 @@ impl Engine {
|
||||
// return EvalAltResult::ErrorDataRace(name.into(), *pos).into();
|
||||
// }
|
||||
|
||||
Ok((val.into(), name, *pos))
|
||||
Ok((val.into(), *pos))
|
||||
}
|
||||
|
||||
/// Chain-evaluate a dot/index chain.
|
||||
@ -1300,7 +1316,7 @@ impl Engine {
|
||||
|
||||
self.inc_operations(state, *var_pos)?;
|
||||
|
||||
let (target, _, pos) =
|
||||
let (target, pos) =
|
||||
self.search_namespace(scope, mods, state, lib, this_ptr, lhs)?;
|
||||
|
||||
// Constants cannot be modified
|
||||
@ -1594,7 +1610,7 @@ impl Engine {
|
||||
match expr {
|
||||
// var - point directly to the value
|
||||
Expr::Variable(_) => {
|
||||
let (mut target, _, pos) =
|
||||
let (mut target, pos) =
|
||||
self.search_namespace(scope, mods, state, lib, this_ptr, expr)?;
|
||||
|
||||
// If necessary, constants are cloned
|
||||
@ -1720,7 +1736,7 @@ impl Engine {
|
||||
}
|
||||
}
|
||||
Expr::Variable(_) => {
|
||||
let (val, _, _) = self.search_namespace(scope, mods, state, lib, this_ptr, expr)?;
|
||||
let (val, _) = self.search_namespace(scope, mods, state, lib, this_ptr, expr)?;
|
||||
Ok(val.take_or_clone())
|
||||
}
|
||||
Expr::Property(_) => unreachable!(),
|
||||
@ -1926,11 +1942,15 @@ impl Engine {
|
||||
let mut rhs_val = self
|
||||
.eval_expr(scope, mods, state, lib, this_ptr, rhs_expr, level)?
|
||||
.flatten();
|
||||
let (mut lhs_ptr, name, pos) =
|
||||
let (mut lhs_ptr, pos) =
|
||||
self.search_namespace(scope, mods, state, lib, this_ptr, lhs_expr)?;
|
||||
|
||||
if !lhs_ptr.is_ref() {
|
||||
return EvalAltResult::ErrorAssignmentToConstant(name.to_string(), pos).into();
|
||||
return EvalAltResult::ErrorAssignmentToConstant(
|
||||
lhs_expr.get_variable_access(false).unwrap().to_string(),
|
||||
pos,
|
||||
)
|
||||
.into();
|
||||
}
|
||||
|
||||
self.inc_operations(state, pos)?;
|
||||
@ -1938,7 +1958,7 @@ impl Engine {
|
||||
if lhs_ptr.as_ref().is_read_only() {
|
||||
// Assignment to constant variable
|
||||
Err(Box::new(EvalAltResult::ErrorAssignmentToConstant(
|
||||
name.to_string(),
|
||||
lhs_expr.get_variable_access(false).unwrap().to_string(),
|
||||
pos,
|
||||
)))
|
||||
} else if op.is_empty() {
|
||||
@ -2194,7 +2214,7 @@ impl Engine {
|
||||
state.scope_level += 1;
|
||||
|
||||
for iter_value in func(iter_obj) {
|
||||
let loop_var = scope.get_mut(index);
|
||||
let loop_var = scope.get_mut_by_index(index);
|
||||
|
||||
let value = iter_value.flatten();
|
||||
if cfg!(not(feature = "no_closure")) && loop_var.is_shared() {
|
||||
@ -2360,31 +2380,24 @@ impl Engine {
|
||||
.eval_expr(scope, mods, state, lib, this_ptr, &expr, level)?
|
||||
.try_cast::<ImmutableString>()
|
||||
{
|
||||
if let Some(resolver) = &self.module_resolver {
|
||||
let module = resolver.resolve(self, &path, expr.position())?;
|
||||
let module = self.module_resolver.resolve(self, &path, expr.position())?;
|
||||
|
||||
if let Some(name_def) = alias {
|
||||
if !module.is_indexed() {
|
||||
// Index the module (making a clone copy if necessary) if it is not indexed
|
||||
let mut module = crate::fn_native::shared_take_or_clone(module);
|
||||
module.build_index();
|
||||
mods.push(name_def.name.clone(), module);
|
||||
} else {
|
||||
mods.push(name_def.name.clone(), module);
|
||||
}
|
||||
// When imports list is modified, clear the functions lookup cache
|
||||
state.functions_cache.clear();
|
||||
if let Some(name_def) = alias {
|
||||
if !module.is_indexed() {
|
||||
// Index the module (making a clone copy if necessary) if it is not indexed
|
||||
let mut module = crate::fn_native::shared_take_or_clone(module);
|
||||
module.build_index();
|
||||
mods.push(name_def.name.clone(), module);
|
||||
} else {
|
||||
mods.push(name_def.name.clone(), module);
|
||||
}
|
||||
|
||||
state.modules += 1;
|
||||
|
||||
Ok(Dynamic::UNIT)
|
||||
} else {
|
||||
Err(
|
||||
EvalAltResult::ErrorModuleNotFound(path.to_string(), expr.position())
|
||||
.into(),
|
||||
)
|
||||
// When imports list is modified, clear the functions lookup cache
|
||||
state.functions_cache.clear();
|
||||
}
|
||||
|
||||
state.modules += 1;
|
||||
|
||||
Ok(Dynamic::UNIT)
|
||||
} else {
|
||||
Err(self.make_type_mismatch_err::<ImmutableString>("", expr.position()))
|
||||
}
|
||||
@ -2410,7 +2423,7 @@ impl Engine {
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
Stmt::Share(x) => {
|
||||
if let Some((index, _)) = scope.get_index(&x.name) {
|
||||
let val = scope.get_mut(index);
|
||||
let val = scope.get_mut_by_index(index);
|
||||
|
||||
if !val.is_shared() {
|
||||
// Replace the variable with a shared value.
|
||||
|
@ -209,9 +209,10 @@ impl Engine {
|
||||
pub fn register_get<T: Variant + Clone, U: Variant + Clone>(
|
||||
&mut self,
|
||||
name: &str,
|
||||
callback: impl Fn(&mut T) -> U + SendSync + 'static,
|
||||
get_fn: impl Fn(&mut T) -> U + SendSync + 'static,
|
||||
) -> &mut Self {
|
||||
crate::RegisterFn::register_fn(self, &crate::engine::make_getter(name), callback)
|
||||
use crate::{engine::make_getter, RegisterFn};
|
||||
self.register_fn(&make_getter(name), get_fn)
|
||||
}
|
||||
/// Register a getter function for a member of a registered type with the [`Engine`].
|
||||
///
|
||||
@ -255,13 +256,10 @@ impl Engine {
|
||||
pub fn register_get_result<T: Variant + Clone>(
|
||||
&mut self,
|
||||
name: &str,
|
||||
callback: impl Fn(&mut T) -> Result<Dynamic, Box<EvalAltResult>> + SendSync + 'static,
|
||||
get_fn: impl Fn(&mut T) -> Result<Dynamic, Box<EvalAltResult>> + SendSync + 'static,
|
||||
) -> &mut Self {
|
||||
crate::RegisterResultFn::register_result_fn(
|
||||
self,
|
||||
&crate::engine::make_getter(name),
|
||||
callback,
|
||||
)
|
||||
use crate::{engine::make_getter, RegisterResultFn};
|
||||
self.register_result_fn(&make_getter(name), get_fn)
|
||||
}
|
||||
/// Register a setter function for a member of a registered type with the [`Engine`].
|
||||
///
|
||||
@ -304,9 +302,10 @@ impl Engine {
|
||||
pub fn register_set<T: Variant + Clone, U: Variant + Clone>(
|
||||
&mut self,
|
||||
name: &str,
|
||||
callback: impl Fn(&mut T, U) + SendSync + 'static,
|
||||
set_fn: impl Fn(&mut T, U) + SendSync + 'static,
|
||||
) -> &mut Self {
|
||||
crate::RegisterFn::register_fn(self, &crate::engine::make_setter(name), callback)
|
||||
use crate::{engine::make_setter, RegisterFn};
|
||||
self.register_fn(&make_setter(name), set_fn)
|
||||
}
|
||||
/// Register a setter function for a member of a registered type with the [`Engine`].
|
||||
///
|
||||
@ -352,13 +351,12 @@ impl Engine {
|
||||
pub fn register_set_result<T: Variant + Clone, U: Variant + Clone>(
|
||||
&mut self,
|
||||
name: &str,
|
||||
callback: impl Fn(&mut T, U) -> Result<(), Box<EvalAltResult>> + SendSync + 'static,
|
||||
set_fn: impl Fn(&mut T, U) -> Result<(), Box<EvalAltResult>> + SendSync + 'static,
|
||||
) -> &mut Self {
|
||||
crate::RegisterResultFn::register_result_fn(
|
||||
self,
|
||||
&crate::engine::make_setter(name),
|
||||
move |obj: &mut T, value: U| callback(obj, value).map(Into::into),
|
||||
)
|
||||
use crate::{engine::make_setter, RegisterResultFn};
|
||||
self.register_result_fn(&make_setter(name), move |obj: &mut T, value: U| {
|
||||
set_fn(obj, value).map(Into::into)
|
||||
})
|
||||
}
|
||||
/// Short-hand for registering both getter and setter functions
|
||||
/// of a registered type with the [`Engine`].
|
||||
@ -453,7 +451,7 @@ impl Engine {
|
||||
#[inline(always)]
|
||||
pub fn register_indexer_get<T: Variant + Clone, X: Variant + Clone, U: Variant + Clone>(
|
||||
&mut self,
|
||||
callback: impl Fn(&mut T, X) -> U + SendSync + 'static,
|
||||
get_fn: impl Fn(&mut T, X) -> U + SendSync + 'static,
|
||||
) -> &mut Self {
|
||||
if TypeId::of::<T>() == TypeId::of::<Array>() {
|
||||
panic!("Cannot register indexer for arrays.");
|
||||
@ -469,7 +467,8 @@ impl Engine {
|
||||
panic!("Cannot register indexer for strings.");
|
||||
}
|
||||
|
||||
crate::RegisterFn::register_fn(self, crate::engine::FN_IDX_GET, callback)
|
||||
use crate::{engine::FN_IDX_GET, RegisterFn};
|
||||
self.register_fn(FN_IDX_GET, get_fn)
|
||||
}
|
||||
/// Register an index getter for a custom type with the [`Engine`].
|
||||
///
|
||||
@ -518,7 +517,7 @@ impl Engine {
|
||||
#[inline(always)]
|
||||
pub fn register_indexer_get_result<T: Variant + Clone, X: Variant + Clone>(
|
||||
&mut self,
|
||||
callback: impl Fn(&mut T, X) -> Result<Dynamic, Box<EvalAltResult>> + SendSync + 'static,
|
||||
get_fn: impl Fn(&mut T, X) -> Result<Dynamic, Box<EvalAltResult>> + SendSync + 'static,
|
||||
) -> &mut Self {
|
||||
if TypeId::of::<T>() == TypeId::of::<Array>() {
|
||||
panic!("Cannot register indexer for arrays.");
|
||||
@ -534,7 +533,8 @@ impl Engine {
|
||||
panic!("Cannot register indexer for strings.");
|
||||
}
|
||||
|
||||
crate::RegisterResultFn::register_result_fn(self, crate::engine::FN_IDX_GET, callback)
|
||||
use crate::{engine::FN_IDX_GET, RegisterResultFn};
|
||||
self.register_result_fn(FN_IDX_GET, get_fn)
|
||||
}
|
||||
/// Register an index setter for a custom type with the [`Engine`].
|
||||
///
|
||||
@ -581,7 +581,7 @@ impl Engine {
|
||||
#[inline(always)]
|
||||
pub fn register_indexer_set<T: Variant + Clone, X: Variant + Clone, U: Variant + Clone>(
|
||||
&mut self,
|
||||
callback: impl Fn(&mut T, X, U) + SendSync + 'static,
|
||||
set_fn: impl Fn(&mut T, X, U) + SendSync + 'static,
|
||||
) -> &mut Self {
|
||||
if TypeId::of::<T>() == TypeId::of::<Array>() {
|
||||
panic!("Cannot register indexer for arrays.");
|
||||
@ -597,7 +597,8 @@ impl Engine {
|
||||
panic!("Cannot register indexer for strings.");
|
||||
}
|
||||
|
||||
crate::RegisterFn::register_fn(self, crate::engine::FN_IDX_SET, callback)
|
||||
use crate::{engine::FN_IDX_SET, RegisterFn};
|
||||
self.register_fn(FN_IDX_SET, set_fn)
|
||||
}
|
||||
/// Register an index setter for a custom type with the [`Engine`].
|
||||
///
|
||||
@ -651,7 +652,7 @@ impl Engine {
|
||||
U: Variant + Clone,
|
||||
>(
|
||||
&mut self,
|
||||
callback: impl Fn(&mut T, X, U) -> Result<(), Box<EvalAltResult>> + SendSync + 'static,
|
||||
set_fn: impl Fn(&mut T, X, U) -> Result<(), Box<EvalAltResult>> + SendSync + 'static,
|
||||
) -> &mut Self {
|
||||
if TypeId::of::<T>() == TypeId::of::<Array>() {
|
||||
panic!("Cannot register indexer for arrays.");
|
||||
@ -667,11 +668,10 @@ impl Engine {
|
||||
panic!("Cannot register indexer for strings.");
|
||||
}
|
||||
|
||||
crate::RegisterResultFn::register_result_fn(
|
||||
self,
|
||||
crate::engine::FN_IDX_SET,
|
||||
move |obj: &mut T, index: X, value: U| callback(obj, index, value).map(Into::into),
|
||||
)
|
||||
use crate::{engine::FN_IDX_SET, RegisterResultFn};
|
||||
self.register_result_fn(FN_IDX_SET, move |obj: &mut T, index: X, value: U| {
|
||||
set_fn(obj, index, value).map(Into::into)
|
||||
})
|
||||
}
|
||||
/// Short-hand for register both index getter and setter functions for a custom type with the [`Engine`].
|
||||
///
|
||||
@ -755,7 +755,7 @@ impl Engine {
|
||||
///
|
||||
/// ```
|
||||
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
||||
/// use rhai::{Engine, Module};
|
||||
/// use rhai::{Engine, Shared, Module};
|
||||
///
|
||||
/// let mut engine = Engine::new();
|
||||
///
|
||||
@ -763,9 +763,18 @@ impl Engine {
|
||||
/// let mut module = Module::new();
|
||||
/// module.set_fn_1("calc", |x: i64| Ok(x + 1));
|
||||
///
|
||||
/// // Register the module as a fixed sub-module
|
||||
/// engine.register_static_module("CalcService", module.into());
|
||||
/// let module: Shared<Module> = module.into();
|
||||
///
|
||||
/// // Register the module as a fixed sub-module
|
||||
/// engine.register_static_module("foo::bar::baz", module.clone());
|
||||
///
|
||||
/// // Multiple registrations to the same partial path is also OK!
|
||||
/// engine.register_static_module("foo::bar::hello", module.clone());
|
||||
///
|
||||
/// engine.register_static_module("CalcService", module);
|
||||
///
|
||||
/// assert_eq!(engine.eval::<i64>("foo::bar::baz::calc(41)")?, 42);
|
||||
/// assert_eq!(engine.eval::<i64>("foo::bar::hello::calc(41)")?, 42);
|
||||
/// assert_eq!(engine.eval::<i64>("CalcService::calc(41)")?, 42);
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
@ -773,19 +782,49 @@ impl Engine {
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
pub fn register_static_module(
|
||||
&mut self,
|
||||
name: impl Into<crate::ImmutableString>,
|
||||
name: impl AsRef<str>,
|
||||
module: Shared<Module>,
|
||||
) -> &mut Self {
|
||||
if !module.is_indexed() {
|
||||
// Index the module (making a clone copy if necessary) if it is not indexed
|
||||
let mut module = crate::fn_native::shared_take_or_clone(module);
|
||||
module.build_index();
|
||||
self.global_sub_modules.push(name, module);
|
||||
} else {
|
||||
self.global_sub_modules.push(name, module);
|
||||
fn register_static_module_raw(
|
||||
root: &mut crate::stdlib::collections::HashMap<crate::ImmutableString, Shared<Module>>,
|
||||
name: impl AsRef<str>,
|
||||
module: Shared<Module>,
|
||||
) {
|
||||
let separator = crate::token::Token::DoubleColon.syntax();
|
||||
|
||||
if !name.as_ref().contains(separator.as_ref()) {
|
||||
if !module.is_indexed() {
|
||||
// Index the module (making a clone copy if necessary) if it is not indexed
|
||||
let mut module = crate::fn_native::shared_take_or_clone(module);
|
||||
module.build_index();
|
||||
root.insert(name.as_ref().trim().into(), module.into());
|
||||
} else {
|
||||
root.insert(name.as_ref().trim().into(), module);
|
||||
}
|
||||
} else {
|
||||
let mut iter = name.as_ref().splitn(2, separator.as_ref());
|
||||
let sub_module = iter.next().unwrap().trim();
|
||||
let remainder = iter.next().unwrap().trim();
|
||||
|
||||
if !root.contains_key(sub_module) {
|
||||
let mut m: Module = Default::default();
|
||||
register_static_module_raw(m.sub_modules_mut(), remainder, module);
|
||||
m.build_index();
|
||||
root.insert(sub_module.into(), m.into());
|
||||
} else {
|
||||
let m = root.remove(sub_module).unwrap();
|
||||
let mut m = crate::fn_native::shared_take_or_clone(m);
|
||||
register_static_module_raw(m.sub_modules_mut(), remainder, module);
|
||||
m.build_index();
|
||||
root.insert(sub_module.into(), m.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
register_static_module_raw(&mut self.global_sub_modules, name.as_ref(), module);
|
||||
self
|
||||
}
|
||||
|
||||
/// Register a shared [`Module`][crate::Module] as a static module namespace with the [`Engine`].
|
||||
///
|
||||
/// ## Deprecated
|
||||
@ -796,7 +835,7 @@ impl Engine {
|
||||
#[deprecated = "use `register_static_module` instead"]
|
||||
pub fn register_module(
|
||||
&mut self,
|
||||
name: impl Into<crate::ImmutableString>,
|
||||
name: impl AsRef<str>,
|
||||
module: impl Into<Shared<Module>>,
|
||||
) -> &mut Self {
|
||||
self.register_static_module(name, module.into())
|
||||
@ -1407,7 +1446,7 @@ impl Engine {
|
||||
scope: &mut Scope,
|
||||
ast: &AST,
|
||||
) -> Result<T, Box<EvalAltResult>> {
|
||||
let mods = &mut self.global_sub_modules.clone();
|
||||
let mods = &mut (&self.global_sub_modules).into();
|
||||
|
||||
let result = self.eval_ast_with_scope_raw(scope, mods, ast)?;
|
||||
|
||||
@ -1493,7 +1532,7 @@ impl Engine {
|
||||
scope: &mut Scope,
|
||||
ast: &AST,
|
||||
) -> Result<(), Box<EvalAltResult>> {
|
||||
let mods = &mut self.global_sub_modules.clone();
|
||||
let mods = &mut (&self.global_sub_modules).into();
|
||||
let state = &mut State {
|
||||
source: ast.clone_source(),
|
||||
..Default::default()
|
||||
@ -1539,12 +1578,12 @@ impl Engine {
|
||||
/// ```
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
#[inline]
|
||||
pub fn call_fn<A: crate::fn_args::FuncArgs, T: Variant + Clone>(
|
||||
pub fn call_fn<T: Variant + Clone>(
|
||||
&self,
|
||||
scope: &mut Scope,
|
||||
ast: &AST,
|
||||
name: &str,
|
||||
args: A,
|
||||
args: impl crate::fn_args::FuncArgs,
|
||||
) -> Result<T, Box<EvalAltResult>> {
|
||||
let mut arg_values = args.into_vec();
|
||||
let mut args: crate::StaticVec<_> = arg_values.as_mut().iter_mut().collect();
|
||||
@ -1650,7 +1689,7 @@ impl Engine {
|
||||
.ok_or_else(|| EvalAltResult::ErrorFunctionNotFound(name.into(), Position::NONE))?;
|
||||
|
||||
let mut state = Default::default();
|
||||
let mut mods = self.global_sub_modules.clone();
|
||||
let mut mods = (&self.global_sub_modules).into();
|
||||
|
||||
// Check for data race.
|
||||
if cfg!(not(feature = "no_closure")) {
|
||||
|
@ -168,9 +168,9 @@ impl Engine {
|
||||
#[inline(always)]
|
||||
pub fn set_module_resolver(
|
||||
&mut self,
|
||||
resolver: Option<impl crate::ModuleResolver + 'static>,
|
||||
resolver: impl crate::ModuleResolver + 'static,
|
||||
) -> &mut Self {
|
||||
self.module_resolver = resolver.map(|f| Box::new(f) as Box<dyn crate::ModuleResolver>);
|
||||
self.module_resolver = Box::new(resolver);
|
||||
self
|
||||
}
|
||||
/// Disable a particular keyword or operator in the language.
|
||||
|
@ -1041,7 +1041,7 @@ impl Engine {
|
||||
.map(|expr| self.eval_expr(scope, mods, state, lib, this_ptr, expr, level))
|
||||
.collect::<Result<_, _>>()?;
|
||||
|
||||
let (mut target, _, pos) =
|
||||
let (mut target, pos) =
|
||||
self.search_namespace(scope, mods, state, lib, this_ptr, &args_expr[0])?;
|
||||
|
||||
if target.as_ref().is_read_only() {
|
||||
@ -1137,7 +1137,7 @@ impl Engine {
|
||||
.collect::<Result<_, _>>()?;
|
||||
|
||||
// Get target reference to first argument
|
||||
let (target, _, pos) =
|
||||
let (target, pos) =
|
||||
self.search_scope_only(scope, mods, state, lib, this_ptr, &args_expr[0])?;
|
||||
|
||||
self.inc_operations(state, pos)?;
|
||||
|
@ -27,15 +27,15 @@ pub trait Func<ARGS, RET> {
|
||||
/// // Func takes two type parameters:
|
||||
/// // 1) a tuple made up of the types of the script function's parameters
|
||||
/// // 2) the return type of the script function
|
||||
/// //
|
||||
///
|
||||
/// // 'func' will have type Box<dyn Fn(i64, String) -> Result<bool, Box<EvalAltResult>>> and is callable!
|
||||
/// let func = Func::<(i64, String), bool>::create_from_ast(
|
||||
/// // ^^^^^^^^^^^^^ function parameter types in tuple
|
||||
///
|
||||
/// engine, // the 'Engine' is consumed into the closure
|
||||
/// ast, // the 'AST'
|
||||
/// "calc" // the entry-point function name
|
||||
/// );
|
||||
/// engine, // the 'Engine' is consumed into the closure
|
||||
/// ast, // the 'AST'
|
||||
/// "calc" // the entry-point function name
|
||||
/// );
|
||||
///
|
||||
/// func(123, "hello".to_string())? == false; // call the anonymous function
|
||||
/// # Ok(())
|
||||
@ -58,15 +58,15 @@ pub trait Func<ARGS, RET> {
|
||||
/// // Func takes two type parameters:
|
||||
/// // 1) a tuple made up of the types of the script function's parameters
|
||||
/// // 2) the return type of the script function
|
||||
/// //
|
||||
///
|
||||
/// // 'func' will have type Box<dyn Fn(i64, String) -> Result<bool, Box<EvalAltResult>>> and is callable!
|
||||
/// let func = Func::<(i64, String), bool>::create_from_script(
|
||||
/// // ^^^^^^^^^^^^^ function parameter types in tuple
|
||||
///
|
||||
/// engine, // the 'Engine' is consumed into the closure
|
||||
/// script, // the script, notice number of parameters must match
|
||||
/// "calc" // the entry-point function name
|
||||
/// )?;
|
||||
/// engine, // the 'Engine' is consumed into the closure
|
||||
/// script, // the script, notice number of parameters must match
|
||||
/// "calc" // the entry-point function name
|
||||
/// )?;
|
||||
///
|
||||
/// func(123, "hello".to_string())? == false; // call the anonymous function
|
||||
/// # Ok(())
|
||||
|
@ -3,7 +3,14 @@
|
||||
use crate::ast::{FnAccess, ScriptFnDef};
|
||||
use crate::engine::Imports;
|
||||
use crate::plugin::PluginFunction;
|
||||
use crate::stdlib::{boxed::Box, convert::TryFrom, fmt, iter::empty, mem, string::String};
|
||||
use crate::stdlib::{
|
||||
boxed::Box,
|
||||
convert::{TryFrom, TryInto},
|
||||
fmt,
|
||||
iter::empty,
|
||||
mem,
|
||||
string::String,
|
||||
};
|
||||
use crate::token::is_valid_identifier;
|
||||
use crate::{
|
||||
calc_script_fn_hash, Dynamic, Engine, EvalAltResult, EvalContext, ImmutableString, Module,
|
||||
@ -153,25 +160,13 @@ impl<'e, 's, 'a, 'm, 'pm> NativeCallContext<'e, 's, 'a, 'm, 'pm> {
|
||||
args: &mut [&mut Dynamic],
|
||||
def_value: Option<&Dynamic>,
|
||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
let mut mods = self.mods.cloned().unwrap_or_default();
|
||||
|
||||
let hash_script = calc_script_fn_hash(
|
||||
empty(),
|
||||
fn_name,
|
||||
if is_method {
|
||||
args.len() - 1
|
||||
} else {
|
||||
args.len()
|
||||
},
|
||||
);
|
||||
|
||||
self.engine()
|
||||
.exec_fn_call(
|
||||
&mut mods,
|
||||
&mut self.mods.cloned().unwrap_or_default(),
|
||||
&mut Default::default(),
|
||||
self.lib,
|
||||
fn_name,
|
||||
hash_script,
|
||||
calc_script_fn_hash(empty(), fn_name, args.len() - if is_method { 1 } else { 0 }),
|
||||
args,
|
||||
is_method,
|
||||
is_method,
|
||||
@ -225,11 +220,15 @@ pub type FnCallArgs<'a> = [&'a mut Dynamic];
|
||||
|
||||
/// A general function pointer, which may carry additional (i.e. curried) argument values
|
||||
/// to be passed onto a function during a call.
|
||||
#[derive(Debug, Clone, Default)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FnPtr(ImmutableString, StaticVec<Dynamic>);
|
||||
|
||||
impl FnPtr {
|
||||
/// Create a new function pointer.
|
||||
pub fn new(name: impl Into<ImmutableString>) -> Result<Self, Box<EvalAltResult>> {
|
||||
name.into().try_into()
|
||||
}
|
||||
/// Create a new function pointer without checking its parameters.
|
||||
#[inline(always)]
|
||||
pub(crate) fn new_unchecked(
|
||||
name: impl Into<ImmutableString>,
|
||||
@ -257,7 +256,24 @@ impl FnPtr {
|
||||
pub fn curry(&self) -> &[Dynamic] {
|
||||
self.1.as_ref()
|
||||
}
|
||||
/// Does this function pointer refer to an anonymous function?
|
||||
/// Add a new curried argument.
|
||||
#[inline(always)]
|
||||
pub fn add_curry(&mut self, value: Dynamic) -> &mut Self {
|
||||
self.1.push(value);
|
||||
self
|
||||
}
|
||||
/// Set curried arguments to the function pointer.
|
||||
#[inline(always)]
|
||||
pub fn set_curry(&mut self, values: impl IntoIterator<Item = Dynamic>) -> &mut Self {
|
||||
self.1 = values.into_iter().collect();
|
||||
self
|
||||
}
|
||||
/// Is the function pointer curried?
|
||||
#[inline(always)]
|
||||
pub fn is_curried(&self) -> bool {
|
||||
!self.1.is_empty()
|
||||
}
|
||||
/// Does the function pointer refer to an anonymous function?
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
#[inline(always)]
|
||||
pub fn is_anonymous(&self) -> bool {
|
||||
|
@ -35,9 +35,9 @@ use crate::Map;
|
||||
/// A type representing the namespace of a function.
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
|
||||
pub enum FnNamespace {
|
||||
/// Global namespace.
|
||||
/// Expose to global namespace.
|
||||
Global,
|
||||
/// Internal only.
|
||||
/// Module namespace only.
|
||||
Internal,
|
||||
}
|
||||
|
||||
@ -465,6 +465,16 @@ impl Module {
|
||||
.map(|FuncInfo { func, .. }| func.get_fn_def())
|
||||
}
|
||||
|
||||
/// Get a mutable reference to the underlying [`HashMap`] of sub-modules.
|
||||
#[inline(always)]
|
||||
pub(crate) fn sub_modules_mut(&mut self) -> &mut HashMap<ImmutableString, Shared<Module>> {
|
||||
// We must assume that the user has changed the sub-modules
|
||||
// (otherwise why take a mutable reference?)
|
||||
self.indexed = false;
|
||||
|
||||
&mut self.modules
|
||||
}
|
||||
|
||||
/// Does a sub-module exist in the module?
|
||||
///
|
||||
/// # Example
|
||||
@ -1699,7 +1709,7 @@ impl Module {
|
||||
ast: &crate::AST,
|
||||
engine: &crate::Engine,
|
||||
) -> Result<Self, Box<EvalAltResult>> {
|
||||
let mut mods = engine.global_sub_modules.clone();
|
||||
let mut mods: crate::engine::Imports = (&engine.global_sub_modules).into();
|
||||
let orig_mods_len = mods.len();
|
||||
|
||||
// Run the script
|
||||
|
@ -16,7 +16,7 @@ use crate::{Engine, EvalAltResult, Module, ModuleResolver, Position, Shared};
|
||||
/// collection.push(resolver);
|
||||
///
|
||||
/// let mut engine = Engine::new();
|
||||
/// engine.set_module_resolver(Some(collection));
|
||||
/// engine.set_module_resolver(collection);
|
||||
/// ```
|
||||
#[derive(Default)]
|
||||
pub struct ModuleResolversCollection(Vec<Box<dyn ModuleResolver>>);
|
||||
@ -36,16 +36,41 @@ impl ModuleResolversCollection {
|
||||
/// collection.push(resolver);
|
||||
///
|
||||
/// let mut engine = Engine::new();
|
||||
/// engine.set_module_resolver(Some(collection));
|
||||
/// engine.set_module_resolver(collection);
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn new() -> Self {
|
||||
Default::default()
|
||||
}
|
||||
/// Add a module keyed by its path.
|
||||
/// Append a module resolver to the end.
|
||||
#[inline(always)]
|
||||
pub fn push(&mut self, resolver: impl ModuleResolver + 'static) {
|
||||
pub fn push(&mut self, resolver: impl ModuleResolver + 'static) -> &mut Self {
|
||||
self.0.push(Box::new(resolver));
|
||||
self
|
||||
}
|
||||
/// Insert a module resolver to an offset index.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the index is out of bounds.
|
||||
#[inline(always)]
|
||||
pub fn insert(&mut self, index: usize, resolver: impl ModuleResolver + 'static) -> &mut Self {
|
||||
self.0.insert(index, Box::new(resolver));
|
||||
self
|
||||
}
|
||||
/// Remove the last module resolver from the end, if any.
|
||||
#[inline(always)]
|
||||
pub fn pop(&mut self) -> Option<Box<dyn ModuleResolver>> {
|
||||
self.0.pop()
|
||||
}
|
||||
/// Remove a module resolver at an offset index.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the index is out of bounds.
|
||||
#[inline(always)]
|
||||
pub fn remove(&mut self, index: usize) -> Box<dyn ModuleResolver> {
|
||||
self.0.remove(index)
|
||||
}
|
||||
/// Get an iterator of all the module resolvers.
|
||||
#[inline(always)]
|
||||
@ -59,8 +84,9 @@ impl ModuleResolversCollection {
|
||||
}
|
||||
/// Remove all module resolvers.
|
||||
#[inline(always)]
|
||||
pub fn clear(&mut self) {
|
||||
pub fn clear(&mut self) -> &mut Self {
|
||||
self.0.clear();
|
||||
self
|
||||
}
|
||||
/// Is this [`ModuleResolversCollection`] empty?
|
||||
#[inline(always)]
|
||||
@ -75,8 +101,9 @@ impl ModuleResolversCollection {
|
||||
/// Add another [`ModuleResolversCollection`] to the end of this collection.
|
||||
/// The other [`ModuleResolversCollection`] is consumed.
|
||||
#[inline(always)]
|
||||
pub fn append(&mut self, other: Self) {
|
||||
pub fn append(&mut self, other: Self) -> &mut Self {
|
||||
self.0.extend(other.0.into_iter());
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
|
48
src/module/resolvers/dummy.rs
Normal file
48
src/module/resolvers/dummy.rs
Normal file
@ -0,0 +1,48 @@
|
||||
use crate::stdlib::boxed::Box;
|
||||
use crate::{Engine, EvalAltResult, Module, ModuleResolver, Position, Shared};
|
||||
|
||||
/// Empty/disabled module resolution service that acts as a dummy.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use rhai::{Engine, Module};
|
||||
/// use rhai::module_resolvers::DummyModuleResolver;
|
||||
///
|
||||
/// let resolver = DummyModuleResolver::new();
|
||||
/// let mut engine = Engine::new();
|
||||
/// engine.set_module_resolver(resolver);
|
||||
/// ```
|
||||
#[derive(Debug, Copy, Eq, PartialEq, Clone, Default, Hash)]
|
||||
pub struct DummyModuleResolver;
|
||||
|
||||
impl DummyModuleResolver {
|
||||
/// Create a new [`DummyModuleResolver`].
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use rhai::{Engine, Module};
|
||||
/// use rhai::module_resolvers::DummyModuleResolver;
|
||||
///
|
||||
/// let resolver = DummyModuleResolver::new();
|
||||
/// let mut engine = Engine::new();
|
||||
/// engine.set_module_resolver(resolver);
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn new() -> Self {
|
||||
Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
impl ModuleResolver for DummyModuleResolver {
|
||||
#[inline(always)]
|
||||
fn resolve(
|
||||
&self,
|
||||
_: &Engine,
|
||||
path: &str,
|
||||
pos: Position,
|
||||
) -> Result<Shared<Module>, Box<EvalAltResult>> {
|
||||
EvalAltResult::ErrorModuleNotFound(path.into(), pos).into()
|
||||
}
|
||||
}
|
@ -1,5 +1,9 @@
|
||||
use crate::stdlib::{
|
||||
boxed::Box, collections::HashMap, io::Error as IoError, path::PathBuf, string::String,
|
||||
boxed::Box,
|
||||
collections::HashMap,
|
||||
io::Error as IoError,
|
||||
path::{Path, PathBuf},
|
||||
string::String,
|
||||
};
|
||||
use crate::{Engine, EvalAltResult, Module, ModuleResolver, Position, Shared};
|
||||
|
||||
@ -31,7 +35,7 @@ use crate::{Engine, EvalAltResult, Module, ModuleResolver, Position, Shared};
|
||||
///
|
||||
/// let mut engine = Engine::new();
|
||||
///
|
||||
/// engine.set_module_resolver(Some(resolver));
|
||||
/// engine.set_module_resolver(resolver);
|
||||
/// ```
|
||||
#[derive(Debug)]
|
||||
pub struct FileModuleResolver {
|
||||
@ -65,10 +69,10 @@ impl FileModuleResolver {
|
||||
/// let resolver = FileModuleResolver::new_with_path("./scripts");
|
||||
///
|
||||
/// let mut engine = Engine::new();
|
||||
/// engine.set_module_resolver(Some(resolver));
|
||||
/// engine.set_module_resolver(resolver);
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn new_with_path<P: Into<PathBuf>>(path: P) -> Self {
|
||||
pub fn new_with_path(path: impl Into<PathBuf>) -> Self {
|
||||
Self::new_with_path_and_extension(path, "rhai")
|
||||
}
|
||||
|
||||
@ -87,12 +91,12 @@ impl FileModuleResolver {
|
||||
/// let resolver = FileModuleResolver::new_with_path_and_extension("./scripts", "x");
|
||||
///
|
||||
/// let mut engine = Engine::new();
|
||||
/// engine.set_module_resolver(Some(resolver));
|
||||
/// engine.set_module_resolver(resolver);
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn new_with_path_and_extension<P: Into<PathBuf>, E: Into<String>>(
|
||||
path: P,
|
||||
extension: E,
|
||||
pub fn new_with_path_and_extension(
|
||||
path: impl Into<PathBuf>,
|
||||
extension: impl Into<String>,
|
||||
) -> Self {
|
||||
Self {
|
||||
path: path.into(),
|
||||
@ -114,12 +118,64 @@ impl FileModuleResolver {
|
||||
/// let resolver = FileModuleResolver::new();
|
||||
///
|
||||
/// let mut engine = Engine::new();
|
||||
/// engine.set_module_resolver(Some(resolver));
|
||||
/// engine.set_module_resolver(resolver);
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn new() -> Self {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
/// Get the base path for script files.
|
||||
#[inline(always)]
|
||||
pub fn path(&self) -> &Path {
|
||||
self.path.as_ref()
|
||||
}
|
||||
/// Set the base path for script files.
|
||||
#[inline(always)]
|
||||
pub fn set_path(&mut self, path: impl Into<PathBuf>) -> &mut Self {
|
||||
self.path = path.into();
|
||||
self
|
||||
}
|
||||
|
||||
/// Get the script file extension.
|
||||
#[inline(always)]
|
||||
pub fn extension(&self) -> &str {
|
||||
&self.extension
|
||||
}
|
||||
|
||||
/// Set the script file extension.
|
||||
#[inline(always)]
|
||||
pub fn set_extension(&mut self, extension: impl Into<String>) -> &mut Self {
|
||||
self.extension = extension.into();
|
||||
self
|
||||
}
|
||||
|
||||
/// Empty the internal cache.
|
||||
#[inline(always)]
|
||||
pub fn clear_cache(&mut self) {
|
||||
#[cfg(not(feature = "sync"))]
|
||||
self.cache.borrow_mut().clear();
|
||||
#[cfg(feature = "sync")]
|
||||
self.cache.write().unwrap().clear();
|
||||
}
|
||||
|
||||
/// Empty the internal cache.
|
||||
#[inline(always)]
|
||||
pub fn clear_cache_for_path(&mut self, path: impl AsRef<Path>) -> Option<Shared<Module>> {
|
||||
#[cfg(not(feature = "sync"))]
|
||||
return self
|
||||
.cache
|
||||
.borrow_mut()
|
||||
.remove_entry(path.as_ref())
|
||||
.map(|(_, v)| v);
|
||||
#[cfg(feature = "sync")]
|
||||
return self
|
||||
.cache
|
||||
.write()
|
||||
.unwrap()
|
||||
.remove_entry(path.as_ref())
|
||||
.map(|(_, v)| v);
|
||||
}
|
||||
}
|
||||
|
||||
impl ModuleResolver for FileModuleResolver {
|
||||
|
@ -2,6 +2,9 @@ use crate::fn_native::SendSync;
|
||||
use crate::stdlib::boxed::Box;
|
||||
use crate::{Engine, EvalAltResult, Module, Position, Shared};
|
||||
|
||||
mod dummy;
|
||||
pub use dummy::DummyModuleResolver;
|
||||
|
||||
mod collection;
|
||||
pub use collection::ModuleResolversCollection;
|
||||
|
||||
|
@ -16,7 +16,7 @@ use crate::{Engine, EvalAltResult, Module, ModuleResolver, Position, Shared};
|
||||
///
|
||||
/// let mut engine = Engine::new();
|
||||
///
|
||||
/// engine.set_module_resolver(Some(resolver));
|
||||
/// engine.set_module_resolver(resolver);
|
||||
/// ```
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct StaticModuleResolver(HashMap<String, Shared<Module>>);
|
||||
@ -36,7 +36,7 @@ impl StaticModuleResolver {
|
||||
/// resolver.insert("hello", module);
|
||||
///
|
||||
/// let mut engine = Engine::new();
|
||||
/// engine.set_module_resolver(Some(resolver));
|
||||
/// engine.set_module_resolver(resolver);
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn new() -> Self {
|
||||
@ -60,8 +60,13 @@ impl StaticModuleResolver {
|
||||
}
|
||||
/// Get an iterator of all the modules.
|
||||
#[inline(always)]
|
||||
pub fn iter(&self) -> impl Iterator<Item = (&str, Shared<Module>)> {
|
||||
self.0.iter().map(|(k, v)| (k.as_str(), v.clone()))
|
||||
pub fn iter(&self) -> impl Iterator<Item = (&str, &Shared<Module>)> {
|
||||
self.0.iter().map(|(k, v)| (k.as_str(), v))
|
||||
}
|
||||
/// Get a mutable iterator of all the modules.
|
||||
#[inline(always)]
|
||||
pub fn iter_mut(&mut self) -> impl Iterator<Item = (&str, &mut Shared<Module>)> {
|
||||
self.0.iter_mut().map(|(k, v)| (k.as_str(), v))
|
||||
}
|
||||
/// Get a mutable iterator of all the modules.
|
||||
#[inline(always)]
|
||||
@ -75,8 +80,8 @@ impl StaticModuleResolver {
|
||||
}
|
||||
/// Get an iterator of all the modules.
|
||||
#[inline(always)]
|
||||
pub fn values<'a>(&'a self) -> impl Iterator<Item = Shared<Module>> + 'a {
|
||||
self.0.values().map(|m| m.clone())
|
||||
pub fn values(&self) -> impl Iterator<Item = &Shared<Module>> {
|
||||
self.0.values().map(|m| m)
|
||||
}
|
||||
/// Remove all modules.
|
||||
#[inline(always)]
|
||||
@ -95,6 +100,8 @@ impl StaticModuleResolver {
|
||||
}
|
||||
/// Merge another [`StaticModuleResolver`] into this.
|
||||
/// The other [`StaticModuleResolver`] is consumed.
|
||||
///
|
||||
/// Existing modules of the same path name are overwritten.
|
||||
#[inline(always)]
|
||||
pub fn merge(&mut self, other: Self) {
|
||||
if !other.is_empty() {
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
use crate::ast::{Expr, ScriptFnDef, Stmt};
|
||||
use crate::dynamic::AccessMode;
|
||||
use crate::engine::{KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_PRINT, KEYWORD_TYPE_OF};
|
||||
use crate::engine::{Imports, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_PRINT, KEYWORD_TYPE_OF};
|
||||
use crate::fn_call::run_builtin_binary_op;
|
||||
use crate::parser::map_dynamic_to_expr;
|
||||
use crate::stdlib::{
|
||||
@ -62,6 +62,8 @@ struct State<'a> {
|
||||
variables: Vec<(String, AccessMode, Expr)>,
|
||||
/// An [`Engine`] instance for eager function evaluation.
|
||||
engine: &'a Engine,
|
||||
/// Collection of sub-modules.
|
||||
mods: Imports,
|
||||
/// [Module] containing script-defined functions.
|
||||
lib: &'a [&'a Module],
|
||||
/// Optimization level.
|
||||
@ -76,6 +78,7 @@ impl<'a> State<'a> {
|
||||
changed: false,
|
||||
variables: vec![],
|
||||
engine,
|
||||
mods: (&engine.global_sub_modules).into(),
|
||||
lib,
|
||||
optimization_level: level,
|
||||
}
|
||||
@ -655,7 +658,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut State) {
|
||||
let arg_types: StaticVec<_> = arg_values.iter().map(Dynamic::type_id).collect();
|
||||
|
||||
// Search for overloaded operators (can override built-in).
|
||||
if !state.engine.has_override_by_name_and_arguments(Some(&state.engine.global_sub_modules), state.lib, x.name.as_ref(), arg_types.as_ref(), false) {
|
||||
if !state.engine.has_override_by_name_and_arguments(Some(&state.mods), state.lib, x.name.as_ref(), arg_types.as_ref(), false) {
|
||||
if let Some(result) = run_builtin_binary_op(x.name.as_ref(), &arg_values[0], &arg_values[1])
|
||||
.ok().flatten()
|
||||
.and_then(|result| map_dynamic_to_expr(result, *pos))
|
||||
|
@ -91,13 +91,16 @@ pub enum ParseErrorType {
|
||||
UnknownOperator(String),
|
||||
/// Expecting a particular token but not finding one. Wrapped values are the token and description.
|
||||
MissingToken(String, String),
|
||||
/// An expression in function call arguments `()` has syntax error. Wrapped value is the error description (if any).
|
||||
/// An expression in function call arguments `()` has syntax error. Wrapped value is the error
|
||||
/// description (if any).
|
||||
MalformedCallExpr(String),
|
||||
/// An expression in indexing brackets `[]` has syntax error. Wrapped value is the error description (if any).
|
||||
/// An expression in indexing brackets `[]` has syntax error. Wrapped value is the error
|
||||
/// description (if any).
|
||||
///
|
||||
/// Never appears under the `no_index` feature.
|
||||
MalformedIndexExpr(String),
|
||||
/// An expression in an `in` expression has syntax error. Wrapped value is the error description (if any).
|
||||
/// An expression in an `in` expression has syntax error. Wrapped value is the error description
|
||||
/// (if any).
|
||||
///
|
||||
/// Never appears under the `no_object` and `no_index` features combination.
|
||||
MalformedInExpr(String),
|
||||
@ -137,7 +140,8 @@ pub enum ParseErrorType {
|
||||
///
|
||||
/// Never appears under the `no_function` feature.
|
||||
FnMissingParams(String),
|
||||
/// A function definition has duplicated parameters. Wrapped values are the function name and parameter name.
|
||||
/// A function definition has duplicated parameters. Wrapped values are the function name and
|
||||
/// parameter name.
|
||||
///
|
||||
/// Never appears under the `no_function` feature.
|
||||
FnDuplicatedParam(String, String),
|
||||
|
@ -1325,6 +1325,7 @@ fn parse_unary(
|
||||
}
|
||||
}
|
||||
|
||||
/// Make an assignment statement.
|
||||
fn make_assignment_stmt<'a>(
|
||||
fn_name: Cow<'static, str>,
|
||||
state: &mut ParseState,
|
||||
|
@ -13,8 +13,8 @@ pub use rhai_codegen::*;
|
||||
pub use rhai_codegen::{export_fn, register_exported_fn};
|
||||
|
||||
/// Trait implemented by a _plugin function_.
|
||||
/// This trait should not be used directly.
|
||||
///
|
||||
/// This trait should not be used directly.
|
||||
/// Use the `#[export_module]` and `#[export_fn]` procedural attributes instead.
|
||||
pub trait PluginFunction {
|
||||
/// Call the plugin function with the arguments provided.
|
||||
|
@ -55,8 +55,8 @@ pub enum EvalAltResult {
|
||||
/// String indexing out-of-bounds.
|
||||
/// Wrapped values are the current number of characters in the string and the index number.
|
||||
ErrorStringBounds(usize, INT, Position),
|
||||
/// Trying to index into a type that is not an array, an object map, or a string, and has no indexer function defined.
|
||||
/// Wrapped value is the type name.
|
||||
/// Trying to index into a type that is not an array, an object map, or a string, and has no
|
||||
/// indexer function defined. Wrapped value is the type name.
|
||||
ErrorIndexingType(String, Position),
|
||||
/// Invalid arguments for `in` operator.
|
||||
ErrorInExpr(Position),
|
||||
|
33
src/scope.rs
33
src/scope.rs
@ -41,9 +41,11 @@ use crate::{Dynamic, ImmutableString, StaticVec};
|
||||
// [`Scope`] is implemented as two [`Vec`]'s of exactly the same length. Variables data (name, type, etc.)
|
||||
// is manually split into two equal-length arrays. That's because variable names take up the most space,
|
||||
// with [`Cow<str>`][Cow] being four words long, but in the vast majority of cases the name is NOT used to
|
||||
/// look up a variable. Variable lookup is usually via direct indexing, by-passing the name altogether.
|
||||
// look up a variable. Variable lookup is usually via direct indexing, by-passing the name altogether.
|
||||
//
|
||||
// Since [`Dynamic`] is reasonably small, packing it tightly improves cache locality when variables are accessed.
|
||||
//
|
||||
// The alias is `Box`'ed because it occurs infrequently.
|
||||
#[derive(Debug, Clone, Hash)]
|
||||
pub struct Scope<'a> {
|
||||
/// Current value of the entry.
|
||||
@ -356,8 +358,35 @@ impl<'a> Scope<'a> {
|
||||
self
|
||||
}
|
||||
/// Get a mutable reference to an entry in the [`Scope`].
|
||||
///
|
||||
/// If the entry by the specified name is not found, of if it is read-only,
|
||||
/// [`None`] is returned.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use rhai::Scope;
|
||||
///
|
||||
/// let mut my_scope = Scope::new();
|
||||
///
|
||||
/// my_scope.push("x", 42_i64);
|
||||
/// assert_eq!(my_scope.get_value::<i64>("x").unwrap(), 42);
|
||||
///
|
||||
/// let ptr = my_scope.get_mut("x").unwrap();
|
||||
/// *ptr = 123_i64.into();
|
||||
///
|
||||
/// assert_eq!(my_scope.get_value::<i64>("x").unwrap(), 123);
|
||||
/// ```
|
||||
pub fn get_mut(&mut self, name: &str) -> Option<&mut Dynamic> {
|
||||
self.get_index(name)
|
||||
.and_then(move |(index, access)| match access {
|
||||
AccessMode::ReadWrite => Some(self.get_mut_by_index(index)),
|
||||
AccessMode::ReadOnly => None,
|
||||
})
|
||||
}
|
||||
/// Get a mutable reference to an entry in the [`Scope`] based on the index.
|
||||
#[inline(always)]
|
||||
pub(crate) fn get_mut(&mut self, index: usize) -> &mut Dynamic {
|
||||
pub(crate) fn get_mut_by_index(&mut self, index: usize) -> &mut Dynamic {
|
||||
self.values.get_mut(index).expect("invalid index in Scope")
|
||||
}
|
||||
/// Update the access type of an entry in the [`Scope`].
|
||||
|
@ -63,7 +63,8 @@ pub fn get_hasher() -> impl Hasher {
|
||||
s
|
||||
}
|
||||
|
||||
/// _(INTERNALS)_ Calculate a [`NonZeroU64`] hash key from a namespace-qualified function name and parameter types.
|
||||
/// _(INTERNALS)_ Calculate a [`NonZeroU64`] hash key from a namespace-qualified function name and
|
||||
/// parameter types.
|
||||
/// Exported under the `internals` feature only.
|
||||
///
|
||||
/// Module names are passed in via `&str` references from an iterator.
|
||||
@ -108,6 +109,7 @@ pub fn calc_script_fn_hash<'a>(
|
||||
/// # Note
|
||||
///
|
||||
/// The first module name is skipped. Hashing starts from the _second_ module in the chain.
|
||||
#[inline(always)]
|
||||
fn calc_fn_hash<'a>(
|
||||
mut modules: impl Iterator<Item = &'a str>,
|
||||
fn_name: &str,
|
||||
|
@ -82,7 +82,7 @@ fn test_call_fn_private() -> Result<(), Box<EvalAltResult>> {
|
||||
let ast = engine.compile("private fn add(x, n, ) { x + n }")?;
|
||||
|
||||
assert!(matches!(
|
||||
*engine.call_fn::<_, INT>(&mut scope, &ast, "add", (40 as INT, 2 as INT))
|
||||
*(engine.call_fn(&mut scope, &ast, "add", (40 as INT, 2 as INT)) as Result<INT, Box<EvalAltResult>>)
|
||||
.expect_err("should error"),
|
||||
EvalAltResult::ErrorFunctionNotFound(fn_name, _) if fn_name == "add"
|
||||
));
|
||||
|
@ -239,7 +239,7 @@ fn test_closures_shared_obj() -> Result<(), Box<EvalAltResult>> {
|
||||
let f = move |p1: TestStruct, p2: TestStruct| -> Result<(), Box<EvalAltResult>> {
|
||||
let action_ptr = res["action"].clone().cast::<FnPtr>();
|
||||
let name = action_ptr.fn_name();
|
||||
engine.call_fn::<_, ()>(&mut Scope::new(), &ast, name, (p1, p2))
|
||||
engine.call_fn(&mut Scope::new(), &ast, name, (p1, p2))
|
||||
};
|
||||
|
||||
// Test closure
|
||||
|
@ -101,7 +101,7 @@ fn test_module_resolver() -> Result<(), Box<EvalAltResult>> {
|
||||
resolver.insert("hello", module);
|
||||
|
||||
let mut engine = Engine::new();
|
||||
engine.set_module_resolver(Some(resolver));
|
||||
engine.set_module_resolver(resolver);
|
||||
|
||||
assert_eq!(
|
||||
engine.eval::<INT>(
|
||||
@ -295,13 +295,13 @@ fn test_module_from_ast() -> Result<(), Box<EvalAltResult>> {
|
||||
"#,
|
||||
)?;
|
||||
|
||||
engine.set_module_resolver(Some(resolver1));
|
||||
engine.set_module_resolver(resolver1);
|
||||
|
||||
let module = Module::eval_ast_as_new(Scope::new(), &ast, &engine)?;
|
||||
|
||||
let mut resolver2 = StaticModuleResolver::new();
|
||||
resolver2.insert("testing", module);
|
||||
engine.set_module_resolver(Some(resolver2));
|
||||
engine.set_module_resolver(resolver2);
|
||||
|
||||
assert_eq!(
|
||||
engine.eval::<INT>(r#"import "testing" as ttt; ttt::abc"#)?,
|
||||
@ -384,7 +384,7 @@ fn test_module_str() -> Result<(), Box<EvalAltResult>> {
|
||||
|
||||
let mut static_modules = rhai::module_resolvers::StaticModuleResolver::new();
|
||||
static_modules.insert("test", module);
|
||||
engine.set_module_resolver(Some(static_modules));
|
||||
engine.set_module_resolver(static_modules);
|
||||
|
||||
assert_eq!(
|
||||
engine.eval::<INT>(r#"import "test" as test; test::test("test");"#)?,
|
||||
@ -418,7 +418,7 @@ fn test_module_ast_namespace() -> Result<(), Box<EvalAltResult>> {
|
||||
|
||||
let mut resolver = StaticModuleResolver::new();
|
||||
resolver.insert("testing", module);
|
||||
engine.set_module_resolver(Some(resolver));
|
||||
engine.set_module_resolver(resolver);
|
||||
|
||||
assert_eq!(
|
||||
engine.eval::<INT>(r#"import "testing" as t; t::foo(41)"#)?,
|
||||
@ -466,7 +466,7 @@ fn test_module_ast_namespace2() -> Result<(), Box<EvalAltResult>> {
|
||||
let module = Module::eval_ast_as_new(Scope::new(), &module_ast, &engine)?;
|
||||
let mut static_modules = rhai::module_resolvers::StaticModuleResolver::new();
|
||||
static_modules.insert("test_module", module);
|
||||
engine.set_module_resolver(Some(static_modules));
|
||||
engine.set_module_resolver(static_modules);
|
||||
|
||||
engine.consume(SCRIPT)?;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user