reorganize module
This commit is contained in:
160
_archive/rhai_engine/rhaibook/engine/compile.md
Normal file
160
_archive/rhai_engine/rhaibook/engine/compile.md
Normal file
@@ -0,0 +1,160 @@
|
||||
Compile a Script (to AST)
|
||||
=========================
|
||||
|
||||
{{#include ../links.md}}
|
||||
|
||||
To repeatedly evaluate a script, _compile_ it first with `Engine::compile` into an `AST`
|
||||
(**A**bstract **S**yntax **T**ree) form.
|
||||
|
||||
`Engine::eval_ast_XXX` and `Engine::run_ast_XXX` evaluate a pre-compiled `AST`.
|
||||
|
||||
```rust
|
||||
// Compile to an AST and store it for later evaluations
|
||||
let ast = engine.compile("40 + 2")?;
|
||||
|
||||
for _ in 0..42 {
|
||||
let result: i64 = engine.eval_ast(&ast)?;
|
||||
|
||||
println!("Answer #{i}: {result}"); // prints 42
|
||||
}
|
||||
```
|
||||
|
||||
~~~admonish tip.small "Tip: Compile script file"
|
||||
|
||||
Compiling script files is also supported via `Engine::compile_file`
|
||||
(not available for [`no_std`] or [WASM] builds).
|
||||
|
||||
```rust
|
||||
let ast = engine.compile_file("hello_world.rhai".into())?;
|
||||
```
|
||||
~~~
|
||||
|
||||
~~~admonish info.small "See also: `AST` manipulation API"
|
||||
|
||||
Advanced users who may want to manipulate an `AST`, especially the functions contained within,
|
||||
should see the section on [_Manage AST's_](ast.md) for more details.
|
||||
~~~
|
||||
|
||||
|
||||
Practical Use – Header Template Scripts
|
||||
---------------------------------------------
|
||||
|
||||
Sometimes it is desirable to include a standardized _header template_ in a script that contains
|
||||
pre-defined [functions], [constants] and [imported][`import`] [modules].
|
||||
|
||||
```rust
|
||||
// START OF THE HEADER TEMPLATE
|
||||
// The following should run before every script...
|
||||
|
||||
import "hello" as h;
|
||||
import "world" as w;
|
||||
|
||||
// Standard constants
|
||||
|
||||
const GLOBAL_CONSTANT = 42;
|
||||
const SCALE_FACTOR = 1.2;
|
||||
|
||||
// Standard functions
|
||||
|
||||
fn foo(x, y) { ... }
|
||||
|
||||
fn bar() { ... }
|
||||
|
||||
fn baz() { ... }
|
||||
|
||||
// END OF THE HEADER TEMPLATE
|
||||
|
||||
// Everything below changes from run to run
|
||||
|
||||
foo(bar() + GLOBAL_CONSTANT, baz() * SCALE_FACTOR)
|
||||
```
|
||||
|
||||
### Option 1 – The easy way
|
||||
|
||||
Prepend the script header template onto independent scripts and run them as a whole.
|
||||
|
||||
> **Pros:** Easy!
|
||||
>
|
||||
> **Cons:** If the header template is long, work is duplicated every time to parse it.
|
||||
|
||||
```rust
|
||||
let header_template = "..... // scripts... .....";
|
||||
|
||||
for index in 0..10000 {
|
||||
let user_script = db.get_script(index);
|
||||
|
||||
// Just merge the two scripts...
|
||||
let combined_script = format!("{header_template}\n{user_script}\n");
|
||||
|
||||
// Run away!
|
||||
let result = engine.eval::<i64>(combined_script)?;
|
||||
|
||||
println!("{result}");
|
||||
}
|
||||
```
|
||||
|
||||
### Option 2 – The hard way
|
||||
|
||||
Option 1 requires the script header template to be recompiled every time. This can be expensive if
|
||||
the header is very long.
|
||||
|
||||
This option compiles both the script header template and independent scripts as separate `AST`'s
|
||||
which are then joined together to form a combined `AST`.
|
||||
|
||||
> **Pros:** No need to recompile the header template!
|
||||
>
|
||||
> **Cons:** More work...
|
||||
|
||||
```rust
|
||||
let header_template = "..... // scripts... .....";
|
||||
|
||||
let mut template_ast = engine.compile(header_template)?;
|
||||
|
||||
// If you don't want to run the template, only keep the functions
|
||||
// defined inside (e.g. closures), clear out the statements.
|
||||
template_ast.clear_statements();
|
||||
|
||||
for index in 0..10000 {
|
||||
let user_script = db.get_script(index);
|
||||
|
||||
let user_ast = engine.compile(user_script)?;
|
||||
|
||||
// Merge the two AST's
|
||||
let combined_ast = template_ast + user_ast;
|
||||
|
||||
// Run away!
|
||||
let result = engine.eval_ast::<i64>(combined_ast)?;
|
||||
|
||||
println!("{result}");
|
||||
```
|
||||
|
||||
### Option 3 – The not-so-hard way
|
||||
|
||||
Option 1 does repeated work, option 2 requires manipulating `AST`'s...
|
||||
|
||||
This option makes the scripted [functions] (not [imported][`import`] [modules] nor [constants]
|
||||
however) available globally by first making it a [module] (via [`Module::eval_ast_as_new`](modules/ast.md))
|
||||
and then loading it into the [`Engine`] via `Engine::register_global_module`.
|
||||
|
||||
> **Pros:** No need to recompile the header template!
|
||||
>
|
||||
> **Cons:** No [imported][`import`] [modules] nor [constants]; if the header template is changed, a new [`Engine`] must be created.
|
||||
|
||||
```rust
|
||||
let header_template = "..... // scripts... .....";
|
||||
|
||||
let template_ast = engine.compile(header_template)?;
|
||||
|
||||
let template_module = Module::eval_ast_as_new(Scope::new(), &template_ast, &engine)?;
|
||||
|
||||
engine.register_global_module(template_module.into());
|
||||
|
||||
for index in 0..10000 {
|
||||
let user_script = db.get_script(index);
|
||||
|
||||
// Run away!
|
||||
let result = engine.eval::<i64>(user_script)?;
|
||||
|
||||
println!("{result}");
|
||||
}
|
||||
```
|
Reference in New Issue
Block a user