Struct rhai::AST

source ·
pub struct AST { /* private fields */ }
Expand description

Compiled AST (abstract syntax tree) of a Rhai script.

Thread Safety

Currently, AST is neither Send nor Sync. Turn on the sync feature to make it Send + Sync.

Implementations§

(internals) Create a new AST. Exported under the internals feature only.

(internals) Create a new AST with a source name. Exported under the internals feature only.

Create an empty AST.

Get the source, if any.

Set the source.

Clear the source.

Get the documentation (if any). Exported under the metadata feature only.

Documentation is a collection of all comment lines beginning with //!.

Leading white-spaces are stripped, and each line always starts with //!.

Clear the documentation. Exported under the metadata feature only.

(internals) Get the statements. Exported under the internals feature only.

Does this AST contain script-defined functions?

Not available under no_function.

(internals) Get the internal shared Module containing all script-defined functions. Exported under the internals feature only.

Not available under no_function.

(internals) Get the embedded module resolver. Exported under the internals feature only.

Not available under no_module.

Clone the AST’s functions into a new AST. No statements are cloned.

Not available under no_function.

This operation is cheap because functions are shared.

Clone the AST’s functions into a new AST based on a filter predicate. No statements are cloned.

Not available under no_function.

This operation is cheap because functions are shared.

Clone the AST’s script statements into a new AST. No functions are cloned.

Merge two AST into one. Both AST’s are untouched and a new, merged, version is returned.

Statements in the second AST are simply appended to the end of the first without any processing. Thus, the return value of the first AST (if using expression-statement syntax) is buried. Of course, if the first AST uses a return statement at the end, then the second AST will essentially be dead code.

All script-defined functions in the second AST overwrite similarly-named functions in the first AST with the same number of parameters.

Example
use rhai::Engine;

let engine = Engine::new();

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

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

let ast = ast1.merge(&ast2);    // Merge 'ast2' into 'ast1'

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

// 'ast' is essentially:
//
//    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!"

// Evaluate it
assert_eq!(engine.eval_ast::<String>(&ast)?, "hello!");

Combine one AST with another. The second AST is consumed.

Statements in the second AST are simply appended to the end of the first without any processing. Thus, the return value of the first AST (if using expression-statement syntax) is buried. Of course, if the first AST uses a return statement at the end, then the second AST will essentially be dead code.

All script-defined functions in the second AST overwrite similarly-named functions in the first AST with the same number of parameters.

Example
use rhai::Engine;

let engine = Engine::new();

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

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

ast1.combine(ast2);    // Combine 'ast2' into 'ast1'

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

// 'ast1' is essentially:
//
//    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!"

// Evaluate it
assert_eq!(engine.eval_ast::<String>(&ast1)?, "hello!");

Merge two AST into one. Both AST’s are untouched and a new, merged, version is returned.

Not available under no_function.

Statements in the second AST are simply appended to the end of the first without any processing. Thus, the return value of the first AST (if using expression-statement syntax) is buried. Of course, if the first AST uses a return statement at the end, then the second AST will essentially be dead code.

All script-defined functions in the second AST are first selected based on a filter predicate, then overwrite similarly-named functions in the first AST with the same number of parameters.

Example
use rhai::Engine;

let engine = Engine::new();

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

