docs: reorganize into en/ru and add English translation
This commit is contained in:
200
docs/en/modules/04-rhei.md
Normal file
200
docs/en/modules/04-rhei.md
Normal file
@@ -0,0 +1,200 @@
|
||||
# Rhai Module: `src/interpreter/rhei.rs`
|
||||
|
||||
Integration of the [Rhai](https://rhai.rs/) scripting engine — compilation, AST caching, and expression/script execution.
|
||||
|
||||
---
|
||||
|
||||
## `RHEI_PREFIX` — Rhai expression prefix
|
||||
|
||||
```rust
|
||||
pub const RHEI_PREFIX: &str = "__rhei:";
|
||||
```
|
||||
|
||||
A marker constant for element properties whose content should be interpreted as Rhai expressions. Used in `collect_and_precompile()` to select properties of the form `!rhei:...`.
|
||||
|
||||
---
|
||||
|
||||
## `RheiContext` — Rhai execution context
|
||||
|
||||
```rust
|
||||
pub struct RheiContext {
|
||||
engine: Engine,
|
||||
init_ast: AST,
|
||||
scope: RefCell<Scope<'static>>,
|
||||
action_cache: RefCell<HashMap<String, AST>>,
|
||||
expr_cache: RefCell<HashMap<String, AST>>,
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Purpose |
|
||||
|---|---|
|
||||
| `engine` | Configured `rhai::Engine` instance |
|
||||
| `init_ast` | Merged AST of all initialization scripts (including function definitions) |
|
||||
| `scope` | Shared scope (`Scope`) shared across calls; wrapped in `RefCell` for interior mutability |
|
||||
| `action_cache` | Cache of compiled scripts (actions), keyed by source code |
|
||||
| `expr_cache` | Cache of compiled expressions, keyed by source code |
|
||||
|
||||
---
|
||||
|
||||
## Constructors
|
||||
|
||||
### `new(scripts)`
|
||||
|
||||
```rust
|
||||
pub fn new(scripts: &[String]) -> Self
|
||||
```
|
||||
|
||||
Creates a context via `new_empty()` and immediately precompiles all provided scripts by calling `precompile_scripts()`.
|
||||
|
||||
### `new_empty(scripts)`
|
||||
|
||||
```rust
|
||||
fn new_empty(scripts: &[String]) -> Self
|
||||
```
|
||||
|
||||
1. Creates `Engine::new()`.
|
||||
2. Configures `on_print` (outputs to stdout with `[rhei]` prefix) and `on_debug` (outputs to stderr) handlers.
|
||||
3. Compiles all scripts and merges their ASTs into a single tree via `merge()`. Compilation errors for individual blocks are logged but do not abort the process.
|
||||
4. Creates a module (`Module::eval_ast_as_new`) from the merged AST with an empty scope — this registers global functions defined in the scripts. The module is registered in the engine as a global module (`register_global_module`).
|
||||
5. Initializes an empty `Scope`, empty `action_cache` and `expr_cache` caches.
|
||||
|
||||
---
|
||||
|
||||
## `sync_scope()` — variable synchronization
|
||||
|
||||
```rust
|
||||
pub fn sync_scope(&self, variables: &HashMap<String, Value>)
|
||||
```
|
||||
|
||||
Synchronizes values from an external `HashMap` into the Rhai `Scope`:
|
||||
- If a variable already exists in the scope and its value has not changed — skip.
|
||||
- If a variable exists — update it via `set_value()`.
|
||||
- If a variable does not exist — add it via `push_dynamic()`.
|
||||
|
||||
Conversion `Value → Dynamic` is performed via `value_to_dynamic()`.
|
||||
|
||||
---
|
||||
|
||||
## `initialize()` — initialization
|
||||
|
||||
```rust
|
||||
pub fn initialize(&self, variables: &mut HashMap<String, Value>)
|
||||
```
|
||||
|
||||
1. Synchronizes variables via `sync_scope()`.
|
||||
2. Runs `init_ast` (merged AST of all scripts) via `run_ast_with_scope()`.
|
||||
3. Iterates over all scope variables via `iter_raw()` and writes back into the `HashMap` those whose values have changed.
|
||||
|
||||
---
|
||||
|
||||
## `eval_expr()` — expression evaluation
|
||||
|
||||
```rust
|
||||
pub fn eval_expr(&self, expr: &str, variables: &HashMap<String, Value>) -> Value
|
||||
```
|
||||
|
||||
1. Synchronizes variables.
|
||||
2. Obtains (compiles or fetches from cache) the expression AST via `get_or_compile_expr()`.
|
||||
3. Executes via `eval_ast_with_scope::<Dynamic>()`.
|
||||
4. Converts the result `Dynamic → Value` via `dynamic_to_value()`.
|
||||
5. On error returns `Value::None`.
|
||||
|
||||
---
|
||||
|
||||
## `eval_condition()` — condition evaluation
|
||||
|
||||
```rust
|
||||
pub fn eval_condition(&self, expr: &str, variables: &HashMap<String, Value>) -> bool
|
||||
```
|
||||
|
||||
Similar to `eval_expr()`, but typed as `bool`. On error returns `false`.
|
||||
|
||||
---
|
||||
|
||||
## `execute_action()` — script execution
|
||||
|
||||
```rust
|
||||
pub fn execute_action(&self, script: &str, variables: &mut HashMap<String, Value>)
|
||||
```
|
||||
|
||||
1. Synchronizes variables.
|
||||
2. Obtains the script AST via `get_or_compile_action()`.
|
||||
3. Executes via `run_ast_with_scope()`.
|
||||
4. After execution iterates over the scope and writes changed variables back into the `HashMap`.
|
||||
|
||||
---
|
||||
|
||||
## AST Caching
|
||||
|
||||
### `get_or_compile_action(script)`
|
||||
|
||||
```rust
|
||||
fn get_or_compile_action(&self, script: &str) -> Option<AST>
|
||||
```
|
||||
|
||||
Checks `action_cache`. On miss compiles via `engine.compile()`, stores in cache.
|
||||
|
||||
### `get_or_compile_expr(expr)`
|
||||
|
||||
```rust
|
||||
fn get_or_compile_expr(&self, expr: &str) -> Option<AST>
|
||||
```
|
||||
|
||||
Checks `expr_cache`. On miss compiles via `engine.compile_expression()`, stores in cache.
|
||||
|
||||
Both methods log the error on compilation failure and return `None`.
|
||||
|
||||
---
|
||||
|
||||
## Batch Precompilation
|
||||
|
||||
```rust
|
||||
pub fn precompile_scripts(&self, scripts: &[String])
|
||||
pub fn precompile_actions(&self, actions: &[String])
|
||||
pub fn precompile_exprs(&self, exprs: &[String])
|
||||
pub fn precompile_all_from_doc(&self, doc: &super::Document)
|
||||
```
|
||||
|
||||
| Method | Action |
|
||||
|---|---|
|
||||
| `precompile_scripts` | Compiles each script as an action |
|
||||
| `precompile_actions` | Same as `precompile_scripts` (alias) |
|
||||
| `precompile_exprs` | Compiles each expression |
|
||||
| `precompile_all_from_doc` | Compiles all `doc.rhei_scripts` and recursively traverses the element tree |
|
||||
|
||||
### `collect_and_precompile()`
|
||||
|
||||
```rust
|
||||
fn collect_and_precompile(el: &super::Element, ctx: &RheiContext)
|
||||
```
|
||||
|
||||
Recursively traverses the `Element` tree:
|
||||
- For properties starting with `__on:*` and non-empty — compiles as an action.
|
||||
- For properties starting with `RHEI_PREFIX` (`!rhei:`) — compiles the remaining part as an expression.
|
||||
|
||||
---
|
||||
|
||||
## Type Conversion
|
||||
|
||||
### `value_to_dynamic(v: &Value) -> Dynamic`
|
||||
|
||||
```rust
|
||||
Value::Int(i) → Dynamic::from(*i)
|
||||
Value::Float(f) → Dynamic::from(*f)
|
||||
Value::Bool(b) → Dynamic::from(*b)
|
||||
Value::Str(s) → str_to_dynamic(s)
|
||||
Value::None → Dynamic::UNIT
|
||||
Value::Array(a) → Dynamic::from_iter(value_to_dynamic of each element)
|
||||
```
|
||||
|
||||
### `dynamic_to_value(d: &Dynamic) -> Value`
|
||||
|
||||
Checks the type via `is_string()`, `is_int()`, `is_float()`, `is_bool()`, `is_array()` in priority order. If the type is not recognized — returns `Value::None`.
|
||||
|
||||
### `str_to_dynamic(s: &str) -> Dynamic`
|
||||
|
||||
A heuristic string parser that tries sequentially:
|
||||
1. `s.parse::<i64>()` — integer
|
||||
2. `s.parse::<f64>()` — float
|
||||
3. `s.parse::<bool>()` — boolean
|
||||
4. Otherwise — `Dynamic::from(s)` as a string
|
||||
Reference in New Issue
Block a user