Code cleanup.
This commit is contained in:
parent
8b773aa15e
commit
22ee12531c
@ -274,7 +274,7 @@ impl Engine {
|
|||||||
|
|
||||||
// Check for data race.
|
// Check for data race.
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
crate::func::call::ensure_no_data_race(name, &args, false).map(|_| Dynamic::UNIT)?;
|
crate::func::ensure_no_data_race(name, &args, false).map(|_| Dynamic::UNIT)?;
|
||||||
|
|
||||||
if let Some(fn_def) = ast.shared_lib().get_script_fn(name, args.len()) {
|
if let Some(fn_def) = ast.shared_lib().get_script_fn(name, args.len()) {
|
||||||
self.call_script_fn(
|
self.call_script_fn(
|
||||||
|
@ -17,7 +17,7 @@ use std::{
|
|||||||
fmt::Write,
|
fmt::Write,
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
iter::once,
|
iter::once,
|
||||||
num::{NonZeroU8, NonZeroUsize},
|
num::{NonZeroU64, NonZeroU8, NonZeroUsize},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
@ -86,7 +86,7 @@ impl CustomExpr {
|
|||||||
///
|
///
|
||||||
/// Two separate hashes are pre-calculated because of the following patterns:
|
/// Two separate hashes are pre-calculated because of the following patterns:
|
||||||
///
|
///
|
||||||
/// ```js
|
/// ```rhai
|
||||||
/// func(a, b, c); // Native: func(a, b, c) - 3 parameters
|
/// func(a, b, c); // Native: func(a, b, c) - 3 parameters
|
||||||
/// // Script: func(a, b, c) - 3 parameters
|
/// // Script: func(a, b, c) - 3 parameters
|
||||||
///
|
///
|
||||||
@ -100,22 +100,22 @@ impl CustomExpr {
|
|||||||
///
|
///
|
||||||
/// Function call hashes are used in the following manner:
|
/// 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
|
/// * First, the script hash (if any) is tried, which contains only the called function's name plus
|
||||||
/// number of parameters.
|
/// the number of parameters.
|
||||||
///
|
///
|
||||||
/// * Next, the actual types of arguments are hashed and _combined_ with the native hash, which is
|
/// * 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 complete native function call
|
/// then used to search for a native function.
|
||||||
/// 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.
|
/// In other words, a complete native function call hash always contains the called function's
|
||||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Default)]
|
/// name plus the types of the arguments. This is due to possible function overloading for
|
||||||
|
/// different parameter types.
|
||||||
|
#[derive(Clone, Copy, Eq, PartialEq, Hash)]
|
||||||
pub struct FnCallHashes {
|
pub struct FnCallHashes {
|
||||||
/// Pre-calculated hash for a script-defined function (zero if native functions only).
|
/// Pre-calculated hash for a script-defined function ([`None`] if native functions only).
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
script: u64,
|
script: Option<NonZeroU64>,
|
||||||
/// Pre-calculated hash for a native Rust function with no parameter types.
|
/// Pre-calculated hash for a native Rust function with no parameter types.
|
||||||
///
|
native: NonZeroU64,
|
||||||
/// This hash can never be zero.
|
|
||||||
native: u64,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for FnCallHashes {
|
impl fmt::Debug for FnCallHashes {
|
||||||
@ -123,11 +123,11 @@ impl fmt::Debug for FnCallHashes {
|
|||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
if self.script != 0 {
|
if let Some(script) = self.script {
|
||||||
return if self.script == self.native {
|
return if script == self.native {
|
||||||
fmt::Debug::fmt(&self.native, f)
|
fmt::Debug::fmt(&self.native, f)
|
||||||
} else {
|
} else {
|
||||||
write!(f, "({}, {})", self.script, self.native)
|
write!(f, "({}, {})", script, self.native)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,11 +138,11 @@ impl fmt::Debug for FnCallHashes {
|
|||||||
impl From<u64> for FnCallHashes {
|
impl From<u64> for FnCallHashes {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(hash: u64) -> Self {
|
fn from(hash: u64) -> Self {
|
||||||
let hash = if hash == 0 { ALT_ZERO_HASH } else { hash };
|
let hash = NonZeroU64::new(if hash == 0 { ALT_ZERO_HASH } else { hash }).unwrap();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
script: hash,
|
script: Some(hash),
|
||||||
native: hash,
|
native: hash,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -150,23 +150,23 @@ impl From<u64> for FnCallHashes {
|
|||||||
|
|
||||||
impl FnCallHashes {
|
impl FnCallHashes {
|
||||||
/// Create a [`FnCallHashes`] with only the native Rust hash.
|
/// Create a [`FnCallHashes`] with only the native Rust hash.
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn from_native(hash: u64) -> Self {
|
pub fn from_native(hash: u64) -> Self {
|
||||||
Self {
|
Self {
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
script: 0,
|
script: None,
|
||||||
native: if hash == 0 { ALT_ZERO_HASH } else { hash },
|
native: NonZeroU64::new(if hash == 0 { ALT_ZERO_HASH } else { hash }).unwrap(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Create a [`FnCallHashes`] with both native Rust and script function hashes.
|
/// Create a [`FnCallHashes`] with both native Rust and script function hashes.
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn from_all(#[cfg(not(feature = "no_function"))] script: u64, native: u64) -> Self {
|
pub fn from_all(#[cfg(not(feature = "no_function"))] script: u64, native: u64) -> Self {
|
||||||
Self {
|
Self {
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
script: if script == 0 { ALT_ZERO_HASH } else { script },
|
script: NonZeroU64::new(if script == 0 { ALT_ZERO_HASH } else { script }),
|
||||||
native: if native == 0 { ALT_ZERO_HASH } else { native },
|
native: NonZeroU64::new(if native == 0 { ALT_ZERO_HASH } else { native }).unwrap(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Is this [`FnCallHashes`] native-only?
|
/// Is this [`FnCallHashes`] native-only?
|
||||||
@ -174,23 +174,31 @@ impl FnCallHashes {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn is_native_only(&self) -> bool {
|
pub const fn is_native_only(&self) -> bool {
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
return self.script == 0;
|
return self.script.is_none();
|
||||||
#[cfg(feature = "no_function")]
|
#[cfg(feature = "no_function")]
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
/// Get the native hash.
|
/// Get the native hash.
|
||||||
|
///
|
||||||
|
/// The hash returned is never zero.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn native(&self) -> u64 {
|
pub fn native(&self) -> u64 {
|
||||||
self.native
|
self.native.get()
|
||||||
}
|
}
|
||||||
/// Get the script hash.
|
/// Get the script hash.
|
||||||
|
///
|
||||||
|
/// The hash returned is never zero.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if this [`FnCallHashes`] is native-only.
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn script(&self) -> u64 {
|
pub fn script(&self) -> u64 {
|
||||||
assert!(self.script != 0);
|
assert!(self.script.is_some());
|
||||||
self.script
|
self.script.as_ref().unwrap().get()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -210,9 +218,7 @@ pub struct FnCallExpr {
|
|||||||
/// Does this function call capture the parent scope?
|
/// Does this function call capture the parent scope?
|
||||||
pub capture_parent_scope: bool,
|
pub capture_parent_scope: bool,
|
||||||
/// Is this function call a native operator?
|
/// Is this function call a native operator?
|
||||||
pub operator_token: Option<Token>,
|
pub op_token: Option<Token>,
|
||||||
/// [Position] of the function name.
|
|
||||||
pub pos: Position,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for FnCallExpr {
|
impl fmt::Debug for FnCallExpr {
|
||||||
@ -227,13 +233,12 @@ impl fmt::Debug for FnCallExpr {
|
|||||||
ff.field("hash", &self.hashes)
|
ff.field("hash", &self.hashes)
|
||||||
.field("name", &self.name)
|
.field("name", &self.name)
|
||||||
.field("args", &self.args);
|
.field("args", &self.args);
|
||||||
if let Some(ref token) = self.operator_token {
|
if let Some(ref token) = self.op_token {
|
||||||
ff.field("operator_token", token);
|
ff.field("op_token", token);
|
||||||
}
|
}
|
||||||
if self.capture_parent_scope {
|
if self.capture_parent_scope {
|
||||||
ff.field("capture_parent_scope", &self.capture_parent_scope);
|
ff.field("capture_parent_scope", &self.capture_parent_scope);
|
||||||
}
|
}
|
||||||
ff.field("pos", &self.pos);
|
|
||||||
ff.finish()
|
ff.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -698,8 +703,7 @@ impl Expr {
|
|||||||
hashes: calc_fn_hash(None, f.fn_name(), 1).into(),
|
hashes: calc_fn_hash(None, f.fn_name(), 1).into(),
|
||||||
args: once(Self::StringConstant(f.fn_name().into(), pos)).collect(),
|
args: once(Self::StringConstant(f.fn_name().into(), pos)).collect(),
|
||||||
capture_parent_scope: false,
|
capture_parent_scope: false,
|
||||||
operator_token: None,
|
op_token: None,
|
||||||
pos,
|
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
pos,
|
pos,
|
||||||
@ -754,6 +758,8 @@ impl Expr {
|
|||||||
| Self::And(.., pos)
|
| Self::And(.., pos)
|
||||||
| Self::Or(.., pos)
|
| Self::Or(.., pos)
|
||||||
| Self::Coalesce(.., pos)
|
| Self::Coalesce(.., pos)
|
||||||
|
| Self::FnCall(.., pos)
|
||||||
|
| Self::MethodCall(.., pos)
|
||||||
| Self::Index(.., pos)
|
| Self::Index(.., pos)
|
||||||
| Self::Dot(.., pos)
|
| Self::Dot(.., pos)
|
||||||
| Self::InterpolatedString(.., pos)
|
| Self::InterpolatedString(.., pos)
|
||||||
@ -762,8 +768,6 @@ impl Expr {
|
|||||||
#[cfg(not(feature = "no_custom_syntax"))]
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
Self::Custom(.., pos) => *pos,
|
Self::Custom(.., pos) => *pos,
|
||||||
|
|
||||||
Self::FnCall(x, ..) | Self::MethodCall(x, ..) => x.pos,
|
|
||||||
|
|
||||||
Self::Stmt(x) => x.position(),
|
Self::Stmt(x) => x.position(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ pub enum FnAccess {
|
|||||||
|
|
||||||
impl FnAccess {
|
impl FnAccess {
|
||||||
/// Is this function private?
|
/// Is this function private?
|
||||||
#[inline]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn is_private(self) -> bool {
|
pub const fn is_private(self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
@ -27,7 +27,7 @@ impl FnAccess {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Is this function public?
|
/// Is this function public?
|
||||||
#[inline]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn is_public(self) -> bool {
|
pub const fn is_public(self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
|
@ -269,7 +269,7 @@ impl Engine {
|
|||||||
if op_info.is_op_assignment() {
|
if op_info.is_op_assignment() {
|
||||||
let args = &mut [target.as_mut()];
|
let args = &mut [target.as_mut()];
|
||||||
let (mut orig_val, ..) = self
|
let (mut orig_val, ..) = self
|
||||||
.call_native_fn(
|
.exec_native_fn_call(
|
||||||
global, caches, lib, getter, *hash_get, args, is_ref_mut,
|
global, caches, lib, getter, *hash_get, args, is_ref_mut,
|
||||||
false, *pos, level,
|
false, *pos, level,
|
||||||
)
|
)
|
||||||
@ -303,7 +303,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let args = &mut [target.as_mut(), &mut new_val];
|
let args = &mut [target.as_mut(), &mut new_val];
|
||||||
self.call_native_fn(
|
self.exec_native_fn_call(
|
||||||
global, caches, lib, setter, *hash_set, args, is_ref_mut, false, *pos,
|
global, caches, lib, setter, *hash_set, args, is_ref_mut, false, *pos,
|
||||||
level,
|
level,
|
||||||
)
|
)
|
||||||
@ -330,7 +330,7 @@ impl Engine {
|
|||||||
|
|
||||||
let ((getter, hash_get), _, name) = &**x;
|
let ((getter, hash_get), _, name) = &**x;
|
||||||
let args = &mut [target.as_mut()];
|
let args = &mut [target.as_mut()];
|
||||||
self.call_native_fn(
|
self.exec_native_fn_call(
|
||||||
global, caches, lib, getter, *hash_get, args, is_ref_mut, false, *pos,
|
global, caches, lib, getter, *hash_get, args, is_ref_mut, false, *pos,
|
||||||
level,
|
level,
|
||||||
)
|
)
|
||||||
@ -429,7 +429,7 @@ impl Engine {
|
|||||||
|
|
||||||
// Assume getters are always pure
|
// Assume getters are always pure
|
||||||
let (mut val, ..) = self
|
let (mut val, ..) = self
|
||||||
.call_native_fn(
|
.exec_native_fn_call(
|
||||||
global, caches, lib, getter, *hash_get, args, is_ref_mut,
|
global, caches, lib, getter, *hash_get, args, is_ref_mut,
|
||||||
false, pos, level,
|
false, pos, level,
|
||||||
)
|
)
|
||||||
@ -465,7 +465,7 @@ impl Engine {
|
|||||||
// Re-use args because the first &mut parameter will not be consumed
|
// Re-use args because the first &mut parameter will not be consumed
|
||||||
let mut arg_values = [target.as_mut(), val.as_mut()];
|
let mut arg_values = [target.as_mut(), val.as_mut()];
|
||||||
let args = &mut arg_values;
|
let args = &mut arg_values;
|
||||||
self.call_native_fn(
|
self.exec_native_fn_call(
|
||||||
global, caches, lib, setter, *hash_set, args, is_ref_mut,
|
global, caches, lib, setter, *hash_set, args, is_ref_mut,
|
||||||
false, pos, level,
|
false, pos, level,
|
||||||
)
|
)
|
||||||
@ -764,7 +764,7 @@ impl Engine {
|
|||||||
let pos = Position::NONE;
|
let pos = Position::NONE;
|
||||||
let level = level + 1;
|
let level = level + 1;
|
||||||
|
|
||||||
self.call_native_fn(
|
self.exec_native_fn_call(
|
||||||
global, caches, lib, fn_name, hash, args, true, false, pos, level,
|
global, caches, lib, fn_name, hash, args, true, false, pos, level,
|
||||||
)
|
)
|
||||||
.map(|(r, ..)| r)
|
.map(|(r, ..)| r)
|
||||||
@ -789,7 +789,7 @@ impl Engine {
|
|||||||
let pos = Position::NONE;
|
let pos = Position::NONE;
|
||||||
let level = level + 1;
|
let level = level + 1;
|
||||||
|
|
||||||
self.call_native_fn(
|
self.exec_native_fn_call(
|
||||||
global, caches, lib, fn_name, hash, args, is_ref_mut, false, pos, level,
|
global, caches, lib, fn_name, hash, args, is_ref_mut, false, pos, level,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -430,7 +430,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
/// Run the debugger callback if there is a debugging interface registered.
|
/// Run the debugger callback if there is a debugging interface registered.
|
||||||
///
|
///
|
||||||
/// Returns `Some` if the debugger needs to be reactivated at the end of the block, statement or
|
/// Returns [`Some`] if the debugger needs to be reactivated at the end of the block, statement or
|
||||||
/// function call.
|
/// function call.
|
||||||
///
|
///
|
||||||
/// It is up to the [`Engine`] to reactivate the debugger.
|
/// It is up to the [`Engine`] to reactivate the debugger.
|
||||||
@ -452,7 +452,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
/// Run the debugger callback.
|
/// Run the debugger callback.
|
||||||
///
|
///
|
||||||
/// Returns `Some` if the debugger needs to be reactivated at the end of the block, statement or
|
/// Returns [`Some`] if the debugger needs to be reactivated at the end of the block, statement or
|
||||||
/// function call.
|
/// function call.
|
||||||
///
|
///
|
||||||
/// It is up to the [`Engine`] to reactivate the debugger.
|
/// It is up to the [`Engine`] to reactivate the debugger.
|
||||||
@ -498,7 +498,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
/// Run the debugger callback unconditionally.
|
/// Run the debugger callback unconditionally.
|
||||||
///
|
///
|
||||||
/// Returns `Some` if the debugger needs to be reactivated at the end of the block, statement or
|
/// Returns [`Some`] if the debugger needs to be reactivated at the end of the block, statement or
|
||||||
/// function call.
|
/// function call.
|
||||||
///
|
///
|
||||||
/// It is up to the [`Engine`] to reactivate the debugger.
|
/// It is up to the [`Engine`] to reactivate the debugger.
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
//! Module defining functions for evaluating an expression.
|
//! Module defining functions for evaluating an expression.
|
||||||
|
|
||||||
use super::{Caches, EvalContext, GlobalRuntimeState, Target};
|
use super::{Caches, EvalContext, GlobalRuntimeState, Target};
|
||||||
use crate::ast::{Expr, FnCallExpr, OpAssignment};
|
use crate::ast::{Expr, OpAssignment};
|
||||||
use crate::engine::{KEYWORD_THIS, OP_CONCAT};
|
use crate::engine::{KEYWORD_THIS, OP_CONCAT};
|
||||||
use crate::func::get_builtin_binary_op_fn;
|
|
||||||
use crate::types::dynamic::AccessMode;
|
use crate::types::dynamic::AccessMode;
|
||||||
use crate::{Dynamic, Engine, Module, Position, RhaiResult, RhaiResultOf, Scope, ERR};
|
use crate::{Dynamic, Engine, Module, Position, RhaiResult, RhaiResultOf, Scope, ERR};
|
||||||
use std::num::NonZeroUsize;
|
use std::num::NonZeroUsize;
|
||||||
@ -206,89 +205,6 @@ impl Engine {
|
|||||||
Ok((val.into(), var_pos))
|
Ok((val.into(), var_pos))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate a function call expression.
|
|
||||||
pub(crate) fn eval_fn_call_expr(
|
|
||||||
&self,
|
|
||||||
scope: &mut Scope,
|
|
||||||
global: &mut GlobalRuntimeState,
|
|
||||||
caches: &mut Caches,
|
|
||||||
lib: &[&Module],
|
|
||||||
this_ptr: &mut Option<&mut Dynamic>,
|
|
||||||
expr: &FnCallExpr,
|
|
||||||
pos: Position,
|
|
||||||
level: usize,
|
|
||||||
) -> RhaiResult {
|
|
||||||
let FnCallExpr {
|
|
||||||
name,
|
|
||||||
hashes,
|
|
||||||
args,
|
|
||||||
operator_token,
|
|
||||||
..
|
|
||||||
} = expr;
|
|
||||||
|
|
||||||
// Short-circuit native binary operator call if under Fast Operators mode
|
|
||||||
if operator_token.is_some() && self.fast_operators() && args.len() == 2 {
|
|
||||||
let mut lhs = self
|
|
||||||
.get_arg_value(scope, global, caches, lib, this_ptr, &args[0], level)?
|
|
||||||
.0
|
|
||||||
.flatten();
|
|
||||||
|
|
||||||
let mut rhs = self
|
|
||||||
.get_arg_value(scope, global, caches, lib, this_ptr, &args[1], level)?
|
|
||||||
.0
|
|
||||||
.flatten();
|
|
||||||
|
|
||||||
let operands = &mut [&mut lhs, &mut rhs];
|
|
||||||
|
|
||||||
if let Some(func) =
|
|
||||||
get_builtin_binary_op_fn(operator_token.as_ref().unwrap(), operands[0], operands[1])
|
|
||||||
{
|
|
||||||
// Built-in found
|
|
||||||
let context = (self, name.as_str(), None, &*global, lib, pos, level + 1).into();
|
|
||||||
return func(context, operands);
|
|
||||||
}
|
|
||||||
|
|
||||||
return self
|
|
||||||
.exec_fn_call(
|
|
||||||
None, global, caches, lib, name, *hashes, operands, false, false, pos, level,
|
|
||||||
)
|
|
||||||
.map(|(v, ..)| v);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
|
||||||
if !expr.namespace.is_empty() {
|
|
||||||
// Qualified function call
|
|
||||||
let hash = hashes.native();
|
|
||||||
let namespace = &expr.namespace;
|
|
||||||
|
|
||||||
return self.make_qualified_function_call(
|
|
||||||
scope, global, caches, lib, this_ptr, namespace, name, args, hash, pos, level,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Normal function call
|
|
||||||
let (first_arg, args) = args.split_first().map_or_else(
|
|
||||||
|| (None, args.as_ref()),
|
|
||||||
|(first, rest)| (Some(first), rest),
|
|
||||||
);
|
|
||||||
|
|
||||||
self.make_function_call(
|
|
||||||
scope,
|
|
||||||
global,
|
|
||||||
caches,
|
|
||||||
lib,
|
|
||||||
this_ptr,
|
|
||||||
name,
|
|
||||||
first_arg,
|
|
||||||
args,
|
|
||||||
*hashes,
|
|
||||||
expr.capture_parent_scope,
|
|
||||||
expr.operator_token.as_ref(),
|
|
||||||
pos,
|
|
||||||
level,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Evaluate an expression.
|
/// Evaluate an expression.
|
||||||
//
|
//
|
||||||
// # Implementation Notes
|
// # Implementation Notes
|
||||||
@ -312,7 +228,7 @@ impl Engine {
|
|||||||
|
|
||||||
// Function calls should account for a relatively larger portion of expressions because
|
// Function calls should account for a relatively larger portion of expressions because
|
||||||
// binary operators are also function calls.
|
// binary operators are also function calls.
|
||||||
if let Expr::FnCall(x, ..) = expr {
|
if let Expr::FnCall(x, pos) = expr {
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
let reset_debugger =
|
let reset_debugger =
|
||||||
self.run_debugger_with_reset(scope, global, lib, this_ptr, expr, level)?;
|
self.run_debugger_with_reset(scope, global, lib, this_ptr, expr, level)?;
|
||||||
@ -320,7 +236,7 @@ impl Engine {
|
|||||||
self.track_operation(global, expr.position())?;
|
self.track_operation(global, expr.position())?;
|
||||||
|
|
||||||
let result =
|
let result =
|
||||||
self.eval_fn_call_expr(scope, global, caches, lib, this_ptr, x, x.pos, level);
|
self.eval_fn_call_expr(scope, global, caches, lib, this_ptr, x, *pos, level);
|
||||||
|
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
global.debugger.reset_status(reset_debugger);
|
global.debugger.reset_status(reset_debugger);
|
||||||
|
@ -153,7 +153,7 @@ impl Engine {
|
|||||||
let op_assign = op_assign.literal_syntax();
|
let op_assign = op_assign.literal_syntax();
|
||||||
let op = op.literal_syntax();
|
let op = op.literal_syntax();
|
||||||
|
|
||||||
match self.call_native_fn(
|
match self.exec_native_fn_call(
|
||||||
global, caches, lib, op_assign, hash, args, true, true, *op_pos, level,
|
global, caches, lib, op_assign, hash, args, true, true, *op_pos, level,
|
||||||
) {
|
) {
|
||||||
Ok(_) => (),
|
Ok(_) => (),
|
||||||
@ -161,7 +161,7 @@ impl Engine {
|
|||||||
{
|
{
|
||||||
// Expand to `var = var op rhs`
|
// Expand to `var = var op rhs`
|
||||||
*args[0] = self
|
*args[0] = self
|
||||||
.call_native_fn(
|
.exec_native_fn_call(
|
||||||
global, caches, lib, op, *hash_op, args, true, false, *op_pos, level,
|
global, caches, lib, op, *hash_op, args, true, false, *op_pos, level,
|
||||||
)
|
)
|
||||||
.map_err(|err| err.fill_position(op_info.pos))?
|
.map_err(|err| err.fill_position(op_info.pos))?
|
||||||
@ -207,11 +207,11 @@ impl Engine {
|
|||||||
// Popular branches are lifted out of the `match` statement into their own branches.
|
// Popular branches are lifted out of the `match` statement into their own branches.
|
||||||
|
|
||||||
// Function calls should account for a relatively larger portion of statements.
|
// Function calls should account for a relatively larger portion of statements.
|
||||||
if let Stmt::FnCall(x, ..) = stmt {
|
if let Stmt::FnCall(x, pos) = stmt {
|
||||||
self.track_operation(global, stmt.position())?;
|
self.track_operation(global, stmt.position())?;
|
||||||
|
|
||||||
let result =
|
let result =
|
||||||
self.eval_fn_call_expr(scope, global, caches, lib, this_ptr, x, x.pos, level);
|
self.eval_fn_call_expr(scope, global, caches, lib, this_ptr, x, *pos, level);
|
||||||
|
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
global.debugger.reset_status(reset_debugger);
|
global.debugger.reset_status(reset_debugger);
|
||||||
@ -1006,4 +1006,28 @@ impl Engine {
|
|||||||
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Evaluate a list of statements with no `this` pointer.
|
||||||
|
/// This is commonly used to evaluate a list of statements in an [`AST`][crate::AST] or a script function body.
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn eval_global_statements(
|
||||||
|
&self,
|
||||||
|
scope: &mut Scope,
|
||||||
|
global: &mut GlobalRuntimeState,
|
||||||
|
caches: &mut Caches,
|
||||||
|
statements: &[Stmt],
|
||||||
|
lib: &[&Module],
|
||||||
|
level: usize,
|
||||||
|
) -> RhaiResult {
|
||||||
|
self.eval_stmt_block(
|
||||||
|
scope, global, caches, lib, &mut None, statements, false, level,
|
||||||
|
)
|
||||||
|
.or_else(|err| match *err {
|
||||||
|
ERR::Return(out, ..) => Ok(out),
|
||||||
|
ERR::LoopBreak(..) => {
|
||||||
|
unreachable!("no outer loop scope to break out of")
|
||||||
|
}
|
||||||
|
_ => Err(err),
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
152
src/func/call.rs
152
src/func/call.rs
@ -1,9 +1,8 @@
|
|||||||
//! Implement function-calling mechanism for [`Engine`].
|
//! Implement function-calling mechanism for [`Engine`].
|
||||||
|
|
||||||
use super::callable_function::CallableFunction;
|
use super::{get_builtin_binary_op_fn, get_builtin_op_assignment_fn, CallableFunction};
|
||||||
use super::{get_builtin_binary_op_fn, get_builtin_op_assignment_fn};
|
|
||||||
use crate::api::default_limits::MAX_DYNAMIC_PARAMETERS;
|
use crate::api::default_limits::MAX_DYNAMIC_PARAMETERS;
|
||||||
use crate::ast::{Expr, FnCallHashes, Stmt};
|
use crate::ast::{Expr, FnCallExpr, FnCallHashes};
|
||||||
use crate::engine::{
|
use crate::engine::{
|
||||||
KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_FN_PTR_CALL, KEYWORD_FN_PTR_CURRY,
|
KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_FN_PTR_CALL, KEYWORD_FN_PTR_CURRY,
|
||||||
KEYWORD_IS_DEF_VAR, KEYWORD_PRINT, KEYWORD_TYPE_OF,
|
KEYWORD_IS_DEF_VAR, KEYWORD_PRINT, KEYWORD_TYPE_OF,
|
||||||
@ -108,17 +107,14 @@ impl Drop for ArgBackup<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ensure no data races in function call arguments.
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn ensure_no_data_race(
|
pub fn ensure_no_data_race(fn_name: &str, args: &FnCallArgs, is_ref_mut: bool) -> RhaiResultOf<()> {
|
||||||
fn_name: &str,
|
|
||||||
args: &FnCallArgs,
|
|
||||||
is_method_call: bool,
|
|
||||||
) -> RhaiResultOf<()> {
|
|
||||||
if let Some((n, ..)) = args
|
if let Some((n, ..)) = args
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.skip(if is_method_call { 1 } else { 0 })
|
.skip(if is_ref_mut { 1 } else { 0 })
|
||||||
.find(|(.., a)| a.is_locked())
|
.find(|(.., a)| a.is_locked())
|
||||||
{
|
{
|
||||||
return Err(ERR::ErrorDataRace(
|
return Err(ERR::ErrorDataRace(
|
||||||
@ -134,7 +130,7 @@ pub fn ensure_no_data_race(
|
|||||||
/// Generate the signature for a function call.
|
/// Generate the signature for a function call.
|
||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn gen_fn_call_signature(engine: &Engine, fn_name: &str, args: &[&mut Dynamic]) -> String {
|
fn gen_fn_call_signature(engine: &Engine, fn_name: &str, args: &[&mut Dynamic]) -> String {
|
||||||
format!(
|
format!(
|
||||||
"{fn_name} ({})",
|
"{fn_name} ({})",
|
||||||
args.iter()
|
args.iter()
|
||||||
@ -154,7 +150,7 @@ pub fn gen_fn_call_signature(engine: &Engine, fn_name: &str, args: &[&mut Dynami
|
|||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn gen_qualified_fn_call_signature(
|
fn gen_qualified_fn_call_signature(
|
||||||
engine: &Engine,
|
engine: &Engine,
|
||||||
namespace: &crate::ast::Namespace,
|
namespace: &crate::ast::Namespace,
|
||||||
fn_name: &str,
|
fn_name: &str,
|
||||||
@ -343,7 +339,7 @@ impl Engine {
|
|||||||
///
|
///
|
||||||
/// **DO NOT** reuse the argument values unless for the first `&mut` argument -
|
/// **DO NOT** reuse the argument values unless for the first `&mut` argument -
|
||||||
/// all others are silently replaced by `()`!
|
/// all others are silently replaced by `()`!
|
||||||
pub(crate) fn call_native_fn(
|
pub(crate) fn exec_native_fn_call(
|
||||||
&self,
|
&self,
|
||||||
global: &mut GlobalRuntimeState,
|
global: &mut GlobalRuntimeState,
|
||||||
caches: &mut Caches,
|
caches: &mut Caches,
|
||||||
@ -716,41 +712,17 @@ impl Engine {
|
|||||||
// Restore the original source
|
// Restore the original source
|
||||||
global.source = orig_source;
|
global.source = orig_source;
|
||||||
|
|
||||||
return Ok((result?, false));
|
return result.map(|r| (r, false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Native function call
|
// Native function call
|
||||||
let hash = hashes.native();
|
let hash = hashes.native();
|
||||||
self.call_native_fn(
|
self.exec_native_fn_call(
|
||||||
global, caches, lib, fn_name, hash, args, is_ref_mut, false, pos, level,
|
global, caches, lib, fn_name, hash, args, is_ref_mut, false, pos, level,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate a list of statements with no `this` pointer.
|
|
||||||
/// This is commonly used to evaluate a list of statements in an [`AST`][crate::AST] or a script function body.
|
|
||||||
#[inline]
|
|
||||||
pub(crate) fn eval_global_statements(
|
|
||||||
&self,
|
|
||||||
scope: &mut Scope,
|
|
||||||
global: &mut GlobalRuntimeState,
|
|
||||||
caches: &mut Caches,
|
|
||||||
statements: &[Stmt],
|
|
||||||
lib: &[&Module],
|
|
||||||
level: usize,
|
|
||||||
) -> RhaiResult {
|
|
||||||
self.eval_stmt_block(
|
|
||||||
scope, global, caches, lib, &mut None, statements, false, level,
|
|
||||||
)
|
|
||||||
.or_else(|err| match *err {
|
|
||||||
ERR::Return(out, ..) => Ok(out),
|
|
||||||
ERR::LoopBreak(..) => {
|
|
||||||
unreachable!("no outer loop scope to break out of")
|
|
||||||
}
|
|
||||||
_ => Err(err),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Evaluate an argument.
|
/// Evaluate an argument.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn get_arg_value(
|
pub(crate) fn get_arg_value(
|
||||||
@ -763,13 +735,14 @@ impl Engine {
|
|||||||
arg_expr: &Expr,
|
arg_expr: &Expr,
|
||||||
level: usize,
|
level: usize,
|
||||||
) -> RhaiResultOf<(Dynamic, Position)> {
|
) -> RhaiResultOf<(Dynamic, Position)> {
|
||||||
#[cfg(feature = "debugging")]
|
// Literal values
|
||||||
if self.debugger.is_some() {
|
if let Some(value) = arg_expr.get_literal_value() {
|
||||||
if let Some(value) = arg_expr.get_literal_value() {
|
self.track_operation(global, arg_expr.start_position())?;
|
||||||
#[cfg(feature = "debugging")]
|
|
||||||
self.run_debugger(scope, global, lib, this_ptr, arg_expr, level)?;
|
#[cfg(feature = "debugging")]
|
||||||
return Ok((value, arg_expr.start_position()));
|
self.run_debugger(scope, global, lib, this_ptr, arg_expr, level)?;
|
||||||
}
|
|
||||||
|
return Ok((value, arg_expr.start_position()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do not match function exit for arguments
|
// Do not match function exit for arguments
|
||||||
@ -784,7 +757,7 @@ impl Engine {
|
|||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
global.debugger.reset_status(reset_debugger);
|
global.debugger.reset_status(reset_debugger);
|
||||||
|
|
||||||
Ok((result?, arg_expr.start_position()))
|
result.map(|r| (r, arg_expr.start_position()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call a dot method.
|
/// Call a dot method.
|
||||||
@ -1022,8 +995,8 @@ impl Engine {
|
|||||||
first_arg: Option<&Expr>,
|
first_arg: Option<&Expr>,
|
||||||
args_expr: &[Expr],
|
args_expr: &[Expr],
|
||||||
hashes: FnCallHashes,
|
hashes: FnCallHashes,
|
||||||
|
is_operator_call: bool,
|
||||||
capture_scope: bool,
|
capture_scope: bool,
|
||||||
operator_token: Option<&Token>,
|
|
||||||
pos: Position,
|
pos: Position,
|
||||||
level: usize,
|
level: usize,
|
||||||
) -> RhaiResult {
|
) -> RhaiResult {
|
||||||
@ -1036,7 +1009,7 @@ impl Engine {
|
|||||||
let redirected; // Handle call() - Redirect function call
|
let redirected; // Handle call() - Redirect function call
|
||||||
|
|
||||||
match name {
|
match name {
|
||||||
_ if operator_token.is_some() => (),
|
_ if is_operator_call => (),
|
||||||
|
|
||||||
// Handle call()
|
// Handle call()
|
||||||
KEYWORD_FN_PTR_CALL if total_args >= 1 => {
|
KEYWORD_FN_PTR_CALL if total_args >= 1 => {
|
||||||
@ -1520,4 +1493,87 @@ impl Engine {
|
|||||||
// Evaluate the AST
|
// Evaluate the AST
|
||||||
self.eval_global_statements(scope, global, caches, statements, lib, level)
|
self.eval_global_statements(scope, global, caches, statements, lib, level)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Evaluate a function call expression.
|
||||||
|
pub(crate) fn eval_fn_call_expr(
|
||||||
|
&self,
|
||||||
|
scope: &mut Scope,
|
||||||
|
global: &mut GlobalRuntimeState,
|
||||||
|
caches: &mut Caches,
|
||||||
|
lib: &[&Module],
|
||||||
|
this_ptr: &mut Option<&mut Dynamic>,
|
||||||
|
expr: &FnCallExpr,
|
||||||
|
pos: Position,
|
||||||
|
level: usize,
|
||||||
|
) -> RhaiResult {
|
||||||
|
let FnCallExpr {
|
||||||
|
name,
|
||||||
|
hashes,
|
||||||
|
args,
|
||||||
|
op_token,
|
||||||
|
..
|
||||||
|
} = expr;
|
||||||
|
|
||||||
|
// Short-circuit native binary operator call if under Fast Operators mode
|
||||||
|
if op_token.is_some() && self.fast_operators() && args.len() == 2 {
|
||||||
|
let mut lhs = self
|
||||||
|
.get_arg_value(scope, global, caches, lib, this_ptr, &args[0], level)?
|
||||||
|
.0
|
||||||
|
.flatten();
|
||||||
|
|
||||||
|
let mut rhs = self
|
||||||
|
.get_arg_value(scope, global, caches, lib, this_ptr, &args[1], level)?
|
||||||
|
.0
|
||||||
|
.flatten();
|
||||||
|
|
||||||
|
let operands = &mut [&mut lhs, &mut rhs];
|
||||||
|
|
||||||
|
if let Some(func) =
|
||||||
|
get_builtin_binary_op_fn(op_token.as_ref().unwrap(), operands[0], operands[1])
|
||||||
|
{
|
||||||
|
// Built-in found
|
||||||
|
let context = (self, name.as_str(), None, &*global, lib, pos, level + 1).into();
|
||||||
|
return func(context, operands);
|
||||||
|
}
|
||||||
|
|
||||||
|
return self
|
||||||
|
.exec_fn_call(
|
||||||
|
None, global, caches, lib, name, *hashes, operands, false, false, pos, level,
|
||||||
|
)
|
||||||
|
.map(|(v, ..)| v);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
if !expr.namespace.is_empty() {
|
||||||
|
// Qualified function call
|
||||||
|
let hash = hashes.native();
|
||||||
|
let namespace = &expr.namespace;
|
||||||
|
|
||||||
|
return self.make_qualified_function_call(
|
||||||
|
scope, global, caches, lib, this_ptr, namespace, name, args, hash, pos, level,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normal function call
|
||||||
|
let (first_arg, args) = args.split_first().map_or_else(
|
||||||
|
|| (None, args.as_ref()),
|
||||||
|
|(first, rest)| (Some(first), rest),
|
||||||
|
);
|
||||||
|
|
||||||
|
self.make_function_call(
|
||||||
|
scope,
|
||||||
|
global,
|
||||||
|
caches,
|
||||||
|
lib,
|
||||||
|
this_ptr,
|
||||||
|
name,
|
||||||
|
first_arg,
|
||||||
|
args,
|
||||||
|
*hashes,
|
||||||
|
expr.op_token.is_some(),
|
||||||
|
expr.capture_parent_scope,
|
||||||
|
pos,
|
||||||
|
level,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,8 +14,7 @@ pub mod script;
|
|||||||
pub use args::FuncArgs;
|
pub use args::FuncArgs;
|
||||||
pub use builtin::{get_builtin_binary_op_fn, get_builtin_op_assignment_fn};
|
pub use builtin::{get_builtin_binary_op_fn, get_builtin_op_assignment_fn};
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
pub use call::gen_qualified_fn_call_signature;
|
pub use call::{ensure_no_data_race, FnCallArgs};
|
||||||
pub use call::{gen_fn_call_signature, FnCallArgs};
|
|
||||||
pub use callable_function::CallableFunction;
|
pub use callable_function::CallableFunction;
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
pub use func::Func;
|
pub use func::Func;
|
||||||
|
@ -382,7 +382,7 @@ impl<'a> NativeCallContext<'a> {
|
|||||||
if native_only {
|
if native_only {
|
||||||
return self
|
return self
|
||||||
.engine()
|
.engine()
|
||||||
.call_native_fn(
|
.exec_native_fn_call(
|
||||||
global,
|
global,
|
||||||
caches,
|
caches,
|
||||||
self.lib,
|
self.lib,
|
||||||
|
@ -147,7 +147,7 @@ impl<'a> OptimizerState<'a> {
|
|||||||
let lib = &[];
|
let lib = &[];
|
||||||
|
|
||||||
self.engine
|
self.engine
|
||||||
.call_native_fn(
|
.exec_native_fn_call(
|
||||||
&mut self.global,
|
&mut self.global,
|
||||||
&mut self.caches,
|
&mut self.caches,
|
||||||
lib,
|
lib,
|
||||||
@ -444,9 +444,9 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
) =>
|
) =>
|
||||||
{
|
{
|
||||||
match x.1.rhs {
|
match x.1.rhs {
|
||||||
Expr::FnCall(ref mut x2, ..) => {
|
Expr::FnCall(ref mut x2, pos) => {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
x.0 = OpAssignment::new_op_assignment_from_base(&x2.name, x2.pos);
|
x.0 = OpAssignment::new_op_assignment_from_base(&x2.name, pos);
|
||||||
x.1.rhs = mem::take(&mut x2.args[1]);
|
x.1.rhs = mem::take(&mut x2.args[1]);
|
||||||
}
|
}
|
||||||
ref expr => unreachable!("Expr::FnCall expected but gets {:?}", expr),
|
ref expr => unreachable!("Expr::FnCall expected but gets {:?}", expr),
|
||||||
@ -1142,8 +1142,8 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, _chaining: bool) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Overloaded operators can override built-in.
|
// Overloaded operators can override built-in.
|
||||||
_ if x.args.len() == 2 && x.operator_token.is_some() && (state.engine.fast_operators() || !has_native_fn_override(state.engine, x.hashes.native(), &arg_types)) => {
|
_ if x.args.len() == 2 && x.op_token.is_some() && (state.engine.fast_operators() || !has_native_fn_override(state.engine, x.hashes.native(), &arg_types)) => {
|
||||||
if let Some(result) = get_builtin_binary_op_fn(x.operator_token.as_ref().unwrap(), &arg_values[0], &arg_values[1])
|
if let Some(result) = get_builtin_binary_op_fn(x.op_token.as_ref().unwrap(), &arg_values[0], &arg_values[1])
|
||||||
.and_then(|f| {
|
.and_then(|f| {
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
let lib = state.lib;
|
let lib = state.lib;
|
||||||
|
129
src/parser.rs
129
src/parser.rs
@ -174,7 +174,7 @@ impl<'e> ParseState<'e> {
|
|||||||
///
|
///
|
||||||
/// # Return value: `(index, is_func_name)`
|
/// # Return value: `(index, is_func_name)`
|
||||||
///
|
///
|
||||||
/// * `index`: `None` when the variable name is not found in the `stack`,
|
/// * `index`: [`None`] when the variable name is not found in the `stack`,
|
||||||
/// otherwise the index value.
|
/// otherwise the index value.
|
||||||
///
|
///
|
||||||
/// * `is_func_name`: `true` if the variable is actually the name of a function
|
/// * `is_func_name`: `true` if the variable is actually the name of a function
|
||||||
@ -223,7 +223,7 @@ impl<'e> ParseState<'e> {
|
|||||||
/// Returns the offset to be deducted from `Stack::len`,
|
/// Returns the offset to be deducted from `Stack::len`,
|
||||||
/// i.e. the top element of the [`ParseState`] is offset 1.
|
/// i.e. the top element of the [`ParseState`] is offset 1.
|
||||||
///
|
///
|
||||||
/// Returns `None` when the variable name is not found in the [`ParseState`].
|
/// Returns [`None`] when the variable name is not found in the [`ParseState`].
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
@ -610,12 +610,11 @@ impl Engine {
|
|||||||
return Ok(FnCallExpr {
|
return Ok(FnCallExpr {
|
||||||
name: state.get_interned_string(id),
|
name: state.get_interned_string(id),
|
||||||
capture_parent_scope,
|
capture_parent_scope,
|
||||||
operator_token: None,
|
op_token: None,
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
namespace,
|
namespace,
|
||||||
hashes,
|
hashes,
|
||||||
args,
|
args,
|
||||||
pos: settings.pos,
|
|
||||||
}
|
}
|
||||||
.into_fn_call_expr(settings.pos));
|
.into_fn_call_expr(settings.pos));
|
||||||
}
|
}
|
||||||
@ -678,12 +677,11 @@ impl Engine {
|
|||||||
return Ok(FnCallExpr {
|
return Ok(FnCallExpr {
|
||||||
name: state.get_interned_string(id),
|
name: state.get_interned_string(id),
|
||||||
capture_parent_scope,
|
capture_parent_scope,
|
||||||
operator_token: None,
|
op_token: None,
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
namespace,
|
namespace,
|
||||||
hashes,
|
hashes,
|
||||||
args,
|
args,
|
||||||
pos: settings.pos,
|
|
||||||
}
|
}
|
||||||
.into_fn_call_expr(settings.pos));
|
.into_fn_call_expr(settings.pos));
|
||||||
}
|
}
|
||||||
@ -1933,8 +1931,7 @@ impl Engine {
|
|||||||
name: state.get_interned_string("-"),
|
name: state.get_interned_string("-"),
|
||||||
hashes: FnCallHashes::from_native(calc_fn_hash(None, "-", 1)),
|
hashes: FnCallHashes::from_native(calc_fn_hash(None, "-", 1)),
|
||||||
args,
|
args,
|
||||||
pos,
|
op_token: Some(token),
|
||||||
operator_token: Some(token),
|
|
||||||
capture_parent_scope: false,
|
capture_parent_scope: false,
|
||||||
}
|
}
|
||||||
.into_fn_call_expr(pos))
|
.into_fn_call_expr(pos))
|
||||||
@ -1963,8 +1960,7 @@ impl Engine {
|
|||||||
name: state.get_interned_string("+"),
|
name: state.get_interned_string("+"),
|
||||||
hashes: FnCallHashes::from_native(calc_fn_hash(None, "+", 1)),
|
hashes: FnCallHashes::from_native(calc_fn_hash(None, "+", 1)),
|
||||||
args,
|
args,
|
||||||
pos,
|
op_token: Some(token),
|
||||||
operator_token: Some(token),
|
|
||||||
capture_parent_scope: false,
|
capture_parent_scope: false,
|
||||||
}
|
}
|
||||||
.into_fn_call_expr(pos))
|
.into_fn_call_expr(pos))
|
||||||
@ -1986,8 +1982,7 @@ impl Engine {
|
|||||||
name: state.get_interned_string("!"),
|
name: state.get_interned_string("!"),
|
||||||
hashes: FnCallHashes::from_native(calc_fn_hash(None, "!", 1)),
|
hashes: FnCallHashes::from_native(calc_fn_hash(None, "!", 1)),
|
||||||
args,
|
args,
|
||||||
pos,
|
op_token: Some(token),
|
||||||
operator_token: Some(token),
|
|
||||||
capture_parent_scope: false,
|
capture_parent_scope: false,
|
||||||
}
|
}
|
||||||
.into_fn_call_expr(pos))
|
.into_fn_call_expr(pos))
|
||||||
@ -2376,25 +2371,24 @@ impl Engine {
|
|||||||
Some(op_token.clone())
|
Some(op_token.clone())
|
||||||
};
|
};
|
||||||
|
|
||||||
let op_base = FnCallExpr {
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
|
||||||
namespace: Default::default(),
|
|
||||||
name: state.get_interned_string(op.as_ref()),
|
|
||||||
hashes: FnCallHashes::from_native(hash),
|
|
||||||
args: StaticVec::new_const(),
|
|
||||||
pos,
|
|
||||||
operator_token,
|
|
||||||
capture_parent_scope: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut args = StaticVec::new_const();
|
let mut args = StaticVec::new_const();
|
||||||
args.push(root);
|
args.push(root);
|
||||||
args.push(rhs);
|
args.push(rhs);
|
||||||
args.shrink_to_fit();
|
args.shrink_to_fit();
|
||||||
|
|
||||||
|
let mut op_base = FnCallExpr {
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
namespace: Default::default(),
|
||||||
|
name: state.get_interned_string(op.as_ref()),
|
||||||
|
hashes: FnCallHashes::from_native(hash),
|
||||||
|
args,
|
||||||
|
op_token: operator_token,
|
||||||
|
capture_parent_scope: false,
|
||||||
|
};
|
||||||
|
|
||||||
root = match op_token {
|
root = match op_token {
|
||||||
// '!=' defaults to true when passed invalid operands
|
// '!=' defaults to true when passed invalid operands
|
||||||
Token::NotEqualsTo => FnCallExpr { args, ..op_base }.into_fn_call_expr(pos),
|
Token::NotEqualsTo => op_base.into_fn_call_expr(pos),
|
||||||
|
|
||||||
// Comparison operators default to false when passed invalid operands
|
// Comparison operators default to false when passed invalid operands
|
||||||
Token::EqualsTo
|
Token::EqualsTo
|
||||||
@ -2402,61 +2396,36 @@ impl Engine {
|
|||||||
| Token::LessThanEqualsTo
|
| Token::LessThanEqualsTo
|
||||||
| Token::GreaterThan
|
| Token::GreaterThan
|
||||||
| Token::GreaterThanEqualsTo => {
|
| Token::GreaterThanEqualsTo => {
|
||||||
let pos = args[0].start_position();
|
let pos = op_base.args[0].start_position();
|
||||||
FnCallExpr { args, ..op_base }.into_fn_call_expr(pos)
|
op_base.into_fn_call_expr(pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
Token::Or => {
|
Token::Or => {
|
||||||
let rhs = args.pop().unwrap();
|
let rhs = op_base.args.pop().unwrap().ensure_bool_expr()?;
|
||||||
let current_lhs = args.pop().unwrap();
|
let lhs = op_base.args.pop().unwrap().ensure_bool_expr()?;
|
||||||
Expr::Or(
|
Expr::Or(BinaryExpr { lhs: lhs, rhs: rhs }.into(), pos)
|
||||||
BinaryExpr {
|
|
||||||
lhs: current_lhs.ensure_bool_expr()?,
|
|
||||||
rhs: rhs.ensure_bool_expr()?,
|
|
||||||
}
|
|
||||||
.into(),
|
|
||||||
pos,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
Token::And => {
|
Token::And => {
|
||||||
let rhs = args.pop().unwrap();
|
let rhs = op_base.args.pop().unwrap().ensure_bool_expr()?;
|
||||||
let current_lhs = args.pop().unwrap();
|
let lhs = op_base.args.pop().unwrap().ensure_bool_expr()?;
|
||||||
Expr::And(
|
Expr::And(BinaryExpr { lhs: lhs, rhs: rhs }.into(), pos)
|
||||||
BinaryExpr {
|
|
||||||
lhs: current_lhs.ensure_bool_expr()?,
|
|
||||||
rhs: rhs.ensure_bool_expr()?,
|
|
||||||
}
|
|
||||||
.into(),
|
|
||||||
pos,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
Token::DoubleQuestion => {
|
Token::DoubleQuestion => {
|
||||||
let rhs = args.pop().unwrap();
|
let rhs = op_base.args.pop().unwrap();
|
||||||
let current_lhs = args.pop().unwrap();
|
let lhs = op_base.args.pop().unwrap();
|
||||||
Expr::Coalesce(
|
Expr::Coalesce(BinaryExpr { lhs, rhs }.into(), pos)
|
||||||
BinaryExpr {
|
|
||||||
lhs: current_lhs,
|
|
||||||
rhs,
|
|
||||||
}
|
|
||||||
.into(),
|
|
||||||
pos,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
Token::In => {
|
Token::In => {
|
||||||
// Swap the arguments
|
// Swap the arguments
|
||||||
let current_lhs = args.remove(0);
|
let lhs = op_base.args.remove(0);
|
||||||
let pos = current_lhs.start_position();
|
let pos = lhs.start_position();
|
||||||
args.push(current_lhs);
|
op_base.args.push(lhs);
|
||||||
args.shrink_to_fit();
|
op_base.args.shrink_to_fit();
|
||||||
|
|
||||||
// Convert into a call to `contains`
|
// Convert into a call to `contains`
|
||||||
FnCallExpr {
|
op_base.hashes = calc_fn_hash(None, OP_CONTAINS, 2).into();
|
||||||
hashes: calc_fn_hash(None, OP_CONTAINS, 2).into(),
|
op_base.name = state.get_interned_string(OP_CONTAINS);
|
||||||
args,
|
op_base.into_fn_call_expr(pos)
|
||||||
name: state.get_interned_string(OP_CONTAINS),
|
|
||||||
..op_base
|
|
||||||
}
|
|
||||||
.into_fn_call_expr(pos)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_custom_syntax"))]
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
@ -2466,24 +2435,17 @@ impl Engine {
|
|||||||
.get(s.as_str())
|
.get(s.as_str())
|
||||||
.map_or(false, Option::is_some) =>
|
.map_or(false, Option::is_some) =>
|
||||||
{
|
{
|
||||||
let hash = calc_fn_hash(None, &s, 2);
|
op_base.hashes = if is_valid_script_function {
|
||||||
let pos = args[0].start_position();
|
calc_fn_hash(None, &s, 2).into()
|
||||||
|
} else {
|
||||||
FnCallExpr {
|
FnCallHashes::from_native(calc_fn_hash(None, &s, 2))
|
||||||
hashes: if is_valid_script_function {
|
};
|
||||||
hash.into()
|
op_base.into_fn_call_expr(pos)
|
||||||
} else {
|
|
||||||
FnCallHashes::from_native(hash)
|
|
||||||
},
|
|
||||||
args,
|
|
||||||
..op_base
|
|
||||||
}
|
|
||||||
.into_fn_call_expr(pos)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
let pos = args[0].start_position();
|
let pos = op_base.args[0].start_position();
|
||||||
FnCallExpr { args, ..op_base }.into_fn_call_expr(pos)
|
op_base.into_fn_call_expr(pos)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -3725,8 +3687,7 @@ impl Engine {
|
|||||||
num_externals + 1,
|
num_externals + 1,
|
||||||
)),
|
)),
|
||||||
args,
|
args,
|
||||||
pos,
|
op_token: None,
|
||||||
operator_token: None,
|
|
||||||
capture_parent_scope: false,
|
capture_parent_scope: false,
|
||||||
}
|
}
|
||||||
.into_fn_call_expr(pos);
|
.into_fn_call_expr(pos);
|
||||||
|
Loading…
Reference in New Issue
Block a user