This repository has been archived on 2025-08-04. You can view files and clone it, but cannot push or open issues or pull requests.
rhaj/_archive/rhai_engine/rhaibook/engine/def-var.md
2025-04-04 08:28:07 +02:00

86 lines
4.0 KiB
Markdown

Variable Definition Filter
==========================
{{#include ../links.md}}
[`Engine::on_def_var`]: https://docs.rs/rhai/{{version}}/rhai/struct.Engine.html#method.on_def_var
Although it is easy to disable variable _[shadowing]_ via [`Engine::set_allow_shadowing`][options],
sometimes more fine-grained control is needed.
For example, it may be the case that not _all_ variables [shadowing] must be disallowed, but that only
a particular variable name needs to be protected and not others. Or only under very special
circumstances.
Under this scenario, it is possible to provide a _filter_ closure to the [`Engine`] via
[`Engine::on_def_var`] that traps variable definitions (i.e. [`let`][variable] or
[`const`][constant] statements) in a Rhai script.
The filter is called when a [variable] or [constant] is defined both during runtime and compilation.
```rust
let mut engine = Engine::new();
// Register a variable definition filter.
engine.on_def_var(|is_runtime, info, context| {
match (info.name, info.is_const) {
// Disallow defining 'MYSTIC_NUMBER' as a constant!
("MYSTIC_NUMBER", true) => Ok(false),
// Disallow defining constants not at global level!
(_, true) if info.nesting_level > 0 => Ok(false),
// Throw any exception you like...
("hello", _) => Err(EvalAltResult::ErrorVariableNotFound(info.name.to_string(), Position::NONE).into()),
// Return Ok(true) to continue with normal variable definition.
_ => Ok(true)
}
});
```
Function Signature
------------------
The function signature passed to [`Engine::on_def_var`] takes the following form.
> ```rust
> Fn(is_runtime: bool, info: VarDefInfo, context: EvalContext) -> Result<bool, Box<EvalAltResult>>
> ```
where:
| Parameter | Type | Description |
| ------------ | :-------------: | ----------------------------------------------------------------------------------------------- |
| `is_runtime` | `bool` | `true` if the [variable] definition event happens during runtime, `false` if during compilation |
| `info` | `VarDefInfo` | information on the [variable] being defined |
| `context` | [`EvalContext`] | the current _evaluation context_ |
and `VarDefInfo` is a simple `struct` that contains the following fields:
| Field | Type | Description |
| --------------- | :-----: | --------------------------------------------------------------------------------------- |
| `name` | `&str` | [variable] name |
| `is_const` | `bool` | `true` if the definition is a [`const`][constant]; `false` if it is a [`let`][variable] |
| `nesting_level` | `usize` | the current nesting level; the global level is zero |
| `will_shadow` | `bool` | will this [variable] _[shadow]_ an existing [variable] of the same name? |
and [`EvalContext`] is a type that encapsulates the current _evaluation context_.
### Return value
The return value is `Result<bool, Box<EvalAltResult>>` where:
| Value | Description |
| ------------------------- | -------------------------------------------------- |
| `Ok(true)` | normal [variable] definition should continue |
| `Ok(false)` | [throws][exception] a runtime or compilation error |
| `Err(Box<EvalAltResult>)` | error that is reflected back to the [`Engine`] |
```admonish bug.small "Error during compilation"
During compilation (i.e. when `is_runtime` is `false`), `EvalAltResult::ErrorParsing` is passed
through as the compilation error.
All other errors map to `ParseErrorType::ForbiddenVariable`.
```