Add Rhai book.
This commit is contained in:
53
doc/src/language/modules/ast.md
Normal file
53
doc/src/language/modules/ast.md
Normal file
@@ -0,0 +1,53 @@
|
||||
Create a Module from an AST
|
||||
==========================
|
||||
|
||||
{{#include ../../links.md}}
|
||||
|
||||
It is easy to convert a pre-compiled `AST` into a module: just use `Module::eval_ast_as_new`.
|
||||
|
||||
Don't forget the [`export`] statement, otherwise there will be no variables exposed by the module
|
||||
other than non-[`private`] functions (unless that's intentional).
|
||||
|
||||
```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 can become sub-modules
|
||||
import "another module" as extra;
|
||||
|
||||
// Variables defined at global level can become module variables
|
||||
const x = 123;
|
||||
let foo = 41;
|
||||
let hello;
|
||||
|
||||
// Variable values become constant module variable values
|
||||
foo = calc(foo);
|
||||
hello = "hello, " + foo + " worlds!";
|
||||
|
||||
// Finally, export the variables and modules
|
||||
export
|
||||
x as abc, // aliased variable name
|
||||
foo,
|
||||
hello,
|
||||
extra as foobar; // export sub-module
|
||||
"#)?;
|
||||
|
||||
// Convert the 'AST' into a module, using the 'Engine' to evaluate it first
|
||||
let module = Module::eval_ast_as_new(Scope::new(), &ast, &engine)?;
|
||||
|
||||
// 'module' now can be loaded into a custom 'Scope' for future use. It contains:
|
||||
// - sub-module: 'foobar' (renamed from 'extra')
|
||||
// - functions: 'calc', 'add_len'
|
||||
// - variables: 'abc' (renamed from 'x'), 'foo', 'hello'
|
||||
```
|
32
doc/src/language/modules/export.md
Normal file
32
doc/src/language/modules/export.md
Normal file
@@ -0,0 +1,32 @@
|
||||
Export Variables and Functions from Modules
|
||||
==========================================
|
||||
|
||||
{{#include ../../links.md}}
|
||||
|
||||
A _module_ is a single script (or pre-compiled `AST`) containing global variables and functions.
|
||||
|
||||
The `export` statement, which can only be at global level, exposes selected variables as members of a module.
|
||||
|
||||
Variables not exported are _private_ and invisible to the outside.
|
||||
|
||||
On the other hand, all functions are automatically exported, _unless_ it is explicitly opt-out with the [`private`] prefix.
|
||||
|
||||
Functions declared [`private`] are invisible to the outside.
|
||||
|
||||
Everything exported from a module is **constant** (**read-only**).
|
||||
|
||||
```rust
|
||||
// This is a module script.
|
||||
|
||||
fn inc(x) { x + 1 } // script-defined function - default public
|
||||
|
||||
private fn foo() {} // private function - invisible to outside
|
||||
|
||||
let private = 123; // variable not exported - default invisible to outside
|
||||
let x = 42; // this will be exported below
|
||||
|
||||
export x; // the variable 'x' is exported under its own name
|
||||
|
||||
export x as answer; // the variable 'x' is exported under the alias 'answer'
|
||||
// another script can load this module and access 'x' as 'module::answer'
|
||||
```
|
45
doc/src/language/modules/import.md
Normal file
45
doc/src/language/modules/import.md
Normal file
@@ -0,0 +1,45 @@
|
||||
Import a Module
|
||||
===============
|
||||
|
||||
{{#include ../../links.md}}
|
||||
|
||||
A module can be _imported_ via the `import` statement, and its members are accessed via '`::`' similar to C++.
|
||||
|
||||
```rust
|
||||
import "crypto" as lock; // import the script file 'crypto.rhai' as a module named 'lock'
|
||||
|
||||
lock::encrypt(secret); // use functions defined under the module via '::'
|
||||
|
||||
lock::hash::sha256(key); // sub-modules are also supported
|
||||
|
||||
print(lock::status); // module variables are constants
|
||||
|
||||
lock::status = "off"; // <- runtime error - cannot modify a constant
|
||||
```
|
||||
|
||||
`import` statements are _scoped_, meaning that they are only accessible inside the scope that they're imported.
|
||||
They can appear anywhere a normal statement can be, but in the vast majority of cases `import` statements are
|
||||
group at the beginning of a script.
|
||||
|
||||
It is, however, not advised to deviate from this common practice unless there is a _Very Good Reason™_.
|
||||
Especially, do not place an `import` statement within a loop; doing so will repeatedly re-load the same module
|
||||
during every iteration of the loop!
|
||||
|
||||
```rust
|
||||
let mod = "crypto";
|
||||
|
||||
if secured { // new block scope
|
||||
import mod as c; // import module (the path needs not be a constant string)
|
||||
|
||||
c::encrypt(key); // use a function in the module
|
||||
} // the module disappears at the end of the block scope
|
||||
|
||||
crypto::encrypt(others); // <- this causes a run-time error because the 'crypto' module
|
||||
// is no longer available!
|
||||
|
||||
for x in range(0, 1000) {
|
||||
import "crypto" as c; // <- importing a module inside a loop is a Very Bad Idea™
|
||||
|
||||
c.encrypt(something);
|
||||
}
|
||||
```
|
29
doc/src/language/modules/resolvers.md
Normal file
29
doc/src/language/modules/resolvers.md
Normal file
@@ -0,0 +1,29 @@
|
||||
Module Resolvers
|
||||
================
|
||||
|
||||
{{#include ../../links.md}}
|
||||
|
||||
When encountering an [`import`] statement, Rhai attempts to _resolve_ the module based on the path string.
|
||||
|
||||
_Module Resolvers_ are service types that implement the [`ModuleResolver`](/rust/traits.md) trait.
|
||||
|
||||
There are a number of standard resolvers built into Rhai, the default being the `FileModuleResolver`
|
||||
which simply loads a script file based on the path (with `.rhai` extension attached) and execute it to form a module.
|
||||
|
||||
Built-in module resolvers are grouped under the `rhai::module_resolvers` module namespace.
|
||||
|
||||
| Module Resolver | Description |
|
||||
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `FileModuleResolver` | The default module resolution service, not available under [`no_std`] or [WASM] builds. 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 under [`no_std`]. |
|
||||
|
||||
An [`Engine`]'s module resolver is set via a call to `Engine::set_module_resolver`:
|
||||
|
||||
```rust
|
||||
// Use the 'StaticModuleResolver'
|
||||
let resolver = rhai::module_resolvers::StaticModuleResolver::new();
|
||||
engine.set_module_resolver(Some(resolver));
|
||||
|
||||
// Effectively disable 'import' statements by setting module resolver to 'None'
|
||||
engine.set_module_resolver(None);
|
||||
```
|
30
doc/src/language/modules/rust.md
Normal file
30
doc/src/language/modules/rust.md
Normal file
@@ -0,0 +1,30 @@
|
||||
Create a Module from Rust
|
||||
========================
|
||||
|
||||
{{#include ../../links.md}}
|
||||
|
||||
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 at the beginning of any script run.
|
||||
|
||||
```rust
|
||||
use rhai::{Engine, Scope, Module, i64};
|
||||
|
||||
let mut engine = Engine::new();
|
||||
let mut scope = Scope::new();
|
||||
|
||||
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
|
||||
|
||||
// Push the module into the custom scope under the name 'question'
|
||||
// This is equivalent to 'import "..." as question;'
|
||||
scope.push_module("question", module);
|
||||
|
||||
// Use module-qualified variables
|
||||
engine.eval_expression_with_scope::<i64>(&scope, "question::answer + 1")? == 42;
|
||||
|
||||
// Call module-qualified functions
|
||||
engine.eval_expression_with_scope::<i64>(&scope, "question::inc(question::answer)")? == 42;
|
||||
```
|
Reference in New Issue
Block a user