docs: reorganize into en/ru and add English translation

This commit is contained in:
Glint Dev
2026-07-24 22:04:29 +03:00
parent 938f05f59d
commit 35f92435a3
20 changed files with 4651 additions and 0 deletions

200
docs/en/modules/04-rhei.md Normal file
View 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