8.2 KiB
Модуль Rhai: src/interpreter/rhei.rs
Интеграция скриптового движка Rhai — компиляция, кеширование AST и выполнение выражений/скриптов.
RHEI_PREFIX — префикс Rhai-выражений
pub const RHEI_PREFIX: &str = "__rhei:";
Константа-маркер для свойств элементов, содержимое которых должно интерпретироваться как Rhai-выражение. Используется в collect_and_precompile() для выборки свойств вида !rhei:....
RheiContext — контекст выполнения Rhai
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)
pub fn new(scripts: &[String]) -> Self
Создаёт контекст через new_empty() и сразу прекомпилирует все переданные скрипты вызовом precompile_scripts().
new_empty(scripts)
fn new_empty(scripts: &[String]) -> Self
- Создаёт
Engine::new(). - Настраивает обработчики
on_print(вывод в stdout с префиксом[rhei]) иon_debug(вывод в stderr). - Компилирует все скрипты и сливает их AST в единое дерево через
merge(). Ошибки компиляции отдельных блоков логируются, но не прерывают процесс. - Из объединённого AST создаёт модуль (
Module::eval_ast_as_new) с пустым скопом — в нём регистрируются глобальные функции, определённые в скриптах. Модуль регистрируется в движке как глобальный (register_global_module). - Инициализирует пустой
Scope, пустые кешиaction_cacheиexpr_cache.
sync_scope() — синхронизация переменных
pub fn sync_scope(&self, variables: &HashMap<String, Value>)
Синхронизирует значения из внешнего HashMap в Rhai Scope:
- Если переменная уже есть в скопе и её значение не изменилось — пропускает.
- Если переменная есть — обновляет через
set_value(). - Если переменной нет — добавляет через
push_dynamic().
Преобразование Value → Dynamic выполняется через value_to_dynamic().
initialize() — инициализация
pub fn initialize(&self, variables: &mut HashMap<String, Value>)
- Синхронизирует переменные через
sync_scope(). - Запускает
init_ast(объединённое AST всех скриптов) черезrun_ast_with_scope(). - Обходит все переменные скопа через
iter_raw()и записывает обратно вHashMapте, чьи значения изменились.
eval_expr() — вычисление выражения
pub fn eval_expr(&self, expr: &str, variables: &HashMap<String, Value>) -> Value
- Синхронизирует переменные.
- Получает (компилирует или берёт из кеша) AST выражения через
get_or_compile_expr(). - Выполняет через
eval_ast_with_scope::<Dynamic>(). - Преобразует результат
Dynamic → Valueчерезdynamic_to_value(). - При ошибке возвращает
Value::None.
eval_condition() — вычисление условия
pub fn eval_condition(&self, expr: &str, variables: &HashMap<String, Value>) -> bool
Аналогичен eval_expr(), но типизирован как bool. При ошибке возвращает false.
execute_action() — выполнение скрипта
pub fn execute_action(&self, script: &str, variables: &mut HashMap<String, Value>)
- Синхронизирует переменные.
- Получает AST скрипта через
get_or_compile_action(). - Выполняет через
run_ast_with_scope(). - После выполнения обходит скоп и записывает обратно в
HashMapизменившиеся переменные.
Кеширование AST
get_or_compile_action(script)
fn get_or_compile_action(&self, script: &str) -> Option<AST>
Проверяет action_cache. При промахе компилирует через engine.compile(), сохраняет в кеш.
get_or_compile_expr(expr)
fn get_or_compile_expr(&self, expr: &str) -> Option<AST>
Проверяет expr_cache. При промахе компилирует через engine.compile_expression(), сохраняет в кеш.
Оба метода при ошибке компиляции логируют её и возвращают None.
Пакетная прекомпиляция
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()
fn collect_and_precompile(el: &super::Element, ctx: &RheiContext)
Рекурсивно обходит дерево Element:
- Для свойств, начинающихся с
__on:*и непустых — компилирует как действие. - Для свойств, начинающихся с
RHEI_PREFIX(!rhei:) — компилирует оставшуюся часть как выражение.
Конвертация типов
value_to_dynamic(v: &Value) -> Dynamic
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
Эвристический парсер строки, пробует последовательно:
s.parse::<i64>()— целое числоs.parse::<f64>()— дробное числоs.parse::<bool>()— булево значение- Иначе —
Dynamic::from(s)как строка