Struct sub_script::engine::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
sourceimpl AST
impl AST
sourcepub fn set_source(
&mut self,
source: impl Into<SmartString<LazyCompact>>
) -> &mut AST
pub fn set_source(
&mut self,
source: impl Into<SmartString<LazyCompact>>
) -> &mut AST
Set the source.
sourcepub fn clear_source(&mut self) -> &mut AST
pub fn clear_source(&mut self) -> &mut AST
Clear the source.
sourcepub fn has_functions(&self) -> bool
pub fn has_functions(&self) -> bool
Does this AST
contain script-defined functions?
Not available under no_function
.
sourcepub fn clone_functions_only(&self) -> AST
pub fn clone_functions_only(&self) -> AST
sourcepub fn clone_functions_only_filtered(
&self,
filter: impl Fn(FnNamespace, FnAccess, bool, &str, usize) -> bool
) -> AST
pub fn clone_functions_only_filtered(
&self,
filter: impl Fn(FnNamespace, FnAccess, bool, &str, usize) -> bool
) -> AST
sourcepub fn clone_statements_only(&self) -> AST
pub fn clone_statements_only(&self) -> AST
sourcepub fn merge(&self, other: &AST) -> AST
pub fn merge(&self, other: &AST) -> AST
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!");
sourcepub fn combine(&mut self, other: AST) -> &mut AST
pub fn combine(&mut self, other: AST) -> &mut AST
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!");
sourcepub fn merge_filtered(
&self,
other: &AST,
filter: impl Fn(FnNamespace, FnAccess, bool, &str, usize) -> bool
) -> AST
pub fn merge_filtered(
&self,
other: &AST,
filter: impl Fn(FnNamespace, FnAccess, bool, &str, usize) -> bool
) -> AST
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!");
sourcepub fn combine_filtered(
&mut self,
other: AST,
filter: impl Fn(FnNamespace, FnAccess, bool, &str, usize) -> bool
) -> &mut AST
pub fn combine_filtered(
&mut self,
other: AST,
filter: impl Fn(FnNamespace, FnAccess, bool, &str, usize) -> bool
) -> &mut AST
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!");
sourcepub fn retain_functions(
&mut self,
filter: impl Fn(FnNamespace, FnAccess, &str, usize) -> bool
) -> &mut AST
pub fn retain_functions(
&mut self,
filter: impl Fn(FnNamespace, FnAccess, &str, usize) -> bool
) -> &mut AST
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);
sourcepub fn iter_functions(
&'a self
) -> impl Iterator<Item = ScriptFnMetadata<'a>> + 'a
pub fn iter_functions(
&'a self
) -> impl Iterator<Item = ScriptFnMetadata<'a>> + 'a
Iterate through all function definitions.
Not available under no_function
.
sourcepub fn clear_functions(&mut self) -> &mut AST
pub fn clear_functions(&mut self) -> &mut AST
Clear all function definitions in the AST
.
Not available under no_function
.
sourcepub fn clear_statements(&mut self) -> &mut AST
pub fn clear_statements(&mut self) -> &mut AST
Clear all statements in the AST
, leaving only function definitions.
sourcepub fn iter_literal_variables(
&self,
include_constants: bool,
include_variables: bool
) -> impl Iterator<Item = (&str, bool, Dynamic)>
pub fn iter_literal_variables(
&self,
include_constants: bool,
include_variables: bool
) -> impl Iterator<Item = (&str, bool, Dynamic)>
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(())
Trait Implementations
sourceimpl<A> AddAssign<A> for AST where
A: Into<AST>,
impl<A> AddAssign<A> for AST where
A: Into<AST>,
sourcefn add_assign(&mut self, rhs: A)
fn add_assign(&mut self, rhs: A)
Performs the +=
operation. Read more
Auto Trait Implementations
impl !RefUnwindSafe for AST
impl Send for AST
impl Sync for AST
impl Unpin for AST
impl !UnwindSafe for AST
Blanket Implementations
sourceimpl<T> BorrowMut<T> for T where
T: ?Sized,
impl<T> BorrowMut<T> for T where
T: ?Sized,
const: unstable · sourcefn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
sourceimpl<T> CheckedConversion for T
impl<T> CheckedConversion for T
sourcefn checked_from<T>(t: T) -> Option<Self> where
Self: TryFrom<T>,
fn checked_from<T>(t: T) -> Option<Self> where
Self: TryFrom<T>,
Convert from a value of T
into an equivalent instance of Option<Self>
. Read more
sourcefn checked_into<T>(self) -> Option<T> where
Self: TryInto<T>,
fn checked_into<T>(self) -> Option<T> where
Self: TryInto<T>,
Consume self to return Some
equivalent value of Option<T>
. Read more
sourceimpl<T> Instrument for T
impl<T> Instrument for T
sourcefn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
sourcefn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
sourceimpl<T, Outer> IsWrappedBy<Outer> for T where
Outer: AsRef<T> + AsMut<T> + From<T>,
T: From<Outer>,
impl<T, Outer> IsWrappedBy<Outer> for T where
Outer: AsRef<T> + AsMut<T> + From<T>,
T: From<Outer>,
impl<T> SaturatedConversion for T
impl<T> SaturatedConversion for T
fn saturated_from<T>(t: T) -> Self where
Self: UniqueSaturatedFrom<T>,
fn saturated_from<T>(t: T) -> Self where
Self: UniqueSaturatedFrom<T>,
Convert from a value of T
into an equivalent instance of Self
. Read more
fn saturated_into<T>(self) -> T where
Self: UniqueSaturatedInto<T>,
fn saturated_into<T>(self) -> T where
Self: UniqueSaturatedInto<T>,
Consume self to return an equivalent value of T
. Read more
sourceimpl<T> ToOwned for T where
T: Clone,
impl<T> ToOwned for T where
T: Clone,
type Owned = T
type Owned = T
The resulting type after obtaining ownership.
sourcefn clone_into(&self, target: &mut T)
fn clone_into(&self, target: &mut T)
toowned_clone_into
)Uses borrowed data to replace owned data, usually by cloning. Read more
sourceimpl<S, T> UncheckedInto<T> for S where
T: UncheckedFrom<S>,
impl<S, T> UncheckedInto<T> for S where
T: UncheckedFrom<S>,
sourcefn unchecked_into(self) -> T
fn unchecked_into(self) -> T
The counterpart to unchecked_from
.
impl<T, S> UniqueSaturatedInto<T> for S where
T: Bounded,
S: TryInto<T>,
impl<T, S> UniqueSaturatedInto<T> for S where
T: Bounded,
S: TryInto<T>,
fn unique_saturated_into(self) -> T
fn unique_saturated_into(self) -> T
Consume self to return an equivalent value of T
.
impl<V, T> VZip<V> for T where
V: MultiLane<T>,
impl<V, T> VZip<V> for T where
V: MultiLane<T>,
fn vzip(self) -> V
sourceimpl<T> WithSubscriber for T
impl<T> WithSubscriber for T
sourcefn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> where
S: Into<Dispatch>,
fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> where
S: Into<Dispatch>,
Attaches the provided Subscriber
to this type, returning a
WithDispatch
wrapper. Read more
sourcefn with_current_subscriber(self) -> WithDispatch<Self>
fn with_current_subscriber(self) -> WithDispatch<Self>
Attaches the current default Subscriber
to this type, returning a
WithDispatch
wrapper. Read more