Merge branch 'namespace'
This commit is contained in:
commit
8e60976cfa
47
README.md
47
README.md
@ -2080,7 +2080,7 @@ crypto::encrypt(others); // <- this causes a run-time error because the 'cryp
|
|||||||
|
|
||||||
### Creating custom modules from Rust
|
### Creating custom modules from Rust
|
||||||
|
|
||||||
To load a custom module into an [`Engine`], first create a `Module` type, add variables/functions into it,
|
To load a custom module (written in Rust) into an [`Engine`], first create a `Module` type, add variables/functions into it,
|
||||||
then finally push it into a custom [`Scope`]. This has the equivalent effect of putting an `import` statement
|
then finally push it into a custom [`Scope`]. This has the equivalent effect of putting an `import` statement
|
||||||
at the beginning of any script run.
|
at the beginning of any script run.
|
||||||
|
|
||||||
@ -2105,6 +2105,47 @@ engine.eval_expression_with_scope::<i64>(&scope, "question::answer + 1")? == 42;
|
|||||||
engine.eval_expression_with_scope::<i64>(&scope, "question::inc(question::answer)")? == 42;
|
engine.eval_expression_with_scope::<i64>(&scope, "question::inc(question::answer)")? == 42;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Creating a module from an `AST`
|
||||||
|
|
||||||
|
It is easy to convert a pre-compiled `AST` into a module, just use `Module::eval_ast_as_new`:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use rhai::{Engine, Module};
|
||||||
|
|
||||||
|
let engine = Engine::new();
|
||||||
|
|
||||||
|
// Compile a script into an 'AST'
|
||||||
|
let ast = engine.compile(r#"
|
||||||
|
// Functions become module functions
|
||||||
|
fn calc(x) {
|
||||||
|
x + 1
|
||||||
|
}
|
||||||
|
fn add_len(x, y) {
|
||||||
|
x + y.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Imported modules become sub-modules
|
||||||
|
import "another module" as extra;
|
||||||
|
|
||||||
|
// Variables defined at global level become module variables
|
||||||
|
const x = 123;
|
||||||
|
let foo = 41;
|
||||||
|
let hello;
|
||||||
|
|
||||||
|
// Final variable values become constant module variable values
|
||||||
|
foo = calc(foo);
|
||||||
|
hello = "hello, " + foo + " worlds!";
|
||||||
|
"#)?;
|
||||||
|
|
||||||
|
// Convert the 'AST' into a module, using the 'Engine' to evaluate it first
|
||||||
|
let module = Module::eval_ast_as_new(&ast, &engine)?;
|
||||||
|
|
||||||
|
// 'module' now can be loaded into a custom 'Scope' for future use. It contains:
|
||||||
|
// - sub-module: 'extra'
|
||||||
|
// - functions: 'calc', 'add_len'
|
||||||
|
// - variables: 'x', 'foo', 'hello'
|
||||||
|
```
|
||||||
|
|
||||||
### Module resolvers
|
### Module resolvers
|
||||||
|
|
||||||
When encountering an `import` statement, Rhai attempts to _resolve_ the module based on the path string.
|
When encountering an `import` statement, Rhai attempts to _resolve_ the module based on the path string.
|
||||||
@ -2115,8 +2156,8 @@ which simply loads a script file based on the path (with `.rhai` extension attac
|
|||||||
Built-in module resolvers are grouped under the `rhai::module_resolvers` module namespace.
|
Built-in module resolvers are grouped under the `rhai::module_resolvers` module namespace.
|
||||||
|
|
||||||
| Module Resolver | Description |
|
| Module Resolver | Description |
|
||||||
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| `FileModuleResolver` | The default module resolution service, not available under the [`no_std`] feature. Loads a script file (based off the current directory) with `.rhai` extension.<br/>The base directory can be changed via the `FileModuleResolver::new_with_path()` constructor function. |
|
| `FileModuleResolver` | The default module resolution service, not available under the [`no_std`] feature. Loads a script file (based off the current directory) with `.rhai` extension.<br/>The base directory can be changed via the `FileModuleResolver::new_with_path()` constructor function.<br/>`FileModuleResolver::create_module()` loads a script file and returns a module. |
|
||||||
| `StaticModuleResolver` | Loads modules that are statically added. This can be used when the [`no_std`] feature is turned on. |
|
| `StaticModuleResolver` | Loads modules that are statically added. This can be used when the [`no_std`] feature is turned on. |
|
||||||
|
|
||||||
An [`Engine`]'s module resolver is set via a call to `set_module_resolver`:
|
An [`Engine`]'s module resolver is set via a call to `set_module_resolver`:
|
||||||
|
@ -740,6 +740,15 @@ mod file {
|
|||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Default::default()
|
Default::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a `Module` from a file path.
|
||||||
|
pub fn create_module<P: Into<PathBuf>>(
|
||||||
|
&self,
|
||||||
|
engine: &Engine,
|
||||||
|
path: &str,
|
||||||
|
) -> Result<Module, Box<EvalAltResult>> {
|
||||||
|
self.resolve(engine, path, Default::default())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModuleResolver for FileModuleResolver {
|
impl ModuleResolver for FileModuleResolver {
|
||||||
|
@ -81,3 +81,71 @@ fn test_module_resolver() -> Result<(), Box<EvalAltResult>> {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_module_from_ast() -> Result<(), Box<EvalAltResult>> {
|
||||||
|
let mut engine = Engine::new();
|
||||||
|
|
||||||
|
let mut resolver = rhai::module_resolvers::StaticModuleResolver::new();
|
||||||
|
let mut sub_module = Module::new();
|
||||||
|
sub_module.set_var("foo", true);
|
||||||
|
resolver.insert("another module".to_string(), sub_module);
|
||||||
|
|
||||||
|
engine.set_module_resolver(Some(resolver));
|
||||||
|
|
||||||
|
let ast = engine.compile(
|
||||||
|
r#"
|
||||||
|
// Functions become module functions
|
||||||
|
fn calc(x) {
|
||||||
|
x + 1
|
||||||
|
}
|
||||||
|
fn add_len(x, y) {
|
||||||
|
x + y.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Imported modules become sub-modules
|
||||||
|
import "another module" as extra;
|
||||||
|
|
||||||
|
// Variables defined at global level become module variables
|
||||||
|
const x = 123;
|
||||||
|
let foo = 41;
|
||||||
|
let hello;
|
||||||
|
|
||||||
|
// Final variable values become constant module variable values
|
||||||
|
foo = calc(foo);
|
||||||
|
hello = "hello, " + foo + " worlds!";
|
||||||
|
"#,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let module = Module::eval_ast_as_new(&ast, &engine)?;
|
||||||
|
|
||||||
|
let mut scope = Scope::new();
|
||||||
|
scope.push_module("testing", module);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
engine.eval_expression_with_scope::<INT>(&mut scope, "testing::x")?,
|
||||||
|
123
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
engine.eval_expression_with_scope::<INT>(&mut scope, "testing::foo")?,
|
||||||
|
42
|
||||||
|
);
|
||||||
|
assert!(engine.eval_expression_with_scope::<bool>(&mut scope, "testing::extra::foo")?);
|
||||||
|
assert_eq!(
|
||||||
|
engine.eval_expression_with_scope::<String>(&mut scope, "testing::hello")?,
|
||||||
|
"hello, 42 worlds!"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
engine.eval_expression_with_scope::<INT>(&mut scope, "testing::calc(999)")?,
|
||||||
|
1000
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
engine.eval_expression_with_scope::<INT>(
|
||||||
|
&mut scope,
|
||||||
|
"testing::add_len(testing::foo, testing::hello)"
|
||||||
|
)?,
|
||||||
|
59
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user