2021-12-17 16:07:13 +08:00
|
|
|
//! Module defining script expressions.
|
|
|
|
|
2022-11-28 23:24:22 +08:00
|
|
|
use super::{ASTFlags, ASTNode, Ident, Namespace, Stmt, StmtBlock};
|
2022-01-08 14:00:41 +08:00
|
|
|
use crate::engine::{KEYWORD_FN_PTR, OP_EXCLUSIVE_RANGE, OP_INCLUSIVE_RANGE};
|
2021-12-17 16:07:13 +08:00
|
|
|
use crate::func::hashing::ALT_ZERO_HASH;
|
2022-12-27 22:51:38 +08:00
|
|
|
use crate::tokenizer::Token;
|
2021-12-17 16:07:13 +08:00
|
|
|
use crate::types::dynamic::Union;
|
2022-07-29 10:49:03 +08:00
|
|
|
use crate::{
|
|
|
|
calc_fn_hash, Dynamic, FnPtr, Identifier, ImmutableString, Position, SmartString, StaticVec,
|
|
|
|
INT,
|
|
|
|
};
|
2021-12-17 16:07:13 +08:00
|
|
|
#[cfg(feature = "no_std")]
|
|
|
|
use std::prelude::v1::*;
|
|
|
|
use std::{
|
|
|
|
collections::BTreeMap,
|
|
|
|
fmt,
|
2022-07-29 10:49:03 +08:00
|
|
|
fmt::Write,
|
2021-12-17 16:07:13 +08:00
|
|
|
hash::Hash,
|
2022-01-08 14:00:41 +08:00
|
|
|
iter::once,
|
2022-10-30 18:43:18 +08:00
|
|
|
num::{NonZeroU64, NonZeroU8, NonZeroUsize},
|
2021-12-17 16:07:13 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
/// _(internals)_ A binary expression.
|
|
|
|
/// Exported under the `internals` feature only.
|
|
|
|
#[derive(Debug, Clone, Hash)]
|
|
|
|
pub struct BinaryExpr {
|
|
|
|
/// LHS expression.
|
|
|
|
pub lhs: Expr,
|
|
|
|
/// RHS expression.
|
|
|
|
pub rhs: Expr,
|
|
|
|
}
|
|
|
|
|
2022-01-28 10:11:40 +08:00
|
|
|
impl From<(Expr, Expr)> for BinaryExpr {
|
|
|
|
#[inline(always)]
|
|
|
|
fn from(value: (Expr, Expr)) -> Self {
|
|
|
|
Self {
|
|
|
|
lhs: value.0,
|
|
|
|
rhs: value.1,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-17 16:07:13 +08:00
|
|
|
/// _(internals)_ A custom syntax expression.
|
|
|
|
/// Exported under the `internals` feature only.
|
2022-07-05 22:59:03 +08:00
|
|
|
///
|
|
|
|
/// Not available under `no_custom_syntax`.
|
|
|
|
#[cfg(not(feature = "no_custom_syntax"))]
|
2021-12-17 16:07:13 +08:00
|
|
|
#[derive(Debug, Clone, Hash)]
|
|
|
|
pub struct CustomExpr {
|
|
|
|
/// List of keywords.
|
|
|
|
pub inputs: StaticVec<Expr>,
|
|
|
|
/// List of tokens actually parsed.
|
2022-08-13 18:07:42 +08:00
|
|
|
pub tokens: StaticVec<ImmutableString>,
|
2022-09-12 12:03:32 +08:00
|
|
|
/// State value.
|
|
|
|
pub state: Dynamic,
|
2021-12-17 16:07:13 +08:00
|
|
|
/// Is the current [`Scope`][crate::Scope] possibly modified by this custom statement
|
|
|
|
/// (e.g. introducing a new variable)?
|
|
|
|
pub scope_may_be_changed: bool,
|
|
|
|
/// Is this custom syntax self-terminated?
|
|
|
|
pub self_terminated: bool,
|
|
|
|
}
|
|
|
|
|
2022-07-05 22:59:03 +08:00
|
|
|
#[cfg(not(feature = "no_custom_syntax"))]
|
2021-12-17 16:07:13 +08:00
|
|
|
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 `;`
|
|
|
|
#[inline(always)]
|
2022-09-28 12:06:22 +08:00
|
|
|
#[must_use]
|
2021-12-17 16:07:13 +08:00
|
|
|
pub const fn is_self_terminated(&self) -> bool {
|
|
|
|
self.self_terminated
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// _(internals)_ A set of function call hashes. Exported under the `internals` feature only.
|
|
|
|
///
|
|
|
|
/// Two separate hashes are pre-calculated because of the following patterns:
|
|
|
|
///
|
2022-10-30 18:43:18 +08:00
|
|
|
/// ```rhai
|
2021-12-17 16:07:13 +08: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:
|
|
|
|
///
|
2022-10-30 18:43:18 +08:00
|
|
|
/// * First, the script hash (if any) is tried, which contains only the called function's name plus
|
|
|
|
/// the number of parameters.
|
2021-12-17 16:07:13 +08:00
|
|
|
///
|
|
|
|
/// * Next, the actual types of arguments are hashed and _combined_ with the native hash, which is
|
2022-10-30 18:43:18 +08:00
|
|
|
/// then used to search for a native function.
|
|
|
|
///
|
|
|
|
/// In other words, a complete native function call hash always contains the called function's
|
|
|
|
/// name plus the types of the arguments. This is due to possible function overloading for
|
|
|
|
/// different parameter types.
|
|
|
|
#[derive(Clone, Copy, Eq, PartialEq, Hash)]
|
2021-12-17 16:07:13 +08:00
|
|
|
pub struct FnCallHashes {
|
2022-10-30 18:43:18 +08:00
|
|
|
/// Pre-calculated hash for a script-defined function ([`None`] if native functions only).
|
2021-12-17 16:07:13 +08:00
|
|
|
#[cfg(not(feature = "no_function"))]
|
2022-10-30 18:43:18 +08:00
|
|
|
script: Option<NonZeroU64>,
|
2021-12-17 16:07:13 +08:00
|
|
|
/// Pre-calculated hash for a native Rust function with no parameter types.
|
2022-10-30 18:43:18 +08:00
|
|
|
native: NonZeroU64,
|
2021-12-17 16:07:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Debug for FnCallHashes {
|
2022-09-27 08:52:39 +08:00
|
|
|
#[cold]
|
|
|
|
#[inline(never)]
|
2021-12-17 16:07:13 +08:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
#[cfg(not(feature = "no_function"))]
|
2022-10-30 18:43:18 +08:00
|
|
|
if let Some(script) = self.script {
|
|
|
|
return if script == self.native {
|
2021-12-17 16:07:13 +08:00
|
|
|
fmt::Debug::fmt(&self.native, f)
|
|
|
|
} else {
|
2022-12-22 17:34:58 +08:00
|
|
|
write!(f, "({script}, {})", self.native)
|
2021-12-17 16:07:13 +08:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
write!(f, "{} (native only)", self.native)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<u64> for FnCallHashes {
|
2022-09-27 23:04:22 +08:00
|
|
|
#[inline]
|
2021-12-17 16:07:13 +08:00
|
|
|
fn from(hash: u64) -> Self {
|
2022-10-30 18:43:18 +08:00
|
|
|
let hash = NonZeroU64::new(if hash == 0 { ALT_ZERO_HASH } else { hash }).unwrap();
|
2021-12-17 16:07:13 +08:00
|
|
|
|
|
|
|
Self {
|
|
|
|
#[cfg(not(feature = "no_function"))]
|
2022-10-30 18:43:18 +08:00
|
|
|
script: Some(hash),
|
2021-12-17 16:07:13 +08:00
|
|
|
native: hash,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl FnCallHashes {
|
|
|
|
/// Create a [`FnCallHashes`] with only the native Rust hash.
|
2022-10-30 18:43:18 +08:00
|
|
|
#[inline]
|
2021-12-17 16:07:13 +08:00
|
|
|
#[must_use]
|
2022-10-30 18:43:18 +08:00
|
|
|
pub fn from_native(hash: u64) -> Self {
|
2021-12-17 16:07:13 +08:00
|
|
|
Self {
|
|
|
|
#[cfg(not(feature = "no_function"))]
|
2022-10-30 18:43:18 +08:00
|
|
|
script: None,
|
|
|
|
native: NonZeroU64::new(if hash == 0 { ALT_ZERO_HASH } else { hash }).unwrap(),
|
2021-12-17 16:07:13 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/// Create a [`FnCallHashes`] with both native Rust and script function hashes.
|
2022-10-30 18:43:18 +08:00
|
|
|
#[inline]
|
2021-12-17 16:07:13 +08:00
|
|
|
#[must_use]
|
2022-10-30 18:43:18 +08:00
|
|
|
pub fn from_all(#[cfg(not(feature = "no_function"))] script: u64, native: u64) -> Self {
|
2021-12-17 16:07:13 +08:00
|
|
|
Self {
|
|
|
|
#[cfg(not(feature = "no_function"))]
|
2022-10-30 18:43:18 +08:00
|
|
|
script: NonZeroU64::new(if script == 0 { ALT_ZERO_HASH } else { script }),
|
|
|
|
native: NonZeroU64::new(if native == 0 { ALT_ZERO_HASH } else { native }).unwrap(),
|
2021-12-17 16:07:13 +08:00
|
|
|
}
|
|
|
|
}
|
2022-10-30 15:45:25 +08:00
|
|
|
/// Is this [`FnCallHashes`] native-only?
|
2021-12-17 16:07:13 +08:00
|
|
|
#[inline(always)]
|
|
|
|
#[must_use]
|
|
|
|
pub const fn is_native_only(&self) -> bool {
|
|
|
|
#[cfg(not(feature = "no_function"))]
|
2022-10-30 18:43:18 +08:00
|
|
|
return self.script.is_none();
|
2021-12-17 16:07:13 +08:00
|
|
|
#[cfg(feature = "no_function")]
|
|
|
|
return true;
|
|
|
|
}
|
2022-10-30 15:45:25 +08:00
|
|
|
/// Get the native hash.
|
2022-10-30 18:43:18 +08:00
|
|
|
///
|
|
|
|
/// The hash returned is never zero.
|
2022-10-30 15:45:25 +08:00
|
|
|
#[inline(always)]
|
|
|
|
#[must_use]
|
2022-11-23 13:24:14 +08:00
|
|
|
pub const fn native(&self) -> u64 {
|
2022-10-30 18:43:18 +08:00
|
|
|
self.native.get()
|
2022-10-30 15:45:25 +08:00
|
|
|
}
|
|
|
|
/// Get the script hash.
|
2022-10-30 18:43:18 +08:00
|
|
|
///
|
|
|
|
/// The hash returned is never zero.
|
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
///
|
|
|
|
/// Panics if this [`FnCallHashes`] is native-only.
|
2022-10-30 15:45:25 +08:00
|
|
|
#[cfg(not(feature = "no_function"))]
|
|
|
|
#[inline(always)]
|
|
|
|
#[must_use]
|
2022-10-30 18:43:18 +08:00
|
|
|
pub fn script(&self) -> u64 {
|
|
|
|
assert!(self.script.is_some());
|
|
|
|
self.script.as_ref().unwrap().get()
|
2022-10-30 15:45:25 +08:00
|
|
|
}
|
2021-12-17 16:07:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// _(internals)_ A function call.
|
|
|
|
/// Exported under the `internals` feature only.
|
2022-10-14 18:31:40 +08:00
|
|
|
#[derive(Clone, Hash)]
|
2021-12-17 16:07:13 +08:00
|
|
|
pub struct FnCallExpr {
|
|
|
|
/// Namespace of the function, if any.
|
2022-11-28 23:24:22 +08:00
|
|
|
pub namespace: Namespace,
|
2021-12-17 16:07:13 +08:00
|
|
|
/// Function name.
|
2022-08-13 18:07:42 +08:00
|
|
|
pub name: ImmutableString,
|
2021-12-17 16:07:13 +08:00
|
|
|
/// Pre-calculated hashes.
|
|
|
|
pub hashes: FnCallHashes,
|
|
|
|
/// List of function call argument expressions.
|
|
|
|
pub args: StaticVec<Expr>,
|
|
|
|
/// Does this function call capture the parent scope?
|
|
|
|
pub capture_parent_scope: bool,
|
2022-09-03 22:07:36 +08:00
|
|
|
/// Is this function call a native operator?
|
2022-12-27 22:51:38 +08:00
|
|
|
pub op_token: Option<Token>,
|
2021-12-17 16:07:13 +08:00
|
|
|
}
|
|
|
|
|
2022-01-31 13:38:27 +08:00
|
|
|
impl fmt::Debug for FnCallExpr {
|
2022-09-27 08:52:39 +08:00
|
|
|
#[cold]
|
|
|
|
#[inline(never)]
|
2022-01-31 13:38:27 +08:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
let mut ff = f.debug_struct("FnCallExpr");
|
2022-03-05 17:57:23 +08:00
|
|
|
if !self.namespace.is_empty() {
|
|
|
|
ff.field("namespace", &self.namespace);
|
2022-01-31 13:38:27 +08:00
|
|
|
}
|
2022-10-16 11:35:21 +08:00
|
|
|
ff.field("hash", &self.hashes)
|
|
|
|
.field("name", &self.name)
|
|
|
|
.field("args", &self.args);
|
2022-12-27 22:51:38 +08:00
|
|
|
if self.op_token.is_some() {
|
2022-11-25 20:42:16 +08:00
|
|
|
ff.field("op_token", &self.op_token);
|
2022-09-02 23:45:25 +08:00
|
|
|
}
|
2022-10-16 11:35:21 +08:00
|
|
|
if self.capture_parent_scope {
|
|
|
|
ff.field("capture_parent_scope", &self.capture_parent_scope);
|
|
|
|
}
|
2022-01-31 13:38:27 +08:00
|
|
|
ff.finish()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-17 16:07:13 +08:00
|
|
|
impl FnCallExpr {
|
|
|
|
/// Does this function call contain a qualified namespace?
|
2022-01-29 11:09:43 +08:00
|
|
|
///
|
|
|
|
/// Always `false` under `no_module`.
|
2021-12-17 16:07:13 +08:00
|
|
|
#[inline(always)]
|
|
|
|
#[must_use]
|
2022-03-05 17:57:23 +08:00
|
|
|
pub fn is_qualified(&self) -> bool {
|
2022-11-28 23:24:22 +08:00
|
|
|
!self.namespace.is_empty()
|
2021-12-17 16:07:13 +08:00
|
|
|
}
|
|
|
|
/// Convert this into an [`Expr::FnCall`].
|
|
|
|
#[inline(always)]
|
|
|
|
#[must_use]
|
|
|
|
pub fn into_fn_call_expr(self, pos: Position) -> Expr {
|
|
|
|
Expr::FnCall(self.into(), pos)
|
|
|
|
}
|
2022-10-30 23:33:44 +08:00
|
|
|
/// Are all arguments constant?
|
|
|
|
#[inline]
|
|
|
|
#[must_use]
|
|
|
|
pub fn constant_args(&self) -> bool {
|
|
|
|
if self.args.is_empty() {
|
|
|
|
true
|
|
|
|
} else {
|
|
|
|
self.args.iter().all(Expr::is_constant)
|
|
|
|
}
|
|
|
|
}
|
2021-12-17 16:07:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// _(internals)_ An expression sub-tree.
|
|
|
|
/// Exported under the `internals` feature only.
|
|
|
|
#[derive(Clone, Hash)]
|
2022-04-26 16:36:24 +08:00
|
|
|
#[non_exhaustive]
|
2021-12-17 16:07:13 +08:00
|
|
|
pub enum Expr {
|
|
|
|
/// Dynamic constant.
|
|
|
|
///
|
|
|
|
/// Used to hold complex constants such as [`Array`][crate::Array] or [`Map`][crate::Map] for quick cloning.
|
|
|
|
/// Primitive data types should use the appropriate variants to avoid an allocation.
|
2022-08-14 18:16:35 +08:00
|
|
|
///
|
|
|
|
/// The [`Dynamic`] value is boxed in order to avoid bloating the size of [`Expr`].
|
2021-12-17 16:07:13 +08:00
|
|
|
DynamicConstant(Box<Dynamic>, Position),
|
|
|
|
/// Boolean constant.
|
|
|
|
BoolConstant(bool, Position),
|
|
|
|
/// Integer constant.
|
|
|
|
IntegerConstant(INT, Position),
|
|
|
|
/// Floating-point constant.
|
|
|
|
#[cfg(not(feature = "no_float"))]
|
2022-11-08 23:17:31 +08:00
|
|
|
FloatConstant(crate::types::FloatWrapper<crate::FLOAT>, Position),
|
2021-12-17 16:07:13 +08:00
|
|
|
/// Character constant.
|
|
|
|
CharConstant(char, Position),
|
|
|
|
/// [String][ImmutableString] constant.
|
|
|
|
StringConstant(ImmutableString, Position),
|
|
|
|
/// An interpolated [string][ImmutableString].
|
|
|
|
InterpolatedString(Box<StaticVec<Expr>>, Position),
|
|
|
|
/// [ expr, ... ]
|
|
|
|
Array(Box<StaticVec<Expr>>, Position),
|
|
|
|
/// #{ name:expr, ... }
|
|
|
|
Map(
|
|
|
|
Box<(StaticVec<(Ident, Expr)>, BTreeMap<Identifier, Dynamic>)>,
|
|
|
|
Position,
|
|
|
|
),
|
|
|
|
/// ()
|
|
|
|
Unit(Position),
|
2022-03-05 17:57:23 +08:00
|
|
|
/// Variable access - (optional long index, namespace, namespace hash, variable name), optional short index, position
|
2021-12-17 16:07:13 +08: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(
|
2022-11-28 23:24:22 +08:00
|
|
|
Box<(Option<NonZeroUsize>, Namespace, u64, ImmutableString)>,
|
2022-03-05 17:57:23 +08:00
|
|
|
Option<NonZeroU8>,
|
|
|
|
Position,
|
2021-12-17 16:07:13 +08:00
|
|
|
),
|
|
|
|
/// Property access - ((getter, hash), (setter, hash), prop)
|
|
|
|
Property(
|
2022-08-13 18:07:42 +08:00
|
|
|
Box<(
|
|
|
|
(ImmutableString, u64),
|
|
|
|
(ImmutableString, u64),
|
|
|
|
ImmutableString,
|
|
|
|
)>,
|
2022-01-28 10:11:40 +08:00
|
|
|
Position,
|
2021-12-17 16:07:13 +08:00
|
|
|
),
|
2022-03-04 12:22:44 +08:00
|
|
|
/// xxx `.` method `(` expr `,` ... `)`
|
|
|
|
MethodCall(Box<FnCallExpr>, Position),
|
2021-12-17 16:07:13 +08:00
|
|
|
/// { [statement][Stmt] ... }
|
|
|
|
Stmt(Box<StmtBlock>),
|
|
|
|
/// func `(` expr `,` ... `)`
|
|
|
|
FnCall(Box<FnCallExpr>, Position),
|
2022-06-10 10:26:06 +08:00
|
|
|
/// lhs `.` rhs | lhs `?.` rhs
|
2022-06-07 20:38:05 +08:00
|
|
|
///
|
|
|
|
/// ### Flags
|
|
|
|
///
|
2022-06-10 10:26:06 +08:00
|
|
|
/// [`NEGATED`][ASTFlags::NEGATED] = `?.` (`.` if unset)
|
|
|
|
/// [`BREAK`][ASTFlags::BREAK] = terminate the chain (recurse into the chain if unset)
|
2022-02-25 11:42:59 +08:00
|
|
|
Dot(Box<BinaryExpr>, ASTFlags, Position),
|
|
|
|
/// lhs `[` rhs `]`
|
|
|
|
///
|
|
|
|
/// ### Flags
|
|
|
|
///
|
2022-06-12 00:32:12 +08:00
|
|
|
/// [`NEGATED`][ASTFlags::NEGATED] = `?[` ... `]` (`[` ... `]` if unset)
|
2022-06-10 10:26:06 +08:00
|
|
|
/// [`BREAK`][ASTFlags::BREAK] = terminate the chain (recurse into the chain if unset)
|
2022-02-25 11:42:59 +08:00
|
|
|
Index(Box<BinaryExpr>, ASTFlags, Position),
|
2021-12-17 16:07:13 +08:00
|
|
|
/// lhs `&&` rhs
|
|
|
|
And(Box<BinaryExpr>, Position),
|
|
|
|
/// lhs `||` rhs
|
|
|
|
Or(Box<BinaryExpr>, Position),
|
2022-06-10 11:22:33 +08:00
|
|
|
/// lhs `??` rhs
|
|
|
|
Coalesce(Box<BinaryExpr>, Position),
|
2021-12-17 16:07:13 +08:00
|
|
|
/// Custom syntax
|
2022-07-05 22:59:03 +08:00
|
|
|
#[cfg(not(feature = "no_custom_syntax"))]
|
2021-12-17 16:07:13 +08:00
|
|
|
Custom(Box<CustomExpr>, Position),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for Expr {
|
|
|
|
#[inline(always)]
|
2022-09-28 12:06:22 +08:00
|
|
|
#[must_use]
|
2021-12-17 16:07:13 +08:00
|
|
|
fn default() -> Self {
|
|
|
|
Self::Unit(Position::NONE)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Debug for Expr {
|
2022-09-27 08:52:39 +08:00
|
|
|
#[cold]
|
|
|
|
#[inline(never)]
|
2021-12-17 16:07:13 +08:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2022-11-22 23:30:43 +08:00
|
|
|
let mut display_pos = self.start_position();
|
2021-12-17 16:07:13 +08:00
|
|
|
|
|
|
|
match self {
|
2022-10-27 13:38:21 +08:00
|
|
|
Self::DynamicConstant(value, ..) => write!(f, "{value:?}"),
|
|
|
|
Self::BoolConstant(value, ..) => write!(f, "{value:?}"),
|
|
|
|
Self::IntegerConstant(value, ..) => write!(f, "{value:?}"),
|
2021-12-17 16:07:13 +08:00
|
|
|
#[cfg(not(feature = "no_float"))]
|
2022-10-27 13:38:21 +08:00
|
|
|
Self::FloatConstant(value, ..) => write!(f, "{value:?}"),
|
|
|
|
Self::CharConstant(value, ..) => write!(f, "{value:?}"),
|
|
|
|
Self::StringConstant(value, ..) => write!(f, "{value:?}"),
|
2022-02-08 09:46:14 +08:00
|
|
|
Self::Unit(..) => f.write_str("()"),
|
2021-12-17 16:07:13 +08:00
|
|
|
|
2022-02-08 09:02:15 +08:00
|
|
|
Self::InterpolatedString(x, ..) => {
|
2021-12-17 16:07:13 +08:00
|
|
|
f.write_str("InterpolatedString")?;
|
|
|
|
return f.debug_list().entries(x.iter()).finish();
|
|
|
|
}
|
2022-02-08 09:02:15 +08:00
|
|
|
Self::Array(x, ..) => {
|
2021-12-17 16:07:13 +08:00
|
|
|
f.write_str("Array")?;
|
|
|
|
f.debug_list().entries(x.iter()).finish()
|
|
|
|
}
|
2022-02-08 09:02:15 +08:00
|
|
|
Self::Map(x, ..) => {
|
2021-12-17 16:07:13 +08:00
|
|
|
f.write_str("Map")?;
|
|
|
|
f.debug_map()
|
|
|
|
.entries(x.0.iter().map(|(k, v)| (k, v)))
|
|
|
|
.finish()
|
|
|
|
}
|
2022-03-05 17:57:23 +08:00
|
|
|
Self::Variable(x, i, ..) => {
|
2021-12-17 16:07:13 +08:00
|
|
|
f.write_str("Variable(")?;
|
2022-01-29 11:09:43 +08:00
|
|
|
|
|
|
|
#[cfg(not(feature = "no_module"))]
|
2022-03-05 17:57:23 +08:00
|
|
|
if !x.1.is_empty() {
|
|
|
|
write!(f, "{}{}", x.1, Token::DoubleColon.literal_syntax())?;
|
|
|
|
let pos = x.1.position();
|
2022-02-10 17:55:32 +08:00
|
|
|
if !pos.is_none() {
|
2022-11-22 23:30:43 +08:00
|
|
|
display_pos = pos;
|
2022-02-10 17:55:32 +08:00
|
|
|
}
|
2021-12-17 16:07:13 +08:00
|
|
|
}
|
2022-03-05 17:57:23 +08:00
|
|
|
f.write_str(&x.3)?;
|
2022-10-14 15:23:58 +08:00
|
|
|
#[cfg(not(feature = "no_module"))]
|
2022-10-14 14:04:54 +08:00
|
|
|
if let Some(n) = x.1.index() {
|
2022-10-27 13:38:21 +08:00
|
|
|
write!(f, " #{n}")?;
|
2022-10-14 14:04:54 +08:00
|
|
|
}
|
2021-12-17 16:07:13 +08:00
|
|
|
if let Some(n) = i.map_or_else(|| x.0, |n| NonZeroUsize::new(n.get() as usize)) {
|
2022-10-27 13:38:21 +08:00
|
|
|
write!(f, " #{n}")?;
|
2021-12-17 16:07:13 +08:00
|
|
|
}
|
|
|
|
f.write_str(")")
|
|
|
|
}
|
2022-02-08 09:02:15 +08:00
|
|
|
Self::Property(x, ..) => write!(f, "Property({})", x.2),
|
2022-03-04 12:22:44 +08:00
|
|
|
Self::MethodCall(x, ..) => f.debug_tuple("MethodCall").field(x).finish(),
|
2021-12-17 16:07:13 +08:00
|
|
|
Self::Stmt(x) => {
|
2022-02-10 17:55:32 +08:00
|
|
|
let pos = x.span();
|
|
|
|
if !pos.is_none() {
|
2022-11-22 23:30:43 +08:00
|
|
|
display_pos = pos.start();
|
2022-02-10 17:55:32 +08:00
|
|
|
}
|
2021-12-17 16:07:13 +08:00
|
|
|
f.write_str("ExprStmtBlock")?;
|
|
|
|
f.debug_list().entries(x.iter()).finish()
|
|
|
|
}
|
2022-02-08 09:02:15 +08:00
|
|
|
Self::FnCall(x, ..) => fmt::Debug::fmt(x, f),
|
2022-06-10 10:26:06 +08:00
|
|
|
Self::Index(x, options, pos) => {
|
2022-02-10 17:55:32 +08:00
|
|
|
if !pos.is_none() {
|
2022-11-22 23:30:43 +08:00
|
|
|
display_pos = *pos;
|
2022-02-10 17:55:32 +08:00
|
|
|
}
|
2021-12-17 16:07:13 +08:00
|
|
|
|
2022-06-10 10:26:06 +08:00
|
|
|
let mut f = f.debug_struct("Index");
|
|
|
|
|
|
|
|
f.field("lhs", &x.lhs).field("rhs", &x.rhs);
|
|
|
|
if !options.is_empty() {
|
|
|
|
f.field("options", options);
|
|
|
|
}
|
|
|
|
f.finish()
|
|
|
|
}
|
|
|
|
Self::Dot(x, options, pos) => {
|
|
|
|
if !pos.is_none() {
|
2022-11-22 23:30:43 +08:00
|
|
|
display_pos = *pos;
|
2022-06-10 10:26:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
let mut f = f.debug_struct("Dot");
|
|
|
|
|
|
|
|
f.field("lhs", &x.lhs).field("rhs", &x.rhs);
|
|
|
|
if !options.is_empty() {
|
|
|
|
f.field("options", options);
|
|
|
|
}
|
|
|
|
f.finish()
|
2021-12-17 16:07:13 +08:00
|
|
|
}
|
2022-06-10 11:22:33 +08:00
|
|
|
Self::And(x, pos) | Self::Or(x, pos) | Self::Coalesce(x, pos) => {
|
2021-12-17 16:07:13 +08:00
|
|
|
let op_name = match self {
|
2022-02-08 09:02:15 +08:00
|
|
|
Self::And(..) => "And",
|
|
|
|
Self::Or(..) => "Or",
|
2022-06-10 11:22:33 +08:00
|
|
|
Self::Coalesce(..) => "Coalesce",
|
|
|
|
expr => unreachable!("`And`, `Or` or `Coalesce` expected but gets {:?}", expr),
|
2021-12-17 16:07:13 +08:00
|
|
|
};
|
|
|
|
|
2022-02-10 17:55:32 +08:00
|
|
|
if !pos.is_none() {
|
2022-11-22 23:30:43 +08:00
|
|
|
display_pos = *pos;
|
2022-02-10 17:55:32 +08:00
|
|
|
}
|
2021-12-17 16:07:13 +08:00
|
|
|
|
|
|
|
f.debug_struct(op_name)
|
|
|
|
.field("lhs", &x.lhs)
|
|
|
|
.field("rhs", &x.rhs)
|
|
|
|
.finish()
|
|
|
|
}
|
2022-07-05 22:59:03 +08:00
|
|
|
#[cfg(not(feature = "no_custom_syntax"))]
|
2022-02-08 09:02:15 +08:00
|
|
|
Self::Custom(x, ..) => f.debug_tuple("Custom").field(x).finish(),
|
2021-12-17 16:07:13 +08:00
|
|
|
}?;
|
|
|
|
|
2022-11-22 23:30:43 +08:00
|
|
|
write!(f, " @ {display_pos:?}")
|
2021-12-17 16:07:13 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Expr {
|
|
|
|
/// Get the [`Dynamic`] value of a literal constant expression.
|
|
|
|
///
|
|
|
|
/// Returns [`None`] if the expression is not a literal constant.
|
|
|
|
#[inline]
|
|
|
|
#[must_use]
|
|
|
|
pub fn get_literal_value(&self) -> Option<Dynamic> {
|
|
|
|
Some(match self {
|
2022-02-08 09:02:15 +08:00
|
|
|
Self::DynamicConstant(x, ..) => x.as_ref().clone(),
|
|
|
|
Self::IntegerConstant(x, ..) => (*x).into(),
|
2021-12-17 16:07:13 +08:00
|
|
|
#[cfg(not(feature = "no_float"))]
|
2022-02-08 09:02:15 +08:00
|
|
|
Self::FloatConstant(x, ..) => (*x).into(),
|
|
|
|
Self::CharConstant(x, ..) => (*x).into(),
|
|
|
|
Self::StringConstant(x, ..) => x.clone().into(),
|
|
|
|
Self::BoolConstant(x, ..) => (*x).into(),
|
2022-02-08 09:46:14 +08:00
|
|
|
Self::Unit(..) => Dynamic::UNIT,
|
2021-12-17 16:07:13 +08:00
|
|
|
|
|
|
|
#[cfg(not(feature = "no_index"))]
|
2022-02-08 09:02:15 +08:00
|
|
|
Self::Array(x, ..) if self.is_constant() => {
|
2021-12-17 16:07:13 +08:00
|
|
|
let mut arr = crate::Array::with_capacity(x.len());
|
2022-01-06 11:07:52 +08:00
|
|
|
arr.extend(x.iter().map(|v| v.get_literal_value().unwrap()));
|
2021-12-17 16:07:13 +08:00
|
|
|
Dynamic::from_array(arr)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(feature = "no_object"))]
|
2022-02-08 09:02:15 +08:00
|
|
|
Self::Map(x, ..) if self.is_constant() => {
|
2022-12-29 17:51:27 +08:00
|
|
|
let mut map = x.1.clone();
|
|
|
|
|
|
|
|
for (k, v) in &x.0 {
|
|
|
|
*map.get_mut(k.name.as_str()).unwrap() = v.get_literal_value().unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
Dynamic::from_map(map)
|
2021-12-17 16:07:13 +08:00
|
|
|
}
|
|
|
|
|
2022-07-29 10:49:03 +08:00
|
|
|
// Interpolated string
|
|
|
|
Self::InterpolatedString(x, ..) if self.is_constant() => {
|
|
|
|
let mut s = SmartString::new_const();
|
|
|
|
for segment in x.iter() {
|
|
|
|
let v = segment.get_literal_value().unwrap();
|
2022-10-29 10:40:07 +08:00
|
|
|
write!(&mut s, "{v}").unwrap();
|
2022-07-29 10:49:03 +08:00
|
|
|
}
|
|
|
|
s.into()
|
|
|
|
}
|
|
|
|
|
2022-01-08 14:00:41 +08:00
|
|
|
// Fn
|
2022-02-08 09:02:15 +08:00
|
|
|
Self::FnCall(ref x, ..)
|
2022-01-08 14:00:41 +08:00
|
|
|
if !x.is_qualified() && x.args.len() == 1 && x.name == KEYWORD_FN_PTR =>
|
|
|
|
{
|
2022-08-27 16:26:41 +08:00
|
|
|
if let Self::StringConstant(ref s, ..) = x.args[0] {
|
2022-10-29 14:59:20 +08:00
|
|
|
FnPtr::new(s.clone()).ok()?.into()
|
2022-01-08 14:00:41 +08:00
|
|
|
} else {
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-17 16:07:13 +08:00
|
|
|
// Binary operators
|
2022-02-08 09:02:15 +08:00
|
|
|
Self::FnCall(x, ..) if !x.is_qualified() && x.args.len() == 2 => {
|
|
|
|
match x.name.as_str() {
|
|
|
|
// x..y
|
|
|
|
OP_EXCLUSIVE_RANGE => {
|
2022-08-27 16:26:41 +08:00
|
|
|
if let Self::IntegerConstant(ref start, ..) = x.args[0] {
|
|
|
|
if let Self::IntegerConstant(ref end, ..) = x.args[1] {
|
2022-02-08 09:02:15 +08:00
|
|
|
(*start..*end).into()
|
|
|
|
} else {
|
|
|
|
return None;
|
|
|
|
}
|
2021-12-17 16:07:13 +08:00
|
|
|
} else {
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
}
|
2022-02-08 09:02:15 +08:00
|
|
|
// x..=y
|
|
|
|
OP_INCLUSIVE_RANGE => {
|
2022-08-27 16:26:41 +08:00
|
|
|
if let Self::IntegerConstant(ref start, ..) = x.args[0] {
|
|
|
|
if let Self::IntegerConstant(ref end, ..) = x.args[1] {
|
2022-02-08 09:02:15 +08:00
|
|
|
(*start..=*end).into()
|
|
|
|
} else {
|
|
|
|
return None;
|
|
|
|
}
|
2021-12-17 16:07:13 +08:00
|
|
|
} else {
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
}
|
2022-02-08 09:02:15 +08:00
|
|
|
_ => return None,
|
2021-12-17 16:07:13 +08:00
|
|
|
}
|
2022-02-08 09:02:15 +08:00
|
|
|
}
|
2021-12-17 16:07:13 +08:00
|
|
|
|
|
|
|
_ => return None,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
/// Create an [`Expr`] from a [`Dynamic`] value.
|
|
|
|
#[inline]
|
|
|
|
#[must_use]
|
|
|
|
pub fn from_dynamic(value: Dynamic, pos: Position) -> Self {
|
|
|
|
match value.0 {
|
2022-02-08 09:02:15 +08:00
|
|
|
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),
|
2021-12-17 16:07:13 +08:00
|
|
|
|
|
|
|
#[cfg(feature = "decimal")]
|
2022-02-08 09:02:15 +08:00
|
|
|
Union::Decimal(value, ..) => Self::DynamicConstant(Box::new((*value).into()), pos),
|
2021-12-17 16:07:13 +08:00
|
|
|
|
|
|
|
#[cfg(not(feature = "no_float"))]
|
2022-02-08 09:02:15 +08:00
|
|
|
Union::Float(f, ..) => Self::FloatConstant(f, pos),
|
2021-12-17 16:07:13 +08:00
|
|
|
|
|
|
|
#[cfg(not(feature = "no_index"))]
|
2022-02-08 09:02:15 +08:00
|
|
|
Union::Array(a, ..) => Self::DynamicConstant(Box::new((*a).into()), pos),
|
2021-12-17 16:07:13 +08:00
|
|
|
|
|
|
|
#[cfg(not(feature = "no_object"))]
|
2022-02-08 09:02:15 +08:00
|
|
|
Union::Map(m, ..) => Self::DynamicConstant(Box::new((*m).into()), pos),
|
2021-12-17 16:07:13 +08:00
|
|
|
|
2022-02-08 09:02:15 +08:00
|
|
|
Union::FnPtr(f, ..) if !f.is_curried() => Self::FnCall(
|
2022-01-08 14:00:41 +08:00
|
|
|
FnCallExpr {
|
2022-11-28 23:24:22 +08:00
|
|
|
namespace: Namespace::NONE,
|
2022-01-08 14:00:41 +08:00
|
|
|
name: KEYWORD_FN_PTR.into(),
|
2022-09-21 11:46:23 +08:00
|
|
|
hashes: calc_fn_hash(None, f.fn_name(), 1).into(),
|
2022-03-05 12:06:47 +08:00
|
|
|
args: once(Self::StringConstant(f.fn_name().into(), pos)).collect(),
|
2022-01-08 14:00:41 +08:00
|
|
|
capture_parent_scope: false,
|
2022-12-27 22:51:38 +08:00
|
|
|
op_token: None,
|
2022-01-08 14:00:41 +08:00
|
|
|
}
|
|
|
|
.into(),
|
|
|
|
pos,
|
|
|
|
),
|
|
|
|
|
2021-12-17 16:07:13 +08:00
|
|
|
_ => Self::DynamicConstant(value.into(), pos),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/// Is the expression a simple variable access?
|
2022-01-29 11:09:43 +08:00
|
|
|
///
|
|
|
|
/// `non_qualified` is ignored under `no_module`.
|
2021-12-17 16:07:13 +08:00
|
|
|
#[inline]
|
|
|
|
#[must_use]
|
2022-04-11 16:29:16 +08:00
|
|
|
pub(crate) fn is_variable_access(&self, _non_qualified: bool) -> bool {
|
2021-12-17 16:07:13 +08:00
|
|
|
match self {
|
2022-01-29 11:09:43 +08:00
|
|
|
#[cfg(not(feature = "no_module"))]
|
2022-03-05 17:57:23 +08:00
|
|
|
Self::Variable(x, ..) if _non_qualified && !x.1.is_empty() => false,
|
2022-02-08 09:02:15 +08:00
|
|
|
Self::Variable(..) => true,
|
2021-12-17 16:07:13 +08:00
|
|
|
_ => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/// Return the variable name if the expression a simple variable access.
|
2022-01-29 11:09:43 +08:00
|
|
|
///
|
|
|
|
/// `non_qualified` is ignored under `no_module`.
|
2021-12-17 16:07:13 +08:00
|
|
|
#[inline]
|
|
|
|
#[must_use]
|
2022-04-11 16:29:16 +08:00
|
|
|
pub(crate) fn get_variable_name(&self, _non_qualified: bool) -> Option<&str> {
|
2021-12-17 16:07:13 +08:00
|
|
|
match self {
|
2022-01-29 11:09:43 +08:00
|
|
|
#[cfg(not(feature = "no_module"))]
|
2022-03-05 17:57:23 +08:00
|
|
|
Self::Variable(x, ..) if _non_qualified && !x.1.is_empty() => None,
|
|
|
|
Self::Variable(x, ..) => Some(x.3.as_str()),
|
2021-12-17 16:07:13 +08:00
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
2022-11-19 18:41:51 +08:00
|
|
|
/// Get the [options][ASTFlags] of the expression.
|
|
|
|
#[inline]
|
|
|
|
#[must_use]
|
|
|
|
pub const fn options(&self) -> ASTFlags {
|
|
|
|
match self {
|
|
|
|
Self::Index(_, options, _) | Self::Dot(_, options, _) => *options,
|
|
|
|
|
|
|
|
#[cfg(not(feature = "no_float"))]
|
|
|
|
Self::FloatConstant(..) => ASTFlags::NONE,
|
|
|
|
|
|
|
|
Self::DynamicConstant(..)
|
|
|
|
| Self::BoolConstant(..)
|
|
|
|
| Self::IntegerConstant(..)
|
|
|
|
| Self::CharConstant(..)
|
|
|
|
| Self::Unit(..)
|
|
|
|
| Self::StringConstant(..)
|
|
|
|
| Self::Array(..)
|
|
|
|
| Self::Map(..)
|
|
|
|
| Self::Variable(..)
|
|
|
|
| Self::And(..)
|
|
|
|
| Self::Or(..)
|
|
|
|
| Self::Coalesce(..)
|
|
|
|
| Self::FnCall(..)
|
|
|
|
| Self::MethodCall(..)
|
|
|
|
| Self::InterpolatedString(..)
|
|
|
|
| Self::Property(..)
|
|
|
|
| Self::Stmt(..) => ASTFlags::NONE,
|
|
|
|
|
|
|
|
#[cfg(not(feature = "no_custom_syntax"))]
|
|
|
|
Self::Custom(..) => ASTFlags::NONE,
|
|
|
|
}
|
|
|
|
}
|
2021-12-17 16:07:13 +08:00
|
|
|
/// Get the [position][Position] of the expression.
|
|
|
|
#[inline]
|
|
|
|
#[must_use]
|
|
|
|
pub const fn position(&self) -> Position {
|
|
|
|
match self {
|
|
|
|
#[cfg(not(feature = "no_float"))]
|
2022-02-08 09:02:15 +08:00
|
|
|
Self::FloatConstant(.., pos) => *pos,
|
2021-12-17 16:07:13 +08:00
|
|
|
|
2022-02-08 09:02:15 +08:00
|
|
|
Self::DynamicConstant(.., pos)
|
|
|
|
| Self::BoolConstant(.., pos)
|
|
|
|
| Self::IntegerConstant(.., pos)
|
|
|
|
| Self::CharConstant(.., pos)
|
2021-12-17 16:07:13 +08:00
|
|
|
| Self::Unit(pos)
|
2022-02-08 09:02:15 +08:00
|
|
|
| Self::StringConstant(.., pos)
|
|
|
|
| Self::Array(.., pos)
|
|
|
|
| Self::Map(.., pos)
|
2022-03-05 17:57:23 +08:00
|
|
|
| Self::Variable(.., pos)
|
2022-02-08 09:02:15 +08:00
|
|
|
| Self::And(.., pos)
|
|
|
|
| Self::Or(.., pos)
|
2022-06-10 11:22:33 +08:00
|
|
|
| Self::Coalesce(.., pos)
|
2022-10-30 18:43:18 +08:00
|
|
|
| Self::FnCall(.., pos)
|
|
|
|
| Self::MethodCall(.., pos)
|
2022-02-08 09:02:15 +08:00
|
|
|
| Self::Index(.., pos)
|
|
|
|
| Self::Dot(.., pos)
|
|
|
|
| Self::InterpolatedString(.., pos)
|
|
|
|
| Self::Property(.., pos) => *pos,
|
|
|
|
|
2022-07-05 22:59:03 +08:00
|
|
|
#[cfg(not(feature = "no_custom_syntax"))]
|
|
|
|
Self::Custom(.., pos) => *pos,
|
|
|
|
|
2022-02-04 12:04:33 +08:00
|
|
|
Self::Stmt(x) => x.position(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/// Get the starting [position][Position] of the expression.
|
|
|
|
/// For a binary expression, this will be the left-most LHS instead of the operator.
|
|
|
|
#[inline]
|
|
|
|
#[must_use]
|
2022-02-10 17:55:32 +08:00
|
|
|
pub fn start_position(&self) -> Position {
|
2022-02-04 12:04:33 +08:00
|
|
|
match self {
|
2022-02-10 17:55:32 +08:00
|
|
|
#[cfg(not(feature = "no_module"))]
|
2022-03-05 17:57:23 +08:00
|
|
|
Self::Variable(x, ..) => {
|
2022-07-27 18:04:59 +08:00
|
|
|
if x.1.is_empty() {
|
2022-02-10 17:55:32 +08:00
|
|
|
self.position()
|
2022-07-27 18:04:59 +08:00
|
|
|
} else {
|
|
|
|
x.1.position()
|
2022-02-10 17:55:32 +08:00
|
|
|
}
|
|
|
|
}
|
2022-06-10 11:22:33 +08:00
|
|
|
|
|
|
|
Self::And(x, ..)
|
|
|
|
| Self::Or(x, ..)
|
|
|
|
| Self::Coalesce(x, ..)
|
|
|
|
| Self::Index(x, ..)
|
|
|
|
| Self::Dot(x, ..) => x.lhs.start_position(),
|
|
|
|
|
2022-02-08 09:02:15 +08:00
|
|
|
Self::FnCall(.., pos) => *pos,
|
2022-06-10 11:22:33 +08:00
|
|
|
|
2022-02-04 12:04:33 +08:00
|
|
|
_ => self.position(),
|
2021-12-17 16:07:13 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/// Override the [position][Position] of the expression.
|
|
|
|
#[inline]
|
|
|
|
pub fn set_position(&mut self, new_pos: Position) -> &mut Self {
|
|
|
|
match self {
|
|
|
|
#[cfg(not(feature = "no_float"))]
|
2022-02-08 09:02:15 +08:00
|
|
|
Self::FloatConstant(.., pos) => *pos = new_pos,
|
2021-12-17 16:07:13 +08:00
|
|
|
|
2022-02-08 09:02:15 +08:00
|
|
|
Self::DynamicConstant(.., pos)
|
|
|
|
| Self::BoolConstant(.., pos)
|
|
|
|
| Self::IntegerConstant(.., pos)
|
|
|
|
| Self::CharConstant(.., pos)
|
2021-12-17 16:07:13 +08:00
|
|
|
| Self::Unit(pos)
|
2022-02-08 09:02:15 +08:00
|
|
|
| Self::StringConstant(.., pos)
|
|
|
|
| Self::Array(.., pos)
|
|
|
|
| Self::Map(.., pos)
|
|
|
|
| Self::And(.., pos)
|
|
|
|
| Self::Or(.., pos)
|
2022-06-10 11:22:33 +08:00
|
|
|
| Self::Coalesce(.., pos)
|
2022-02-08 09:02:15 +08:00
|
|
|
| Self::Dot(.., pos)
|
|
|
|
| Self::Index(.., pos)
|
2022-03-05 17:57:23 +08:00
|
|
|
| Self::Variable(.., pos)
|
2022-02-08 09:02:15 +08:00
|
|
|
| Self::FnCall(.., pos)
|
2022-03-04 12:22:44 +08:00
|
|
|
| Self::MethodCall(.., pos)
|
2022-02-08 09:02:15 +08:00
|
|
|
| Self::InterpolatedString(.., pos)
|
|
|
|
| Self::Property(.., pos) => *pos = new_pos,
|
2021-12-17 16:07:13 +08:00
|
|
|
|
2022-07-05 22:59:03 +08:00
|
|
|
#[cfg(not(feature = "no_custom_syntax"))]
|
|
|
|
Self::Custom(.., pos) => *pos = new_pos,
|
|
|
|
|
2022-02-04 12:04:33 +08:00
|
|
|
Self::Stmt(x) => x.set_position(new_pos, Position::NONE),
|
2021-12-17 16:07:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
self
|
|
|
|
}
|
|
|
|
/// Is the expression pure?
|
|
|
|
///
|
|
|
|
/// A pure expression has no side effects.
|
|
|
|
#[inline]
|
|
|
|
#[must_use]
|
|
|
|
pub fn is_pure(&self) -> bool {
|
|
|
|
match self {
|
2022-02-08 09:02:15 +08:00
|
|
|
Self::InterpolatedString(x, ..) | Self::Array(x, ..) => x.iter().all(Self::is_pure),
|
2021-12-17 16:07:13 +08:00
|
|
|
|
2022-02-08 09:02:15 +08:00
|
|
|
Self::Map(x, ..) => x.0.iter().map(|(.., v)| v).all(Self::is_pure),
|
2021-12-17 16:07:13 +08:00
|
|
|
|
2022-06-10 11:22:33 +08:00
|
|
|
Self::And(x, ..) | Self::Or(x, ..) | Self::Coalesce(x, ..) => {
|
|
|
|
x.lhs.is_pure() && x.rhs.is_pure()
|
|
|
|
}
|
2021-12-17 16:07:13 +08:00
|
|
|
|
|
|
|
Self::Stmt(x) => x.iter().all(Stmt::is_pure),
|
|
|
|
|
2022-03-05 12:06:47 +08:00
|
|
|
Self::Variable(..) => true,
|
2021-12-17 16:07:13 +08:00
|
|
|
|
|
|
|
_ => self.is_constant(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/// Is the expression the unit `()` literal?
|
|
|
|
#[inline(always)]
|
|
|
|
#[must_use]
|
|
|
|
pub const fn is_unit(&self) -> bool {
|
2022-02-08 09:46:14 +08:00
|
|
|
matches!(self, Self::Unit(..))
|
2021-12-17 16:07:13 +08:00
|
|
|
}
|
|
|
|
/// Is the expression a constant?
|
|
|
|
#[inline]
|
|
|
|
#[must_use]
|
|
|
|
pub fn is_constant(&self) -> bool {
|
|
|
|
match self {
|
|
|
|
#[cfg(not(feature = "no_float"))]
|
2022-02-08 09:02:15 +08:00
|
|
|
Self::FloatConstant(..) => true,
|
2021-12-17 16:07:13 +08:00
|
|
|
|
2022-02-08 09:02:15 +08:00
|
|
|
Self::DynamicConstant(..)
|
|
|
|
| Self::BoolConstant(..)
|
|
|
|
| Self::IntegerConstant(..)
|
|
|
|
| Self::CharConstant(..)
|
|
|
|
| Self::StringConstant(..)
|
2022-03-05 12:06:47 +08:00
|
|
|
| Self::Unit(..) => true,
|
2021-12-17 16:07:13 +08:00
|
|
|
|
2022-02-08 09:02:15 +08:00
|
|
|
Self::InterpolatedString(x, ..) | Self::Array(x, ..) => x.iter().all(Self::is_constant),
|
2021-12-17 16:07:13 +08:00
|
|
|
|
2022-02-08 09:02:15 +08:00
|
|
|
Self::Map(x, ..) => x.0.iter().map(|(.., expr)| expr).all(Self::is_constant),
|
2021-12-17 16:07:13 +08:00
|
|
|
|
|
|
|
_ => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/// Is a particular [token][Token] allowed as a postfix operator to this expression?
|
|
|
|
#[inline]
|
|
|
|
#[must_use]
|
|
|
|
pub const fn is_valid_postfix(&self, token: &Token) -> bool {
|
|
|
|
match token {
|
|
|
|
#[cfg(not(feature = "no_object"))]
|
2022-06-10 10:26:06 +08:00
|
|
|
Token::Period | Token::Elvis => return true,
|
2022-05-17 11:06:34 +08:00
|
|
|
#[cfg(not(feature = "no_index"))]
|
2022-06-12 00:32:12 +08:00
|
|
|
Token::LeftBracket | Token::QuestionBracket => return true,
|
2021-12-17 16:07:13 +08:00
|
|
|
_ => (),
|
|
|
|
}
|
|
|
|
|
|
|
|
match self {
|
|
|
|
#[cfg(not(feature = "no_float"))]
|
2022-02-08 09:02:15 +08:00
|
|
|
Self::FloatConstant(..) => false,
|
2021-12-17 16:07:13 +08:00
|
|
|
|
2022-02-08 09:02:15 +08:00
|
|
|
Self::DynamicConstant(..)
|
|
|
|
| Self::BoolConstant(..)
|
|
|
|
| Self::CharConstant(..)
|
|
|
|
| Self::And(..)
|
|
|
|
| Self::Or(..)
|
2022-06-10 11:22:33 +08:00
|
|
|
| Self::Coalesce(..)
|
2022-02-08 09:46:14 +08:00
|
|
|
| Self::Unit(..) => false,
|
2021-12-17 16:07:13 +08:00
|
|
|
|
2022-02-08 09:02:15 +08:00
|
|
|
Self::IntegerConstant(..)
|
|
|
|
| Self::StringConstant(..)
|
|
|
|
| Self::InterpolatedString(..)
|
|
|
|
| Self::FnCall(..)
|
2022-03-04 12:22:44 +08:00
|
|
|
| Self::MethodCall(..)
|
2022-02-08 09:46:14 +08:00
|
|
|
| Self::Stmt(..)
|
2022-02-08 09:02:15 +08:00
|
|
|
| Self::Dot(..)
|
|
|
|
| Self::Index(..)
|
|
|
|
| Self::Array(..)
|
2022-07-05 22:59:03 +08:00
|
|
|
| Self::Map(..) => false,
|
|
|
|
|
|
|
|
#[cfg(not(feature = "no_custom_syntax"))]
|
|
|
|
Self::Custom(..) => false,
|
2021-12-17 16:07:13 +08:00
|
|
|
|
2022-11-23 13:24:14 +08:00
|
|
|
Self::Variable(..) => matches!(
|
|
|
|
token,
|
|
|
|
Token::LeftParen | Token::Unit | Token::Bang | Token::DoubleColon
|
|
|
|
),
|
|
|
|
|
|
|
|
Self::Property(..) => matches!(token, Token::LeftParen),
|
2021-12-17 16:07:13 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/// Recursively walk this expression.
|
|
|
|
/// 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 {
|
|
|
|
// Push the current node onto the path
|
|
|
|
path.push(self.into());
|
|
|
|
|
|
|
|
if !on_node(path) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
match self {
|
|
|
|
Self::Stmt(x) => {
|
2022-07-05 16:26:38 +08:00
|
|
|
for s in &**x {
|
2021-12-17 16:07:13 +08:00
|
|
|
if !s.walk(path, on_node) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-02-08 09:02:15 +08:00
|
|
|
Self::InterpolatedString(x, ..) | Self::Array(x, ..) => {
|
2022-07-05 16:26:38 +08:00
|
|
|
for e in &**x {
|
2021-12-17 16:07:13 +08:00
|
|
|
if !e.walk(path, on_node) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-02-08 09:02:15 +08:00
|
|
|
Self::Map(x, ..) => {
|
|
|
|
for (.., e) in &x.0 {
|
2021-12-17 16:07:13 +08:00
|
|
|
if !e.walk(path, on_node) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-06-10 11:22:33 +08:00
|
|
|
Self::Index(x, ..)
|
|
|
|
| Self::Dot(x, ..)
|
2022-08-27 16:26:41 +08:00
|
|
|
| Self::And(x, ..)
|
|
|
|
| Self::Or(x, ..)
|
|
|
|
| Self::Coalesce(x, ..) => {
|
2021-12-17 16:07:13 +08:00
|
|
|
if !x.lhs.walk(path, on_node) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if !x.rhs.walk(path, on_node) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2022-02-08 09:02:15 +08:00
|
|
|
Self::FnCall(x, ..) => {
|
2021-12-17 16:07:13 +08:00
|
|
|
for e in &x.args {
|
|
|
|
if !e.walk(path, on_node) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-07-05 22:59:03 +08:00
|
|
|
#[cfg(not(feature = "no_custom_syntax"))]
|
2022-02-08 09:02:15 +08:00
|
|
|
Self::Custom(x, ..) => {
|
2021-12-17 16:07:13 +08:00
|
|
|
for e in &x.inputs {
|
|
|
|
if !e.walk(path, on_node) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => (),
|
|
|
|
}
|
|
|
|
|
2022-01-06 11:07:52 +08:00
|
|
|
path.pop().unwrap();
|
2021-12-17 16:07:13 +08:00
|
|
|
|
|
|
|
true
|
|
|
|
}
|
|
|
|
}
|