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/rhai_engine/rhaibook/rust/modules/ast.md
2025-04-03 09:18:05 +02:00

2.8 KiB
Raw Blame History

Create a Module from an AST

{{#include ../../links.md}}

Module::eval_ast_as_new


`Module::eval_ast_as_new` encapsulates the entire [`AST`] into each function call, merging the
[module namespace][function namespace] with the [global namespace][function namespace].

Therefore, [functions] defined within the same [module] script can cross-call each other.

See [_Export Variables, Functions and Sub-Modules from Script_][`export`] for details on how to prepare
a Rhai script for this purpose as well as to control which [functions]/[variables] to export.

A [module] can be created from a single script (or pre-compiled [AST]) containing global [variables], [functions] and [sub-modules][module] via Module::eval_ast_as_new.

When given an [AST], it is first evaluated (usually to [import][import] [modules] and set up global [constants] used by [functions]), then the following items are exposed as members of the new [module]:

  • global [variables] and [constants] all [variables] and [constants] exported via the [export] statement (those not exported remain hidden),

  • [functions] not specifically marked [private],

  • imported [modules] that remain in the [Scope] at the end of a script run become sub-modules.

Examples

Don't forget the [export] statement, otherwise there will be no [variables] exposed by the [module] other than non-[private] [functions] (unless that's intentional).

use rhai::{Engine, Module};

let engine = Engine::new();

// Compile a script into an 'AST'
let ast = engine.compile(
r#"
    // Functions become module functions
    fn calc(x) {
        x + add_len(x, 1)       // functions within the same module
                                // can always cross-call each other!
    }
    fn add_len(x, y) {
        x + y.len
    }

    // Imported modules become sub-modules
    import "another module" as extra;

    // Variables defined at global level can become module variables
    const x = 123;
    let foo = 41;
    let hello;

    // Variable values become constant module variable values
    foo = calc(foo);
    hello = `hello, ${foo} worlds!`;

    // Finally, export the variables and modules
    export x as abc;            // aliased variable name
    export foo;
    export hello;
"#)?;

// Convert the 'AST' into a module, using the 'Engine' to evaluate it first
// A copy of the entire 'AST' is encapsulated into each function,
// allowing functions in the module script to cross-call each other.
let module = Module::eval_ast_as_new(Scope::new(), &ast, &engine)?;

// 'module' now contains:
//   - sub-module: 'extra'
//   - functions: 'calc', 'add_len'
//   - constants: 'abc' (renamed from 'x'), 'foo', 'hello'