Manage AST’s

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

DataTypeDescriptionRequires featureAccess API
Source nameImmutableStringoptional text name to identify the source of the scriptsource(&self),
clone_source(&self),
set_source(&mut self, source),
clear_source(&mut self)
Module documentationVec<SmartString>documentation of the scriptmetadatadoc(&self),
clear_doc(&mut self)
StatementsVec<Stmt>list of script statements at global levelinternalsstatements(&self),
statements_mut(&mut self)
FunctionsShared<Module>functions defined in the scriptinternals,
not no_function
shared_lib(&self)
Embedded module resolverStaticModuleResolverembedded module resolver for self-contained ASTinternals,
not no_module
resolver(&self)

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

Tip: Source name

Use the source name to identify the source script in errors – useful when multiple modules are imported recursively.

AST public API

For the complete AST API, refer to the documentation online.

Extract Only Functions

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

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

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

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

TypeDescription
ASTNodean enum with two variants: Expr or Stmt
Expran expression
Stmta statement
BinaryExpra sub-type containing the LHS and RHS of a binary expression
FnCallExpra sub-type containing information on a function call
CustomExpra 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 typeChildren 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 statementreturn value expression
throw statementexception value expression
trycatch statement
  1. try statements body
  2. catch statements body
import statementpath expression
Array literaleach of the element expressions, in order
Object map literaleach of the element expressions, in order
Interpolated stringeach 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 expressioneach of the argument expressions, in order
let, const statementvalue expression
Assignment statement
  1. l-value expression
  2. value expression
Statements blockeach of the statements, in order
Custom syntax expressioneach of the inputs stream, in order
All otherssingle child (if any)