Add more module tests.

This commit is contained in:
Stephen Chung 2020-10-02 14:55:02 +08:00
parent e8d5f78f88
commit d2c94ba07c
5 changed files with 139 additions and 5 deletions

87
benches/eval_module.rs Normal file
View File

@ -0,0 +1,87 @@
#![feature(test)]
///! Test evaluating with scope
extern crate test;
use rhai::{module_resolvers::StaticModuleResolver, Engine, Module, OptimizationLevel};
use test::Bencher;
#[bench]
fn bench_eval_module_merged(bench: &mut Bencher) {
let script = r#"
fn foo(x) { x + 1 }
fn bar(x) { foo(x) }
"#;
let mut engine = Engine::new();
engine.set_optimization_level(OptimizationLevel::None);
let ast = engine.compile(script).unwrap();
let module = Module::eval_ast_as_new(Default::default(), &ast, true, &engine).unwrap();
let mut resolver = StaticModuleResolver::new();
resolver.insert("testing", module);
engine.set_module_resolver(Some(resolver));
let ast = engine
.compile(
r#"
fn foo(x) { x - 1 }
import "testing" as t;
t::bar(41)
"#,
)
.unwrap();
bench.iter(|| engine.consume_ast(&ast).unwrap());
}
#[bench]
fn bench_eval_module_unmerged(bench: &mut Bencher) {
let script = r#"
fn foo(x) { x + 1 }
fn bar(x) { foo(x) }
"#;
let mut engine = Engine::new();
engine.set_optimization_level(OptimizationLevel::None);
let ast = engine.compile(script).unwrap();
let module = Module::eval_ast_as_new(Default::default(), &ast, false, &engine).unwrap();
let mut resolver = StaticModuleResolver::new();
resolver.insert("testing", module);
engine.set_module_resolver(Some(resolver));
let ast = engine
.compile(
r#"
fn foo(x) { x - 1 }
import "testing" as t;
t::bar(41)
"#,
)
.unwrap();
bench.iter(|| engine.consume_ast(&ast).unwrap());
}
#[bench]
fn bench_eval_function_call(bench: &mut Bencher) {
let mut engine = Engine::new();
engine.set_optimization_level(OptimizationLevel::None);
let ast = engine
.compile(
r#"
fn foo(x) { x - 1 }
fn bar(x) { foo(x) }
bar(41)
"#,
)
.unwrap();
bench.iter(|| engine.consume_ast(&ast).unwrap());
}

View File

@ -27,9 +27,13 @@ functions exposed by the module and the namespace that they can access:
| `merge_namespaces` value | Description | Namespace | Performance | Call global functions | Call functions in same module | | `merge_namespaces` value | Description | Namespace | Performance | Call global functions | Call functions in same module |
| :----------------------: | ------------------------------------------------ | :-----------------: | :---------: | :-------------------: | :---------------------------: | | :----------------------: | ------------------------------------------------ | :-----------------: | :---------: | :-------------------: | :---------------------------: |
| `true` | encapsulate entire `AST` into each function call | module, then global | slower | yes | yes | | `true` | encapsulate entire `AST` into each function call | module, then global | 2x slower | yes | yes |
| `false` | register each function independently | global only | fast | yes | no | | `false` | register each function independently | global only | fast | yes | no |
If the ultimate intention is to load the [module] directly into an [`Engine`] via `Engine::load_package`,
set `merge_namespaces` to `false` because there will not be any _module_ namespace as `Engine::load_package`
flattens everything into the _global_ namespace anyway.
Examples Examples
-------- --------
@ -78,7 +82,9 @@ let ast = engine.compile(r#"
// a copy of the entire 'AST' into each function, allowing functions in the module script // a copy of the entire 'AST' into each function, allowing functions in the module script
// to cross-call each other. // to cross-call each other.
// //
// This incurs additional overhead, avoidable by setting 'merge_namespaces' to false. // This incurs additional overhead, avoidable by setting 'merge_namespaces' to false
// which makes function calls 2x faster but at the expense of not being able to cross-call
// functions in the same module script.
let module = Module::eval_ast_as_new(Scope::new(), &ast, true, &engine)?; let module = Module::eval_ast_as_new(Scope::new(), &ast, true, &engine)?;
// 'module' now contains: // 'module' now contains:

View File

@ -1260,8 +1260,12 @@ impl Module {
/// defined in the module, are _merged_ into a _unified_ namespace before each call. /// defined in the module, are _merged_ into a _unified_ namespace before each call.
/// Therefore, all functions will be found, at the expense of some performance. /// Therefore, all functions will be found, at the expense of some performance.
/// ///
/// * If `false`, each function is registered independently and cannot cross-call /// * If `false`, each function is registered independently and cannot cross-call each other.
/// each other. Functions are searched in the global namespace. /// Functions are searched in the global namespace.
/// This is roughly 2x faster than the `true` case.
///
/// Set `merge_namespaces` to `false` if the ultimate intention is to load the module
/// via `Engine::load_package` because it does not create any module namespace.
/// ///
/// # Examples /// # Examples
/// ///

View File

@ -361,3 +361,40 @@ fn test_module_str() -> Result<(), Box<EvalAltResult>> {
Ok(()) Ok(())
} }
#[test]
fn test_module_ast_namespace() -> Result<(), Box<EvalAltResult>> {
let script = r#"
fn foo(x) { x + 1 }
fn bar(x) { foo(x) }
"#;
let mut engine = Engine::new();
let ast = engine.compile(script)?;
let module = Module::eval_ast_as_new(Default::default(), &ast, true, &engine)?;
let mut resolver = StaticModuleResolver::new();
resolver.insert("testing", module);
engine.set_module_resolver(Some(resolver));
assert_eq!(
engine.eval::<INT>(r#"import "testing" as t; t::foo(41)"#)?,
42
);
assert_eq!(
engine.eval::<INT>(r#"import "testing" as t; t::bar(41)"#)?,
42
);
assert_eq!(
engine.eval::<INT>(r#"fn foo(x) { x - 1 } import "testing" as t; t::foo(41)"#)?,
42
);
assert_eq!(
engine.eval::<INT>(r#"fn foo(x) { x - 1 } import "testing" as t; t::bar(41)"#)?,
42
);
Ok(())
}