5.9 KiB
Rhai Module: src/interpreter/rhei.rs
Integration of the Rhai scripting engine — compilation, AST caching, and expression/script execution.
RHEI_PREFIX — Rhai expression prefix
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
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)
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)
fn new_empty(scripts: &[String]) -> Self
- Creates
Engine::new(). - Configures
on_print(outputs to stdout with[rhei]prefix) andon_debug(outputs to stderr) handlers. - 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. - 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). - Initializes an empty
Scope, emptyaction_cacheandexpr_cachecaches.
sync_scope() — variable synchronization
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
pub fn initialize(&self, variables: &mut HashMap<String, Value>)
- Synchronizes variables via
sync_scope(). - Runs
init_ast(merged AST of all scripts) viarun_ast_with_scope(). - Iterates over all scope variables via
iter_raw()and writes back into theHashMapthose whose values have changed.
eval_expr() — expression evaluation
pub fn eval_expr(&self, expr: &str, variables: &HashMap<String, Value>) -> Value
- Synchronizes variables.
- Obtains (compiles or fetches from cache) the expression AST via
get_or_compile_expr(). - Executes via
eval_ast_with_scope::<Dynamic>(). - Converts the result
Dynamic → Valueviadynamic_to_value(). - On error returns
Value::None.
eval_condition() — condition evaluation
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
pub fn execute_action(&self, script: &str, variables: &mut HashMap<String, Value>)
- Synchronizes variables.
- Obtains the script AST via
get_or_compile_action(). - Executes via
run_ast_with_scope(). - After execution iterates over the scope and writes changed variables back into the
HashMap.
AST Caching
get_or_compile_action(script)
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)
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
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()
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
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:
s.parse::<i64>()— integers.parse::<f64>()— floats.parse::<bool>()— boolean- Otherwise —
Dynamic::from(s)as a string