rhai/src/ast.rs

2488 lines
78 KiB
Rust
Raw Normal View History

2020-10-28 15:18:44 +01:00
//! Module defining the AST (abstract syntax tree).
2021-06-16 12:36:33 +02:00
use crate::calc_fn_hash;
use crate::dynamic::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;
2021-04-17 09:15:54 +02:00
use crate::token::Token;
use crate::{
2021-04-20 17:40:52 +02:00
Dynamic, FnNamespace, Identifier, ImmutableString, Module, Position, Shared, StaticVec, INT,
2021-04-17 09:15:54 +02:00
};
#[cfg(feature = "no_std")]
use std::prelude::v1::*;
use std::{
2021-03-29 07:07:10 +02:00
collections::BTreeMap,
2020-10-29 04:37:51 +01:00
fmt,
2021-01-18 03:56:42 +01:00
hash::Hash,
2021-05-05 12:38:52 +02:00
mem,
2021-04-05 17:06:48 +02:00
num::{NonZeroU8, NonZeroUsize},
2021-09-12 07:21:53 +02:00
ops::{
Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, Deref, DerefMut, Not, Sub,
SubAssign,
},
2020-11-17 05:23:53 +01:00
};
2020-11-16 16:10:14 +01:00
#[cfg(not(feature = "no_float"))]
2021-04-17 09:15:54 +02:00
use std::str::FromStr;
#[cfg(not(feature = "no_float"))]
use crate::FLOAT;
2020-11-16 16:10:14 +01:00
2021-04-06 17:18:41 +02:00
#[cfg(not(feature = "no_float"))]
use num_traits::Float;
2020-11-16 16:10:14 +01:00
#[cfg(not(feature = "no_index"))]
use crate::Array;
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,
}
2021-07-25 16:56:05 +02: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.
2021-03-10 15:12:48 +01:00
pub body: StmtBlock,
2020-11-04 05:34:54 +01:00
/// Encapsulated running environment, if any.
pub lib: Option<Shared<Module>>,
2020-11-09 14:52:23 +01:00
/// Encapsulated imported modules.
2021-05-10 05:07:19 +02:00
///
/// Not available under `no_module`.
2020-11-09 14:52:23 +01:00
#[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.
2021-03-29 05:36:02 +02:00
pub name: Identifier,
2020-10-29 04:37:51 +01:00
/// Function access mode.
pub access: FnAccess,
/// Names of function parameters.
2021-03-29 05:36:02 +02:00
pub params: StaticVec<Identifier>,
2020-11-09 14:52:23 +01:00
/// Access to external variables.
2021-05-10 05:07:19 +02:00
///
/// Not available under `no_closure`.
2020-10-29 04:37:51 +01:00
#[cfg(not(feature = "no_closure"))]
2021-04-17 09:15:54 +02:00
pub externals: std::collections::BTreeSet<Identifier>,
2021-07-25 16:56:05 +02:00
/// _(metadata)_ Function doc-comments (if any).
2021-05-10 05:07:19 +02:00
/// Exported under the `metadata` feature only.
///
/// Not available under `no_function`.
2021-04-09 16:49:47 +02:00
#[cfg(not(feature = "no_function"))]
#[cfg(feature = "metadata")]
2021-04-20 13:19:35 +02:00
pub comments: StaticVec<String>,
2020-10-29 04:37:51 +01:00
}
impl fmt::Display for ScriptFnDef {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
2020-12-28 02:49:54 +01:00
"{}{}({})",
match self.access {
FnAccess::Public => "",
2021-03-15 14:30:55 +01:00
FnAccess::Private => "private ",
2020-10-29 04:37:51 +01:00
},
self.name,
self.params
.iter()
.map(|s| s.as_str())
2021-06-06 06:17:04 +02:00
.collect::<StaticVec<_>>()
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.
///
/// Not available under `no_function`.
///
/// Created by [`AST::iter_functions`].
2021-03-07 15:10:54 +01:00
#[cfg(not(feature = "no_function"))]
#[derive(Debug, Eq, PartialEq, Clone, Hash)]
pub struct ScriptFnMetadata<'a> {
2021-07-25 16:56:05 +02:00
/// _(metadata)_ Function doc-comments (if any).
2021-05-10 05:07:19 +02:00
/// Exported under the `metadata` feature only.
///
/// Not available under `no_function`.
///
/// 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 `/**`.
2021-04-09 16:49:47 +02:00
#[cfg(not(feature = "no_function"))]
#[cfg(feature = "metadata")]
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
}
2021-03-07 15:10:54 +01:00
#[cfg(not(feature = "no_function"))]
impl fmt::Display for ScriptFnMetadata<'_> {
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
"{}{}({})",
match self.access {
FnAccess::Public => "",
2021-03-15 14:30:55 +01:00
FnAccess::Private => "private ",
2020-12-12 11:44:28 +01:00
},
self.name,
2021-06-06 06:17:04 +02:00
self.params
.iter()
.cloned()
.collect::<StaticVec<_>>()
.join(", ")
2020-12-12 11:44:28 +01:00
)
}
}
2021-03-07 15:10:54 +01:00
#[cfg(not(feature = "no_function"))]
2021-07-24 08:11:16 +02:00
impl<'a> From<&'a ScriptFnDef> for ScriptFnMetadata<'a> {
#[inline]
2021-07-24 08:11:16 +02:00
fn from(value: &'a ScriptFnDef) -> Self {
Self {
2021-04-09 16:49:47 +02:00
#[cfg(not(feature = "no_function"))]
#[cfg(feature = "metadata")]
2021-07-24 08:23:14 +02:00
comments: value.comments.iter().map(|s| s.as_str()).collect(),
2021-07-24 08:11:16 +02:00
access: value.access,
name: &value.name,
params: value.params.iter().map(|s| s.as_str()).collect(),
2020-12-12 11:44:28 +01:00
}
}
}
#[cfg(not(feature = "no_function"))]
impl std::cmp::PartialOrd for ScriptFnMetadata<'_> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
#[cfg(not(feature = "no_function"))]
impl std::cmp::Ord for ScriptFnMetadata<'_> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
match self.name.cmp(other.name) {
std::cmp::Ordering::Equal => self.params.len().cmp(&other.params.len()),
cmp => cmp,
}
}
}
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`].
2021-03-29 05:36:02 +02:00
source: Option<Identifier>,
2020-10-28 15:18:44 +01:00
/// Global statements.
body: StmtBlock,
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-05-10 05:07:19 +02:00
///
/// Not available under `no_module`.
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 {
2021-09-12 07:21:53 +02:00
Self::empty()
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`].
#[inline]
2021-06-12 16:47:43 +02:00
#[must_use]
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,
body: StmtBlock::new(statements, Position::NONE),
2020-12-12 08:57:55 +01:00
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,
2021-09-11 13:40:40 +02:00
}
}
/// Create an empty [`AST`].
#[inline]
#[must_use]
pub fn empty() -> Self {
2021-09-11 13:40:40 +02:00
Self {
source: None,
body: StmtBlock::empty(),
functions: Module::new().into(),
2021-09-11 13:40:40 +02:00
#[cfg(not(feature = "no_module"))]
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)]
2021-06-12 16:47:43 +02:00
#[must_use]
2020-12-21 15:04:46 +01:00
pub fn new_with_source(
statements: impl IntoIterator<Item = Stmt>,
functions: impl Into<Shared<Module>>,
2021-03-29 05:36:02 +02:00
source: impl Into<Identifier>,
2020-12-21 15:04:46 +01:00
) -> Self {
Self {
source: Some(source.into()),
body: StmtBlock::new(statements, Position::NONE),
2020-12-21 15:04:46 +01:00
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)]
2021-06-12 16:47:43 +02:00
#[must_use]
2020-12-21 15:04:46 +01:00
pub fn source(&self) -> Option<&str> {
self.source.as_ref().map(|s| s.as_str())
}
/// Get a reference to the source.
2020-12-29 03:41:20 +01:00
#[inline(always)]
2021-06-12 16:47:43 +02:00
#[must_use]
pub(crate) fn source_raw(&self) -> Option<&Identifier> {
self.source.as_ref()
2020-12-21 15:04:46 +01:00
}
/// Set the source.
#[inline]
2021-03-29 05:36:02 +02:00
pub fn set_source(&mut self, source: impl Into<Identifier>) -> &mut Self {
let source = source.into();
2021-05-25 04:54:48 +02:00
Shared::get_mut(&mut self.functions)
.as_mut()
.map(|m| m.set_id(source.clone()));
self.source = Some(source);
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)]
2021-06-12 16:47:43 +02:00
#[must_use]
2020-10-28 15:18:44 +01:00
pub(crate) fn statements(&self) -> &[Stmt] {
2021-04-16 06:04:33 +02:00
&self.body.0
2020-10-28 15:18:44 +01:00
}
2021-07-25 16:56:05 +02: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)]
2021-06-12 16:47:43 +02:00
#[must_use]
2020-10-28 15:18:44 +01:00
pub fn statements(&self) -> &[Stmt] {
2021-04-16 07:15:11 +02:00
&self.body.0
2020-10-28 15:18:44 +01:00
}
/// Get a mutable reference to the statements.
#[cfg(not(feature = "no_optimize"))]
#[inline(always)]
2021-06-12 16:47:43 +02:00
#[must_use]
pub(crate) fn statements_mut(&mut self) -> &mut StaticVec<Stmt> {
2021-04-16 06:04:33 +02:00
&mut self.body.0
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)]
2021-06-12 16:47:43 +02:00
#[must_use]
pub(crate) fn shared_lib(&self) -> Shared<Module> {
2020-12-12 08:57:55 +01:00
self.functions.clone()
}
2021-07-25 16:56:05 +02:00
/// _(internals)_ Get the internal shared [`Module`] containing all script-defined functions.
2021-01-16 07:46:03 +01:00
/// Exported under the `internals` feature only.
///
2021-05-10 05:07:19 +02:00
/// Not available under `no_function` or `no_module`.
#[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)]
2021-06-12 16:47:43 +02:00
#[must_use]
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)]
2021-06-12 16:47:43 +02:00
#[must_use]
2020-10-28 15:18:44 +01:00
pub(crate) fn lib(&self) -> &Module {
2020-12-12 08:57:55 +01:00
&self.functions
2020-10-28 15:18:44 +01:00
}
2021-07-25 16:56:05 +02: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.
///
/// Not available under `no_function`.
2020-10-28 15:18:44 +01:00
#[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)]
2021-06-12 16:47:43 +02:00
#[must_use]
2020-10-28 15:18:44 +01:00
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-06-12 16:47:43 +02:00
#[must_use]
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-07-25 16:56:05 +02:00
/// _(internals)_ Get the embedded [module resolver][crate::ModuleResolver].
2021-01-08 17:24:55 +01:00
/// Exported under the `internals` feature only.
2021-05-10 05:07:19 +02:00
///
/// Not available under `no_module`.
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-06-12 16:47:43 +02:00
#[must_use]
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.
///
/// Not available under `no_function`.
2020-10-28 15:18:44 +01:00
///
/// This operation is cheap because functions are shared.
2020-10-29 04:37:51 +01:00
#[cfg(not(feature = "no_function"))]
2020-10-28 15:18:44 +01:00
#[inline(always)]
2021-06-12 16:47:43 +02:00
#[must_use]
2020-10-28 15:18:44 +01:00
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.
///
/// Not available under `no_function`.
2020-10-28 15:18:44 +01:00
///
/// This operation is cheap because functions are shared.
2020-10-29 04:37:51 +01:00
#[cfg(not(feature = "no_function"))]
#[inline]
2021-06-12 16:47:43 +02:00
#[must_use]
2020-10-28 15:18:44 +01:00
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::new();
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(),
body: StmtBlock::empty(),
2020-12-12 08:57:55 +01:00
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)]
2021-06-12 16:47:43 +02:00
#[must_use]
2020-10-28 15:18:44 +01:00
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(),
body: self.body.clone(),
functions: Module::new().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
}
/// Merge two [`AST`] into one. Both [`AST`]'s are untouched and a new, merged,
/// version is returned.
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();
///
2021-06-05 09:26:43 +02:00
/// let ast1 = engine.compile("
/// fn foo(x) { 42 + x }
/// foo(1)
/// ")?;
2020-10-28 15:18:44 +01:00
///
/// let ast2 = engine.compile(r#"
2021-06-05 09:26:43 +02:00
/// fn foo(n) { `hello${n}` }
/// foo("!")
/// "#)?;
2020-10-28 15:18:44 +01:00
///
/// let ast = ast1.merge(&ast2); // Merge 'ast2' into 'ast1'
///
/// // Notice that using the '+' operator also works:
/// // let ast = &ast1 + &ast2;
///
/// // 'ast' is essentially:
/// //
2021-04-04 17:22:45 +02:00
/// // fn foo(n) { `hello${n}` } // <- definition of first 'foo' is overwritten
2020-10-28 15:18:44 +01:00
/// // 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)]
2021-06-12 16:47:43 +02:00
#[must_use]
2020-10-28 15:18:44 +01:00
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();
///
2021-06-05 09:26:43 +02:00
/// let mut ast1 = engine.compile("
/// fn foo(x) { 42 + x }
/// foo(1)
/// ")?;
2020-10-28 15:18:44 +01:00
///
/// let ast2 = engine.compile(r#"
2021-06-05 09:26:43 +02:00
/// fn foo(n) { `hello${n}` }
/// foo("!")
/// "#)?;
2020-10-28 15:18:44 +01:00
///
/// ast1.combine(ast2); // Combine 'ast2' into 'ast1'
///
/// // Notice that using the '+=' operator also works:
/// // ast1 += ast2;
///
/// // 'ast1' is essentially:
/// //
2021-04-04 17:22:45 +02:00
/// // fn foo(n) { `hello${n}` } // <- definition of first 'foo' is overwritten
2020-10-28 15:18:44 +01:00
/// // 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();
///
2021-06-05 09:26:43 +02:00
/// let ast1 = engine.compile("
/// fn foo(x) { 42 + x }
/// foo(1)
/// ")?;
2020-10-28 15:18:44 +01:00
///
/// let ast2 = engine.compile(r#"
2021-06-05 09:26:43 +02:00
/// fn foo(n) { `hello${n}` }
/// fn error() { 0 }
/// foo("!")
/// "#)?;
2020-10-28 15:18:44 +01:00
///
/// // 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]
2021-06-12 16:47:43 +02:00
#[must_use]
2020-10-28 15:18:44 +01:00
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 {
body, functions, ..
2020-12-12 08:57:55 +01:00
} = self;
2020-10-28 15:18:44 +01:00
let merged = match (body.is_empty(), other.body.is_empty()) {
2020-10-28 15:18:44 +01:00
(false, false) => {
let mut body = body.clone();
2021-04-16 06:04:33 +02:00
body.0.extend(other.body.0.iter().cloned());
body
2020-10-28 15:18:44 +01:00
}
(false, true) => body.clone(),
(true, false) => other.body.clone(),
(true, true) => StmtBlock::empty(),
2020-10-28 15:18:44 +01:00
};
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 {
2021-04-16 06:04:33 +02:00
Self::new_with_source(merged.0, functions, source)
2020-12-21 15:04:46 +01:00
} else {
2021-04-16 06:04:33 +02:00
Self::new(merged.0, functions)
2020-12-21 15:04:46 +01:00
}
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();
///
2021-06-05 09:26:43 +02:00
/// let mut ast1 = engine.compile("
/// fn foo(x) { 42 + x }
/// foo(1)
/// ")?;
2020-10-28 15:18:44 +01:00
///
/// let ast2 = engine.compile(r#"
2021-06-05 09:26:43 +02:00
/// fn foo(n) { `hello${n}` }
/// fn error() { 0 }
/// foo("!")
/// "#)?;
2020-10-28 15:18:44 +01:00
///
/// // 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]
2020-10-28 15:18:44 +01:00
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 {
2021-04-16 06:04:33 +02:00
self.body.0.extend(other.body.0.into_iter());
2020-12-12 08:57:55 +01:00
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#"
2021-06-05 09:26:43 +02:00
/// fn foo(n) { n + 1 }
/// fn bar() { print("hello"); }
/// "#)?;
2020-10-28 15:18:44 +01:00
///
/// // 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]
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-10-29 11:01:29 +02:00
#[allow(dead_code)]
#[inline]
2021-01-08 17:24:55 +01:00
pub(crate) fn iter_fn_def(&self) -> impl Iterator<Item = &ScriptFnDef> {
self.functions
.iter_script_fn()
2021-03-12 07:11:08 +01:00
.map(|(_, _, _, _, fn_def)| fn_def.as_ref())
2021-01-08 17:24:55 +01:00
}
/// 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]
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()
2021-03-12 07:11:08 +01:00
.map(|(_, _, _, _, fn_def)| fn_def.as_ref().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)]
2021-06-12 16:47:43 +02:00
pub fn clear_functions(&mut self) -> &mut Self {
self.functions = Module::new().into();
2021-06-12 16:47:43 +02:00
self
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)]
2021-06-12 16:47:43 +02:00
pub fn clear_statements(&mut self) -> &mut Self {
self.body = StmtBlock::empty();
2021-06-12 16:47:43 +02:00
self
2020-10-28 15:18:44 +01:00
}
2021-11-09 06:22:45 +01:00
/// 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
///
/// ```
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
/// 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()));
///
2021-11-09 08:42:17 +01:00
/// # #[cfg(not(feature = "no_optimize"))]
2021-11-09 06:22:45 +01:00
/// 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()));
///
2021-11-09 08:42:17 +01:00
/// # #[cfg(not(feature = "no_optimize"))]
2021-11-09 06:22:45 +01:00
/// 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(())
/// # }
/// ```
pub fn iter_literal_variables(
&self,
include_constants: bool,
include_variables: bool,
) -> impl Iterator<Item = (&str, bool, Dynamic)> {
self.statements().iter().filter_map(move |stmt| match stmt {
Stmt::Var(expr, name, options, _)
if options.contains(AST_OPTION_FLAGS::AST_OPTION_CONSTANT) && include_constants
|| !options.contains(AST_OPTION_FLAGS::AST_OPTION_CONSTANT)
&& include_variables =>
{
if let Some(value) = expr.get_literal_value() {
Some((
name.as_str(),
options.contains(AST_OPTION_FLAGS::AST_OPTION_CONSTANT),
value,
))
} else {
None
}
}
_ => None,
})
}
2021-01-09 09:52:22 +01:00
/// Recursively walk the [`AST`], including function bodies (if any).
2021-03-11 14:55:55 +01:00
/// Return `false` from the callback to terminate the walk.
2021-01-09 09:52:22 +01:00
#[cfg(not(feature = "internals"))]
2021-01-09 10:06:01 +01:00
#[cfg(not(feature = "no_module"))]
#[inline]
2021-03-11 14:55:55 +01:00
pub(crate) fn walk(&self, on_node: &mut impl FnMut(&[ASTNode]) -> bool) -> bool {
let path = &mut Vec::new();
2021-03-11 14:55:55 +01:00
for stmt in self.statements() {
if !stmt.walk(path, on_node) {
return false;
}
}
#[cfg(not(feature = "no_function"))]
2021-04-16 06:04:33 +02:00
for stmt in self.iter_fn_def().flat_map(|f| f.body.0.iter()) {
2021-03-11 14:55:55 +01:00
if !stmt.walk(path, on_node) {
return false;
}
}
true
2021-01-09 09:52:22 +01:00
}
2021-07-25 16:56:05 +02:00
/// _(internals)_ Recursively walk the [`AST`], including function bodies (if any).
2021-03-11 14:55:55 +01:00
/// Return `false` from the callback to terminate the walk.
2021-01-09 09:52:22 +01:00
/// Exported under the `internals` feature only.
#[cfg(feature = "internals")]
#[inline]
2021-03-11 15:27:35 +01:00
pub fn walk(&self, on_node: &mut impl FnMut(&[ASTNode]) -> bool) -> bool {
let path = &mut Vec::new();
2021-03-11 15:27:35 +01:00
for stmt in self.statements() {
if !stmt.walk(path, on_node) {
return false;
}
}
#[cfg(not(feature = "no_function"))]
2021-04-16 07:15:11 +02:00
for stmt in self.iter_fn_def().flat_map(|f| f.body.0.iter()) {
2021-03-11 15:27:35 +01:00
if !stmt.walk(path, on_node) {
return false;
}
}
true
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
2021-07-25 16:56:05 +02:00
/// _(internals)_ An identifier containing a name and a [position][Position].
2020-11-25 02:36:06 +01:00
/// 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.
2021-03-29 05:36:02 +02:00
pub name: Identifier,
2021-11-09 06:22:45 +01:00
/// 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 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2021-04-22 17:02:25 +02:00
write!(f, "{:?}", self.name)?;
2021-04-23 08:24:53 +02:00
self.pos.debug_print(f)
2020-12-28 02:49:54 +01:00
}
}
2021-11-09 06:22:45 +01:00
impl AsRef<str> for Ident {
#[inline(always)]
fn as_ref(&self) -> &str {
self.name.as_ref()
}
}
impl Ident {
#[inline(always)]
pub fn as_str(&self) -> &str {
self.name.as_str()
}
}
2021-07-25 16:56:05 +02:00
/// _(internals)_ An [`AST`] node, consisting of either an [`Expr`] or a [`Stmt`].
2021-01-09 09:52:22 +01:00
/// 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> {
/// A statement ([`Stmt`]).
2021-01-09 09:52:22 +01:00
Stmt(&'a Stmt),
/// An expression ([`Expr`]).
2021-01-09 09:52:22 +01:00
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)
}
}
2021-09-03 14:47:45 +02:00
impl ASTNode<'_> {
/// Get the [`Position`] of this [`ASTNode`].
pub const fn position(&self) -> Position {
match self {
ASTNode::Stmt(stmt) => stmt.position(),
ASTNode::Expr(expr) => expr.position(),
}
}
}
/// _(internals)_ A scoped block of statements.
2021-03-10 05:27:10 +01:00
/// Exported under the `internals` feature only.
///
/// # Volatile Data Structure
///
/// This type is volatile and may change.
#[derive(Clone, Hash, Default)]
2021-04-16 07:15:11 +02:00
pub struct StmtBlock(StaticVec<Stmt>, Position);
2021-03-10 05:27:10 +01:00
impl StmtBlock {
2021-04-16 07:15:11 +02:00
/// Create a new [`StmtBlock`].
2021-06-12 16:47:43 +02:00
#[must_use]
pub fn new(statements: impl IntoIterator<Item = Stmt>, pos: Position) -> Self {
let mut statements: StaticVec<_> = statements.into_iter().collect();
2021-05-05 12:38:52 +02:00
statements.shrink_to_fit();
Self(statements, pos)
2021-04-16 07:15:11 +02:00
}
/// Create an empty [`StmtBlock`].
#[inline(always)]
#[must_use]
pub fn empty() -> Self {
Default::default()
}
2021-03-10 05:27:10 +01:00
/// Is this statements block empty?
#[inline(always)]
2021-06-12 16:47:43 +02:00
#[must_use]
2021-03-10 05:27:10 +01:00
pub fn is_empty(&self) -> bool {
2021-04-16 06:04:33 +02:00
self.0.is_empty()
2021-03-10 05:27:10 +01:00
}
/// Number of statements in this statements block.
#[inline(always)]
2021-06-12 16:47:43 +02:00
#[must_use]
2021-03-10 05:27:10 +01:00
pub fn len(&self) -> usize {
2021-04-16 06:04:33 +02:00
self.0.len()
2021-03-10 05:27:10 +01:00
}
/// Get the position (location of the beginning `{`) of this statements block.
2021-06-12 16:47:43 +02:00
#[inline(always)]
#[must_use]
2021-06-28 12:06:05 +02:00
pub const fn position(&self) -> Position {
2021-04-16 07:15:11 +02:00
self.1
}
}
impl Deref for StmtBlock {
type Target = StaticVec<Stmt>;
2021-06-12 16:47:43 +02:00
#[inline(always)]
2021-04-16 07:15:11 +02:00
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for StmtBlock {
2021-06-12 16:47:43 +02:00
#[inline(always)]
2021-04-16 07:15:11 +02:00
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
2021-03-10 05:27:10 +01:00
}
impl fmt::Debug for StmtBlock {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2021-05-22 13:14:24 +02:00
f.write_str("Block")?;
2021-04-16 06:04:33 +02:00
fmt::Debug::fmt(&self.0, f)?;
2021-04-23 08:24:53 +02:00
self.1.debug_print(f)
}
}
2021-04-16 07:15:11 +02:00
impl From<StmtBlock> for Stmt {
#[inline]
2021-04-16 07:15:11 +02:00
fn from(block: StmtBlock) -> Self {
let block_pos = block.position();
2021-05-05 12:38:52 +02:00
Self::Block(block.0.into_boxed_slice(), block_pos)
2021-04-16 07:15:11 +02:00
}
}
/// A type that holds a configuration option with bit-flags.
/// Exported under the `internals` feature only.
#[derive(PartialEq, Eq, Copy, Clone, Hash, Default)]
pub struct OptionFlags(u8);
impl OptionFlags {
2021-09-12 07:21:53 +02:00
/// Does this [`OptionFlags`] contain a particular option flag?
#[inline(always)]
#[must_use]
pub const fn contains(self, flag: Self) -> bool {
self.0 & flag.0 != 0
}
}
impl Not for OptionFlags {
type Output = Self;
2021-09-12 07:21:53 +02:00
/// Return the negation of the [`OptionFlags`].
#[inline(always)]
fn not(self) -> Self::Output {
2021-09-12 07:21:53 +02:00
Self(!self.0) & AST_OPTION_FLAGS::AST_OPTION_ALL
}
}
impl Add for OptionFlags {
type Output = Self;
2021-09-12 07:21:53 +02:00
/// Return the union of two [`OptionFlags`].
#[inline(always)]
fn add(self, rhs: Self) -> Self::Output {
Self(self.0 | rhs.0)
}
}
impl AddAssign for OptionFlags {
2021-09-12 07:21:53 +02:00
/// Add the option flags in one [`OptionFlags`] to another.
#[inline(always)]
fn add_assign(&mut self, rhs: Self) {
self.0 |= rhs.0
}
}
2021-09-12 07:21:53 +02:00
impl BitOr for OptionFlags {
type Output = Self;
/// Return the union of two [`OptionFlags`].
#[inline(always)]
fn bitor(self, rhs: Self) -> Self::Output {
Self(self.0 | rhs.0)
}
}
impl BitOrAssign for OptionFlags {
/// Add the option flags in one [`OptionFlags`] to another.
#[inline(always)]
fn bitor_assign(&mut self, rhs: Self) {
self.0 |= rhs.0
}
}
impl Sub for OptionFlags {
type Output = Self;
2021-09-12 07:21:53 +02:00
/// Return the difference of two [`OptionFlags`].
#[inline(always)]
fn sub(self, rhs: Self) -> Self::Output {
Self(self.0 & !rhs.0)
}
}
impl SubAssign for OptionFlags {
2021-09-12 07:21:53 +02:00
/// Remove the option flags in one [`OptionFlags`] from another.
#[inline(always)]
fn sub_assign(&mut self, rhs: Self) {
self.0 &= !rhs.0
}
}
2021-09-12 07:21:53 +02:00
impl BitAnd for OptionFlags {
type Output = Self;
/// Return the intersection of two [`OptionFlags`].
#[inline(always)]
fn bitand(self, rhs: Self) -> Self::Output {
Self(self.0 & !rhs.0)
}
}
impl BitAndAssign for OptionFlags {
/// Keep only the intersection of one [`OptionFlags`] with another.
#[inline(always)]
fn bitand_assign(&mut self, rhs: Self) {
self.0 &= !rhs.0
}
}
/// Option bit-flags for [`AST`] nodes.
#[allow(non_snake_case)]
pub mod AST_OPTION_FLAGS {
use super::OptionFlags;
/// _(internals)_ No options for the [`AST`][crate::AST] node.
/// Exported under the `internals` feature only.
pub const AST_OPTION_NONE: OptionFlags = OptionFlags(0b0000_0000);
/// _(internals)_ The [`AST`][crate::AST] node is constant.
/// Exported under the `internals` feature only.
pub const AST_OPTION_CONSTANT: OptionFlags = OptionFlags(0b0000_0001);
/// _(internals)_ The [`AST`][crate::AST] node is public.
/// Exported under the `internals` feature only.
pub const AST_OPTION_PUBLIC: OptionFlags = OptionFlags(0b0000_0010);
/// _(internals)_ The [`AST`][crate::AST] node is in negated mode.
/// Exported under the `internals` feature only.
pub const AST_OPTION_NEGATED: OptionFlags = OptionFlags(0b0000_0100);
/// _(internals)_ The [`AST`][crate::AST] node breaks out of normal control flow.
/// Exported under the `internals` feature only.
pub const AST_OPTION_BREAK_OUT: OptionFlags = OptionFlags(0b0000_1000);
2021-09-12 07:21:53 +02:00
/// _(internals)_ Mask of all options.
/// Exported under the `internals` feature only.
pub(crate) const AST_OPTION_ALL: OptionFlags = OptionFlags(
AST_OPTION_CONSTANT.0 | AST_OPTION_PUBLIC.0 | AST_OPTION_NEGATED.0 | AST_OPTION_BREAK_OUT.0,
);
impl std::fmt::Debug for OptionFlags {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fn write_option(
options: &OptionFlags,
f: &mut std::fmt::Formatter<'_>,
num_flags: &mut usize,
flag: OptionFlags,
name: &str,
) -> std::fmt::Result {
if options.contains(flag) {
if *num_flags > 0 {
f.write_str("+")?;
}
f.write_str(name)?;
*num_flags += 1;
}
Ok(())
}
let num_flags = &mut 0;
f.write_str("(")?;
write_option(self, f, num_flags, AST_OPTION_CONSTANT, "Constant")?;
write_option(self, f, num_flags, AST_OPTION_PUBLIC, "Public")?;
write_option(self, f, num_flags, AST_OPTION_NEGATED, "Negated")?;
write_option(self, f, num_flags, AST_OPTION_BREAK_OUT, "Break")?;
f.write_str(")")?;
Ok(())
}
}
}
2021-07-25 16:56:05 +02: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 `}`
2021-03-10 05:27:10 +01:00
If(Expr, Box<(StmtBlock, StmtBlock)>, Position),
2021-04-16 06:04:33 +02:00
/// `switch` expr `if` condition `{` literal or _ `=>` stmt `,` ... `}`
2021-03-30 17:55:29 +02:00
Switch(
Expr,
2021-04-16 06:04:33 +02:00
Box<(BTreeMap<u64, Box<(Option<Expr>, StmtBlock)>>, StmtBlock)>,
2021-03-30 17:55:29 +02:00
Position,
),
2021-08-04 11:37:56 +02:00
/// `while` expr `{` stmt `}` | `loop` `{` stmt `}`
///
/// If the guard expression is [`UNIT`][Expr::Unit], then it is a `loop` statement.
2021-03-10 05:27:10 +01:00
While(Expr, Box<StmtBlock>, Position),
2020-11-20 15:23:37 +01:00
/// `do` `{` stmt `}` `while`|`until` expr
///
/// ### Option Flags
///
2021-09-12 07:21:53 +02:00
/// * [`AST_OPTION_NONE`][AST_OPTION_FLAGS::AST_OPTION_NONE] = `while`
/// * [`AST_OPTION_NEGATED`][AST_OPTION_FLAGS::AST_OPTION_NEGATED] = `until`
Do(Box<StmtBlock>, Expr, OptionFlags, Position),
2021-06-07 05:01:16 +02:00
/// `for` `(` id `,` counter `)` `in` expr `{` stmt `}`
For(Expr, Box<(Ident, Option<Ident>, StmtBlock)>, Position),
2021-08-04 11:37:56 +02:00
/// \[`export`\] `let`|`const` id `=` expr
///
/// ### Option Flags
///
2021-09-12 07:21:53 +02:00
/// * [`AST_OPTION_PUBLIC`][AST_OPTION_FLAGS::AST_OPTION_PUBLIC] = `export`
/// * [`AST_OPTION_CONSTANT`][AST_OPTION_FLAGS::AST_OPTION_CONSTANT] = `const`
Var(Expr, Box<Ident>, OptionFlags, Position),
2020-11-20 09:52:28 +01:00
/// expr op`=` expr
Assignment(Box<(Expr, Option<OpAssignment<'static>>, Expr)>, Position),
2021-04-21 12:16:24 +02:00
/// func `(` expr `,` ... `)`
///
/// Note - this is a duplicate of [`Expr::FnCall`] to cover the very common pattern of a single
/// function call forming one statement.
FnCall(Box<FnCallExpr>, Position),
2020-11-20 09:52:28 +01:00
/// `{` stmt`;` ... `}`
2021-05-05 12:38:52 +02:00
Block(Box<[Stmt]>, Position),
2020-11-20 09:52:28 +01:00
/// `try` `{` stmt; ... `}` `catch` `(` var `)` `{` stmt; ... `}`
2021-06-16 10:15:29 +02:00
TryCatch(Box<(StmtBlock, Option<Ident>, StmtBlock)>, Position),
2020-11-20 09:52:28 +01:00
/// [expression][Expr]
2020-10-29 04:37:51 +01:00
Expr(Expr),
/// `continue`/`break`
///
/// ### Option Flags
///
2021-09-12 07:21:53 +02:00
/// * [`AST_OPTION_NONE`][AST_OPTION_FLAGS::AST_OPTION_NONE] = `continue`
/// * [`AST_OPTION_BREAK_OUT`][AST_OPTION_FLAGS::AST_OPTION_BREAK_OUT] = `break`
BreakLoop(OptionFlags, Position),
2020-11-20 09:52:28 +01:00
/// `return`/`throw`
///
/// ### Option Flags
///
2021-09-12 07:21:53 +02:00
/// * [`AST_OPTION_NONE`][AST_OPTION_FLAGS::AST_OPTION_NONE] = `return`
/// * [`AST_OPTION_BREAK_OUT`][AST_OPTION_FLAGS::AST_OPTION_BREAK_OUT] = `throw`
Return(OptionFlags, Option<Expr>, Position),
2020-11-20 09:52:28 +01:00
/// `import` expr `as` var
2021-05-10 05:07:19 +02:00
///
/// Not available under `no_module`.
2020-10-29 04:37:51 +01:00
#[cfg(not(feature = "no_module"))]
2021-03-29 05:36:02 +02:00
Import(Expr, Option<Box<Ident>>, Position),
2020-11-20 09:52:28 +01:00
/// `export` var `as` var `,` ...
2021-05-10 05:07:19 +02:00
///
/// Not available under `no_module`.
2020-10-29 04:37:51 +01:00
#[cfg(not(feature = "no_module"))]
2021-06-16 10:35:56 +02:00
Export(Box<[(Ident, Ident)]>, Position),
2020-10-29 04:37:51 +01:00
/// Convert a variable to shared.
2021-05-10 05:07:19 +02:00
///
/// Not available under `no_closure`.
///
/// # Notes
///
/// This variant does not map to any language structure. It is currently only used only to
/// convert a normal variable into a shared variable when the variable is _captured_ by a closure.
2020-10-29 04:37:51 +01:00
#[cfg(not(feature = "no_closure"))]
2021-03-30 17:55:29 +02:00
Share(Identifier),
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
}
}
2021-03-10 05:27:10 +01:00
impl From<Stmt> for StmtBlock {
#[inline]
2021-03-10 05:27:10 +01:00
fn from(stmt: Stmt) -> Self {
match stmt {
2021-06-06 06:17:04 +02:00
Stmt::Block(mut block, pos) => Self(block.iter_mut().map(mem::take).collect(), pos),
Stmt::Noop(pos) => Self(StaticVec::new(), pos),
2021-03-10 15:12:48 +01:00
_ => {
let pos = stmt.position();
2021-04-16 06:04:33 +02:00
Self(vec![stmt].into(), pos)
2021-03-10 15:12:48 +01:00
}
2021-03-10 05:27:10 +01:00
}
}
}
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)]
2021-06-12 16:47:43 +02:00
#[must_use]
2021-06-28 12:06:05 +02:00
pub const fn is_noop(&self) -> bool {
2021-07-24 08:11:16 +02:00
matches!(self, Self::Noop(_))
2020-10-29 04:37:51 +01:00
}
2020-12-26 16:21:16 +01:00
/// Get the [position][Position] of this statement.
2021-06-12 16:47:43 +02:00
#[must_use]
2021-06-29 12:41:03 +02:00
pub const fn position(&self) -> Position {
2020-10-29 04:37:51 +01:00
match self {
Self::Noop(pos)
| Self::BreakLoop(_, pos)
2020-10-29 04:37:51 +01:00
| Self::Block(_, pos)
| Self::Assignment(_, pos)
2021-04-21 12:16:24 +02:00
| Self::FnCall(_, 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)
2021-03-09 16:48:40 +01:00
| Self::For(_, _, pos)
2021-03-09 16:30:48 +01:00
| Self::Return(_, _, pos)
| Self::Var(_, _, _, pos)
2021-06-16 10:15:29 +02:00
| 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"))]
2021-03-30 17:55:29 +02:00
Self::Share(_) => Position::NONE,
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::BreakLoop(_, pos)
2020-10-29 04:37:51 +01:00
| Self::Block(_, pos)
| Self::Assignment(_, pos)
2021-04-21 12:16:24 +02:00
| Self::FnCall(_, 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)
2021-03-09 16:48:40 +01:00
| Self::For(_, _, pos)
2021-03-09 16:30:48 +01:00
| Self::Return(_, _, pos)
| Self::Var(_, _, _, pos)
2021-06-16 10:15:29 +02:00
| 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"))]
2021-03-30 17:55:29 +02:00
Self::Share(_) => (),
2020-10-29 04:37:51 +01:00
}
self
}
2021-03-11 11:29:22 +01:00
/// Does this statement return a value?
2021-06-12 16:47:43 +02:00
#[must_use]
2021-06-28 12:06:05 +02:00
pub const fn returns_value(&self) -> bool {
2021-03-11 11:29:22 +01:00
match self {
2021-04-21 12:16:24 +02:00
Self::If(_, _, _)
| Self::Switch(_, _, _)
| Self::Block(_, _)
| Self::Expr(_)
| Self::FnCall(_, _) => true,
2021-03-11 11:29:22 +01:00
Self::Noop(_)
| Self::While(_, _, _)
| Self::Do(_, _, _, _)
| Self::For(_, _, _)
2021-06-16 10:15:29 +02:00
| Self::TryCatch(_, _) => false,
2021-03-11 11:29:22 +01:00
Self::Var(_, _, _, _)
2021-03-11 11:29:22 +01:00
| Self::Assignment(_, _)
| Self::BreakLoop(_, _)
2021-03-11 11:29:22 +01:00
| Self::Return(_, _, _) => false,
#[cfg(not(feature = "no_module"))]
Self::Import(_, _, _) | Self::Export(_, _) => false,
#[cfg(not(feature = "no_closure"))]
2021-06-28 12:06:05 +02:00
Self::Share(_) => false,
2021-03-11 11:29:22 +01:00
}
}
2020-10-29 04:37:51 +01:00
/// Is this statement self-terminated (i.e. no need for a semicolon terminator)?
2021-06-12 16:47:43 +02:00
#[must_use]
2021-06-28 12:06:05 +02:00
pub const fn is_self_terminated(&self) -> bool {
2020-10-29 04:37:51 +01:00
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(_, _, _)
2021-03-09 16:48:40 +01:00
| Self::For(_, _, _)
2020-10-29 04:37:51 +01:00
| Self::Block(_, _)
2021-06-16 10:15:29 +02: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,
2021-08-02 04:24:03 +02:00
Self::Expr(Expr::Custom(x, _)) if x.is_self_terminated() => true,
Self::Var(_, _, _, _)
2020-10-29 04:37:51 +01:00
| Self::Assignment(_, _)
| Self::Expr(_)
2021-08-02 04:24:03 +02:00
| Self::FnCall(_, _)
2020-11-20 15:23:37 +01:00
| Self::Do(_, _, _, _)
| Self::BreakLoop(_, _)
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"))]
2021-06-28 12:06:05 +02:00
Self::Share(_) => false,
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.
2021-06-12 16:47:43 +02:00
#[must_use]
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(),
2021-03-10 05:27:10 +01:00
Self::If(condition, x, _) => {
condition.is_pure()
2021-04-16 06:04:33 +02:00
&& (x.0).0.iter().all(Stmt::is_pure)
&& (x.1).0.iter().all(Stmt::is_pure)
2021-03-10 05:27:10 +01:00
}
2020-11-14 16:43:36 +01:00
Self::Switch(expr, x, _) => {
expr.is_pure()
2021-04-16 06:04:33 +02:00
&& x.0.values().all(|block| {
block.0.as_ref().map(Expr::is_pure).unwrap_or(true)
&& (block.1).0.iter().all(Stmt::is_pure)
})
&& (x.1).0.iter().all(Stmt::is_pure)
2020-10-29 04:37:51 +01:00
}
2021-08-04 11:37:56 +02:00
// Loops that exit can be pure because it can never be infinite.
Self::While(Expr::BoolConstant(false, _), _, _) => true,
Self::Do(body, Expr::BoolConstant(x, _), options, _)
if *x == options.contains(AST_OPTION_FLAGS::AST_OPTION_NEGATED) =>
{
body.iter().all(Stmt::is_pure)
2021-03-10 05:27:10 +01:00
}
2021-08-04 11:37:56 +02:00
// Loops are never pure since they can be infinite - and that's a side effect.
Self::While(_, _, _) | Self::Do(_, _, _, _) => false,
// For loops can be pure because if the iterable is pure, it is finite,
// so infinite loops can never occur.
2021-06-07 05:01:16 +02:00
Self::For(iterable, x, _) => iterable.is_pure() && (x.2).0.iter().all(Stmt::is_pure),
2021-08-04 11:37:56 +02:00
Self::Var(_, _, _, _) | Self::Assignment(_, _) | Self::FnCall(_, _) => false,
2020-10-29 04:37:51 +01:00
Self::Block(block, _) => block.iter().all(|stmt| stmt.is_pure()),
Self::BreakLoop(_, _) | Self::Return(_, _, _) => false,
2021-06-16 10:15:29 +02:00
Self::TryCatch(x, _) => {
2021-04-16 06:04:33 +02:00
(x.0).0.iter().all(Stmt::is_pure) && (x.2).0.iter().all(Stmt::is_pure)
2021-03-10 05:27:10 +01:00
}
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-03-11 11:29:22 +01:00
/// Is this statement _pure_ within the containing block?
///
/// An internally pure statement only has side effects that disappear outside the block.
///
2021-11-09 06:22:45 +01:00
/// Currently only variable definitions (i.e. `let` and `const`) and `import`/`export`
/// statements are internally pure.
#[inline]
2021-06-12 16:47:43 +02:00
#[must_use]
2021-03-11 11:29:22 +01:00
pub fn is_internally_pure(&self) -> bool {
match self {
Self::Var(expr, _, _, _) => expr.is_pure(),
2021-03-11 11:29:22 +01:00
#[cfg(not(feature = "no_module"))]
Self::Import(expr, _, _) => expr.is_pure(),
#[cfg(not(feature = "no_module"))]
Self::Export(_, _) => true,
_ => self.is_pure(),
}
}
/// Does this statement break the current control flow through the containing block?
///
/// Currently this is only true for `return`, `throw`, `break` and `continue`.
///
/// All statements following this statement will essentially be dead code.
#[inline]
2021-06-12 16:47:43 +02:00
#[must_use]
2021-06-28 12:06:05 +02:00
pub const fn is_control_flow_break(&self) -> bool {
2021-03-11 11:29:22 +01:00
match self {
Self::Return(_, _, _) | Self::BreakLoop(_, _) => true,
2021-03-11 14:55:55 +01:00
_ => false,
2021-03-11 11:29:22 +01:00
}
}
2021-01-08 17:24:55 +01:00
/// Recursively walk this statement.
2021-03-11 14:55:55 +01:00
/// Return `false` from the callback to terminate the walk.
pub fn walk<'a>(
&'a self,
path: &mut Vec<ASTNode<'a>>,
on_node: &mut impl FnMut(&[ASTNode]) -> bool,
) -> bool {
2021-05-22 13:14:24 +02:00
// Push the current node onto the path
2021-01-09 09:52:22 +01:00
path.push(self.into());
2021-03-11 14:55:55 +01:00
if !on_node(path) {
return false;
}
2021-01-08 17:24:55 +01:00
match self {
Self::Var(e, _, _, _) => {
2021-03-11 14:55:55 +01:00
if !e.walk(path, on_node) {
return false;
}
}
2021-01-08 17:24:55 +01:00
Self::If(e, x, _) => {
2021-03-11 14:55:55 +01:00
if !e.walk(path, on_node) {
return false;
}
2021-04-16 06:04:33 +02:00
for s in &(x.0).0 {
2021-03-11 14:55:55 +01:00
if !s.walk(path, on_node) {
return false;
}
}
2021-04-16 06:04:33 +02:00
for s in &(x.1).0 {
2021-03-11 14:55:55 +01:00
if !s.walk(path, on_node) {
return false;
}
}
2021-01-08 17:24:55 +01:00
}
Self::Switch(e, x, _) => {
2021-03-11 14:55:55 +01:00
if !e.walk(path, on_node) {
return false;
}
2021-04-16 06:04:33 +02:00
for b in x.0.values() {
if !b.0.as_ref().map(|e| e.walk(path, on_node)).unwrap_or(true) {
2021-03-11 14:55:55 +01:00
return false;
}
2021-04-16 06:04:33 +02:00
for s in &(b.1).0 {
if !s.walk(path, on_node) {
return false;
}
}
2021-03-11 14:55:55 +01:00
}
2021-04-16 06:04:33 +02:00
for s in &(x.1).0 {
2021-03-11 14:55:55 +01:00
if !s.walk(path, on_node) {
return false;
}
}
2021-01-08 17:24:55 +01:00
}
2021-03-09 16:30:48 +01:00
Self::While(e, s, _) | Self::Do(s, e, _, _) => {
2021-03-11 14:55:55 +01:00
if !e.walk(path, on_node) {
return false;
}
2021-04-16 06:04:33 +02:00
for s in &s.0 {
2021-03-11 14:55:55 +01:00
if !s.walk(path, on_node) {
return false;
}
}
2021-01-08 17:24:55 +01:00
}
2021-03-09 16:48:40 +01:00
Self::For(e, x, _) => {
2021-03-11 14:55:55 +01:00
if !e.walk(path, on_node) {
return false;
}
2021-06-07 05:01:16 +02:00
for s in &(x.2).0 {
2021-03-11 14:55:55 +01:00
if !s.walk(path, on_node) {
return false;
}
}
2021-01-08 17:24:55 +01:00
}
Self::Assignment(x, _) => {
2021-03-11 14:55:55 +01:00
if !x.0.walk(path, on_node) {
return false;
}
2021-03-30 17:55:29 +02:00
if !x.2.walk(path, on_node) {
2021-03-11 14:55:55 +01:00
return false;
}
}
2021-04-21 12:16:24 +02:00
Self::FnCall(x, _) => {
for s in &x.args {
if !s.walk(path, on_node) {
return false;
}
}
}
2021-03-11 14:55:55 +01:00
Self::Block(x, _) => {
2021-05-05 12:38:52 +02:00
for s in x.iter() {
2021-03-11 14:55:55 +01:00
if !s.walk(path, on_node) {
return false;
}
}
2021-01-08 17:24:55 +01:00
}
2021-06-16 10:15:29 +02:00
Self::TryCatch(x, _) => {
2021-04-16 06:04:33 +02:00
for s in &(x.0).0 {
2021-03-11 14:55:55 +01:00
if !s.walk(path, on_node) {
return false;
}
}
2021-04-16 06:04:33 +02:00
for s in &(x.2).0 {
2021-03-11 14:55:55 +01:00
if !s.walk(path, on_node) {
return false;
}
}
}
Self::Expr(e) | Self::Return(_, Some(e), _) => {
if !e.walk(path, on_node) {
return false;
}
2021-01-08 17:24:55 +01:00
}
2021-01-08 17:40:44 +01:00
#[cfg(not(feature = "no_module"))]
2021-03-11 14:55:55 +01:00
Self::Import(e, _, _) => {
if !e.walk(path, on_node) {
return false;
}
}
2021-01-08 17:24:55 +01:00
_ => (),
}
2021-01-09 09:52:22 +01:00
2021-08-26 17:58:41 +02:00
path.pop().expect("`path` contains current node");
2021-03-11 14:55:55 +01:00
true
2021-01-08 17:24:55 +01:00
}
2020-10-29 04:37:51 +01:00
}
2021-07-25 16:56:05 +02: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.
2021-10-25 16:41:42 +02:00
pub inputs: StaticVec<Expr>,
/// Is the current [`Scope`][crate::Scope] possibly modified by this custom statement
/// (e.g. introducing a new variable)?
pub scope_may_be_changed: bool,
2021-05-05 12:38:52 +02:00
/// List of tokens actually parsed.
pub tokens: StaticVec<Identifier>,
2021-08-02 04:24:03 +02:00
/// Is this custom syntax self-terminated?
pub self_terminated: bool,
}
impl CustomExpr {
/// Is this custom syntax self-terminated (i.e. no need for a semicolon terminator)?
///
/// A self-terminated custom syntax always ends in `$block$`, `}` or `;`
#[must_use]
#[inline(always)]
pub const fn is_self_terminated(&self) -> bool {
self.self_terminated
}
2020-10-29 04:37:51 +01:00
}
2021-07-25 16:56:05 +02: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.
2021-04-13 09:52:45 +02:00
#[derive(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
}
2021-07-25 16:56:05 +02:00
/// _(internals)_ An op-assignment operator.
2021-03-08 08:30:32 +01:00
/// Exported under the `internals` feature only.
///
/// # Volatile Data Structure
///
/// This type is volatile and may change.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub struct OpAssignment<'a> {
/// Hash of the op-assignment call.
2021-03-08 08:30:32 +01:00
pub hash_op_assign: u64,
/// Hash of the underlying operator call.
2021-03-08 08:30:32 +01:00
pub hash_op: u64,
/// Op-assignment operator.
pub op: &'a str,
2021-03-08 08:30:32 +01:00
}
impl OpAssignment<'_> {
2021-04-24 05:55:40 +02:00
/// Create a new [`OpAssignment`].
///
/// # Panics
///
/// Panics if the operator name is not an op-assignment operator.
2021-06-12 16:47:43 +02:00
#[must_use]
2021-04-24 05:55:40 +02:00
pub fn new(op: Token) -> Self {
let op_raw = op
.map_op_assignment()
2021-08-26 17:58:41 +02:00
.expect("token is op-assignment operator")
2021-07-10 09:50:31 +02:00
.literal_syntax();
let op_assignment = op.literal_syntax();
2021-04-04 07:13:07 +02:00
Self {
2021-05-19 14:26:11 +02:00
hash_op_assign: calc_fn_hash(op_assignment, 2),
hash_op: calc_fn_hash(op_raw, 2),
2021-04-24 05:55:40 +02:00
op: op_assignment,
2021-04-04 07:13:07 +02:00
}
}
}
2021-07-25 16:56:05 +02:00
/// _(internals)_ An set of function call hashes.
2021-03-08 08:30:32 +01:00
/// Exported under the `internals` feature only.
///
2021-03-17 06:30:47 +01:00
/// Two separate hashes are pre-calculated because of the following pattern:
///
2021-03-22 04:18:09 +01:00
/// ```ignore
2021-03-17 06:30:47 +01:00
/// func(a, b, c); // Native: func(a, b, c) - 3 parameters
/// // Script: func(a, b, c) - 3 parameters
///
/// a.func(b, c); // Native: func(&mut a, b, c) - 3 parameters
/// // Script: func(b, c) - 2 parameters
/// ```
///
/// For normal function calls, the native hash equals the script hash.
/// For method-style calls, the script hash contains one fewer parameter.
///
/// Function call hashes are used in the following manner:
///
/// * First, the script hash is tried, which contains only the called function's name plus the
/// of parameters.
///
/// * Next, the actual types of arguments are hashed and _combined_ with the native hash, which is
/// then used to search for a native function.
/// In other words, a native function call hash always contains the called function's name plus
/// the types of the arguments. This is to due to possible function overloading for different parameter types.
///
2021-03-08 08:30:32 +01:00
/// # Volatile Data Structure
///
/// This type is volatile and may change.
2021-03-09 07:00:21 +01:00
#[derive(Clone, Copy, Eq, PartialEq, Hash, Default)]
2021-04-20 16:26:08 +02:00
pub struct FnCallHashes {
2021-03-08 08:30:32 +01:00
/// Pre-calculated hash for a script-defined function ([`None`] if native functions only).
2021-03-17 06:30:47 +01:00
pub script: Option<u64>,
2021-03-08 08:30:32 +01:00
/// Pre-calculated hash for a native Rust function with no parameter types.
2021-03-17 06:30:47 +01:00
pub native: u64,
2021-03-08 08:30:32 +01:00
}
2021-04-20 16:26:08 +02:00
impl fmt::Debug for FnCallHashes {
2021-03-09 07:00:21 +01:00
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(script) = self.script {
if script == self.native {
2021-06-21 13:12:28 +02:00
fmt::Debug::fmt(&self.native, f)
2021-03-09 07:00:21 +01:00
} else {
write!(f, "({}, {})", script, self.native)
}
} else {
2021-06-21 13:12:28 +02:00
write!(f, "{} (native only)", self.native)
2021-03-09 07:00:21 +01:00
}
}
}
2021-04-20 16:26:08 +02:00
impl FnCallHashes {
2021-05-02 17:57:35 +02:00
/// Create a [`FnCallHashes`] with only the native Rust hash.
2021-03-08 08:30:32 +01:00
#[inline(always)]
2021-06-12 16:47:43 +02:00
#[must_use]
2021-06-28 12:06:05 +02:00
pub const fn from_native(hash: u64) -> Self {
2021-03-08 08:30:32 +01:00
Self {
script: None,
native: hash,
}
}
2021-05-02 17:57:35 +02:00
/// Create a [`FnCallHashes`] with both native Rust and script function hashes set to the same value.
2021-03-08 08:30:32 +01:00
#[inline(always)]
2021-06-12 16:47:43 +02:00
#[must_use]
2021-06-28 12:06:05 +02:00
pub const fn from_script(hash: u64) -> Self {
2021-03-08 08:30:32 +01:00
Self {
script: Some(hash),
native: hash,
}
}
2021-05-02 17:57:35 +02:00
/// Create a [`FnCallHashes`] with both native Rust and script function hashes.
2021-03-08 08:30:32 +01:00
#[inline(always)]
2021-06-12 16:47:43 +02:00
#[must_use]
2021-06-28 12:06:05 +02:00
pub const fn from_script_and_native(script: u64, native: u64) -> Self {
2021-03-08 08:30:32 +01:00
Self {
script: Some(script),
native,
}
}
2021-05-02 17:57:35 +02:00
/// Is this [`FnCallHashes`] native Rust only?
2021-03-08 08:30:32 +01:00
#[inline(always)]
2021-06-12 16:47:43 +02:00
#[must_use]
2021-06-28 12:06:05 +02:00
pub const fn is_native_only(&self) -> bool {
2021-03-08 08:30:32 +01:00
self.script.is_none()
}
}
2021-07-25 16:56:05 +02: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.
2021-04-21 12:16:24 +02:00
#[derive(Debug, Clone, Default, Hash)]
2020-11-10 16:26:50 +01:00
pub struct FnCallExpr {
2021-04-20 17:28:04 +02:00
/// Namespace of the function, if any.
pub namespace: Option<NamespaceRef>,
2021-04-20 16:26:08 +02:00
/// Pre-calculated hashes.
pub hashes: FnCallHashes,
/// List of function call argument expressions.
2021-03-08 08:55:26 +01:00
pub args: StaticVec<Expr>,
/// List of function call arguments that are constants.
///
/// Any arguments in `args` that is [`Expr::Stack`][Expr::Stack] indexes into this
/// array to find the constant for use as its argument value.
pub constants: smallvec::SmallVec<[Dynamic; 2]>,
2020-11-02 16:54:19 +01:00
/// Function name.
2021-03-29 05:36:02 +02:00
pub name: Identifier,
2021-04-20 17:28:04 +02:00
/// Does this function call capture the parent scope?
pub capture: bool,
2020-10-29 04:37:51 +01:00
}
impl FnCallExpr {
2021-04-20 17:28:04 +02:00
/// Does this function call contain a qualified namespace?
#[inline(always)]
2021-06-12 16:47:43 +02:00
#[must_use]
2021-06-28 12:06:05 +02:00
pub const fn is_qualified(&self) -> bool {
2021-04-20 17:28:04 +02:00
self.namespace.is_some()
}
2021-06-16 12:36:33 +02:00
/// Convert this into a [`FnCall`][Expr::FnCall].
#[inline(always)]
#[must_use]
pub fn into_fn_call_expr(self, pos: Position) -> Expr {
Expr::FnCall(self.into(), pos)
}
}
2021-04-06 17:18:41 +02:00
/// A type that wraps a floating-point number and implements [`Hash`].
2021-05-10 05:07:19 +02:00
///
/// Not available under `no_float`.
#[cfg(not(feature = "no_float"))]
2021-02-12 16:07:28 +01:00
#[derive(Clone, Copy, PartialEq, PartialOrd)]
2021-04-06 17:18:41 +02:00
pub struct FloatWrapper<F>(F);
#[cfg(not(feature = "no_float"))]
2021-04-06 17:18:41 +02:00
impl Hash for FloatWrapper<FLOAT> {
#[inline(always)]
2021-04-17 09:15:54 +02:00
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.0.to_ne_bytes().hash(state);
}
}
#[cfg(not(feature = "no_float"))]
2021-04-06 17:18:41 +02:00
impl<F: Float> AsRef<F> for FloatWrapper<F> {
#[inline(always)]
2021-04-06 17:18:41 +02:00
fn as_ref(&self) -> &F {
&self.0
}
}
#[cfg(not(feature = "no_float"))]
2021-04-06 17:18:41 +02:00
impl<F: Float> AsMut<F> for FloatWrapper<F> {
#[inline(always)]
2021-04-06 17:18:41 +02:00
fn as_mut(&mut self) -> &mut F {
&mut self.0
}
}
#[cfg(not(feature = "no_float"))]
2021-04-17 09:15:54 +02:00
impl<F: Float> std::ops::Deref for FloatWrapper<F> {
2021-04-06 17:18:41 +02:00
type Target = F;
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[cfg(not(feature = "no_float"))]
2021-04-17 09:15:54 +02:00
impl<F: Float> std::ops::DerefMut for FloatWrapper<F> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
#[cfg(not(feature = "no_float"))]
2021-04-11 05:20:34 +02:00
impl<F: Float + fmt::Debug> fmt::Debug for FloatWrapper<F> {
#[inline(always)]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2021-04-11 05:20:34 +02:00
fmt::Debug::fmt(&self.0, f)
}
}
#[cfg(not(feature = "no_float"))]
2021-04-06 17:18:41 +02:00
impl<F: Float + fmt::Display + fmt::LowerExp + From<f32>> fmt::Display for FloatWrapper<F> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let abs = self.0.abs();
2021-11-09 01:46:02 +01:00
if abs.is_zero() {
2021-11-03 01:44:07 +01:00
f.write_str("0.0")
} else if abs > Self::MAX_NATURAL_FLOAT_FOR_DISPLAY.into()
2021-04-06 17:18:41 +02:00
|| abs < Self::MIN_NATURAL_FLOAT_FOR_DISPLAY.into()
{
write!(f, "{:e}", self.0)
} else {
2021-04-06 17:18:41 +02:00
fmt::Display::fmt(&self.0, f)?;
if abs.fract().is_zero() {
f.write_str(".0")?;
}
Ok(())
}
}
}
#[cfg(not(feature = "no_float"))]
2021-04-06 17:18:41 +02:00
impl<F: Float> From<F> for FloatWrapper<F> {
#[inline(always)]
2021-04-06 17:18:41 +02:00
fn from(value: F) -> Self {
Self::new(value)
}
}
2021-02-12 16:07:28 +01:00
#[cfg(not(feature = "no_float"))]
2021-04-06 17:18:41 +02:00
impl<F: Float + FromStr> FromStr for FloatWrapper<F> {
type Err = <F as FromStr>::Err;
2021-02-12 16:07:28 +01:00
#[inline]
2021-02-12 16:07:28 +01:00
fn from_str(s: &str) -> Result<Self, Self::Err> {
2021-04-06 17:18:41 +02:00
F::from_str(s).map(Into::<Self>::into)
2021-02-12 16:07:28 +01:00
}
}
#[cfg(not(feature = "no_float"))]
2021-04-06 17:18:41 +02:00
impl<F: Float> FloatWrapper<F> {
/// Maximum floating-point number for natural display before switching to scientific notation.
pub const MAX_NATURAL_FLOAT_FOR_DISPLAY: f32 = 10000000000000.0;
/// Minimum floating-point number for natural display before switching to scientific notation.
pub const MIN_NATURAL_FLOAT_FOR_DISPLAY: f32 = 0.0000000000001;
2021-06-28 12:06:05 +02:00
/// Create a new [`FloatWrapper`].
2021-04-06 17:18:41 +02:00
#[inline(always)]
2021-06-12 16:47:43 +02:00
#[must_use]
2021-04-06 17:18:41 +02:00
pub fn new(value: F) -> Self {
Self(value)
}
}
2021-04-06 17:28:22 +02:00
#[cfg(not(feature = "no_float"))]
2021-04-06 17:18:41 +02:00
impl FloatWrapper<FLOAT> {
2021-06-28 12:06:05 +02:00
/// Create a new [`FloatWrapper`].
#[inline(always)]
2021-06-12 16:47:43 +02:00
#[must_use]
pub const fn new_const(value: FLOAT) -> Self {
Self(value)
}
}
2021-07-25 16:56:05 +02: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.
2021-04-06 17:18:41 +02:00
#[derive(Clone, Hash)]
2020-10-29 04:37:51 +01:00
pub enum Expr {
2020-11-14 12:04:49 +01:00
/// Dynamic constant.
2021-03-24 03:02:50 +01:00
/// Used to hold either an [`Array`] or [`Map`][crate::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.
2021-05-10 05:07:19 +02:00
///
/// Not available under `no_float`.
2020-10-29 04:37:51 +01:00
#[cfg(not(feature = "no_float"))]
2021-04-06 17:18:41 +02:00
FloatConstant(FloatWrapper<FLOAT>, 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),
2021-04-04 07:13:07 +02:00
/// An interpolated [string][ImmutableString].
2021-06-29 12:41:03 +02:00
InterpolatedString(Box<StaticVec<Expr>>, Position),
2020-11-13 11:32:18 +01:00
/// [ expr, ... ]
Array(Box<StaticVec<Expr>>, Position),
/// #{ name:expr, ... }
2021-03-23 11:25:40 +01:00
Map(
2021-03-29 11:14:22 +02:00
Box<(StaticVec<(Ident, Expr)>, BTreeMap<Identifier, Dynamic>)>,
2021-03-23 11:25:40 +01:00
Position,
),
2020-11-13 11:32:18 +01:00
/// ()
Unit(Position),
2021-04-05 17:59:15 +02:00
/// Variable access - optional short index, position, (optional index, optional (hash, modules), variable name)
2021-04-05 17:06:48 +02:00
///
/// The short index is [`u8`] which is used when the index is <= 255, which should be the vast
/// majority of cases (unless there are more than 255 variables defined!).
/// This is to avoid reading a pointer redirection during each variable access.
Variable(
Option<NonZeroU8>,
2021-04-05 17:59:15 +02:00
Position,
Box<(
Option<NonZeroUsize>,
2021-06-16 12:36:33 +02:00
Option<(NamespaceRef, u64)>,
2021-04-05 17:59:15 +02:00
Identifier,
)>,
2021-04-05 17:06:48 +02:00
),
2021-03-10 15:12:48 +01:00
/// Property access - ((getter, hash), (setter, hash), prop)
2021-05-18 14:12:30 +02:00
Property(
Box<(
(Identifier, u64),
(Identifier, u64),
(ImmutableString, Position),
)>,
),
/// Stack slot
///
/// # Notes
///
/// This variant does not map to any language structure. It is currently only used in function
/// calls with constant arguments where the `usize` number indexes into an array containing a
/// list of constant arguments for the function call. See [`FnCallExpr`] for more details.
Stack(usize, Position),
/// { [statement][Stmt] ... }
2021-03-10 15:12:48 +01:00
Stmt(Box<StmtBlock>),
2020-11-20 09:52:28 +01:00
/// func `(` expr `,` ... `)`
2020-11-10 16:26:50 +01:00
FnCall(Box<FnCallExpr>, Position),
2021-07-24 06:27:33 +02:00
/// lhs `.` rhs - bool variable is a dummy
Dot(Box<BinaryExpr>, bool, Position),
/// expr `[` expr `]` - boolean indicates whether the dotting/indexing chain stops
Index(Box<BinaryExpr>, bool, 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
}
}
2021-04-06 17:18:41 +02:00
impl fmt::Debug for Expr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2021-04-23 08:24:53 +02:00
let mut display_pos = self.position();
2021-04-06 17:18:41 +02:00
match self {
2021-04-22 17:02:25 +02:00
Self::DynamicConstant(value, _) => write!(f, "{:?}", value),
Self::BoolConstant(value, _) => write!(f, "{:?}", value),
Self::IntegerConstant(value, _) => write!(f, "{:?}", value),
#[cfg(not(feature = "no_float"))]
Self::FloatConstant(value, _) => write!(f, "{:?}", value),
Self::CharConstant(value, _) => write!(f, "{:?}", value),
Self::StringConstant(value, _) => write!(f, "{:?}", value),
Self::Unit(_) => f.write_str("()"),
2021-06-29 12:41:03 +02:00
Self::InterpolatedString(x, _) => {
2021-04-06 17:18:41 +02:00
f.write_str("InterpolatedString")?;
2021-04-23 08:24:53 +02:00
return f.debug_list().entries(x.iter()).finish();
2021-04-06 17:18:41 +02:00
}
2021-04-23 08:24:53 +02:00
Self::Array(x, _) => {
2021-04-06 17:18:41 +02:00
f.write_str("Array")?;
2021-04-23 08:24:53 +02:00
f.debug_list().entries(x.iter()).finish()
2021-04-06 17:18:41 +02:00
}
2021-04-23 08:24:53 +02:00
Self::Map(x, _) => {
2021-04-06 17:18:41 +02:00
f.write_str("Map")?;
f.debug_map()
.entries(x.0.iter().map(|(k, v)| (k, v)))
2021-04-23 08:24:53 +02:00
.finish()
2021-04-06 17:18:41 +02:00
}
2021-04-23 08:24:53 +02:00
Self::Variable(i, _, x) => {
2021-04-06 17:18:41 +02:00
f.write_str("Variable(")?;
2021-10-18 09:09:07 +02:00
if let Some((_, ref namespace)) = x.1 {
2021-10-27 17:30:25 +02:00
write!(f, "{}{}", namespace, Token::DoubleColon.literal_syntax())?
2021-04-06 17:18:41 +02:00
}
2021-06-04 08:23:40 +02:00
f.write_str(&x.2)?;
2021-10-18 09:09:07 +02:00
if let Some(n) = i.map_or_else(|| x.0, |n| NonZeroUsize::new(n.get() as usize)) {
write!(f, " #{}", n)?
2021-04-06 17:18:41 +02:00
}
2021-04-23 08:24:53 +02:00
f.write_str(")")
2021-04-06 17:18:41 +02:00
}
2021-05-18 14:12:30 +02:00
Self::Property(x) => write!(f, "Property({})", (x.2).0),
Self::Stack(x, _) => write!(f, "StackSlot({})", x),
2021-04-06 17:18:41 +02:00
Self::Stmt(x) => {
2021-05-22 13:14:24 +02:00
f.write_str("ExprStmtBlock")?;
2021-04-23 08:24:53 +02:00
f.debug_list().entries(x.0.iter()).finish()
2021-04-06 17:18:41 +02:00
}
2021-04-23 08:24:53 +02:00
Self::FnCall(x, _) => {
2021-04-13 09:52:45 +02:00
let mut ff = f.debug_struct("FnCall");
2021-05-25 04:54:48 +02:00
x.namespace.as_ref().map(|ns| ff.field("namespace", ns));
2021-04-13 09:52:45 +02:00
ff.field("name", &x.name)
2021-04-20 16:26:08 +02:00
.field("hash", &x.hashes)
2021-04-13 09:52:45 +02:00
.field("args", &x.args);
if !x.constants.is_empty() {
ff.field("constants", &x.constants);
2021-04-13 09:52:45 +02:00
}
if x.capture {
ff.field("capture", &x.capture);
}
2021-04-23 08:24:53 +02:00
ff.finish()
2021-04-06 17:18:41 +02:00
}
2021-07-24 06:27:33 +02:00
Self::Index(x, term, pos) => {
display_pos = *pos;
f.debug_struct("Index")
.field("lhs", &x.lhs)
.field("rhs", &x.rhs)
.field("terminate", term)
.finish()
}
Self::Dot(x, _, pos) | Self::And(x, pos) | Self::Or(x, pos) => {
2021-04-13 09:52:45 +02:00
let op_name = match self {
2021-07-24 06:27:33 +02:00
Self::Dot(_, _, _) => "Dot",
2021-04-06 17:18:41 +02:00
Self::And(_, _) => "And",
Self::Or(_, _) => "Or",
_ => unreachable!(),
};
2021-04-23 08:24:53 +02:00
display_pos = *pos;
2021-04-13 09:52:45 +02:00
f.debug_struct(op_name)
2021-04-06 17:18:41 +02:00
.field("lhs", &x.lhs)
.field("rhs", &x.rhs)
2021-04-23 08:24:53 +02:00
.finish()
2021-04-06 17:18:41 +02:00
}
2021-04-23 08:24:53 +02:00
Self::Custom(x, _) => f.debug_tuple("Custom").field(x).finish(),
}?;
display_pos.debug_print(f)
2021-04-06 17:18:41 +02:00
}
}
2020-10-29 04:37:51 +01:00
impl Expr {
2021-06-10 04:16:39 +02:00
/// Get the [`Dynamic`] value of a literal constant expression.
2020-10-29 04:37:51 +01:00
///
2021-06-10 04:16:39 +02:00
/// Returns [`None`] if the expression is not a literal constant.
#[inline]
2021-06-12 16:47:43 +02:00
#[must_use]
2021-06-10 04:16:39 +02:00
pub fn get_literal_value(&self) -> Option<Dynamic> {
2020-10-29 04:37:51 +01:00
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(),
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() => {
2021-03-23 05:13:53 +01:00
let mut arr = Array::with_capacity(x.len());
2021-05-22 13:14:24 +02:00
arr.extend(x.iter().map(|v| {
2021-06-10 04:16:39 +02:00
v.get_literal_value()
2021-08-26 17:58:41 +02:00
.expect("constant array has constant value")
2021-05-22 13:14:24 +02:00
}));
Dynamic::from_array(arr)
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() => {
2021-03-23 11:25:40 +01:00
let mut map = x.1.clone();
x.0.iter().for_each(|(k, v)| {
2021-05-22 13:14:24 +02:00
*map.get_mut(k.name.as_str())
2021-08-26 17:58:41 +02:00
.expect("template contains all keys") = v
2021-06-10 04:16:39 +02:00
.get_literal_value()
2021-08-26 17:58:41 +02:00
.expect("constant map has constant value")
2021-03-23 11:25:40 +01:00
});
Dynamic::from_map(map)
2020-10-29 04:37:51 +01:00
}
_ => return None,
})
}
/// Create an [`Expr`] from a [`Dynamic`] value.
#[inline]
2021-06-12 16:47:43 +02:00
#[must_use]
pub fn from_dynamic(value: Dynamic, pos: Position) -> Self {
match value.0 {
Union::Unit(_, _, _) => Self::Unit(pos),
Union::Bool(b, _, _) => Self::BoolConstant(b, pos),
Union::Str(s, _, _) => Self::StringConstant(s, pos),
Union::Char(c, _, _) => Self::CharConstant(c, pos),
Union::Int(i, _, _) => Self::IntegerConstant(i, pos),
#[cfg(feature = "decimal")]
Union::Decimal(value, _, _) => Self::DynamicConstant(Box::new((*value).into()), pos),
#[cfg(not(feature = "no_float"))]
Union::Float(f, _, _) => Self::FloatConstant(f, pos),
#[cfg(not(feature = "no_index"))]
Union::Array(a, _, _) => Self::DynamicConstant(Box::new((*a).into()), pos),
#[cfg(not(feature = "no_object"))]
Union::Map(m, _, _) => Self::DynamicConstant(Box::new((*m).into()), pos),
2021-06-29 12:25:20 +02:00
_ => Self::DynamicConstant(value.into(), pos),
}
}
2021-04-05 17:59:15 +02:00
/// Is the expression a simple variable access?
#[inline]
2021-06-12 16:47:43 +02:00
#[must_use]
2021-06-28 12:06:05 +02:00
pub(crate) const fn is_variable_access(&self, non_qualified: bool) -> bool {
2021-04-05 17:59:15 +02:00
match self {
Self::Variable(_, _, x) => !non_qualified || x.1.is_none(),
_ => false,
}
}
2021-02-03 12:14:26 +01:00
/// Return the variable name if the expression a simple variable access.
#[inline]
2021-06-12 16:47:43 +02:00
#[must_use]
2021-04-05 17:59:15 +02:00
pub(crate) fn get_variable_name(&self, non_qualified: bool) -> Option<&str> {
2020-10-29 04:37:51 +01:00
match self {
2021-04-05 17:59:15 +02:00
Self::Variable(_, _, x) if !non_qualified || x.1.is_none() => Some(x.2.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.
#[inline]
2021-06-12 16:47:43 +02:00
#[must_use]
2021-06-29 12:41:03 +02:00
pub const fn position(&self) -> Position {
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(_, pos) => *pos,
2020-10-29 04:37:51 +01:00
2021-04-23 08:24:53 +02:00
Self::DynamicConstant(_, pos)
| Self::BoolConstant(_, pos)
| Self::IntegerConstant(_, pos)
| Self::CharConstant(_, pos)
| Self::Unit(pos)
| Self::StringConstant(_, pos)
| Self::Array(_, pos)
| Self::Map(_, pos)
| Self::Variable(_, pos, _)
| Self::Stack(_, pos)
2021-04-23 08:24:53 +02:00
| Self::FnCall(_, pos)
2021-06-29 12:41:03 +02:00
| Self::Custom(_, pos)
| Self::InterpolatedString(_, pos) => *pos,
2021-04-23 08:24:53 +02:00
2021-05-18 14:12:30 +02:00
Self::Property(x) => (x.2).1,
2021-04-16 06:04:33 +02:00
Self::Stmt(x) => x.1,
2020-10-29 04:37:51 +01:00
2021-07-24 06:27:33 +02:00
Self::And(x, _) | Self::Or(x, _) | Self::Dot(x, _, _) | Self::Index(x, _, _) => {
2021-04-23 08:24:53 +02:00
x.lhs.position()
}
2020-10-29 04:37:51 +01:00
}
}
2020-12-26 16:21:16 +01:00
/// Override the [position][Position] of the expression.
#[inline]
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
2021-04-23 08:24:53 +02:00
Self::DynamicConstant(_, pos)
| Self::BoolConstant(_, pos)
| Self::IntegerConstant(_, pos)
| Self::CharConstant(_, pos)
| Self::Unit(pos)
| Self::StringConstant(_, pos)
| Self::Array(_, pos)
| Self::Map(_, pos)
| Self::And(_, pos)
| Self::Or(_, pos)
2021-07-24 06:27:33 +02:00
| Self::Dot(_, _, pos)
| Self::Index(_, _, pos)
2021-04-23 08:24:53 +02:00
| Self::Variable(_, pos, _)
| Self::Stack(_, pos)
2021-04-23 08:24:53 +02:00
| Self::FnCall(_, pos)
2021-06-29 12:41:03 +02:00
| Self::Custom(_, pos)
| Self::InterpolatedString(_, pos) => *pos = new_pos,
2021-04-23 08:24:53 +02:00
2021-05-18 14:12:30 +02:00
Self::Property(x) => (x.2).1 = new_pos,
2021-04-16 06:04:33 +02:00
Self::Stmt(x) => x.1 = new_pos,
2020-10-29 04:37:51 +01:00
}
self
}
/// Is the expression pure?
///
/// A pure expression has no side effects.
#[inline]
2021-06-12 16:47:43 +02:00
#[must_use]
2020-10-29 04:37:51 +01:00
pub fn is_pure(&self) -> bool {
match self {
2021-06-29 12:41:03 +02:00
Self::InterpolatedString(x, _) | Self::Array(x, _) => x.iter().all(Self::is_pure),
2020-10-31 16:26:21 +01:00
2021-03-23 11:25:40 +01:00
Self::Map(x, _) => x.0.iter().map(|(_, v)| v).all(Self::is_pure),
2020-10-29 04:37:51 +01:00
Self::And(x, _) | Self::Or(x, _) => x.lhs.is_pure() && x.rhs.is_pure(),
2020-10-29 04:37:51 +01:00
2021-04-16 06:04:33 +02:00
Self::Stmt(x) => x.0.iter().all(Stmt::is_pure),
2020-10-29 04:37:51 +01:00
Self::Variable(_, _, _) | Self::Stack(_, _) => true,
2020-10-29 04:37:51 +01:00
_ => self.is_constant(),
}
}
/// Is the expression the unit `()` literal?
#[inline(always)]
2021-06-12 16:47:43 +02:00
#[must_use]
2021-06-28 12:06:05 +02:00
pub const fn is_unit(&self) -> bool {
2021-07-24 08:11:16 +02:00
matches!(self, Self::Unit(_))
2020-10-29 04:37:51 +01:00
}
/// Is the expression a constant?
#[inline]
2021-06-12 16:47:43 +02:00
#[must_use]
2020-10-29 04:37:51 +01:00
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::Unit(_)
| Self::Stack(_, _) => true,
2020-10-29 04:37:51 +01:00
2021-06-29 12:41:03 +02:00
Self::InterpolatedString(x, _) | Self::Array(x, _) => x.iter().all(Self::is_constant),
2020-10-29 04:37:51 +01:00
2021-03-23 11:25:40 +01:00
Self::Map(x, _) => x.0.iter().map(|(_, expr)| expr).all(Self::is_constant),
2020-10-29 04:37:51 +01:00
_ => false,
}
}
2020-11-25 02:36:06 +01:00
/// Is a particular [token][Token] allowed as a postfix operator to this expression?
#[inline]
2021-06-12 16:47:43 +02:00
#[must_use]
2021-06-28 12:06:05 +02:00
pub const 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-10-31 07:13:45 +01:00
| Self::CharConstant(_, _)
2020-10-31 16:26:21 +01:00
| Self::And(_, _)
| Self::Or(_, _)
2020-10-29 04:37:51 +01:00
| Self::Unit(_) => false,
2021-06-02 08:29:18 +02:00
Self::IntegerConstant(_, _)
| Self::StringConstant(_, _)
2021-06-29 12:41:03 +02:00
| Self::InterpolatedString(_, _)
2020-10-31 16:26:21 +01:00
| Self::FnCall(_, _)
2021-03-10 15:12:48 +01:00
| Self::Stmt(_)
2021-07-24 06:27:33 +02:00
| Self::Dot(_, _, _)
| Self::Index(_, _, _)
2020-10-31 16:26:21 +01:00
| Self::Array(_, _)
| Self::Map(_, _) => match token {
2020-10-29 04:37:51 +01:00
#[cfg(not(feature = "no_index"))]
Token::LeftBracket => true,
_ => false,
},
2021-04-05 17:59:15 +02:00
Self::Variable(_, _, _) => match token {
2020-10-29 04:37:51 +01:00
#[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,
2021-06-28 12:06:05 +02:00
Self::Stack(_, _) => false,
2020-10-29 04:37:51 +01:00
}
}
2021-01-08 17:24:55 +01:00
/// Recursively walk this expression.
2021-03-11 14:55:55 +01:00
/// Return `false` from the callback to terminate the walk.
pub fn walk<'a>(
&'a self,
path: &mut Vec<ASTNode<'a>>,
on_node: &mut impl FnMut(&[ASTNode]) -> bool,
) -> bool {
2021-05-22 13:14:24 +02:00
// Push the current node onto the path
2021-01-09 09:52:22 +01:00
path.push(self.into());
2021-03-11 14:55:55 +01:00
if !on_node(path) {
return false;
}
2021-01-08 17:24:55 +01:00
match self {
2021-03-11 14:55:55 +01:00
Self::Stmt(x) => {
2021-04-16 06:04:33 +02:00
for s in &x.0 {
2021-03-11 14:55:55 +01:00
if !s.walk(path, on_node) {
return false;
}
}
}
2021-06-29 12:41:03 +02:00
Self::InterpolatedString(x, _) | Self::Array(x, _) => {
2021-03-11 14:55:55 +01:00
for e in x.as_ref() {
if !e.walk(path, on_node) {
return false;
}
}
}
Self::Map(x, _) => {
2021-03-23 11:25:40 +01:00
for (_, e) in &x.0 {
2021-03-11 14:55:55 +01:00
if !e.walk(path, on_node) {
return false;
}
}
}
2021-07-24 06:27:33 +02:00
Self::Index(x, _, _) | Self::Dot(x, _, _) | Expr::And(x, _) | Expr::Or(x, _) => {
2021-03-11 14:55:55 +01:00
if !x.lhs.walk(path, on_node) {
return false;
}
if !x.rhs.walk(path, on_node) {
return false;
}
}
Self::FnCall(x, _) => {
for e in &x.args {
if !e.walk(path, on_node) {
return false;
}
}
}
Self::Custom(x, _) => {
2021-10-25 16:41:42 +02:00
for e in &x.inputs {
2021-03-11 14:55:55 +01:00
if !e.walk(path, on_node) {
return false;
}
}
2021-01-08 17:24:55 +01:00
}
_ => (),
}
2021-01-09 09:52:22 +01:00
2021-08-26 17:58:41 +02:00
path.pop().expect("`path` contains current node");
2021-03-11 14:55:55 +01:00
true
2021-01-08 17:24:55 +01:00
}
2020-10-29 04:37:51 +01:00
}