docs: reorganize into en/ru and add English translation
This commit is contained in:
200
docs/ru/modules/04-rhei.md
Normal file
200
docs/ru/modules/04-rhei.md
Normal file
@@ -0,0 +1,200 @@
|
||||
# Модуль Rhai: `src/interpreter/rhei.rs`
|
||||
|
||||
Интеграция скриптового движка [Rhai](https://rhai.rs/) — компиляция, кеширование AST и выполнение выражений/скриптов.
|
||||
|
||||
---
|
||||
|
||||
## `RHEI_PREFIX` — префикс Rhai-выражений
|
||||
|
||||
```rust
|
||||
pub const RHEI_PREFIX: &str = "__rhei:";
|
||||
```
|
||||
|
||||
Константа-маркер для свойств элементов, содержимое которых должно интерпретироваться как Rhai-выражение. Используется в `collect_and_precompile()` для выборки свойств вида `!rhei:...`.
|
||||
|
||||
---
|
||||
|
||||
## `RheiContext` — контекст выполнения Rhai
|
||||
|
||||
```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>>,
|
||||
}
|
||||
```
|
||||
|
||||
| Поле | Назначение |
|
||||
|---|---|
|
||||
| `engine` | Настроенный экземпляр `rhai::Engine` |
|
||||
| `init_ast` | Объединённое AST всех скриптов инициализации (включая определения функций) |
|
||||
| `scope` | Общая область видимости (`Scope`), разделяемая между вызовами; обёрнута в `RefCell` для interior mutability |
|
||||
| `action_cache` | Кеш скомпилированных скриптов (действий), ключ — исходный код |
|
||||
| `expr_cache` | Кеш скомпилированных выражений, ключ — исходный код |
|
||||
|
||||
---
|
||||
|
||||
## Конструкторы
|
||||
|
||||
### `new(scripts)`
|
||||
|
||||
```rust
|
||||
pub fn new(scripts: &[String]) -> Self
|
||||
```
|
||||
|
||||
Создаёт контекст через `new_empty()` и сразу прекомпилирует все переданные скрипты вызовом `precompile_scripts()`.
|
||||
|
||||
### `new_empty(scripts)`
|
||||
|
||||
```rust
|
||||
fn new_empty(scripts: &[String]) -> Self
|
||||
```
|
||||
|
||||
1. Создаёт `Engine::new()`.
|
||||
2. Настраивает обработчики `on_print` (вывод в stdout с префиксом `[rhei]`) и `on_debug` (вывод в stderr).
|
||||
3. Компилирует все скрипты и сливает их AST в единое дерево через `merge()`. Ошибки компиляции отдельных блоков логируются, но не прерывают процесс.
|
||||
4. Из объединённого AST создаёт модуль (`Module::eval_ast_as_new`) с пустым скопом — в нём регистрируются глобальные функции, определённые в скриптах. Модуль регистрируется в движке как глобальный (`register_global_module`).
|
||||
5. Инициализирует пустой `Scope`, пустые кеши `action_cache` и `expr_cache`.
|
||||
|
||||
---
|
||||
|
||||
## `sync_scope()` — синхронизация переменных
|
||||
|
||||
```rust
|
||||
pub fn sync_scope(&self, variables: &HashMap<String, Value>)
|
||||
```
|
||||
|
||||
Синхронизирует значения из внешнего `HashMap` в Rhai `Scope`:
|
||||
- Если переменная уже есть в скопе и её значение не изменилось — пропускает.
|
||||
- Если переменная есть — обновляет через `set_value()`.
|
||||
- Если переменной нет — добавляет через `push_dynamic()`.
|
||||
|
||||
Преобразование `Value → Dynamic` выполняется через `value_to_dynamic()`.
|
||||
|
||||
---
|
||||
|
||||
## `initialize()` — инициализация
|
||||
|
||||
```rust
|
||||
pub fn initialize(&self, variables: &mut HashMap<String, Value>)
|
||||
```
|
||||
|
||||
1. Синхронизирует переменные через `sync_scope()`.
|
||||
2. Запускает `init_ast` (объединённое AST всех скриптов) через `run_ast_with_scope()`.
|
||||
3. Обходит все переменные скопа через `iter_raw()` и записывает обратно в `HashMap` те, чьи значения изменились.
|
||||
|
||||
---
|
||||
|
||||
## `eval_expr()` — вычисление выражения
|
||||
|
||||
```rust
|
||||
pub fn eval_expr(&self, expr: &str, variables: &HashMap<String, Value>) -> Value
|
||||
```
|
||||
|
||||
1. Синхронизирует переменные.
|
||||
2. Получает (компилирует или берёт из кеша) AST выражения через `get_or_compile_expr()`.
|
||||
3. Выполняет через `eval_ast_with_scope::<Dynamic>()`.
|
||||
4. Преобразует результат `Dynamic → Value` через `dynamic_to_value()`.
|
||||
5. При ошибке возвращает `Value::None`.
|
||||
|
||||
---
|
||||
|
||||
## `eval_condition()` — вычисление условия
|
||||
|
||||
```rust
|
||||
pub fn eval_condition(&self, expr: &str, variables: &HashMap<String, Value>) -> bool
|
||||
```
|
||||
|
||||
Аналогичен `eval_expr()`, но типизирован как `bool`. При ошибке возвращает `false`.
|
||||
|
||||
---
|
||||
|
||||
## `execute_action()` — выполнение скрипта
|
||||
|
||||
```rust
|
||||
pub fn execute_action(&self, script: &str, variables: &mut HashMap<String, Value>)
|
||||
```
|
||||
|
||||
1. Синхронизирует переменные.
|
||||
2. Получает AST скрипта через `get_or_compile_action()`.
|
||||
3. Выполняет через `run_ast_with_scope()`.
|
||||
4. После выполнения обходит скоп и записывает обратно в `HashMap` изменившиеся переменные.
|
||||
|
||||
---
|
||||
|
||||
## Кеширование AST
|
||||
|
||||
### `get_or_compile_action(script)`
|
||||
|
||||
```rust
|
||||
fn get_or_compile_action(&self, script: &str) -> Option<AST>
|
||||
```
|
||||
|
||||
Проверяет `action_cache`. При промахе компилирует через `engine.compile()`, сохраняет в кеш.
|
||||
|
||||
### `get_or_compile_expr(expr)`
|
||||
|
||||
```rust
|
||||
fn get_or_compile_expr(&self, expr: &str) -> Option<AST>
|
||||
```
|
||||
|
||||
Проверяет `expr_cache`. При промахе компилирует через `engine.compile_expression()`, сохраняет в кеш.
|
||||
|
||||
Оба метода при ошибке компиляции логируют её и возвращают `None`.
|
||||
|
||||
---
|
||||
|
||||
## Пакетная прекомпиляция
|
||||
|
||||
```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)
|
||||
```
|
||||
|
||||
| Метод | Действие |
|
||||
|---|---|
|
||||
| `precompile_scripts` | Компилирует каждый скрипт как действие |
|
||||
| `precompile_actions` | То же, что `precompile_scripts` (алиас) |
|
||||
| `precompile_exprs` | Компилирует каждое выражение |
|
||||
| `precompile_all_from_doc` | Компилирует все `doc.rhei_scripts` и рекурсивно обходит дерево элементов |
|
||||
|
||||
### `collect_and_precompile()`
|
||||
|
||||
```rust
|
||||
fn collect_and_precompile(el: &super::Element, ctx: &RheiContext)
|
||||
```
|
||||
|
||||
Рекурсивно обходит дерево `Element`:
|
||||
- Для свойств, начинающихся с `__on:*` и непустых — компилирует как действие.
|
||||
- Для свойств, начинающихся с `RHEI_PREFIX` (`!rhei:`) — компилирует оставшуюся часть как выражение.
|
||||
|
||||
---
|
||||
|
||||
## Конвертация типов
|
||||
|
||||
### `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 каждого элемента)
|
||||
```
|
||||
|
||||
### `dynamic_to_value(d: &Dynamic) -> Value`
|
||||
|
||||
Проверяет тип через `is_string()`, `is_int()`, `is_float()`, `is_bool()`, `is_array()` в порядке приоритета. Если тип не распознан — возвращает `Value::None`.
|
||||
|
||||
### `str_to_dynamic(s: &str) -> Dynamic`
|
||||
|
||||
Эвристический парсер строки, пробует последовательно:
|
||||
1. `s.parse::<i64>()` — целое число
|
||||
2. `s.parse::<f64>()` — дробное число
|
||||
3. `s.parse::<bool>()` — булево значение
|
||||
4. Иначе — `Dynamic::from(s)` как строка
|
||||
Reference in New Issue
Block a user