rhai/src/ast.rs

1545 lines
50 KiB
Rust
Raw Normal View History

2020-10-28 15:18:44 +01:00
//! Module defining the AST (abstract syntax tree).
use crate::dynamic::{AccessMode, Union};
2020-11-19 03:41:08 +01:00
use crate::fn_native::shared_make_mut;
2021-01-08 17:40:44 +01:00
use crate::module::NamespaceRef;
2020-10-28 15:18:44 +01:00
use crate::stdlib::{
2020-10-29 04:37:51 +01:00
borrow::Cow,
2020-10-29 05:00:02 +01:00
boxed::Box,
2020-10-29 04:37:51 +01:00
fmt,
2021-01-18 03:56:42 +01:00
hash::Hash,
2020-12-24 09:32:43 +01:00
num::{NonZeroU64, NonZeroUsize},
2021-01-18 03:56:42 +01:00
ops::{Add, AddAssign},
2020-10-29 04:37:51 +01:00
string::String,
2020-10-28 15:18:44 +01:00
vec,
vec::Vec,
};
2020-11-16 16:10:14 +01:00
use crate::token::Token;
2021-01-05 11:37:07 +01:00
use crate::utils::{HashableHashMap, StraightHasherBuilder};
2020-11-17 05:23:53 +01:00
use crate::{
2020-11-20 09:52:28 +01:00
Dynamic, FnNamespace, FnPtr, ImmutableString, Module, Position, Shared, StaticVec, INT,
2020-11-17 05:23:53 +01:00
};
2020-11-16 16:10:14 +01:00
#[cfg(not(feature = "no_float"))]
2021-02-13 13:57:56 +01:00
use crate::{stdlib::str::FromStr, FLOAT};
2020-11-16 16:10:14 +01:00
#[cfg(not(feature = "no_index"))]
use crate::Array;
#[cfg(not(feature = "no_object"))]
use crate::Map;
2020-10-28 15:18:44 +01:00
2020-11-17 05:23:53 +01:00
/// A type representing the access mode of a function.
2020-10-29 04:37:51 +01:00
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub enum FnAccess {
/// Public function.
Public,
/// Private function.
Private,
}
impl FnAccess {
2020-11-25 02:36:06 +01:00
/// Is this access mode [private][FnAccess::Private]?
2020-10-29 04:37:51 +01:00
#[inline(always)]
pub fn is_private(self) -> bool {
match self {
Self::Private => true,
2020-11-16 16:10:14 +01:00
Self::Public => false,
2020-10-29 04:37:51 +01:00
}
}
2020-11-25 02:36:06 +01:00
/// Is this access mode [public][FnAccess::Public]?
2020-10-29 04:37:51 +01:00
#[inline(always)]
pub fn is_public(self) -> bool {
match self {
Self::Private => false,
2020-11-16 16:10:14 +01:00
Self::Public => true,
2020-10-29 04:37:51 +01:00
}
}
}
2020-11-20 09:52:28 +01:00
/// _(INTERNALS)_ A type containing information on a scripted function.
2020-10-29 04:37:51 +01:00
/// Exported under the `internals` feature only.
///
2021-01-16 07:46:03 +01:00
/// # Volatile Data Structure
2020-10-29 04:37:51 +01:00
///
/// This type is volatile and may change.
#[derive(Debug, Clone)]
pub struct ScriptFnDef {
2020-11-04 05:34:54 +01:00
/// Function body.
pub body: Stmt,
/// Encapsulated running environment, if any.
pub lib: Option<Shared<Module>>,
2020-11-09 14:52:23 +01:00
/// Encapsulated imported modules.
#[cfg(not(feature = "no_module"))]
2020-11-16 09:28:04 +01:00
pub mods: crate::engine::Imports,
2020-10-29 04:37:51 +01:00
/// Function name.
pub name: ImmutableString,
/// Function access mode.
pub access: FnAccess,
/// Names of function parameters.
2020-11-13 03:43:54 +01:00
pub params: StaticVec<ImmutableString>,
2020-11-09 14:52:23 +01:00
/// Access to external variables.
2020-10-29 04:37:51 +01:00
#[cfg(not(feature = "no_closure"))]
2020-12-12 09:31:13 +01:00
pub externals: Vec<ImmutableString>,
/// Function doc-comments (if any).
pub comments: Vec<String>,
2020-10-29 04:37:51 +01:00
}
impl fmt::Display for ScriptFnDef {
2020-12-29 03:41:20 +01:00
#[inline(always)]
2020-10-29 04:37:51 +01:00
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
2020-12-28 02:49:54 +01:00
"{}{}({})",
2020-10-29 04:37:51 +01:00
if self.access.is_private() {
"private "
} else {
""
},
self.name,
self.params
.iter()
.map(|s| s.as_str())
.collect::<Vec<_>>()
2020-11-22 10:21:34 +01:00
.join(", ")
2020-10-29 04:37:51 +01:00
)
}
}
/// A type containing the metadata of a script-defined function.
///
/// Created by [`AST::iter_functions`].
#[derive(Debug, Eq, PartialEq, Clone, Hash)]
pub struct ScriptFnMetadata<'a> {
/// Function doc-comments (if any).
///
/// Block doc-comments are kept in a single string slice with line-breaks within.
///
/// Line doc-comments are kept in one string slice per line without the termination line-break.
///
/// Leading white-spaces are stripped, and each string slice always starts with the corresponding
/// doc-comment leader: `///` or `/**`.
pub comments: Vec<&'a str>,
/// Function access mode.
2020-12-12 11:44:28 +01:00
pub access: FnAccess,
/// Function name.
pub name: &'a str,
/// Function parameters (if any).
pub params: Vec<&'a str>,
2020-12-12 11:44:28 +01:00
}
impl fmt::Display for ScriptFnMetadata<'_> {
2020-12-29 03:41:20 +01:00
#[inline(always)]
2020-12-12 11:44:28 +01:00
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
2020-12-28 02:49:54 +01:00
"{}{}({})",
2020-12-12 11:44:28 +01:00
if self.access.is_private() {
"private "
} else {
""
},
self.name,
self.params.iter().cloned().collect::<Vec<_>>().join(", ")
2020-12-12 11:44:28 +01:00
)
}
}
impl<'a> Into<ScriptFnMetadata<'a>> for &'a ScriptFnDef {
2020-12-29 03:41:20 +01:00
#[inline(always)]
fn into(self) -> ScriptFnMetadata<'a> {
2020-12-12 11:44:28 +01:00
ScriptFnMetadata {
comments: self.comments.iter().map(|s| s.as_str()).collect(),
2020-12-12 11:44:28 +01:00
access: self.access,
name: &self.name,
params: self.params.iter().map(|s| s.as_str()).collect(),
2020-12-12 11:44:28 +01:00
}
}
}
2020-10-28 15:18:44 +01:00
/// Compiled AST (abstract syntax tree) of a Rhai script.
///
/// # Thread Safety
///
2020-11-20 09:52:28 +01:00
/// Currently, [`AST`] is neither `Send` nor `Sync`. Turn on the `sync` feature to make it `Send + Sync`.
2020-11-15 06:49:54 +01:00
#[derive(Debug, Clone)]
2020-12-12 08:57:55 +01:00
pub struct AST {
2020-12-21 15:04:46 +01:00
/// Source of the [`AST`].
source: Option<ImmutableString>,
2020-10-28 15:18:44 +01:00
/// Global statements.
2020-12-12 08:57:55 +01:00
statements: Vec<Stmt>,
2020-10-28 15:18:44 +01:00
/// Script-defined functions.
2020-12-12 08:57:55 +01:00
functions: Shared<Module>,
2021-01-08 17:24:55 +01:00
/// Embedded module resolver, if any.
2021-01-08 17:40:44 +01:00
#[cfg(not(feature = "no_module"))]
resolver: Option<Shared<crate::module::resolvers::StaticModuleResolver>>,
2020-12-12 08:57:55 +01:00
}
2020-10-28 15:18:44 +01:00
2020-11-15 06:49:54 +01:00
impl Default for AST {
2020-12-29 03:41:20 +01:00
#[inline(always)]
2020-11-15 06:49:54 +01:00
fn default() -> Self {
2020-12-12 08:57:55 +01:00
Self {
2020-12-21 15:04:46 +01:00
source: None,
2020-12-12 08:57:55 +01:00
statements: Vec::with_capacity(16),
functions: Default::default(),
2021-01-08 17:40:44 +01:00
#[cfg(not(feature = "no_module"))]
2021-01-08 17:24:55 +01:00
resolver: None,
2020-12-12 08:57:55 +01:00
}
2020-11-15 06:49:54 +01:00
}
}
2020-10-28 15:18:44 +01:00
impl AST {
2020-11-20 09:52:28 +01:00
/// Create a new [`AST`].
2020-10-28 15:18:44 +01:00
#[inline(always)]
2020-12-12 08:57:55 +01:00
pub fn new(
statements: impl IntoIterator<Item = Stmt>,
functions: impl Into<Shared<Module>>,
) -> Self {
Self {
2020-12-21 15:04:46 +01:00
source: None,
2020-12-12 08:57:55 +01:00
statements: statements.into_iter().collect(),
functions: functions.into(),
2021-01-08 17:40:44 +01:00
#[cfg(not(feature = "no_module"))]
2021-01-08 17:24:55 +01:00
resolver: None,
2020-12-12 08:57:55 +01:00
}
2020-10-28 15:18:44 +01:00
}
2020-12-21 15:04:46 +01:00
/// Create a new [`AST`] with a source name.
#[inline(always)]
pub fn new_with_source(
statements: impl IntoIterator<Item = Stmt>,
functions: impl Into<Shared<Module>>,
source: impl Into<ImmutableString>,
) -> Self {
Self {
source: Some(source.into()),
statements: statements.into_iter().collect(),
functions: functions.into(),
2021-01-08 17:40:44 +01:00
#[cfg(not(feature = "no_module"))]
2021-01-08 17:24:55 +01:00
resolver: None,
2020-12-21 15:04:46 +01:00
}
}
/// Get the source, if any.
2020-12-29 03:41:20 +01:00
#[inline(always)]
2020-12-21 15:04:46 +01:00
pub fn source(&self) -> Option<&str> {
self.source.as_ref().map(|s| s.as_str())
}
/// Clone the source, if any.
2020-12-29 03:41:20 +01:00
#[inline(always)]
2020-12-21 15:04:46 +01:00
pub(crate) fn clone_source(&self) -> Option<ImmutableString> {
self.source.clone()
}
/// Set the source.
2020-12-29 03:41:20 +01:00
#[inline(always)]
pub fn set_source(&mut self, source: impl Into<ImmutableString>) -> &mut Self {
self.source = Some(source.into());
if let Some(module) = Shared::get_mut(&mut self.functions) {
module.set_id(self.source.clone());
}
self
}
/// Clear the source.
#[inline(always)]
pub fn clear_source(&mut self) -> &mut Self {
self.source = None;
self
2020-12-21 15:04:46 +01:00
}
2020-10-28 15:18:44 +01:00
/// Get the statements.
#[cfg(not(feature = "internals"))]
#[inline(always)]
pub(crate) fn statements(&self) -> &[Stmt] {
2020-12-12 08:57:55 +01:00
&self.statements
2020-10-28 15:18:44 +01:00
}
2020-11-20 09:52:28 +01:00
/// _(INTERNALS)_ Get the statements.
2020-10-28 15:18:44 +01:00
/// Exported under the `internals` feature only.
#[cfg(feature = "internals")]
2020-12-23 08:30:35 +01:00
#[deprecated = "this method is volatile and may change"]
2020-10-28 15:18:44 +01:00
#[inline(always)]
pub fn statements(&self) -> &[Stmt] {
2020-12-12 08:57:55 +01:00
&self.statements
2020-10-28 15:18:44 +01:00
}
/// Get a mutable reference to the statements.
#[cfg(not(feature = "no_optimize"))]
#[inline(always)]
pub(crate) fn statements_mut(&mut self) -> &mut Vec<Stmt> {
2020-12-12 08:57:55 +01:00
&mut self.statements
2020-10-28 15:18:44 +01:00
}
2020-11-20 09:52:28 +01:00
/// Get the internal shared [`Module`] containing all script-defined functions.
#[cfg(not(feature = "internals"))]
2020-11-27 16:37:59 +01:00
#[cfg(not(feature = "no_module"))]
2020-11-22 15:15:17 +01:00
#[cfg(not(feature = "no_function"))]
#[inline(always)]
pub(crate) fn shared_lib(&self) -> Shared<Module> {
2020-12-12 08:57:55 +01:00
self.functions.clone()
}
2021-01-16 07:46:03 +01:00
/// _(INTERNALS)_ Get the internal shared [`Module`] containing all script-defined functions.
/// Exported under the `internals` feature only.
#[cfg(feature = "internals")]
2021-01-16 07:46:03 +01:00
#[deprecated = "this method is volatile and may change"]
#[cfg(not(feature = "no_module"))]
#[cfg(not(feature = "no_function"))]
#[inline(always)]
pub fn shared_lib(&self) -> Shared<Module> {
self.functions.clone()
}
2020-11-20 09:52:28 +01:00
/// Get the internal [`Module`] containing all script-defined functions.
2020-10-28 15:18:44 +01:00
#[cfg(not(feature = "internals"))]
#[inline(always)]
pub(crate) fn lib(&self) -> &Module {
2020-12-12 08:57:55 +01:00
&self.functions
2020-10-28 15:18:44 +01:00
}
2020-11-20 09:52:28 +01:00
/// _(INTERNALS)_ Get the internal [`Module`] containing all script-defined functions.
2020-10-28 15:18:44 +01:00
/// Exported under the `internals` feature only.
#[cfg(feature = "internals")]
2020-12-23 08:30:35 +01:00
#[deprecated = "this method is volatile and may change"]
2020-10-28 15:18:44 +01:00
#[inline(always)]
pub fn lib(&self) -> &Module {
2020-12-12 08:57:55 +01:00
&self.functions
2020-10-28 15:18:44 +01:00
}
2021-01-08 17:24:55 +01:00
/// Get the embedded [module resolver][`ModuleResolver`].
2021-01-08 17:40:44 +01:00
#[cfg(not(feature = "no_module"))]
2021-01-08 17:49:50 +01:00
#[cfg(not(feature = "internals"))]
2021-01-08 17:24:55 +01:00
#[inline(always)]
2021-01-08 17:49:50 +01:00
pub(crate) fn resolver(
2021-01-08 17:40:44 +01:00
&self,
) -> Option<Shared<crate::module::resolvers::StaticModuleResolver>> {
2021-01-08 17:24:55 +01:00
self.resolver.clone()
}
2021-01-11 16:09:33 +01:00
/// _(INTERNALS)_ Get the embedded [module resolver][crate::ModuleResolver].
2021-01-08 17:24:55 +01:00
/// Exported under the `internals` feature only.
2021-01-08 17:40:44 +01:00
#[cfg(not(feature = "no_module"))]
2021-01-08 17:24:55 +01:00
#[cfg(feature = "internals")]
#[inline(always)]
2021-01-08 17:49:50 +01:00
pub fn resolver(&self) -> Option<Shared<crate::module::resolvers::StaticModuleResolver>> {
self.resolver.clone()
2021-01-08 17:24:55 +01:00
}
/// Set the embedded [module resolver][`ModuleResolver`].
2021-01-08 17:40:44 +01:00
#[cfg(not(feature = "no_module"))]
2021-01-08 17:24:55 +01:00
#[inline(always)]
pub(crate) fn set_resolver(
&mut self,
2021-01-08 17:40:44 +01:00
resolver: impl Into<Shared<crate::module::resolvers::StaticModuleResolver>>,
2021-01-08 17:24:55 +01:00
) -> &mut Self {
self.resolver = Some(resolver.into());
self
}
2020-11-20 09:52:28 +01:00
/// Clone the [`AST`]'s functions into a new [`AST`].
2020-10-28 15:18:44 +01:00
/// No statements are cloned.
///
/// This operation is cheap because functions are shared.
2021-01-02 16:30:10 +01:00
///
2021-01-11 16:09:33 +01:00
/// Not available under `no_function`.
2020-10-29 04:37:51 +01:00
#[cfg(not(feature = "no_function"))]
2020-10-28 15:18:44 +01:00
#[inline(always)]
pub fn clone_functions_only(&self) -> Self {
2020-11-17 05:23:53 +01:00
self.clone_functions_only_filtered(|_, _, _, _, _| true)
2020-10-28 15:18:44 +01:00
}
2020-11-20 09:52:28 +01:00
/// Clone the [`AST`]'s functions into a new [`AST`] based on a filter predicate.
2020-10-28 15:18:44 +01:00
/// No statements are cloned.
///
/// This operation is cheap because functions are shared.
2021-01-02 16:30:10 +01:00
///
2021-01-11 16:09:33 +01:00
/// Not available under `no_function`.
2020-10-29 04:37:51 +01:00
#[cfg(not(feature = "no_function"))]
2020-10-28 15:18:44 +01:00
#[inline(always)]
pub fn clone_functions_only_filtered(
&self,
2021-02-13 03:56:09 +01:00
filter: impl Fn(FnNamespace, FnAccess, bool, &str, usize) -> bool,
2020-10-28 15:18:44 +01:00
) -> Self {
let mut functions: Module = Default::default();
2021-02-13 03:56:09 +01:00
functions.merge_filtered(&self.functions, &filter);
2020-12-12 08:57:55 +01:00
Self {
2020-12-21 15:04:46 +01:00
source: self.source.clone(),
2020-12-12 08:57:55 +01:00
statements: Default::default(),
functions: functions.into(),
2021-01-08 17:40:44 +01:00
#[cfg(not(feature = "no_module"))]
2021-01-08 17:24:55 +01:00
resolver: self.resolver.clone(),
2020-12-12 08:57:55 +01:00
}
2020-10-28 15:18:44 +01:00
}
2020-11-20 09:52:28 +01:00
/// Clone the [`AST`]'s script statements into a new [`AST`].
2020-10-28 15:18:44 +01:00
/// No functions are cloned.
#[inline(always)]
pub fn clone_statements_only(&self) -> Self {
2020-12-12 08:57:55 +01:00
Self {
2020-12-21 15:04:46 +01:00
source: self.source.clone(),
2020-12-12 08:57:55 +01:00
statements: self.statements.clone(),
functions: Default::default(),
2021-01-08 17:40:44 +01:00
#[cfg(not(feature = "no_module"))]
2021-01-08 17:24:55 +01:00
resolver: self.resolver.clone(),
2020-12-12 08:57:55 +01:00
}
2020-10-28 15:18:44 +01:00
}
2020-11-20 09:52:28 +01:00
/// Merge two [`AST`] into one. Both [`AST`]'s are untouched and a new, merged, version
2020-10-28 15:18:44 +01:00
/// is returned.
///
2020-11-20 09:52:28 +01:00
/// 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.
2020-10-28 15:18:44 +01:00
///
2020-11-20 09:52:28 +01:00
/// All script-defined functions in the second [`AST`] overwrite similarly-named functions
/// in the first [`AST`] with the same number of parameters.
2020-10-28 15:18:44 +01:00
///
/// # Example
///
/// ```
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
/// # #[cfg(not(feature = "no_function"))]
/// # {
/// use rhai::Engine;
///
/// let engine = Engine::new();
///
/// let ast1 = engine.compile(r#"
/// 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!");
/// # }
/// # Ok(())
/// # }
/// ```
#[inline(always)]
pub fn merge(&self, other: &Self) -> Self {
2020-11-17 05:23:53 +01:00
self.merge_filtered(other, |_, _, _, _, _| true)
2020-10-28 15:18:44 +01:00
}
2020-11-20 09:52:28 +01:00
/// Combine one [`AST`] with another. The second [`AST`] is consumed.
2020-10-28 15:18:44 +01:00
///
2020-11-20 09:52:28 +01:00
/// 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.
2020-10-28 15:18:44 +01:00
///
2020-11-20 09:52:28 +01:00
/// All script-defined functions in the second [`AST`] overwrite similarly-named functions
/// in the first [`AST`] with the same number of parameters.
2020-10-28 15:18:44 +01:00
///
/// # Example
///
/// ```
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
/// # #[cfg(not(feature = "no_function"))]
/// # {
/// use rhai::Engine;
///
/// let engine = Engine::new();
///
/// let mut ast1 = engine.compile(r#"
/// 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!");
/// # }
/// # Ok(())
/// # }
/// ```
#[inline(always)]
pub fn combine(&mut self, other: Self) -> &mut Self {
2020-11-17 05:23:53 +01:00
self.combine_filtered(other, |_, _, _, _, _| true)
2020-10-28 15:18:44 +01:00
}
2020-11-20 09:52:28 +01:00
/// Merge two [`AST`] into one. Both [`AST`]'s are untouched and a new, merged, version
2020-10-28 15:18:44 +01:00
/// is returned.
///
2020-11-20 09:52:28 +01:00
/// 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.
2020-10-28 15:18:44 +01:00
///
2020-11-20 09:52:28 +01:00
/// 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
2020-10-28 15:18:44 +01:00
/// same number of parameters.
///
/// # Example
///
/// ```
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
/// # #[cfg(not(feature = "no_function"))]
/// # {
/// use rhai::Engine;
///
/// let engine = Engine::new();
///
/// let ast1 = engine.compile(r#"
/// 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'
2020-11-17 05:23:53 +01:00
/// let ast = ast1.merge_filtered(&ast2, |_, _, script, name, params|
/// script && name == "error" && params == 0);
2020-10-28 15:18:44 +01:00
///
/// // '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!");
/// # }
/// # Ok(())
/// # }
/// ```
#[inline]
pub fn merge_filtered(
&self,
other: &Self,
2021-02-13 03:56:09 +01:00
filter: impl Fn(FnNamespace, FnAccess, bool, &str, usize) -> bool,
2020-10-28 15:18:44 +01:00
) -> Self {
2020-12-12 08:57:55 +01:00
let Self {
statements,
functions,
2020-12-21 15:04:46 +01:00
..
2020-12-12 08:57:55 +01:00
} = self;
2020-10-28 15:18:44 +01:00
2020-12-12 08:57:55 +01:00
let ast = match (statements.is_empty(), other.statements.is_empty()) {
2020-10-28 15:18:44 +01:00
(false, false) => {
let mut statements = statements.clone();
2020-12-12 08:57:55 +01:00
statements.extend(other.statements.iter().cloned());
2020-10-28 15:18:44 +01:00
statements
}
(false, true) => statements.clone(),
2020-12-12 08:57:55 +01:00
(true, false) => other.statements.clone(),
2020-10-28 15:18:44 +01:00
(true, true) => vec![],
};
let source = other.source.clone().or_else(|| self.source.clone());
2020-12-21 15:04:46 +01:00
2020-11-19 03:41:08 +01:00
let mut functions = functions.as_ref().clone();
2021-02-13 03:56:09 +01:00
functions.merge_filtered(&other.functions, &filter);
2020-10-28 15:18:44 +01:00
2020-12-21 15:04:46 +01:00
if let Some(source) = source {
Self::new_with_source(ast, functions, source)
} else {
Self::new(ast, functions)
}
2020-10-28 15:18:44 +01:00
}
2020-11-20 09:52:28 +01:00
/// Combine one [`AST`] with another. The second [`AST`] is consumed.
2020-10-28 15:18:44 +01:00
///
2020-11-20 09:52:28 +01:00
/// 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.
2020-10-28 15:18:44 +01:00
///
2020-11-20 09:52:28 +01:00
/// 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
2020-10-28 15:18:44 +01:00
/// same number of parameters.
///
/// # Example
///
/// ```
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
/// # #[cfg(not(feature = "no_function"))]
/// # {
/// use rhai::Engine;
///
/// let engine = Engine::new();
///
/// let mut ast1 = engine.compile(r#"
/// 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'
2020-11-17 05:23:53 +01:00
/// ast1.combine_filtered(ast2, |_, _, script, name, params|
/// script && name == "error" && params == 0);
2020-10-28 15:18:44 +01:00
///
/// // '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!");
/// # }
/// # Ok(())
/// # }
/// ```
#[inline(always)]
pub fn combine_filtered(
&mut self,
other: Self,
2021-02-13 03:56:09 +01:00
filter: impl Fn(FnNamespace, FnAccess, bool, &str, usize) -> bool,
2020-10-28 15:18:44 +01:00
) -> &mut Self {
2020-12-12 08:57:55 +01:00
self.statements.extend(other.statements.into_iter());
if !other.functions.is_empty() {
2021-02-13 03:56:09 +01:00
shared_make_mut(&mut self.functions).merge_filtered(&other.functions, &filter);
2020-11-19 03:41:08 +01:00
}
2020-10-28 15:18:44 +01:00
self
}
/// Filter out the functions, retaining only some based on a filter predicate.
///
2021-01-11 16:09:33 +01:00
/// Not available under `no_function`.
2021-01-02 16:30:10 +01:00
///
2020-10-28 15:18:44 +01:00
/// # Example
///
/// ```
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
/// # #[cfg(not(feature = "no_function"))]
/// # {
/// 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(_)'
2020-11-17 05:23:53 +01:00
/// ast.retain_functions(|_, _, name, params| name == "foo" && params == 1);
2020-10-28 15:18:44 +01:00
/// # }
/// # Ok(())
/// # }
/// ```
#[cfg(not(feature = "no_function"))]
#[inline(always)]
2020-11-17 05:23:53 +01:00
pub fn retain_functions(
&mut self,
2021-02-13 03:56:09 +01:00
filter: impl Fn(FnNamespace, FnAccess, &str, usize) -> bool,
2020-11-19 03:41:08 +01:00
) -> &mut Self {
2020-12-12 08:57:55 +01:00
if !self.functions.is_empty() {
shared_make_mut(&mut self.functions).retain_script_functions(filter);
2020-11-19 03:41:08 +01:00
}
self
2020-10-28 15:18:44 +01:00
}
/// Iterate through all function definitions.
2021-01-02 16:30:10 +01:00
///
/// Not available under [`no_function`].
2020-10-28 15:18:44 +01:00
#[cfg(not(feature = "no_function"))]
2021-01-08 17:40:44 +01:00
#[cfg(not(feature = "no_module"))]
2020-10-28 15:18:44 +01:00
#[inline(always)]
2021-01-08 17:24:55 +01:00
pub(crate) fn iter_fn_def(&self) -> impl Iterator<Item = &ScriptFnDef> {
self.functions
.iter_script_fn()
.map(|(_, _, _, _, fn_def)| fn_def)
}
/// Iterate through all function definitions.
///
2021-01-11 16:09:33 +01:00
/// Not available under `no_function`.
2021-01-08 17:24:55 +01:00
#[cfg(not(feature = "no_function"))]
#[inline(always)]
2020-12-12 11:44:28 +01:00
pub fn iter_functions<'a>(&'a self) -> impl Iterator<Item = ScriptFnMetadata> + 'a {
2020-12-12 09:31:13 +01:00
self.functions
.iter_script_fn()
2020-12-12 11:44:28 +01:00
.map(|(_, _, _, _, fn_def)| fn_def.into())
2020-10-28 15:18:44 +01:00
}
2020-11-20 09:52:28 +01:00
/// Clear all function definitions in the [`AST`].
2021-01-02 16:30:10 +01:00
///
2021-01-11 16:09:33 +01:00
/// Not available under `no_function`.
2020-10-28 15:18:44 +01:00
#[cfg(not(feature = "no_function"))]
#[inline(always)]
pub fn clear_functions(&mut self) {
2020-12-12 08:57:55 +01:00
self.functions = Default::default();
2020-10-28 15:18:44 +01:00
}
2020-11-20 09:52:28 +01:00
/// Clear all statements in the [`AST`], leaving only function definitions.
2020-10-28 15:18:44 +01:00
#[inline(always)]
pub fn clear_statements(&mut self) {
2020-12-12 08:57:55 +01:00
self.statements = vec![];
2020-10-28 15:18:44 +01:00
}
2021-01-09 09:52:22 +01:00
/// Recursively walk the [`AST`], including function bodies (if any).
#[cfg(not(feature = "internals"))]
2021-01-09 10:06:01 +01:00
#[cfg(not(feature = "no_module"))]
2021-01-09 09:52:22 +01:00
#[inline(always)]
pub(crate) fn walk(&self, on_node: &mut impl FnMut(&[ASTNode])) {
self.statements()
.iter()
.chain({
#[cfg(not(feature = "no_function"))]
{
self.iter_fn_def().map(|f| &f.body)
}
#[cfg(feature = "no_function")]
{
crate::stdlib::iter::empty()
}
})
2021-01-09 10:06:01 +01:00
.for_each(|stmt| stmt.walk(&mut Default::default(), on_node));
2021-01-09 09:52:22 +01:00
}
/// _(INTERNALS)_ Recursively walk the [`AST`], including function bodies (if any).
/// Exported under the `internals` feature only.
#[cfg(feature = "internals")]
#[inline(always)]
pub fn walk(&self, on_node: &mut impl FnMut(&[ASTNode])) {
self.statements()
.iter()
.chain({
#[cfg(not(feature = "no_function"))]
{
self.iter_fn_def().map(|f| &f.body)
}
#[cfg(feature = "no_function")]
{
crate::stdlib::iter::empty()
}
})
2021-01-09 10:06:01 +01:00
.for_each(|stmt| stmt.walk(&mut Default::default(), on_node));
2021-01-09 09:52:22 +01:00
}
2020-10-28 15:18:44 +01:00
}
impl<A: AsRef<AST>> Add<A> for &AST {
type Output = AST;
#[inline(always)]
fn add(self, rhs: A) -> Self::Output {
self.merge(rhs.as_ref())
}
}
impl<A: Into<AST>> AddAssign<A> for AST {
#[inline(always)]
fn add_assign(&mut self, rhs: A) {
self.combine(rhs.into());
}
}
impl AsRef<[Stmt]> for AST {
#[inline(always)]
fn as_ref(&self) -> &[Stmt] {
self.statements()
}
}
impl AsRef<Module> for AST {
#[inline(always)]
fn as_ref(&self) -> &Module {
self.lib()
}
}
2020-10-29 04:37:51 +01:00
2020-11-25 02:36:06 +01:00
/// _(INTERNALS)_ An identifier containing an [immutable string][ImmutableString] name and a [position][Position].
/// Exported under the `internals` feature only.
///
2021-01-16 07:46:03 +01:00
/// # Volatile Data Structure
2020-11-25 02:36:06 +01:00
///
/// This type is volatile and may change.
2020-12-28 02:49:54 +01:00
#[derive(Clone, Eq, PartialEq, Hash)]
2020-12-22 09:45:56 +01:00
pub struct Ident {
2020-12-22 15:35:25 +01:00
/// Identifier name.
2020-10-29 04:37:51 +01:00
pub name: ImmutableString,
2020-12-22 15:35:25 +01:00
/// Declaration position.
2020-10-29 04:37:51 +01:00
pub pos: Position,
}
2020-12-28 02:49:54 +01:00
impl fmt::Debug for Ident {
2020-12-29 03:41:20 +01:00
#[inline(always)]
2020-12-28 02:49:54 +01:00
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Ident({:?} @ {:?})", self.name, self.pos)
}
}
2020-11-20 09:52:28 +01:00
/// _(INTERNALS)_ A type encapsulating the mode of a `return`/`throw` statement.
2020-10-29 04:37:51 +01:00
/// Exported under the `internals` feature only.
///
2021-01-16 07:46:03 +01:00
/// # Volatile Data Structure
2020-10-29 04:37:51 +01:00
///
/// This type is volatile and may change.
#[derive(Debug, Eq, PartialEq, Clone, Copy, Hash)]
pub enum ReturnType {
/// `return` statement.
Return,
/// `throw` statement.
Exception,
}
2021-01-09 09:52:22 +01:00
/// _(INTERNALS)_ An [`AST`] node, consisting of either an [`Expr`] or a [`Stmt`].
/// Exported under the `internals` feature only.
///
2021-01-16 07:46:03 +01:00
/// # Volatile Data Structure
2021-01-09 09:52:22 +01:00
///
/// This type is volatile and may change.
#[derive(Debug, Clone, Hash)]
pub enum ASTNode<'a> {
Stmt(&'a Stmt),
Expr(&'a Expr),
}
impl<'a> From<&'a Stmt> for ASTNode<'a> {
fn from(stmt: &'a Stmt) -> Self {
Self::Stmt(stmt)
}
}
impl<'a> From<&'a Expr> for ASTNode<'a> {
fn from(expr: &'a Expr) -> Self {
Self::Expr(expr)
}
}
2020-11-20 09:52:28 +01:00
/// _(INTERNALS)_ A statement.
2020-10-29 04:37:51 +01:00
/// Exported under the `internals` feature only.
///
2021-01-16 07:46:03 +01:00
/// # Volatile Data Structure
2020-11-06 09:27:40 +01:00
///
/// This type is volatile and may change.
#[derive(Debug, Clone, Hash)]
2020-10-29 04:37:51 +01:00
pub enum Stmt {
/// No-op.
Noop(Position),
2020-11-20 09:52:28 +01:00
/// `if` expr `{` stmt `}` `else` `{` stmt `}`
2020-11-14 15:55:23 +01:00
If(Expr, Box<(Stmt, Option<Stmt>)>, Position),
2020-11-20 09:52:28 +01:00
/// `switch` expr `{` literal or _ `=>` stmt `,` ... `}`
2021-01-05 11:37:07 +01:00
Switch(
Expr,
Box<(
HashableHashMap<u64, Stmt, StraightHasherBuilder>,
Option<Stmt>,
)>,
Position,
),
2020-11-20 09:52:28 +01:00
/// `while` expr `{` stmt `}`
2020-10-29 04:37:51 +01:00
While(Expr, Box<Stmt>, Position),
2020-11-20 15:23:37 +01:00
/// `do` `{` stmt `}` `while`|`until` expr
Do(Box<Stmt>, Expr, bool, Position),
2020-11-20 09:52:28 +01:00
/// `for` id `in` expr `{` stmt `}`
2020-10-29 04:37:51 +01:00
For(Expr, Box<(String, Stmt)>, Position),
2020-11-20 09:52:28 +01:00
/// \[`export`\] `let` id `=` expr
2020-12-22 09:45:56 +01:00
Let(Box<Ident>, Option<Expr>, bool, Position),
2020-11-20 09:52:28 +01:00
/// \[`export`\] `const` id `=` expr
2020-12-22 09:45:56 +01:00
Const(Box<Ident>, Option<Expr>, bool, Position),
2020-11-20 09:52:28 +01:00
/// expr op`=` expr
2020-10-29 04:37:51 +01:00
Assignment(Box<(Expr, Cow<'static, str>, Expr)>, Position),
2020-11-20 09:52:28 +01:00
/// `{` stmt`;` ... `}`
2020-10-29 04:37:51 +01:00
Block(Vec<Stmt>, Position),
2020-11-20 09:52:28 +01:00
/// `try` `{` stmt; ... `}` `catch` `(` var `)` `{` stmt; ... `}`
2020-11-06 09:27:40 +01:00
TryCatch(Box<(Stmt, Option<Ident>, Stmt)>, Position, Position),
2020-11-20 09:52:28 +01:00
/// [expression][Expr]
2020-10-29 04:37:51 +01:00
Expr(Expr),
2020-11-20 09:52:28 +01:00
/// `continue`
2020-10-29 04:37:51 +01:00
Continue(Position),
2020-11-20 09:52:28 +01:00
/// `break`
2020-10-29 04:37:51 +01:00
Break(Position),
2020-11-20 09:52:28 +01:00
/// `return`/`throw`
2020-11-14 15:55:23 +01:00
Return((ReturnType, Position), Option<Expr>, Position),
2020-11-20 09:52:28 +01:00
/// `import` expr `as` var
2020-10-29 04:37:51 +01:00
#[cfg(not(feature = "no_module"))]
2020-12-22 09:45:56 +01:00
Import(Expr, Option<Box<Ident>>, Position),
2020-11-20 09:52:28 +01:00
/// `export` var `as` var `,` ...
2020-10-29 04:37:51 +01:00
#[cfg(not(feature = "no_module"))]
2020-12-22 09:45:56 +01:00
Export(Vec<(Ident, Option<Ident>)>, Position),
2020-10-29 04:37:51 +01:00
/// Convert a variable to shared.
#[cfg(not(feature = "no_closure"))]
2020-12-22 09:45:56 +01:00
Share(Ident),
2020-10-29 04:37:51 +01:00
}
impl Default for Stmt {
#[inline(always)]
fn default() -> Self {
2020-11-20 09:52:28 +01:00
Self::Noop(Position::NONE)
2020-10-29 04:37:51 +01:00
}
}
impl Stmt {
2020-11-20 09:52:28 +01:00
/// Is this statement [`Noop`][Stmt::Noop]?
2020-12-29 03:41:20 +01:00
#[inline(always)]
2020-10-29 04:37:51 +01:00
pub fn is_noop(&self) -> bool {
match self {
Self::Noop(_) => true,
_ => false,
}
}
2020-12-26 16:21:16 +01:00
/// Get the [position][Position] of this statement.
2020-10-29 04:37:51 +01:00
pub fn position(&self) -> Position {
match self {
Self::Noop(pos)
| Self::Continue(pos)
| Self::Break(pos)
| Self::Block(_, pos)
| Self::Assignment(_, pos)
2020-11-14 15:55:23 +01:00
| Self::If(_, _, pos)
2020-11-14 16:43:36 +01:00
| Self::Switch(_, _, pos)
2020-10-29 04:37:51 +01:00
| Self::While(_, _, pos)
2020-11-20 15:23:37 +01:00
| Self::Do(_, _, _, pos)
2020-10-29 04:37:51 +01:00
| Self::For(_, _, pos)
2020-11-14 15:55:23 +01:00
| Self::Return((_, pos), _, _)
| Self::Let(_, _, _, pos)
| Self::Const(_, _, _, pos)
| Self::TryCatch(_, pos, _) => *pos,
2020-10-29 04:37:51 +01:00
Self::Expr(x) => x.position(),
#[cfg(not(feature = "no_module"))]
Self::Import(_, _, pos) => *pos,
#[cfg(not(feature = "no_module"))]
Self::Export(_, pos) => *pos,
#[cfg(not(feature = "no_closure"))]
2020-10-31 07:13:45 +01:00
Self::Share(x) => x.pos,
2020-10-29 04:37:51 +01:00
}
}
2020-12-26 16:21:16 +01:00
/// Override the [position][Position] of this statement.
2020-10-29 04:37:51 +01:00
pub fn set_position(&mut self, new_pos: Position) -> &mut Self {
match self {
Self::Noop(pos)
| Self::Continue(pos)
| Self::Break(pos)
| Self::Block(_, pos)
| Self::Assignment(_, pos)
2020-11-14 15:55:23 +01:00
| Self::If(_, _, pos)
2020-11-14 16:43:36 +01:00
| Self::Switch(_, _, pos)
2020-10-29 04:37:51 +01:00
| Self::While(_, _, pos)
2020-11-20 15:23:37 +01:00
| Self::Do(_, _, _, pos)
2020-10-29 04:37:51 +01:00
| Self::For(_, _, pos)
2020-11-14 15:55:23 +01:00
| Self::Return((_, pos), _, _)
| Self::Let(_, _, _, pos)
| Self::Const(_, _, _, pos)
| Self::TryCatch(_, pos, _) => *pos = new_pos,
2020-10-29 04:37:51 +01:00
Self::Expr(x) => {
x.set_position(new_pos);
}
#[cfg(not(feature = "no_module"))]
Self::Import(_, _, pos) => *pos = new_pos,
#[cfg(not(feature = "no_module"))]
Self::Export(_, pos) => *pos = new_pos,
#[cfg(not(feature = "no_closure"))]
2020-10-31 07:13:45 +01:00
Self::Share(x) => x.pos = new_pos,
2020-10-29 04:37:51 +01:00
}
self
}
/// Is this statement self-terminated (i.e. no need for a semicolon terminator)?
pub fn is_self_terminated(&self) -> bool {
match self {
2020-11-14 15:55:23 +01:00
Self::If(_, _, _)
2020-11-14 16:43:36 +01:00
| Self::Switch(_, _, _)
2020-10-29 04:37:51 +01:00
| Self::While(_, _, _)
| Self::For(_, _, _)
| Self::Block(_, _)
2020-11-06 09:27:40 +01:00
| Self::TryCatch(_, _, _) => true,
2020-10-29 04:37:51 +01:00
// A No-op requires a semicolon in order to know it is an empty statement!
Self::Noop(_) => false,
Self::Let(_, _, _, _)
| Self::Const(_, _, _, _)
2020-10-29 04:37:51 +01:00
| Self::Assignment(_, _)
| Self::Expr(_)
2020-11-20 15:23:37 +01:00
| Self::Do(_, _, _, _)
2020-10-29 04:37:51 +01:00
| Self::Continue(_)
| Self::Break(_)
2020-11-14 15:55:23 +01:00
| Self::Return(_, _, _) => false,
2020-10-29 04:37:51 +01:00
#[cfg(not(feature = "no_module"))]
Self::Import(_, _, _) | Self::Export(_, _) => false,
#[cfg(not(feature = "no_closure"))]
Self::Share(_) => unreachable!("Stmt::Share should not be parsed"),
2020-10-29 04:37:51 +01:00
}
}
/// Is this statement _pure_?
2020-11-25 02:36:06 +01:00
///
/// A pure statement has no side effects.
2020-10-29 04:37:51 +01:00
pub fn is_pure(&self) -> bool {
match self {
Self::Noop(_) => true,
Self::Expr(expr) => expr.is_pure(),
2020-11-14 16:43:36 +01:00
Self::If(condition, x, _) => {
condition.is_pure()
&& x.0.is_pure()
&& x.1.as_ref().map(Stmt::is_pure).unwrap_or(true)
}
Self::Switch(expr, x, _) => {
expr.is_pure()
&& x.0.values().all(Stmt::is_pure)
&& x.1.as_ref().map(Stmt::is_pure).unwrap_or(true)
2020-10-29 04:37:51 +01:00
}
2020-11-20 15:23:37 +01:00
Self::While(condition, block, _) | Self::Do(block, condition, _, _) => {
condition.is_pure() && block.is_pure()
}
2020-10-29 04:37:51 +01:00
Self::For(iterable, x, _) => iterable.is_pure() && x.1.is_pure(),
Self::Let(_, _, _, _) | Self::Const(_, _, _, _) | Self::Assignment(_, _) => false,
2020-10-29 04:37:51 +01:00
Self::Block(block, _) => block.iter().all(|stmt| stmt.is_pure()),
2020-11-14 15:55:23 +01:00
Self::Continue(_) | Self::Break(_) | Self::Return(_, _, _) => false,
2020-11-06 09:27:40 +01:00
Self::TryCatch(x, _, _) => x.0.is_pure() && x.2.is_pure(),
2020-10-29 04:37:51 +01:00
#[cfg(not(feature = "no_module"))]
Self::Import(_, _, _) => false,
#[cfg(not(feature = "no_module"))]
Self::Export(_, _) => false,
#[cfg(not(feature = "no_closure"))]
Self::Share(_) => false,
}
}
2021-01-08 17:24:55 +01:00
/// Recursively walk this statement.
#[inline(always)]
2021-01-09 09:52:22 +01:00
pub fn walk<'a>(&'a self, path: &mut Vec<ASTNode<'a>>, on_node: &mut impl FnMut(&[ASTNode])) {
path.push(self.into());
on_node(path);
2021-01-08 17:24:55 +01:00
match self {
2021-01-09 09:52:22 +01:00
Self::Let(_, Some(e), _, _) | Self::Const(_, Some(e), _, _) => e.walk(path, on_node),
2021-01-08 17:24:55 +01:00
Self::If(e, x, _) => {
2021-01-09 09:52:22 +01:00
e.walk(path, on_node);
x.0.walk(path, on_node);
2021-01-08 17:24:55 +01:00
if let Some(ref s) = x.1 {
2021-01-09 09:52:22 +01:00
s.walk(path, on_node);
2021-01-08 17:24:55 +01:00
}
}
Self::Switch(e, x, _) => {
2021-01-09 09:52:22 +01:00
e.walk(path, on_node);
x.0.values().for_each(|s| s.walk(path, on_node));
2021-01-08 17:24:55 +01:00
if let Some(ref s) = x.1 {
2021-01-09 09:52:22 +01:00
s.walk(path, on_node);
2021-01-08 17:24:55 +01:00
}
}
Self::While(e, s, _) | Self::Do(s, e, _, _) => {
2021-01-09 09:52:22 +01:00
e.walk(path, on_node);
s.walk(path, on_node);
2021-01-08 17:24:55 +01:00
}
Self::For(e, x, _) => {
2021-01-09 09:52:22 +01:00
e.walk(path, on_node);
x.1.walk(path, on_node);
2021-01-08 17:24:55 +01:00
}
Self::Assignment(x, _) => {
2021-01-09 09:52:22 +01:00
x.0.walk(path, on_node);
x.2.walk(path, on_node);
2021-01-08 17:24:55 +01:00
}
2021-01-09 09:52:22 +01:00
Self::Block(x, _) => x.iter().for_each(|s| s.walk(path, on_node)),
2021-01-08 17:24:55 +01:00
Self::TryCatch(x, _, _) => {
2021-01-09 09:52:22 +01:00
x.0.walk(path, on_node);
x.2.walk(path, on_node);
2021-01-08 17:24:55 +01:00
}
2021-01-09 09:52:22 +01:00
Self::Expr(e) | Self::Return(_, Some(e), _) => e.walk(path, on_node),
2021-01-08 17:40:44 +01:00
#[cfg(not(feature = "no_module"))]
2021-01-09 09:52:22 +01:00
Self::Import(e, _, _) => e.walk(path, on_node),
2021-01-08 17:24:55 +01:00
_ => (),
}
2021-01-09 09:52:22 +01:00
path.pop().unwrap();
2021-01-08 17:24:55 +01:00
}
2020-10-29 04:37:51 +01:00
}
2021-01-14 12:07:03 +01:00
/// _(INTERNALS)_ A custom syntax expression.
2020-10-29 04:37:51 +01:00
/// Exported under the `internals` feature only.
///
2021-01-16 07:46:03 +01:00
/// # Volatile Data Structure
2020-10-29 04:37:51 +01:00
///
/// This type is volatile and may change.
2021-01-14 12:07:03 +01:00
#[derive(Debug, Clone, Hash)]
2020-10-29 04:37:51 +01:00
pub struct CustomExpr {
/// List of keywords.
2020-12-14 16:05:13 +01:00
pub keywords: StaticVec<Expr>,
/// List of tokens actually parsed.
2020-12-14 16:05:13 +01:00
pub tokens: Vec<ImmutableString>,
2021-01-12 16:52:50 +01:00
/// Delta number of variables in the scope.
pub scope_delta: isize,
2020-10-29 04:37:51 +01:00
}
2020-11-20 09:52:28 +01:00
/// _(INTERNALS)_ A binary expression.
2020-11-06 09:27:40 +01:00
/// Exported under the `internals` feature only.
///
2021-01-16 07:46:03 +01:00
/// # Volatile Data Structure
2020-11-06 09:27:40 +01:00
///
/// This type is volatile and may change.
#[derive(Debug, Clone, Hash)]
2020-10-29 04:37:51 +01:00
pub struct BinaryExpr {
2020-10-31 07:13:45 +01:00
/// LHS expression.
2020-10-29 04:37:51 +01:00
pub lhs: Expr,
2020-10-31 07:13:45 +01:00
/// RHS expression.
2020-10-29 04:37:51 +01:00
pub rhs: Expr,
2020-10-31 07:13:45 +01:00
}
2020-11-20 09:52:28 +01:00
/// _(INTERNALS)_ A function call.
2020-11-06 09:27:40 +01:00
/// Exported under the `internals` feature only.
///
2021-01-16 07:46:03 +01:00
/// # Volatile Data Structure
2020-11-06 09:27:40 +01:00
///
/// This type is volatile and may change.
#[derive(Debug, Clone, Default, Hash)]
2020-11-10 16:26:50 +01:00
pub struct FnCallExpr {
2020-11-02 16:54:19 +01:00
/// Pre-calculated hash for a script-defined function of the same name and number of parameters.
2020-12-24 09:32:43 +01:00
/// None if native Rust only.
pub hash_script: Option<NonZeroU64>,
2020-10-31 07:13:45 +01:00
/// Does this function call capture the parent scope?
pub capture: bool,
2020-11-06 09:27:40 +01:00
/// Namespace of the function, if any. Boxed because it occurs rarely.
2020-12-24 16:22:50 +01:00
pub namespace: Option<NamespaceRef>,
2020-11-02 16:54:19 +01:00
/// Function name.
2020-11-20 09:52:28 +01:00
/// Use [`Cow<'static, str>`][Cow] because a lot of operators (e.g. `==`, `>=`) are implemented as
/// function calls and the function names are predictable, so no need to allocate a new [`String`].
2020-11-02 16:54:19 +01:00
pub name: Cow<'static, str>,
/// List of function call arguments.
pub args: StaticVec<Expr>,
2020-10-29 04:37:51 +01:00
}
/// A type that wraps a [`FLOAT`] and implements [`Hash`].
#[cfg(not(feature = "no_float"))]
2021-02-12 16:07:28 +01:00
#[derive(Clone, Copy, PartialEq, PartialOrd)]
pub struct FloatWrapper(FLOAT);
#[cfg(not(feature = "no_float"))]
impl Hash for FloatWrapper {
2021-01-18 03:56:42 +01:00
fn hash<H: crate::stdlib::hash::Hasher>(&self, state: &mut H) {
self.0.to_le_bytes().hash(state);
}
}
#[cfg(not(feature = "no_float"))]
impl AsRef<FLOAT> for FloatWrapper {
fn as_ref(&self) -> &FLOAT {
&self.0
}
}
#[cfg(not(feature = "no_float"))]
impl AsMut<FLOAT> for FloatWrapper {
fn as_mut(&mut self) -> &mut FLOAT {
&mut self.0
}
}
#[cfg(not(feature = "no_float"))]
2021-01-18 03:56:42 +01:00
impl crate::stdlib::ops::Deref for FloatWrapper {
type Target = FLOAT;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[cfg(not(feature = "no_float"))]
2021-01-18 03:56:42 +01:00
impl crate::stdlib::ops::DerefMut for FloatWrapper {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
#[cfg(not(feature = "no_float"))]
impl fmt::Debug for FloatWrapper {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}
#[cfg(not(feature = "no_float"))]
impl fmt::Display for FloatWrapper {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2021-02-11 14:46:11 +01:00
#[cfg(feature = "no_std")]
use num_traits::Float;
let abs = self.0.abs();
if abs > 10000000000000.0 || abs < 0.0000000000001 {
write!(f, "{:e}", self.0)
} else {
self.0.fmt(f)
}
}
}
#[cfg(not(feature = "no_float"))]
impl From<FLOAT> for FloatWrapper {
fn from(value: FLOAT) -> Self {
Self::new(value)
}
}
2021-02-12 16:07:28 +01:00
#[cfg(not(feature = "no_float"))]
impl FromStr for FloatWrapper {
type Err = <FLOAT as FromStr>::Err;
fn from_str(s: &str) -> Result<Self, Self::Err> {
FLOAT::from_str(s).map(Into::<Self>::into)
}
}
#[cfg(not(feature = "no_float"))]
impl FloatWrapper {
pub const fn new(value: FLOAT) -> Self {
Self(value)
}
}
2020-11-20 09:52:28 +01:00
/// _(INTERNALS)_ An expression sub-tree.
2020-10-29 04:37:51 +01:00
/// Exported under the `internals` feature only.
///
2021-01-16 07:46:03 +01:00
/// # Volatile Data Structure
2020-10-29 04:37:51 +01:00
///
/// This type is volatile and may change.
#[derive(Debug, Clone, Hash)]
2020-10-29 04:37:51 +01:00
pub enum Expr {
2020-11-14 12:04:49 +01:00
/// Dynamic constant.
2020-11-20 09:52:28 +01:00
/// Used to hold either an [`Array`] or [`Map`] literal for quick cloning.
2020-11-14 15:43:56 +01:00
/// All other primitive data types should use the appropriate variants for better speed.
2020-11-14 12:04:49 +01:00
DynamicConstant(Box<Dynamic>, Position),
/// Boolean constant.
BoolConstant(bool, Position),
2020-10-29 04:37:51 +01:00
/// Integer constant.
2020-10-31 07:13:45 +01:00
IntegerConstant(INT, Position),
2020-10-29 04:37:51 +01:00
/// Floating-point constant.
#[cfg(not(feature = "no_float"))]
FloatConstant(FloatWrapper, Position),
2020-10-29 04:37:51 +01:00
/// Character constant.
2020-10-31 07:13:45 +01:00
CharConstant(char, Position),
2020-11-20 09:52:28 +01:00
/// [String][ImmutableString] constant.
2020-11-13 03:43:54 +01:00
StringConstant(ImmutableString, Position),
2020-11-20 09:52:28 +01:00
/// [`FnPtr`] constant.
2020-11-13 03:43:54 +01:00
FnPointer(ImmutableString, Position),
2020-11-13 11:32:18 +01:00
/// [ expr, ... ]
Array(Box<StaticVec<Expr>>, Position),
/// #{ name:expr, ... }
2020-12-22 09:45:56 +01:00
Map(Box<StaticVec<(Ident, Expr)>>, Position),
2020-11-13 11:32:18 +01:00
/// ()
Unit(Position),
2020-12-24 16:22:50 +01:00
/// Variable access - (optional index, optional (hash, modules), variable name)
2020-12-24 09:32:43 +01:00
Variable(
Box<(
Option<NonZeroUsize>,
2020-12-24 16:22:50 +01:00
Option<(NonZeroU64, NamespaceRef)>,
2020-12-24 09:32:43 +01:00
Ident,
)>,
),
2020-11-02 16:54:19 +01:00
/// Property access - (getter, setter), prop
2020-12-25 04:02:29 +01:00
Property(Box<(ImmutableString, ImmutableString, Ident)>),
2020-11-20 09:52:28 +01:00
/// { [statement][Stmt] }
2020-11-04 04:49:02 +01:00
Stmt(Box<StaticVec<Stmt>>, Position),
2020-11-20 09:52:28 +01:00
/// func `(` expr `,` ... `)`
2020-11-10 16:26:50 +01:00
FnCall(Box<FnCallExpr>, Position),
2020-11-20 09:52:28 +01:00
/// lhs `.` rhs
2020-10-31 16:26:21 +01:00
Dot(Box<BinaryExpr>, Position),
2020-11-20 09:52:28 +01:00
/// expr `[` expr `]`
2020-10-31 16:26:21 +01:00
Index(Box<BinaryExpr>, Position),
2020-11-20 09:52:28 +01:00
/// lhs `in` rhs
2020-10-31 16:26:21 +01:00
In(Box<BinaryExpr>, Position),
2020-11-20 09:52:28 +01:00
/// lhs `&&` rhs
2020-10-31 16:26:21 +01:00
And(Box<BinaryExpr>, Position),
2020-11-20 09:52:28 +01:00
/// lhs `||` rhs
2020-10-31 16:26:21 +01:00
Or(Box<BinaryExpr>, Position),
2020-10-29 04:37:51 +01:00
/// Custom syntax
2020-10-31 16:26:21 +01:00
Custom(Box<CustomExpr>, Position),
2020-10-29 04:37:51 +01:00
}
impl Default for Expr {
#[inline(always)]
fn default() -> Self {
2020-11-20 09:52:28 +01:00
Self::Unit(Position::NONE)
2020-10-29 04:37:51 +01:00
}
}
impl Expr {
2020-11-20 09:52:28 +01:00
/// Get the [`Dynamic`] value of a constant expression.
2020-10-29 04:37:51 +01:00
///
2020-11-20 09:52:28 +01:00
/// Returns [`None`] if the expression is not constant.
2020-10-29 04:37:51 +01:00
pub fn get_constant_value(&self) -> Option<Dynamic> {
Some(match self {
2020-11-14 12:04:49 +01:00
Self::DynamicConstant(x, _) => x.as_ref().clone(),
2020-10-31 07:13:45 +01:00
Self::IntegerConstant(x, _) => (*x).into(),
2020-10-29 04:37:51 +01:00
#[cfg(not(feature = "no_float"))]
2020-11-13 11:32:18 +01:00
Self::FloatConstant(x, _) => (*x).into(),
2020-10-31 07:13:45 +01:00
Self::CharConstant(x, _) => (*x).into(),
2020-11-13 03:43:54 +01:00
Self::StringConstant(x, _) => x.clone().into(),
2020-12-08 15:47:38 +01:00
Self::FnPointer(x, _) => Dynamic(Union::FnPtr(
Box::new(FnPtr::new_unchecked(x.clone(), Default::default())),
AccessMode::ReadOnly,
2020-12-08 15:47:38 +01:00
)),
Self::BoolConstant(x, _) => (*x).into(),
2021-01-02 16:30:10 +01:00
Self::Unit(_) => Dynamic::UNIT,
2020-10-29 04:37:51 +01:00
#[cfg(not(feature = "no_index"))]
2020-11-15 05:07:35 +01:00
Self::Array(x, _) if self.is_constant() => {
let mut arr = Array::with_capacity(crate::stdlib::cmp::max(
crate::engine::TYPICAL_ARRAY_SIZE,
x.len(),
));
2020-11-15 05:07:35 +01:00
arr.extend(x.iter().map(|v| v.get_constant_value().unwrap()));
Dynamic(Union::Array(Box::new(arr), AccessMode::ReadOnly))
2020-11-15 05:07:35 +01:00
}
2020-10-29 04:37:51 +01:00
#[cfg(not(feature = "no_object"))]
2020-11-15 05:07:35 +01:00
Self::Map(x, _) if self.is_constant() => {
let mut map = Map::with_capacity(crate::stdlib::cmp::max(
crate::engine::TYPICAL_MAP_SIZE,
x.len(),
));
2020-11-15 05:07:35 +01:00
map.extend(
2020-10-31 16:26:21 +01:00
x.iter()
2020-11-15 05:07:35 +01:00
.map(|(k, v)| (k.name.clone(), v.get_constant_value().unwrap())),
);
Dynamic(Union::Map(Box::new(map), AccessMode::ReadOnly))
2020-10-29 04:37:51 +01:00
}
_ => return None,
})
}
2021-02-03 12:14:26 +01:00
/// Return the variable name if the expression a simple variable access.
2020-12-29 03:41:20 +01:00
#[inline(always)]
2020-10-29 04:37:51 +01:00
pub(crate) fn get_variable_access(&self, non_qualified: bool) -> Option<&str> {
match self {
2020-12-24 16:22:50 +01:00
Self::Variable(x) if !non_qualified || x.1.is_none() => Some((x.2).name.as_str()),
2020-10-29 04:37:51 +01:00
_ => None,
}
}
2020-12-26 16:21:16 +01:00
/// Get the [position][Position] of the expression.
2020-10-29 04:37:51 +01:00
pub fn position(&self) -> Position {
match self {
#[cfg(not(feature = "no_float"))]
2020-10-31 07:13:45 +01:00
Self::FloatConstant(_, pos) => *pos,
2020-10-29 04:37:51 +01:00
2020-11-14 12:04:49 +01:00
Self::DynamicConstant(_, pos) => *pos,
Self::BoolConstant(_, pos) => *pos,
2020-10-31 07:13:45 +01:00
Self::IntegerConstant(_, pos) => *pos,
Self::CharConstant(_, pos) => *pos,
2020-11-13 03:43:54 +01:00
Self::StringConstant(_, pos) => *pos,
Self::FnPointer(_, pos) => *pos,
2020-10-31 16:26:21 +01:00
Self::Array(_, pos) => *pos,
Self::Map(_, pos) => *pos,
2020-12-25 04:02:29 +01:00
Self::Property(x) => (x.2).pos,
2020-10-31 07:13:45 +01:00
Self::Stmt(_, pos) => *pos,
2020-12-24 16:22:50 +01:00
Self::Variable(x) => (x.2).pos,
2020-10-31 16:26:21 +01:00
Self::FnCall(_, pos) => *pos,
2020-10-29 04:37:51 +01:00
2020-10-31 16:26:21 +01:00
Self::And(x, _) | Self::Or(x, _) | Self::In(x, _) => x.lhs.position(),
2020-10-29 04:37:51 +01:00
Self::Unit(pos) => *pos,
2020-10-29 04:37:51 +01:00
2020-10-31 16:26:21 +01:00
Self::Dot(x, _) | Self::Index(x, _) => x.lhs.position(),
2020-10-29 04:37:51 +01:00
2020-10-31 16:26:21 +01:00
Self::Custom(_, pos) => *pos,
2020-10-29 04:37:51 +01:00
}
}
2020-12-26 16:21:16 +01:00
/// Override the [position][Position] of the expression.
2020-10-29 04:37:51 +01:00
pub fn set_position(&mut self, new_pos: Position) -> &mut Self {
match self {
#[cfg(not(feature = "no_float"))]
2020-10-31 07:13:45 +01:00
Self::FloatConstant(_, pos) => *pos = new_pos,
2020-10-29 04:37:51 +01:00
2020-11-14 12:04:49 +01:00
Self::DynamicConstant(_, pos) => *pos = new_pos,
Self::BoolConstant(_, pos) => *pos = new_pos,
2020-10-31 07:13:45 +01:00
Self::IntegerConstant(_, pos) => *pos = new_pos,
Self::CharConstant(_, pos) => *pos = new_pos,
2020-11-13 03:43:54 +01:00
Self::StringConstant(_, pos) => *pos = new_pos,
Self::FnPointer(_, pos) => *pos = new_pos,
2020-10-31 16:26:21 +01:00
Self::Array(_, pos) => *pos = new_pos,
Self::Map(_, pos) => *pos = new_pos,
2020-12-24 16:22:50 +01:00
Self::Variable(x) => (x.2).pos = new_pos,
2020-12-25 04:02:29 +01:00
Self::Property(x) => (x.2).pos = new_pos,
2020-10-31 07:13:45 +01:00
Self::Stmt(_, pos) => *pos = new_pos,
2020-10-31 16:26:21 +01:00
Self::FnCall(_, pos) => *pos = new_pos,
Self::And(_, pos) | Self::Or(_, pos) | Self::In(_, pos) => *pos = new_pos,
Self::Unit(pos) => *pos = new_pos,
2020-10-31 16:26:21 +01:00
Self::Dot(_, pos) | Self::Index(_, pos) => *pos = new_pos,
Self::Custom(_, pos) => *pos = new_pos,
2020-10-29 04:37:51 +01:00
}
self
}
/// Is the expression pure?
///
/// A pure expression has no side effects.
pub fn is_pure(&self) -> bool {
match self {
2020-10-31 16:26:21 +01:00
Self::Array(x, _) => x.iter().all(Self::is_pure),
Self::Map(x, _) => x.iter().map(|(_, v)| v).all(Self::is_pure),
2020-10-29 04:37:51 +01:00
2020-10-31 16:26:21 +01:00
Self::Index(x, _) | Self::And(x, _) | Self::Or(x, _) | Self::In(x, _) => {
2020-10-29 04:37:51 +01:00
x.lhs.is_pure() && x.rhs.is_pure()
}
2020-11-04 04:49:02 +01:00
Self::Stmt(x, _) => x.iter().all(Stmt::is_pure),
2020-10-29 04:37:51 +01:00
Self::Variable(_) => true,
_ => self.is_constant(),
}
}
/// Is the expression the unit `()` literal?
#[inline(always)]
pub fn is_unit(&self) -> bool {
match self {
Self::Unit(_) => true,
_ => false,
}
}
/// Is the expression a constant?
pub fn is_constant(&self) -> bool {
match self {
#[cfg(not(feature = "no_float"))]
2020-10-31 07:13:45 +01:00
Self::FloatConstant(_, _) => true,
2020-10-29 04:37:51 +01:00
2020-11-14 12:04:49 +01:00
Self::DynamicConstant(_, _)
| Self::BoolConstant(_, _)
2020-11-14 12:04:49 +01:00
| Self::IntegerConstant(_, _)
2020-10-31 07:13:45 +01:00
| Self::CharConstant(_, _)
2020-11-13 03:43:54 +01:00
| Self::StringConstant(_, _)
| Self::FnPointer(_, _)
2020-10-29 04:37:51 +01:00
| Self::Unit(_) => true,
// An array literal is constant if all items are constant
2020-10-31 16:26:21 +01:00
Self::Array(x, _) => x.iter().all(Self::is_constant),
2020-10-29 04:37:51 +01:00
// An map literal is constant if all items are constant
2020-10-31 16:26:21 +01:00
Self::Map(x, _) => x.iter().map(|(_, expr)| expr).all(Self::is_constant),
2020-10-29 04:37:51 +01:00
// Check in expression
2020-10-31 16:26:21 +01:00
Self::In(x, _) => match (&x.lhs, &x.rhs) {
2020-11-13 03:43:54 +01:00
(Self::StringConstant(_, _), Self::StringConstant(_, _))
| (Self::CharConstant(_, _), Self::StringConstant(_, _)) => true,
2020-10-29 04:37:51 +01:00
_ => false,
},
_ => false,
}
}
2020-11-25 02:36:06 +01:00
/// Is a particular [token][Token] allowed as a postfix operator to this expression?
2020-10-29 04:37:51 +01:00
pub fn is_valid_postfix(&self, token: &Token) -> bool {
2020-12-27 09:50:48 +01:00
match token {
#[cfg(not(feature = "no_object"))]
Token::Period => return true,
_ => (),
}
2020-10-29 04:37:51 +01:00
match self {
#[cfg(not(feature = "no_float"))]
2020-10-31 07:13:45 +01:00
Self::FloatConstant(_, _) => false,
2020-10-29 04:37:51 +01:00
2020-11-14 12:04:49 +01:00
Self::DynamicConstant(_, _)
| Self::BoolConstant(_, _)
2020-11-14 12:04:49 +01:00
| Self::IntegerConstant(_, _)
2020-10-31 07:13:45 +01:00
| Self::CharConstant(_, _)
2020-11-13 03:43:54 +01:00
| Self::FnPointer(_, _)
2020-10-31 16:26:21 +01:00
| Self::In(_, _)
| Self::And(_, _)
| Self::Or(_, _)
2020-10-29 04:37:51 +01:00
| Self::Unit(_) => false,
2020-11-13 03:43:54 +01:00
Self::StringConstant(_, _)
2020-10-31 16:26:21 +01:00
| Self::FnCall(_, _)
2020-12-27 09:50:48 +01:00
| Self::Stmt(_, _)
2020-10-31 16:26:21 +01:00
| Self::Dot(_, _)
| Self::Index(_, _)
| Self::Array(_, _)
| Self::Map(_, _) => match token {
2020-10-29 04:37:51 +01:00
#[cfg(not(feature = "no_index"))]
Token::LeftBracket => true,
_ => false,
},
Self::Variable(_) => match token {
#[cfg(not(feature = "no_index"))]
Token::LeftBracket => true,
Token::LeftParen => true,
Token::Bang => true,
Token::DoubleColon => true,
_ => false,
},
Self::Property(_) => match token {
#[cfg(not(feature = "no_index"))]
Token::LeftBracket => true,
Token::LeftParen => true,
_ => false,
},
2020-10-31 16:26:21 +01:00
Self::Custom(_, _) => false,
2020-10-29 04:37:51 +01:00
}
}
2021-01-08 17:24:55 +01:00
/// Recursively walk this expression.
#[inline(always)]
2021-01-09 09:52:22 +01:00
pub fn walk<'a>(&'a self, path: &mut Vec<ASTNode<'a>>, on_node: &mut impl FnMut(&[ASTNode])) {
path.push(self.into());
on_node(path);
2021-01-08 17:24:55 +01:00
match self {
2021-01-09 09:52:22 +01:00
Self::Stmt(x, _) => x.iter().for_each(|s| s.walk(path, on_node)),
Self::Array(x, _) => x.iter().for_each(|e| e.walk(path, on_node)),
Self::Map(x, _) => x.iter().for_each(|(_, e)| e.walk(path, on_node)),
2021-02-10 18:47:09 +01:00
Self::Index(x, _)
| Self::Dot(x, _)
| Expr::In(x, _)
| Expr::And(x, _)
| Expr::Or(x, _) => {
2021-01-09 09:52:22 +01:00
x.lhs.walk(path, on_node);
x.rhs.walk(path, on_node);
2021-01-08 17:24:55 +01:00
}
2021-02-10 18:47:09 +01:00
Self::FnCall(x, _) => x.args.iter().for_each(|e| e.walk(path, on_node)),
2021-01-09 09:52:22 +01:00
Self::Custom(x, _) => x.keywords.iter().for_each(|e| e.walk(path, on_node)),
2021-01-08 17:24:55 +01:00
_ => (),
}
2021-01-09 09:52:22 +01:00
path.pop().unwrap();
2021-01-08 17:24:55 +01:00
}
2020-10-29 04:37:51 +01:00
}
2020-11-04 05:34:54 +01:00
#[cfg(test)]
mod tests {
/// This test is to make sure no code changes increase the sizes of critical data structures.
#[test]
fn check_struct_sizes() {
use crate::stdlib::mem::size_of;
use crate::*;
assert_eq!(size_of::<Dynamic>(), 16);
assert_eq!(size_of::<Option<Dynamic>>(), 16);
assert_eq!(size_of::<Position>(), 4);
assert_eq!(size_of::<ast::Expr>(), 16);
assert_eq!(size_of::<Option<ast::Expr>>(), 16);
assert_eq!(size_of::<ast::Stmt>(), 32);
assert_eq!(size_of::<Option<ast::Stmt>>(), 32);
assert_eq!(size_of::<FnPtr>(), 32);
assert_eq!(size_of::<Scope>(), 48);
assert_eq!(size_of::<LexError>(), 56);
assert_eq!(size_of::<ParseError>(), 16);
assert_eq!(size_of::<EvalAltResult>(), 72);
2020-11-04 05:34:54 +01:00
}
}