let ast2 = engine.compile(r#"
    fn foo(n) { `hello${n}` }
    fn error() { 0 }
    foo("!")
"#)?;

// Merge 'ast2', picking only 'error()' but not 'foo(..)', into 'ast1'
let ast = ast1.merge_filtered(&ast2, |_, _, script, name, params|
                                script && name == "error" && params == 0);

// 'ast' is essentially:
//
//    fn foo(n) { 42 + n }      // <- definition of 'ast1::foo' is not overwritten
//                              //    because 'ast2::foo' is filtered away
//    foo(1)                    // <- notice this will be 43 instead of "hello1",
//                              //    but it is no longer the return value
//    fn error() { 0 }          // <- this function passes the filter and is merged
//    foo("!")                  // <- returns "42!"

// Evaluate it
assert_eq!(engine.eval_ast::<String>(&ast)?, "42!");

Combine one AST with another. The second AST is consumed.

Not available under no_function.

Statements in the second AST are simply appended to the end of the first without any processing. Thus, the return value of the first AST (if using expression-statement syntax) is buried. Of course, if the first AST uses a return statement at the end, then the second AST will essentially be dead code.

All script-defined functions in the second AST are first selected based on a filter predicate, then overwrite similarly-named functions in the first AST with the same number of parameters.

Example
use rhai::Engine;

let engine = Engine::new();

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

let ast2 = engine.compile(r#"
    fn foo(n) { `hello${n}` }
    fn error() { 0 }
    foo("!")
"#)?;

// Combine 'ast2', picking only 'error()' but not 'foo(..)', into 'ast1'
ast1.combine_filtered(ast2, |_, _, script, name, params|
                                script && name == "error" && params == 0);

// 'ast1' is essentially:
//
//    fn foo(n) { 42 + n }      // <- definition of 'ast1::foo' is not overwritten
//                              //    because 'ast2::foo' is filtered away
//    foo(1)                    // <- notice this will be 43 instead of "hello1",
//                              //    but it is no longer the return value
//    fn error() { 0 }          // <- this function passes the filter and is merged
//    foo("!")                  // <- returns "42!"

// Evaluate it
assert_eq!(engine.eval_ast::<String>(&ast1)?, "42!");

Filter out the functions, retaining only some based on a filter predicate.

Not available under no_function.

Example
use rhai::Engine;

let engine = Engine::new();

let mut ast = engine.compile(r#"
    fn foo(n) { n + 1 }
    fn bar() { print("hello"); }
"#)?;

// Remove all functions except 'foo(..)'
ast.retain_functions(|_, _, name, params| name == "foo" && params == 1);

(internals) Iterate through all function definitions. Exported under the internals feature only.

Not available under no_function.

Iterate through all function definitions.

Not available under no_function.

Clear all function definitions in the AST.

Not available under no_function.

Clear all statements in the AST, leaving only function definitions.

Extract all top-level literal constant and/or variable definitions. This is useful for extracting all global constants from a script without actually running it.

A literal constant/variable definition takes the form of: const VAR = value; and let VAR = value; where value is a literal expression or will be optimized into a literal.

Example
use rhai::{Engine, Scope};

let engine = Engine::new();

let ast = engine.compile(
"
    const A = 40 + 2;   // constant that optimizes into a literal
    let b = 123;        // literal variable
    const B = b * A;    // non-literal constant
    const C = 999;      // literal constant
    b = A + C;          // expression

    {                   // <- new block scope
        const Z = 0;    // <- literal constant not at top-level
    }
")?;

let mut iter = ast.iter_literal_variables(true, false)
                  .map(|(name, is_const, value)| (name, is_const, value.as_int().unwrap()));

assert_eq!(iter.next(), Some(("A", true, 42)));
assert_eq!(iter.next(), Some(("C", true, 999)));
assert_eq!(iter.next(), None);

let mut iter = ast.iter_literal_variables(false, true)
                  .map(|(name, is_const, value)| (name, is_const, value.as_int().unwrap()));

assert_eq!(iter.next(), Some(("b", false, 123)));
assert_eq!(iter.next(), None);

let mut iter = ast.iter_literal_variables(true, true)
                  .map(|(name, is_const, value)| (name, is_const, value.as_int().unwrap()));

assert_eq!(iter.next(), Some(("A", true, 42)));
assert_eq!(iter.next(), Some(("b", false, 123)));
assert_eq!(iter.next(), Some(("C", true, 999)));
assert_eq!(iter.next(), None);

let scope: Scope = ast.iter_literal_variables(true, false).collect();

assert_eq!(scope.len(), 2);

Ok(())

(internals) Recursively walk the AST, including function bodies (if any). Return false from the callback to terminate the walk. Exported under the internals feature only.

👎Deprecated since 1.3.0: use shared_lib instead

(internals) Get the internal Module containing all script-defined functions. Exported under the internals feature only.

Not available under no_function.

Deprecated

This method is deprecated. Use shared_lib instead.

This method will be removed in the next major version.

Trait Implementations§

The resulting type after applying the + operator.
Performs the + operation. Read more
Performs the += operation. Read more
Converts this type into a shared reference of the (usually inferred) input type.
Converts this type into a shared reference of the (usually inferred) input type.
Converts this type into a shared reference of the (usually inferred) input type.
Immutably borrows from an owned value. Read more
Immutably borrows from an owned value. Read more
Immutably borrows from an owned value. Read more
Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.