Files
Glint-Runtime/docs/en/modules/04-rhei.md

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
  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

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>)
  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

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

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>)
  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)

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:

  1. s.parse::<i64>() — integer
  2. s.parse::<f64>() — float
  3. s.parse::<bool>() — boolean
  4. Otherwise — Dynamic::from(s) as a string