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

15 KiB

Manage AST's

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

When compiling a Rhai script to an [AST], the following data are packaged together as a single unit:

Data Type Description Requires feature Access API
Source name [ImmutableString] optional text name to identify the source of the script source(&self),
clone_source(&self),
set_source(&mut self, source),
clear_source(&mut self)
[Module documentation][comments] [Vec<SmartString>][SmartString] documentation of the script [metadata] doc(&self),
clear_doc(&mut self)
Statements Vec<Stmt> list of script statements at global level [internals] statements(&self),
statements_mut(&mut self)
Functions [Shared<Module>][Module] [functions] defined in the script [internals],
not [no_function]
shared_lib(&self)
Embedded [module resolver] [StaticModuleResolver][module resolver] embedded [module resolver] for self-contained AST [internals],
not [no_module]
resolver(&self)

Most of the [AST] API is available only under the [internals] feature.


Use the source name to identify the source script in errors &ndash; useful when multiple [modules]
are imported recursively.

For the complete [`AST`] API, refer to the [documentation](https://docs.rs/rhai/{{version}}/rhai/struct.AST.html) online.

Extract Only Functions

The following methods, not available under [no_function], allow manipulation of the [functions] encapsulated within an [AST]:

Method Description
clone_functions_only(&self) clone the [AST] into a new [AST] with only [functions], excluding statements
clone_functions_only_filtered(&self, filter) clone the [AST] into a new [AST] with only [functions] that pass the filter predicate, excluding statements
retain_functions(&mut self, filter) remove all [functions] in the [AST] that do not pass a particular predicate filter; statements are untouched
iter_functions(&self) return an iterator on all the [functions] in the [AST]
clear_functions(&mut self) remove all [functions] from the [AST], leaving only statements

Extract Only Statements

The following methods allow manipulation of the statements in an [AST]:

Method Description
clone_statements_only(&self) clone the [AST] into a new [AST] with only the statements, excluding [functions]
clear_statements(&mut self) remove all statements from the [AST], leaving only [functions]
iter_literal_variables(&self, constants, variables) return an iterator on all top-level literal constant and/or variable definitions in the [AST]

Merge and Combine AST's

The following methods merge one [AST] with another:

Method Description
merge(&self, &ast),
+ operator
append the second [AST] to this [AST], yielding a new [AST] that is a combination of the two; statements are simply appended, [functions] in the second [AST] of the same name and arity override similar [functions] in this [AST]
merge_filtered(&self, &ast, filter) append the second [AST] (but only [functions] that pass the predicate filter) to this [AST], yielding a new [AST] that is a combination of the two; statements are simply appended, [functions] in the second [AST] of the same name and arity override similar [functions] in this [AST]
combine(&mut self, ast),
+= operator
append the second [AST] to this [AST]; statements are simply appended, [functions] in the second [AST] of the same name and arity override similar [functions] in this [AST]
combine_filtered(&mut self, ast, filter) append the second [AST] (but only [functions] that pass the predicate filter) to this [AST]; statements are simply appended, [functions] in the second [AST] of the same name and arity override similar [functions] in this [AST]

When statements are appended, beware that this may change the semantics of the script.

// First script
let ast1 = engine.compile(
"
     fn foo(x) { 42 + x }
     foo(1)
")?;

// Second script
let ast2 = engine.compile(
"
     fn foo(n) { `hello${n}` }
     foo("!")
")?;

// Merge them
let merged = ast1.merge(&ast2);

// Notice that using the '+' operator also works:
let merged = &ast1 + &ast2;

merged in the above example essentially contains the following script program:

fn foo(n) { `hello${n}` }   // <- definition of first 'foo' is overwritten
foo(1)                      // <- notice this will be "hello1" instead of 43,
                            //    but it is no longer the return value
foo("!")                    // <- returns "hello!"

Walk an AST

The [internals] feature allows access to internal Rhai data structures, particularly the nodes that make up the [AST].

AST node types

There are a few useful types when walking an [AST]:

Type Description
ASTNode an enum with two variants: Expr or Stmt
Expr an expression
Stmt a statement
BinaryExpr a sub-type containing the LHS and RHS of a binary expression
FnCallExpr a sub-type containing information on a function call
CustomExpr a sub-type containing information on a [custom syntax] expression

The AST::walk method takes a callback function and recursively walks the [AST] in depth-first manner, with the parent node visited before its children.

Callback function signature

The signature of the callback function takes the following form.

FnMut(&[ASTNode]) -> bool

The single argument passed to the method contains a slice of ASTNode types representing the path from the current node to the root of the [AST].

Return true to continue walking the [AST], or false to terminate.

Children visit order

The order of visits to the children of each node type:

Node type Children visit order
[if] statement
  1. condition expression
  2. then statements
  3. else statements (if any)
[switch] statement
  1. match element
  2. each of the case conditions and statements, in order
  3. each of the range conditions and statements, in order
  4. default statements (if any)
[while], [do], [loop] statement
  1. condition expression
  2. statements body
[for] statement
  1. collection expression
  2. statements body
[return] statement return value expression
[throw] statement exception value expression
[try ... catch][exception] statement
  1. try statements body
  2. catch statements body
[import] statement path expression
[Array] literal each of the element expressions, in order
[Object map] literal each of the element expressions, in order
Interpolated [string] each of the [string]/expression segments, in order
Indexing
  1. LHS expression
  2. RHS (index) expression
Field access/method call
  1. LHS expression
  2. RHS expression
&&, ||, ??
  1. LHS expression
  2. RHS expression
[Function] call, [operator] expression each of the argument expressions, in order
[let][variable], [const][constant] statement value expression
Assignment statement
  1. l-value expression
  2. value expression
Statements block each of the statements, in order
Custom syntax expression each of the inputs stream, in order
All others single child (if any)