2020-11-20 09:52:28 +01:00
|
|
|
//! Implement function-calling mechanism for [`Engine`].
|
2017-12-20 22:16:53 +01:00
|
|
|
|
2021-12-20 15:13:00 +01:00
|
|
|
use super::callable_function::CallableFunction;
|
|
|
|
use super::native::FnAny;
|
2021-11-16 05:26:37 +01:00
|
|
|
use super::{get_builtin_binary_op_fn, get_builtin_op_assignment_fn};
|
2021-12-17 09:55:24 +01:00
|
|
|
use crate::api::default_limits::MAX_DYNAMIC_PARAMETERS;
|
2021-12-25 16:49:14 +01:00
|
|
|
use crate::ast::{Expr, FnCallHashes, Stmt};
|
2020-07-23 12:40:42 +02:00
|
|
|
use crate::engine::{
|
2022-01-07 04:43:47 +01:00
|
|
|
KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_FN_PTR_CALL, KEYWORD_FN_PTR_CURRY,
|
|
|
|
KEYWORD_IS_DEF_VAR, KEYWORD_PRINT, KEYWORD_TYPE_OF,
|
2020-07-23 12:40:42 +02:00
|
|
|
};
|
2022-01-07 04:43:47 +01:00
|
|
|
use crate::eval::{EvalState, GlobalRuntimeState};
|
2021-03-01 09:53:03 +01:00
|
|
|
use crate::{
|
2021-12-27 05:27:44 +01:00
|
|
|
calc_fn_hash, calc_fn_params_hash, combine_hashes, Dynamic, Engine, FnArgsVec, FnPtr,
|
2022-02-07 14:03:39 +01:00
|
|
|
Identifier, ImmutableString, Module, OptimizationLevel, Position, RhaiResult, RhaiResultOf,
|
|
|
|
Scope, ERR,
|
2020-11-16 16:10:14 +01:00
|
|
|
};
|
2021-04-17 09:15:54 +02:00
|
|
|
#[cfg(feature = "no_std")]
|
|
|
|
use std::prelude::v1::*;
|
|
|
|
use std::{
|
|
|
|
any::{type_name, TypeId},
|
2022-01-01 10:20:00 +01:00
|
|
|
collections::BTreeMap,
|
2021-04-17 09:15:54 +02:00
|
|
|
convert::TryFrom,
|
|
|
|
mem,
|
|
|
|
};
|
2020-11-16 16:10:14 +01:00
|
|
|
|
2021-06-17 03:50:32 +02:00
|
|
|
/// Arguments to a function call, which is a list of [`&mut Dynamic`][Dynamic].
|
|
|
|
pub type FnCallArgs<'a> = [&'a mut Dynamic];
|
|
|
|
|
2020-07-31 06:11:16 +02:00
|
|
|
/// A type that temporarily stores a mutable reference to a `Dynamic`,
|
|
|
|
/// replacing it with a cloned copy.
|
2021-11-07 11:12:37 +01:00
|
|
|
#[derive(Debug)]
|
2020-07-31 06:11:16 +02:00
|
|
|
struct ArgBackup<'a> {
|
|
|
|
orig_mut: Option<&'a mut Dynamic>,
|
|
|
|
value_copy: Dynamic,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> ArgBackup<'a> {
|
2021-11-07 11:12:37 +01:00
|
|
|
/// Create a new `ArgBackup`.
|
|
|
|
pub fn new() -> Self {
|
|
|
|
Self {
|
|
|
|
orig_mut: None,
|
|
|
|
value_copy: Dynamic::UNIT,
|
|
|
|
}
|
|
|
|
}
|
2020-07-31 06:11:16 +02:00
|
|
|
/// This function replaces the first argument of a method call with a clone copy.
|
|
|
|
/// This is to prevent a pure function unintentionally consuming the first argument.
|
|
|
|
///
|
2022-02-08 02:25:53 +01:00
|
|
|
/// `restore_first_arg` must be called before the end of the scope to prevent the shorter
|
|
|
|
/// lifetime from leaking.
|
2020-07-31 06:11:16 +02:00
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
///
|
2022-02-08 02:25:53 +01:00
|
|
|
/// This method blindly casts a reference to another lifetime, which saves allocation and
|
|
|
|
/// string cloning.
|
2020-07-31 06:11:16 +02:00
|
|
|
///
|
2021-05-22 13:14:24 +02:00
|
|
|
/// As long as `restore_first_arg` is called before the end of the scope, the shorter lifetime
|
|
|
|
/// will not leak.
|
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
///
|
|
|
|
/// Panics when `args` is empty.
|
2021-10-21 11:26:43 +02:00
|
|
|
#[inline]
|
2021-03-02 07:44:21 +01:00
|
|
|
fn change_first_arg_to_copy(&mut self, args: &mut FnCallArgs<'a>) {
|
2020-07-31 06:11:16 +02:00
|
|
|
// Clone the original value.
|
|
|
|
self.value_copy = args[0].clone();
|
|
|
|
|
|
|
|
// Replace the first reference with a reference to the clone, force-casting the lifetime.
|
|
|
|
// Must remember to restore it later with `restore_first_arg`.
|
|
|
|
//
|
|
|
|
// # Safety
|
|
|
|
//
|
|
|
|
// Blindly casting a reference to another lifetime saves allocation and string cloning,
|
|
|
|
// but must be used with the utmost care.
|
|
|
|
//
|
2022-02-08 02:25:53 +01:00
|
|
|
// We can do this here because, before the end of this scope, we'd restore the original
|
|
|
|
// reference via `restore_first_arg`. Therefore this shorter lifetime does not leak.
|
2021-05-25 04:54:48 +02:00
|
|
|
self.orig_mut = Some(mem::replace(&mut args[0], unsafe {
|
2020-07-31 06:11:16 +02:00
|
|
|
mem::transmute(&mut self.value_copy)
|
|
|
|
}));
|
2020-07-23 12:40:42 +02:00
|
|
|
}
|
2020-07-31 06:11:16 +02:00
|
|
|
/// This function restores the first argument that was replaced by `change_first_arg_to_copy`.
|
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
///
|
2022-02-08 02:25:53 +01:00
|
|
|
/// If `change_first_arg_to_copy` has been called, this function **MUST** be called _BEFORE_
|
|
|
|
/// exiting the current scope. Otherwise it is undefined behavior as the shorter lifetime will leak.
|
2020-12-29 03:41:20 +01:00
|
|
|
#[inline(always)]
|
2021-03-02 07:44:21 +01:00
|
|
|
fn restore_first_arg(mut self, args: &mut FnCallArgs<'a>) {
|
2021-07-24 08:11:16 +02:00
|
|
|
if let Some(p) = self.orig_mut.take() {
|
|
|
|
args[0] = p;
|
|
|
|
}
|
2020-07-31 06:11:16 +02:00
|
|
|
}
|
2017-12-20 22:16:53 +01:00
|
|
|
}
|
|
|
|
|
2020-07-31 06:11:16 +02:00
|
|
|
impl Drop for ArgBackup<'_> {
|
2021-10-21 11:26:43 +02:00
|
|
|
#[inline]
|
2020-07-31 06:11:16 +02:00
|
|
|
fn drop(&mut self) {
|
|
|
|
// Panic if the shorter lifetime leaks.
|
|
|
|
assert!(
|
|
|
|
self.orig_mut.is_none(),
|
2020-12-28 07:21:13 +01:00
|
|
|
"ArgBackup::restore_first_arg has not been called prior to existing this scope"
|
2020-07-31 06:11:16 +02:00
|
|
|
);
|
2020-07-23 12:40:42 +02:00
|
|
|
}
|
2017-12-20 22:16:53 +01:00
|
|
|
}
|
|
|
|
|
2021-03-29 07:07:10 +02:00
|
|
|
#[cfg(not(feature = "no_closure"))]
|
2021-07-10 05:06:13 +02:00
|
|
|
#[inline]
|
2020-08-02 07:33:51 +02:00
|
|
|
pub fn ensure_no_data_race(
|
2022-01-04 08:22:48 +01:00
|
|
|
fn_name: &str,
|
2020-08-02 07:33:51 +02:00
|
|
|
args: &FnCallArgs,
|
2021-06-17 03:50:32 +02:00
|
|
|
is_method_call: bool,
|
2021-12-25 16:49:14 +01:00
|
|
|
) -> RhaiResultOf<()> {
|
2022-02-08 02:02:15 +01:00
|
|
|
if let Some((n, ..)) = args
|
2021-03-20 16:57:43 +01:00
|
|
|
.iter()
|
|
|
|
.enumerate()
|
2021-06-17 03:50:32 +02:00
|
|
|
.skip(if is_method_call { 1 } else { 0 })
|
2022-02-08 02:02:15 +01:00
|
|
|
.find(|(.., a)| a.is_locked())
|
2021-03-20 16:57:43 +01:00
|
|
|
{
|
2021-12-27 05:27:31 +01:00
|
|
|
return Err(ERR::ErrorDataRace(
|
2022-01-04 08:22:48 +01:00
|
|
|
format!("argument #{} of function '{}'", n + 1, fn_name),
|
2021-03-20 16:57:43 +01:00
|
|
|
Position::NONE,
|
|
|
|
)
|
2021-10-19 17:52:58 +02:00
|
|
|
.into());
|
2020-08-02 07:33:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2022-01-01 10:20:00 +01:00
|
|
|
/// _(internals)_ An entry in a function resolution cache.
|
|
|
|
/// Exported under the `internals` feature only.
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub struct FnResolutionCacheEntry {
|
|
|
|
/// Function.
|
|
|
|
pub func: CallableFunction,
|
|
|
|
/// Optional source.
|
|
|
|
/// No source if the string is empty.
|
|
|
|
pub source: Identifier,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// _(internals)_ A function resolution cache.
|
|
|
|
/// Exported under the `internals` feature only.
|
|
|
|
///
|
|
|
|
/// [`FnResolutionCacheEntry`] is [`Box`]ed in order to pack as many entries inside a single B-Tree
|
|
|
|
/// level as possible.
|
|
|
|
pub type FnResolutionCache = BTreeMap<u64, Option<Box<FnResolutionCacheEntry>>>;
|
|
|
|
|
2020-07-23 12:40:42 +02:00
|
|
|
impl Engine {
|
2021-02-27 08:07:16 +01:00
|
|
|
/// Generate the signature for a function call.
|
2021-03-17 02:58:08 +01:00
|
|
|
#[inline]
|
2021-06-12 16:47:43 +02:00
|
|
|
#[must_use]
|
2021-02-27 08:07:16 +01:00
|
|
|
fn gen_call_signature(
|
|
|
|
&self,
|
2022-01-29 04:09:43 +01:00
|
|
|
#[cfg(not(feature = "no_module"))] namespace: Option<&crate::module::Namespace>,
|
2022-01-04 08:22:48 +01:00
|
|
|
fn_name: &str,
|
2021-02-27 08:07:16 +01:00
|
|
|
args: &[&mut Dynamic],
|
|
|
|
) -> String {
|
2022-01-29 04:09:43 +01:00
|
|
|
#[cfg(not(feature = "no_module"))]
|
|
|
|
let (ns, sep) = (
|
2022-01-03 16:16:47 +01:00
|
|
|
namespace.map_or_else(|| String::new(), |ns| ns.to_string()),
|
2021-10-27 17:30:25 +02:00
|
|
|
if namespace.is_some() {
|
2022-01-29 04:09:43 +01:00
|
|
|
crate::tokenizer::Token::DoubleColon.literal_syntax()
|
2021-10-27 17:30:25 +02:00
|
|
|
} else {
|
|
|
|
""
|
|
|
|
},
|
2022-01-29 04:09:43 +01:00
|
|
|
);
|
|
|
|
#[cfg(feature = "no_module")]
|
|
|
|
let (ns, sep) = ("", "");
|
|
|
|
|
|
|
|
format!(
|
|
|
|
"{}{}{} ({})",
|
|
|
|
ns,
|
|
|
|
sep,
|
2022-01-04 08:22:48 +01:00
|
|
|
fn_name,
|
2021-02-27 08:07:16 +01:00
|
|
|
args.iter()
|
|
|
|
.map(|a| if a.is::<ImmutableString>() {
|
|
|
|
"&str | ImmutableString | String"
|
|
|
|
} else {
|
2021-06-21 13:12:28 +02:00
|
|
|
self.map_type_name(a.type_name())
|
2021-02-27 08:07:16 +01:00
|
|
|
})
|
2021-12-27 05:27:44 +01:00
|
|
|
.collect::<FnArgsVec<_>>()
|
2021-02-27 08:07:16 +01:00
|
|
|
.join(", ")
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2021-03-01 09:53:03 +01:00
|
|
|
/// Resolve a function call.
|
2020-07-23 12:40:42 +02:00
|
|
|
///
|
2021-03-01 09:53:03 +01:00
|
|
|
/// Search order:
|
|
|
|
/// 1) AST - script functions in the AST
|
|
|
|
/// 2) Global namespace - functions registered via Engine::register_XXX
|
2022-01-20 01:17:34 +01:00
|
|
|
/// 3) Global registered modules - packages
|
2021-03-01 09:53:03 +01:00
|
|
|
/// 4) Imported modules - functions marked with global namespace
|
2022-01-20 01:17:34 +01:00
|
|
|
/// 5) Static registered modules
|
2021-06-12 16:47:43 +02:00
|
|
|
#[must_use]
|
|
|
|
fn resolve_fn<'s>(
|
2020-07-23 12:40:42 +02:00
|
|
|
&self,
|
2021-12-27 16:03:30 +01:00
|
|
|
global: &GlobalRuntimeState,
|
2021-07-04 10:40:15 +02:00
|
|
|
state: &'s mut EvalState,
|
2020-10-20 04:54:32 +02:00
|
|
|
lib: &[&Module],
|
2022-01-04 08:22:48 +01:00
|
|
|
fn_name: &str,
|
2021-03-08 08:30:32 +01:00
|
|
|
hash_script: u64,
|
|
|
|
args: Option<&mut FnCallArgs>,
|
2021-03-01 09:53:03 +01:00
|
|
|
allow_dynamic: bool,
|
2021-03-02 06:48:41 +01:00
|
|
|
is_op_assignment: bool,
|
2021-11-08 02:27:08 +01:00
|
|
|
) -> Option<&'s FnResolutionCacheEntry> {
|
2022-01-29 04:09:43 +01:00
|
|
|
let _global = global;
|
|
|
|
|
2021-12-05 10:05:19 +01:00
|
|
|
if hash_script == 0 {
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
2021-05-25 04:54:48 +02:00
|
|
|
let mut hash = args.as_ref().map_or(hash_script, |args| {
|
2021-06-21 13:12:28 +02:00
|
|
|
combine_hashes(
|
|
|
|
hash_script,
|
|
|
|
calc_fn_params_hash(args.iter().map(|a| a.type_id())),
|
|
|
|
)
|
2021-05-25 04:54:48 +02:00
|
|
|
});
|
2021-03-08 08:30:32 +01:00
|
|
|
|
2021-11-08 02:27:08 +01:00
|
|
|
let result = state
|
2021-02-07 10:56:29 +01:00
|
|
|
.fn_resolution_cache_mut()
|
2021-03-01 09:53:03 +01:00
|
|
|
.entry(hash)
|
2021-02-07 08:41:40 +01:00
|
|
|
.or_insert_with(|| {
|
2021-03-17 02:58:08 +01:00
|
|
|
let num_args = args.as_ref().map_or(0, |a| a.len());
|
2021-03-01 09:53:03 +01:00
|
|
|
let max_bitmask = if !allow_dynamic {
|
|
|
|
0
|
|
|
|
} else {
|
2021-12-27 05:27:31 +01:00
|
|
|
1usize << usize::min(num_args, MAX_DYNAMIC_PARAMETERS)
|
2021-03-01 09:53:03 +01:00
|
|
|
};
|
2021-02-23 12:08:05 +01:00
|
|
|
let mut bitmask = 1usize; // Bitmask of which parameter to replace with `Dynamic`
|
2021-02-23 09:06:36 +01:00
|
|
|
|
|
|
|
loop {
|
2021-08-26 17:58:41 +02:00
|
|
|
let func = lib
|
|
|
|
.iter()
|
2022-01-20 01:17:34 +01:00
|
|
|
.find_map(|&m| {
|
2021-08-26 17:58:41 +02:00
|
|
|
m.get_fn(hash).cloned().map(|func| FnResolutionCacheEntry {
|
|
|
|
func,
|
2022-01-01 10:20:00 +01:00
|
|
|
source: m.id_raw().clone(),
|
2021-08-26 17:58:41 +02:00
|
|
|
})
|
|
|
|
})
|
|
|
|
.or_else(|| {
|
|
|
|
self.global_modules.iter().find_map(|m| {
|
|
|
|
m.get_fn(hash).cloned().map(|func| FnResolutionCacheEntry {
|
|
|
|
func,
|
2022-01-01 10:20:00 +01:00
|
|
|
source: m.id_raw().clone(),
|
2021-08-26 17:58:41 +02:00
|
|
|
})
|
|
|
|
})
|
2022-01-29 06:37:58 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
#[cfg(not(feature = "no_module"))]
|
|
|
|
let func = func
|
2021-08-26 17:58:41 +02:00
|
|
|
.or_else(|| {
|
2022-01-29 06:37:58 +01:00
|
|
|
_global.get_qualified_fn(hash).map(|(func, source)| {
|
2022-01-20 01:17:34 +01:00
|
|
|
FnResolutionCacheEntry {
|
2021-08-26 17:58:41 +02:00
|
|
|
func: func.clone(),
|
2022-01-01 10:20:00 +01:00
|
|
|
source: source
|
|
|
|
.map_or_else(|| Identifier::new_const(), Into::into),
|
2022-01-20 01:17:34 +01:00
|
|
|
}
|
2022-01-29 06:37:58 +01:00
|
|
|
})
|
2021-08-26 17:58:41 +02:00
|
|
|
})
|
|
|
|
.or_else(|| {
|
2022-01-29 06:37:58 +01:00
|
|
|
self.global_sub_modules.values().find_map(|m| {
|
2021-08-26 17:58:41 +02:00
|
|
|
m.get_qualified_fn(hash).cloned().map(|func| {
|
|
|
|
FnResolutionCacheEntry {
|
|
|
|
func,
|
2022-01-01 10:20:00 +01:00
|
|
|
source: m.id_raw().clone(),
|
2021-08-26 17:58:41 +02:00
|
|
|
}
|
|
|
|
})
|
2022-01-29 06:37:58 +01:00
|
|
|
})
|
2021-08-26 17:58:41 +02:00
|
|
|
});
|
2021-03-05 13:07:35 +01:00
|
|
|
|
|
|
|
match func {
|
2021-02-23 09:06:36 +01:00
|
|
|
// Specific version found
|
2021-05-03 07:45:41 +02:00
|
|
|
Some(f) => return Some(Box::new(f)),
|
2021-02-23 09:06:36 +01:00
|
|
|
|
2021-02-24 15:40:18 +01:00
|
|
|
// Stop when all permutations are exhausted
|
2021-03-02 06:48:41 +01:00
|
|
|
None if bitmask >= max_bitmask => {
|
2021-03-17 02:58:08 +01:00
|
|
|
if num_args != 2 {
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
|
|
|
return args.and_then(|args| {
|
2021-03-08 08:30:32 +01:00
|
|
|
if !is_op_assignment {
|
2021-03-17 02:58:08 +01:00
|
|
|
get_builtin_binary_op_fn(fn_name, &args[0], &args[1]).map(|f| {
|
2021-08-26 17:58:41 +02:00
|
|
|
FnResolutionCacheEntry {
|
|
|
|
func: CallableFunction::from_method(
|
|
|
|
Box::new(f) as Box<FnAny>
|
|
|
|
),
|
2022-01-01 10:20:00 +01:00
|
|
|
source: Identifier::new_const(),
|
2021-08-26 17:58:41 +02:00
|
|
|
}
|
2021-03-17 02:58:08 +01:00
|
|
|
})
|
2021-03-02 06:48:41 +01:00
|
|
|
} else {
|
2022-01-06 04:07:52 +01:00
|
|
|
let (first_arg, rest_args) = args.split_first().unwrap();
|
2021-08-26 17:58:41 +02:00
|
|
|
|
2021-11-11 14:47:35 +01:00
|
|
|
get_builtin_op_assignment_fn(fn_name, *first_arg, rest_args[0])
|
|
|
|
.map(|f| FnResolutionCacheEntry {
|
2021-08-26 17:58:41 +02:00
|
|
|
func: CallableFunction::from_method(
|
|
|
|
Box::new(f) as Box<FnAny>
|
|
|
|
),
|
2022-01-01 10:20:00 +01:00
|
|
|
source: Identifier::new_const(),
|
2021-11-11 14:47:35 +01:00
|
|
|
})
|
2021-03-02 06:48:41 +01:00
|
|
|
}
|
2021-05-03 07:45:41 +02:00
|
|
|
.map(Box::new)
|
2021-03-17 02:58:08 +01:00
|
|
|
});
|
2021-03-02 06:48:41 +01:00
|
|
|
}
|
2021-02-23 09:06:36 +01:00
|
|
|
|
|
|
|
// Try all permutations with `Dynamic` wildcards
|
2021-03-01 09:53:03 +01:00
|
|
|
None => {
|
2021-03-08 08:30:32 +01:00
|
|
|
let hash_params = calc_fn_params_hash(
|
2021-08-26 17:58:41 +02:00
|
|
|
args.as_ref()
|
2021-11-13 05:23:35 +01:00
|
|
|
.expect("no permutations")
|
2021-08-26 17:58:41 +02:00
|
|
|
.iter()
|
|
|
|
.enumerate()
|
|
|
|
.map(|(i, a)| {
|
|
|
|
let mask = 1usize << (num_args - i - 1);
|
|
|
|
if bitmask & mask != 0 {
|
|
|
|
// Replace with `Dynamic`
|
|
|
|
TypeId::of::<Dynamic>()
|
|
|
|
} else {
|
|
|
|
a.type_id()
|
|
|
|
}
|
|
|
|
}),
|
2021-03-08 08:30:32 +01:00
|
|
|
);
|
|
|
|
hash = combine_hashes(hash_script, hash_params);
|
2021-02-23 12:08:05 +01:00
|
|
|
|
2021-02-23 09:06:36 +01:00
|
|
|
bitmask += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-11-08 02:27:08 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
result.as_ref().map(Box::as_ref)
|
2021-03-01 09:53:03 +01:00
|
|
|
}
|
|
|
|
|
2022-02-02 07:47:35 +01:00
|
|
|
/// # Main Entry-Point
|
|
|
|
///
|
2021-03-01 09:53:03 +01:00
|
|
|
/// Call a native Rust function registered with the [`Engine`].
|
|
|
|
///
|
|
|
|
/// # WARNING
|
|
|
|
///
|
|
|
|
/// Function call arguments be _consumed_ when the function requires them to be passed by value.
|
|
|
|
/// All function arguments not in the first position are always passed by value and thus consumed.
|
2021-11-29 03:17:04 +01:00
|
|
|
///
|
2021-03-01 09:53:03 +01:00
|
|
|
/// **DO NOT** reuse the argument values unless for the first `&mut` argument - all others are silently replaced by `()`!
|
|
|
|
pub(crate) fn call_native_fn(
|
|
|
|
&self,
|
2021-12-27 16:03:30 +01:00
|
|
|
global: &mut GlobalRuntimeState,
|
2021-07-04 10:40:15 +02:00
|
|
|
state: &mut EvalState,
|
2021-03-01 09:53:03 +01:00
|
|
|
lib: &[&Module],
|
2022-01-04 08:22:48 +01:00
|
|
|
name: &str,
|
2021-06-12 16:47:43 +02:00
|
|
|
hash: u64,
|
2021-03-01 09:53:03 +01:00
|
|
|
args: &mut FnCallArgs,
|
2021-12-02 05:49:46 +01:00
|
|
|
is_ref_mut: bool,
|
2021-06-12 16:47:43 +02:00
|
|
|
is_op_assign: bool,
|
2021-03-01 09:53:03 +01:00
|
|
|
pos: Position,
|
2022-02-02 07:47:35 +01:00
|
|
|
level: usize,
|
2021-12-25 16:49:14 +01:00
|
|
|
) -> RhaiResultOf<(Dynamic, bool)> {
|
2021-04-25 09:27:58 +02:00
|
|
|
#[cfg(not(feature = "unchecked"))]
|
2021-12-27 16:03:30 +01:00
|
|
|
self.inc_operations(&mut global.num_operations, pos)?;
|
2021-03-01 09:53:03 +01:00
|
|
|
|
2021-12-27 16:03:30 +01:00
|
|
|
let parent_source = global.source.clone();
|
2021-03-01 09:53:03 +01:00
|
|
|
|
|
|
|
// Check if function access already in the cache
|
2021-12-27 16:03:30 +01:00
|
|
|
let func = self.resolve_fn(
|
|
|
|
global,
|
|
|
|
state,
|
|
|
|
lib,
|
|
|
|
name,
|
|
|
|
hash,
|
|
|
|
Some(args),
|
|
|
|
true,
|
|
|
|
is_op_assign,
|
|
|
|
);
|
2020-12-30 14:12:51 +01:00
|
|
|
|
2022-02-02 07:47:35 +01:00
|
|
|
if func.is_some() {
|
|
|
|
let is_method = func.map(|f| f.func.is_method()).unwrap_or(false);
|
2020-07-23 12:40:42 +02:00
|
|
|
|
2022-02-02 07:47:35 +01:00
|
|
|
// Push a new call stack frame
|
|
|
|
#[cfg(feature = "debugging")]
|
|
|
|
let orig_call_stack_len = global.debugger.call_stack().len();
|
2021-06-11 13:59:50 +02:00
|
|
|
|
2022-02-02 07:57:30 +01:00
|
|
|
let mut _result = if let Some(FnResolutionCacheEntry { func, source }) = func {
|
2022-02-02 07:47:35 +01:00
|
|
|
assert!(func.is_native());
|
2021-11-08 02:27:08 +01:00
|
|
|
|
2022-02-02 07:47:35 +01:00
|
|
|
// Calling pure function but the first argument is a reference?
|
|
|
|
let mut backup: Option<ArgBackup> = None;
|
|
|
|
if is_ref_mut && func.is_pure() && !args.is_empty() {
|
|
|
|
// Clone the first argument
|
|
|
|
backup = Some(ArgBackup::new());
|
|
|
|
backup
|
|
|
|
.as_mut()
|
|
|
|
.expect("`Some`")
|
|
|
|
.change_first_arg_to_copy(args);
|
|
|
|
}
|
|
|
|
|
|
|
|
let source = match (source.as_str(), parent_source.as_str()) {
|
|
|
|
("", "") => None,
|
2022-02-08 02:02:15 +01:00
|
|
|
("", s) | (s, ..) => Some(s),
|
2022-02-02 07:47:35 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
#[cfg(feature = "debugging")]
|
|
|
|
if self.debugger.is_some() {
|
|
|
|
global.debugger.push_call_stack_frame(
|
|
|
|
name,
|
|
|
|
args.iter().map(|v| (*v).clone()).collect(),
|
|
|
|
source.unwrap_or(""),
|
|
|
|
pos,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Run external function
|
|
|
|
let context = (self, name, source, &*global, lib, pos, level).into();
|
|
|
|
|
|
|
|
let result = if func.is_plugin_fn() {
|
|
|
|
func.get_plugin_fn()
|
|
|
|
.expect("plugin function")
|
|
|
|
.call(context, args)
|
|
|
|
} else {
|
|
|
|
func.get_native_fn().expect("native function")(context, args)
|
|
|
|
};
|
|
|
|
|
|
|
|
// Restore the original reference
|
|
|
|
if let Some(bk) = backup {
|
|
|
|
bk.restore_first_arg(args)
|
|
|
|
}
|
|
|
|
|
|
|
|
result
|
2020-08-02 12:53:25 +02:00
|
|
|
} else {
|
2022-02-02 07:47:35 +01:00
|
|
|
unreachable!("`Some`");
|
2020-08-02 12:53:25 +02:00
|
|
|
};
|
2020-07-23 12:40:42 +02:00
|
|
|
|
2022-02-02 07:47:35 +01:00
|
|
|
#[cfg(feature = "debugging")]
|
2022-02-04 05:04:33 +01:00
|
|
|
{
|
|
|
|
let trigger = match global.debugger.status {
|
|
|
|
crate::eval::DebuggerStatus::FunctionExit(n) => n >= level,
|
2022-02-08 02:02:15 +01:00
|
|
|
crate::eval::DebuggerStatus::Next(.., true) => true,
|
2022-02-04 05:04:33 +01:00
|
|
|
_ => false,
|
|
|
|
};
|
|
|
|
if trigger {
|
|
|
|
let scope = &mut &mut Scope::new();
|
|
|
|
let node = crate::ast::Stmt::Noop(pos);
|
|
|
|
let node = (&node).into();
|
|
|
|
let event = match _result {
|
|
|
|
Ok(ref r) => crate::eval::DebuggerEvent::FunctionExitWithValue(r),
|
|
|
|
Err(ref err) => crate::eval::DebuggerEvent::FunctionExitWithError(err),
|
|
|
|
};
|
|
|
|
match self
|
|
|
|
.run_debugger_raw(scope, global, state, lib, &mut None, node, event, level)
|
|
|
|
{
|
|
|
|
Ok(_) => (),
|
|
|
|
Err(err) => _result = Err(err),
|
2022-02-02 07:47:35 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Pop the call stack
|
|
|
|
global.debugger.rewind_call_stack(orig_call_stack_len);
|
2021-07-24 08:11:16 +02:00
|
|
|
}
|
2020-07-31 06:11:16 +02:00
|
|
|
|
2022-01-06 15:10:16 +01:00
|
|
|
// Check the return value (including data sizes)
|
2022-02-02 07:57:30 +01:00
|
|
|
let result = self.check_return_value(_result, pos)?;
|
2022-01-06 15:10:16 +01:00
|
|
|
|
|
|
|
// Check the data size of any `&mut` object, which may be changed.
|
|
|
|
#[cfg(not(feature = "unchecked"))]
|
|
|
|
if is_ref_mut && args.len() > 0 {
|
|
|
|
self.check_data_size(&args[0], pos)?;
|
|
|
|
}
|
2020-07-23 12:40:42 +02:00
|
|
|
|
|
|
|
// See if the function match print/debug (which requires special processing)
|
2021-06-12 16:47:43 +02:00
|
|
|
return Ok(match name {
|
2020-12-22 08:27:27 +01:00
|
|
|
KEYWORD_PRINT => {
|
2021-06-29 11:42:03 +02:00
|
|
|
if let Some(ref print) = self.print {
|
2021-07-24 10:24:59 +02:00
|
|
|
let text = result.into_immutable_string().map_err(|typ| {
|
2021-12-27 05:27:31 +01:00
|
|
|
ERR::ErrorMismatchOutputType(
|
2021-06-29 11:42:03 +02:00
|
|
|
self.map_type_name(type_name::<ImmutableString>()).into(),
|
|
|
|
typ.into(),
|
|
|
|
pos,
|
|
|
|
)
|
|
|
|
})?;
|
|
|
|
(print(&text).into(), false)
|
|
|
|
} else {
|
|
|
|
(Dynamic::UNIT, false)
|
|
|
|
}
|
2020-12-22 08:27:27 +01:00
|
|
|
}
|
2020-12-21 15:04:46 +01:00
|
|
|
KEYWORD_DEBUG => {
|
2021-06-29 11:42:03 +02:00
|
|
|
if let Some(ref debug) = self.debug {
|
2021-07-24 10:24:59 +02:00
|
|
|
let text = result.into_immutable_string().map_err(|typ| {
|
2021-12-27 05:27:31 +01:00
|
|
|
ERR::ErrorMismatchOutputType(
|
2021-06-29 11:42:03 +02:00
|
|
|
self.map_type_name(type_name::<ImmutableString>()).into(),
|
|
|
|
typ.into(),
|
|
|
|
pos,
|
|
|
|
)
|
|
|
|
})?;
|
2022-01-03 16:16:47 +01:00
|
|
|
let source = match global.source.as_str() {
|
|
|
|
"" => None,
|
|
|
|
s => Some(s),
|
2022-01-01 10:20:00 +01:00
|
|
|
};
|
2021-06-29 11:42:03 +02:00
|
|
|
(debug(&text, source, pos).into(), false)
|
|
|
|
} else {
|
|
|
|
(Dynamic::UNIT, false)
|
|
|
|
}
|
2020-12-21 15:04:46 +01:00
|
|
|
}
|
2022-02-02 07:47:35 +01:00
|
|
|
_ => (result, is_method),
|
2020-07-23 12:40:42 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-12-02 05:49:46 +01:00
|
|
|
// Error handling
|
|
|
|
|
2021-06-12 16:47:43 +02:00
|
|
|
match name {
|
2021-03-16 11:16:40 +01:00
|
|
|
// index getter function not found?
|
2021-05-18 15:38:09 +02:00
|
|
|
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
2021-03-16 11:16:40 +01:00
|
|
|
crate::engine::FN_IDX_GET => {
|
|
|
|
assert!(args.len() == 2);
|
2020-07-23 12:40:42 +02:00
|
|
|
|
2021-12-27 05:27:31 +01:00
|
|
|
Err(ERR::ErrorIndexingType(
|
2021-06-16 13:45:45 +02:00
|
|
|
format!(
|
|
|
|
"{} [{}]",
|
|
|
|
self.map_type_name(args[0].type_name()),
|
|
|
|
self.map_type_name(args[1].type_name())
|
|
|
|
),
|
2021-03-16 11:16:40 +01:00
|
|
|
pos,
|
|
|
|
)
|
2021-10-19 17:52:58 +02:00
|
|
|
.into())
|
2021-03-16 11:16:40 +01:00
|
|
|
}
|
2020-07-23 12:40:42 +02:00
|
|
|
|
2021-03-16 11:16:40 +01:00
|
|
|
// index setter function not found?
|
2021-05-18 15:38:09 +02:00
|
|
|
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
2021-03-16 11:16:40 +01:00
|
|
|
crate::engine::FN_IDX_SET => {
|
|
|
|
assert!(args.len() == 3);
|
|
|
|
|
2021-12-27 05:27:31 +01:00
|
|
|
Err(ERR::ErrorIndexingType(
|
2021-06-16 13:45:45 +02:00
|
|
|
format!(
|
|
|
|
"{} [{}] = {}",
|
|
|
|
self.map_type_name(args[0].type_name()),
|
|
|
|
self.map_type_name(args[1].type_name()),
|
|
|
|
self.map_type_name(args[2].type_name())
|
|
|
|
),
|
2021-03-16 11:16:40 +01:00
|
|
|
pos,
|
|
|
|
)
|
2021-10-19 17:52:58 +02:00
|
|
|
.into())
|
2021-03-16 11:16:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Getter function not found?
|
|
|
|
#[cfg(not(feature = "no_object"))]
|
2021-06-12 16:47:43 +02:00
|
|
|
_ if name.starts_with(crate::engine::FN_GET) => {
|
2021-03-16 11:16:40 +01:00
|
|
|
assert!(args.len() == 1);
|
|
|
|
|
2021-12-27 05:27:31 +01:00
|
|
|
Err(ERR::ErrorDotExpr(
|
2021-03-16 11:16:40 +01:00
|
|
|
format!(
|
|
|
|
"Unknown property '{}' - a getter is not registered for type '{}'",
|
2021-06-12 16:47:43 +02:00
|
|
|
&name[crate::engine::FN_GET.len()..],
|
2021-03-16 11:16:40 +01:00
|
|
|
self.map_type_name(args[0].type_name())
|
|
|
|
),
|
|
|
|
pos,
|
|
|
|
)
|
2021-10-19 17:52:58 +02:00
|
|
|
.into())
|
2021-03-16 11:16:40 +01:00
|
|
|
}
|
2020-07-23 12:40:42 +02:00
|
|
|
|
2021-03-16 11:16:40 +01:00
|
|
|
// Setter function not found?
|
|
|
|
#[cfg(not(feature = "no_object"))]
|
2021-06-12 16:47:43 +02:00
|
|
|
_ if name.starts_with(crate::engine::FN_SET) => {
|
2021-03-16 11:16:40 +01:00
|
|
|
assert!(args.len() == 2);
|
|
|
|
|
2021-12-27 05:27:31 +01:00
|
|
|
Err(ERR::ErrorDotExpr(
|
2021-03-16 11:16:40 +01:00
|
|
|
format!(
|
|
|
|
"No writable property '{}' - a setter is not registered for type '{}' to handle '{}'",
|
2021-06-12 16:47:43 +02:00
|
|
|
&name[crate::engine::FN_SET.len()..],
|
2021-03-16 11:16:40 +01:00
|
|
|
self.map_type_name(args[0].type_name()),
|
|
|
|
self.map_type_name(args[1].type_name()),
|
|
|
|
),
|
|
|
|
pos,
|
|
|
|
)
|
2021-10-19 17:52:58 +02:00
|
|
|
.into())
|
2021-03-16 11:16:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Raise error
|
2022-01-29 04:09:43 +01:00
|
|
|
_ => Err(ERR::ErrorFunctionNotFound(
|
|
|
|
self.gen_call_signature(
|
|
|
|
#[cfg(not(feature = "no_module"))]
|
|
|
|
None,
|
|
|
|
name,
|
|
|
|
args,
|
|
|
|
),
|
|
|
|
pos,
|
|
|
|
)
|
|
|
|
.into()),
|
2020-07-23 12:40:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-02 07:47:35 +01:00
|
|
|
/// # Main Entry-Point
|
|
|
|
///
|
2020-07-31 06:11:16 +02:00
|
|
|
/// Perform an actual function call, native Rust or scripted, taking care of special functions.
|
2020-07-23 12:40:42 +02:00
|
|
|
///
|
2021-01-02 16:30:10 +01:00
|
|
|
/// # WARNING
|
2020-07-23 12:40:42 +02:00
|
|
|
///
|
|
|
|
/// Function call arguments may be _consumed_ when the function requires them to be passed by value.
|
|
|
|
/// All function arguments not in the first position are always passed by value and thus consumed.
|
2021-11-29 03:17:04 +01:00
|
|
|
///
|
2020-07-23 12:40:42 +02:00
|
|
|
/// **DO NOT** reuse the argument values unless for the first `&mut` argument - all others are silently replaced by `()`!
|
|
|
|
pub(crate) fn exec_fn_call(
|
|
|
|
&self,
|
2022-02-02 15:42:33 +01:00
|
|
|
scope: Option<&mut Scope>,
|
2021-12-27 16:03:30 +01:00
|
|
|
global: &mut GlobalRuntimeState,
|
2021-07-04 10:40:15 +02:00
|
|
|
state: &mut EvalState,
|
2020-10-20 04:54:32 +02:00
|
|
|
lib: &[&Module],
|
2022-01-04 08:22:48 +01:00
|
|
|
fn_name: &str,
|
2021-06-13 11:41:34 +02:00
|
|
|
hashes: FnCallHashes,
|
2020-07-23 12:40:42 +02:00
|
|
|
args: &mut FnCallArgs,
|
2021-06-17 03:50:32 +02:00
|
|
|
is_ref_mut: bool,
|
2021-08-13 07:42:39 +02:00
|
|
|
is_method_call: bool,
|
2020-12-12 04:15:09 +01:00
|
|
|
pos: Position,
|
2021-11-16 06:42:46 +01:00
|
|
|
level: usize,
|
2021-12-25 16:49:14 +01:00
|
|
|
) -> RhaiResultOf<(Dynamic, bool)> {
|
|
|
|
fn no_method_err(name: &str, pos: Position) -> RhaiResultOf<(Dynamic, bool)> {
|
2021-06-08 17:40:10 +02:00
|
|
|
let msg = format!("'{0}' should not be called this way. Try {0}(...);", name);
|
2021-12-27 05:27:31 +01:00
|
|
|
Err(ERR::ErrorRuntime(msg.into(), pos).into())
|
2021-06-08 17:40:10 +02:00
|
|
|
}
|
|
|
|
|
2020-08-02 07:33:51 +02:00
|
|
|
// Check for data race.
|
2021-03-20 16:57:43 +01:00
|
|
|
#[cfg(not(feature = "no_closure"))]
|
2021-06-17 03:50:32 +02:00
|
|
|
ensure_no_data_race(fn_name, args, is_ref_mut)?;
|
2020-08-02 07:33:51 +02:00
|
|
|
|
2021-11-16 06:42:46 +01:00
|
|
|
let _scope = scope;
|
2021-08-13 07:42:39 +02:00
|
|
|
let _is_method_call = is_method_call;
|
|
|
|
|
2021-03-01 15:44:56 +01:00
|
|
|
// These may be redirected from method style calls.
|
2020-07-23 12:40:42 +02:00
|
|
|
match fn_name {
|
2021-03-01 15:44:56 +01:00
|
|
|
// Handle type_of()
|
|
|
|
KEYWORD_TYPE_OF if args.len() == 1 => {
|
|
|
|
return Ok((
|
|
|
|
self.map_type_name(args[0].type_name()).to_string().into(),
|
|
|
|
false,
|
2021-06-08 17:40:10 +02:00
|
|
|
))
|
2021-03-01 15:44:56 +01:00
|
|
|
}
|
2020-07-23 12:40:42 +02:00
|
|
|
|
2021-03-01 15:44:56 +01:00
|
|
|
// Handle is_def_fn()
|
2020-07-30 12:18:28 +02:00
|
|
|
#[cfg(not(feature = "no_function"))]
|
2021-03-01 15:44:56 +01:00
|
|
|
crate::engine::KEYWORD_IS_DEF_FN
|
2021-03-07 15:10:54 +01:00
|
|
|
if args.len() == 2 && args[0].is::<FnPtr>() && args[1].is::<crate::INT>() =>
|
2021-03-01 15:44:56 +01:00
|
|
|
{
|
2021-11-13 05:23:35 +01:00
|
|
|
let fn_name = args[0].read_lock::<ImmutableString>().expect("`FnPtr`");
|
|
|
|
let num_params = args[1].as_int().expect("`INT`");
|
2020-09-25 13:07:24 +02:00
|
|
|
|
2021-03-01 15:44:56 +01:00
|
|
|
return Ok((
|
|
|
|
if num_params < 0 {
|
2021-10-11 09:49:51 +02:00
|
|
|
false
|
2021-03-01 15:44:56 +01:00
|
|
|
} else {
|
2021-07-04 10:40:15 +02:00
|
|
|
let hash_script = calc_fn_hash(fn_name.as_str(), num_params as usize);
|
2021-12-27 16:03:30 +01:00
|
|
|
self.has_script_fn(Some(global), state, lib, hash_script)
|
2021-10-11 09:49:51 +02:00
|
|
|
}
|
|
|
|
.into(),
|
2021-03-01 15:44:56 +01:00
|
|
|
false,
|
|
|
|
));
|
|
|
|
}
|
2020-12-21 15:04:46 +01:00
|
|
|
|
2021-03-01 15:44:56 +01:00
|
|
|
// Handle is_shared()
|
|
|
|
#[cfg(not(feature = "no_closure"))]
|
|
|
|
crate::engine::KEYWORD_IS_SHARED if args.len() == 1 => {
|
2021-06-08 17:40:10 +02:00
|
|
|
return no_method_err(fn_name, pos)
|
2021-03-01 15:44:56 +01:00
|
|
|
}
|
2020-12-21 15:04:46 +01:00
|
|
|
|
2021-03-01 15:44:56 +01:00
|
|
|
KEYWORD_FN_PTR | KEYWORD_EVAL | KEYWORD_IS_DEF_VAR if args.len() == 1 => {
|
2021-06-08 17:40:10 +02:00
|
|
|
return no_method_err(fn_name, pos)
|
2021-03-01 15:44:56 +01:00
|
|
|
}
|
2020-12-29 05:29:45 +01:00
|
|
|
|
2021-03-01 15:44:56 +01:00
|
|
|
KEYWORD_FN_PTR_CALL | KEYWORD_FN_PTR_CURRY if !args.is_empty() => {
|
2021-06-08 17:40:10 +02:00
|
|
|
return no_method_err(fn_name, pos)
|
2021-03-01 15:44:56 +01:00
|
|
|
}
|
2020-12-21 15:04:46 +01:00
|
|
|
|
2021-03-01 15:44:56 +01:00
|
|
|
_ => (),
|
|
|
|
}
|
2020-12-21 15:04:46 +01:00
|
|
|
|
2022-02-02 07:47:35 +01:00
|
|
|
let level = level + 1;
|
|
|
|
|
2021-12-17 09:07:13 +01:00
|
|
|
// Script-defined function call?
|
2021-03-14 03:47:21 +01:00
|
|
|
#[cfg(not(feature = "no_function"))]
|
2022-01-01 10:20:00 +01:00
|
|
|
if let Some(FnResolutionCacheEntry { func, mut source }) = self
|
2021-12-27 16:03:30 +01:00
|
|
|
.resolve_fn(
|
|
|
|
global,
|
|
|
|
state,
|
|
|
|
lib,
|
|
|
|
fn_name,
|
|
|
|
hashes.script,
|
|
|
|
None,
|
|
|
|
false,
|
|
|
|
false,
|
|
|
|
)
|
2021-12-05 10:05:19 +01:00
|
|
|
.cloned()
|
|
|
|
{
|
2021-03-01 15:44:56 +01:00
|
|
|
// Script function call
|
|
|
|
assert!(func.is_script());
|
2020-07-30 12:18:28 +02:00
|
|
|
|
2021-12-17 09:07:13 +01:00
|
|
|
let func = func.get_script_fn_def().expect("script-defined function");
|
2020-12-21 15:04:46 +01:00
|
|
|
|
2021-03-10 15:12:48 +01:00
|
|
|
if func.body.is_empty() {
|
|
|
|
return Ok((Dynamic::UNIT, false));
|
|
|
|
}
|
|
|
|
|
2021-11-14 15:48:57 +01:00
|
|
|
let mut empty_scope;
|
2021-12-12 05:33:22 +01:00
|
|
|
let scope = match _scope {
|
|
|
|
Some(scope) => scope,
|
|
|
|
None => {
|
|
|
|
empty_scope = Scope::new();
|
|
|
|
&mut empty_scope
|
|
|
|
}
|
2021-11-14 15:48:57 +01:00
|
|
|
};
|
2020-07-30 12:18:28 +02:00
|
|
|
|
2022-01-01 10:20:00 +01:00
|
|
|
mem::swap(&mut global.source, &mut source);
|
|
|
|
|
2021-06-17 03:50:32 +02:00
|
|
|
let result = if _is_method_call {
|
2021-03-01 15:44:56 +01:00
|
|
|
// Method call of script function - map first argument to `this`
|
2022-01-06 04:07:52 +01:00
|
|
|
let (first_arg, rest_args) = args.split_first_mut().unwrap();
|
2020-12-21 15:04:46 +01:00
|
|
|
|
2021-03-01 15:44:56 +01:00
|
|
|
let result = self.call_script_fn(
|
2021-11-14 15:48:57 +01:00
|
|
|
scope,
|
2021-12-27 16:03:30 +01:00
|
|
|
global,
|
2021-03-01 15:44:56 +01:00
|
|
|
state,
|
|
|
|
lib,
|
2021-11-11 14:47:35 +01:00
|
|
|
&mut Some(*first_arg),
|
2021-03-01 15:44:56 +01:00
|
|
|
func,
|
2021-11-11 14:47:35 +01:00
|
|
|
rest_args,
|
2021-11-15 04:13:00 +01:00
|
|
|
true,
|
2022-02-02 15:42:33 +01:00
|
|
|
pos,
|
2021-03-01 15:44:56 +01:00
|
|
|
level,
|
|
|
|
);
|
|
|
|
|
|
|
|
result?
|
|
|
|
} else {
|
|
|
|
// Normal call of script function
|
|
|
|
// The first argument is a reference?
|
2021-03-02 07:44:21 +01:00
|
|
|
let mut backup: Option<ArgBackup> = None;
|
2021-06-17 03:50:32 +02:00
|
|
|
if is_ref_mut && !args.is_empty() {
|
2021-11-07 11:12:37 +01:00
|
|
|
backup = Some(ArgBackup::new());
|
2021-08-26 17:58:41 +02:00
|
|
|
backup
|
|
|
|
.as_mut()
|
2021-11-13 05:23:35 +01:00
|
|
|
.expect("`Some`")
|
2021-08-26 17:58:41 +02:00
|
|
|
.change_first_arg_to_copy(args);
|
2021-03-02 07:44:21 +01:00
|
|
|
}
|
2020-09-11 16:32:59 +02:00
|
|
|
|
2021-11-15 04:13:00 +01:00
|
|
|
let result = self.call_script_fn(
|
2022-02-02 15:42:33 +01:00
|
|
|
scope, global, state, lib, &mut None, func, args, true, pos, level,
|
2021-11-15 04:13:00 +01:00
|
|
|
);
|
2021-03-01 15:44:56 +01:00
|
|
|
|
|
|
|
// Restore the original reference
|
2021-07-24 08:11:16 +02:00
|
|
|
if let Some(bk) = backup {
|
|
|
|
bk.restore_first_arg(args)
|
|
|
|
}
|
2021-03-01 15:44:56 +01:00
|
|
|
|
|
|
|
result?
|
|
|
|
};
|
|
|
|
|
2022-01-01 10:20:00 +01:00
|
|
|
// Restore the original source
|
|
|
|
mem::swap(&mut global.source, &mut source);
|
|
|
|
|
2021-03-01 15:44:56 +01:00
|
|
|
return Ok((result, false));
|
2020-07-23 12:40:42 +02:00
|
|
|
}
|
2021-03-01 15:44:56 +01:00
|
|
|
|
|
|
|
// Native function call
|
2021-06-13 11:41:34 +02:00
|
|
|
let hash = hashes.native;
|
2021-06-17 03:50:32 +02:00
|
|
|
self.call_native_fn(
|
2022-02-02 07:47:35 +01:00
|
|
|
global, state, lib, fn_name, hash, args, is_ref_mut, false, pos, level,
|
2021-06-17 03:50:32 +02:00
|
|
|
)
|
2020-07-23 12:40:42 +02:00
|
|
|
}
|
|
|
|
|
2021-02-07 10:06:33 +01:00
|
|
|
/// Evaluate a list of statements with no `this` pointer.
|
2020-11-20 09:52:28 +01:00
|
|
|
/// This is commonly used to evaluate a list of statements in an [`AST`] or a script function body.
|
2021-07-10 05:06:13 +02:00
|
|
|
#[inline]
|
2021-03-01 08:58:11 +01:00
|
|
|
pub(crate) fn eval_global_statements(
|
2020-10-20 04:54:32 +02:00
|
|
|
&self,
|
|
|
|
scope: &mut Scope,
|
2021-12-27 16:03:30 +01:00
|
|
|
global: &mut GlobalRuntimeState,
|
2021-07-04 10:40:15 +02:00
|
|
|
state: &mut EvalState,
|
2021-03-01 08:58:11 +01:00
|
|
|
statements: &[Stmt],
|
2020-10-20 04:54:32 +02:00
|
|
|
lib: &[&Module],
|
2020-12-29 05:29:45 +01:00
|
|
|
level: usize,
|
2021-03-02 08:02:28 +01:00
|
|
|
) -> RhaiResult {
|
2021-11-15 04:13:00 +01:00
|
|
|
self.eval_stmt_block(
|
2021-12-28 10:50:49 +01:00
|
|
|
scope, global, state, lib, &mut None, statements, false, level,
|
2021-11-15 04:13:00 +01:00
|
|
|
)
|
|
|
|
.or_else(|err| match *err {
|
2022-02-08 02:02:15 +01:00
|
|
|
ERR::Return(out, ..) => Ok(out),
|
|
|
|
ERR::LoopBreak(..) => {
|
2021-11-15 04:13:00 +01:00
|
|
|
unreachable!("no outer loop scope to break out of")
|
|
|
|
}
|
|
|
|
_ => Err(err),
|
|
|
|
})
|
2020-10-20 04:54:32 +02:00
|
|
|
}
|
|
|
|
|
2020-07-23 12:40:42 +02:00
|
|
|
/// Call a dot method.
|
2020-07-26 09:53:22 +02:00
|
|
|
#[cfg(not(feature = "no_object"))]
|
2020-07-23 12:40:42 +02:00
|
|
|
pub(crate) fn make_method_call(
|
|
|
|
&self,
|
2021-12-27 16:03:30 +01:00
|
|
|
global: &mut GlobalRuntimeState,
|
2021-07-04 10:40:15 +02:00
|
|
|
state: &mut EvalState,
|
2020-10-20 04:54:32 +02:00
|
|
|
lib: &[&Module],
|
2022-01-04 08:22:48 +01:00
|
|
|
fn_name: &str,
|
2021-04-20 16:26:08 +02:00
|
|
|
mut hash: FnCallHashes,
|
2022-01-07 04:43:47 +01:00
|
|
|
target: &mut crate::eval::Target,
|
2021-12-27 05:27:44 +01:00
|
|
|
(call_args, call_arg_pos): &mut (FnArgsVec<Dynamic>, Position),
|
2020-12-12 04:15:09 +01:00
|
|
|
pos: Position,
|
2020-07-23 12:40:42 +02:00
|
|
|
level: usize,
|
2021-12-25 16:49:14 +01:00
|
|
|
) -> RhaiResultOf<(Dynamic, bool)> {
|
2021-06-17 03:50:32 +02:00
|
|
|
let is_ref_mut = target.is_ref();
|
2020-07-23 12:40:42 +02:00
|
|
|
|
2021-03-01 15:44:56 +01:00
|
|
|
let (result, updated) = match fn_name {
|
2021-05-29 12:33:29 +02:00
|
|
|
KEYWORD_FN_PTR_CALL if target.is::<FnPtr>() => {
|
2021-03-01 15:44:56 +01:00
|
|
|
// FnPtr call
|
2021-11-13 05:23:35 +01:00
|
|
|
let fn_ptr = target.read_lock::<FnPtr>().expect("`FnPtr`");
|
2021-03-01 15:44:56 +01:00
|
|
|
// Redirect function name
|
|
|
|
let fn_name = fn_ptr.fn_name();
|
|
|
|
let args_len = call_args.len() + fn_ptr.curry().len();
|
2021-03-08 08:30:32 +01:00
|
|
|
// Recalculate hashes
|
2021-11-16 06:42:46 +01:00
|
|
|
let new_hash = calc_fn_hash(fn_name, args_len).into();
|
2021-03-01 15:44:56 +01:00
|
|
|
// Arguments are passed as-is, adding the curried arguments
|
2021-12-27 05:27:44 +01:00
|
|
|
let mut curry = FnArgsVec::with_capacity(fn_ptr.num_curried());
|
2021-06-08 09:48:55 +02:00
|
|
|
curry.extend(fn_ptr.curry().iter().cloned());
|
2021-12-27 05:27:44 +01:00
|
|
|
let mut args = FnArgsVec::with_capacity(curry.len() + call_args.len());
|
2021-06-08 09:48:55 +02:00
|
|
|
args.extend(curry.iter_mut());
|
|
|
|
args.extend(call_args.iter_mut());
|
2021-03-01 15:44:56 +01:00
|
|
|
|
|
|
|
// Map it to name(args) in function-call style
|
|
|
|
self.exec_fn_call(
|
2022-02-02 15:42:33 +01:00
|
|
|
None, global, state, lib, fn_name, new_hash, &mut args, false, false, pos,
|
2021-12-27 16:03:30 +01:00
|
|
|
level,
|
2020-07-23 12:40:42 +02:00
|
|
|
)
|
2020-10-03 10:25:58 +02:00
|
|
|
}
|
2021-03-08 17:07:05 +01:00
|
|
|
KEYWORD_FN_PTR_CALL => {
|
2021-07-24 08:11:16 +02:00
|
|
|
if !call_args.is_empty() {
|
2021-03-09 11:11:43 +01:00
|
|
|
if !call_args[0].is::<FnPtr>() {
|
2021-03-08 17:07:05 +01:00
|
|
|
return Err(self.make_type_mismatch_err::<FnPtr>(
|
2021-06-12 16:47:43 +02:00
|
|
|
self.map_type_name(call_args[0].type_name()),
|
2021-05-29 12:33:29 +02:00
|
|
|
*call_arg_pos,
|
2021-03-08 17:07:05 +01:00
|
|
|
));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return Err(self.make_type_mismatch_err::<FnPtr>(
|
2021-05-29 12:33:29 +02:00
|
|
|
self.map_type_name(target.type_name()),
|
2021-03-08 17:07:05 +01:00
|
|
|
pos,
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
2021-03-01 15:44:56 +01:00
|
|
|
// FnPtr call on object
|
2021-03-09 11:11:43 +01:00
|
|
|
let fn_ptr = call_args.remove(0).cast::<FnPtr>();
|
2021-03-01 15:44:56 +01:00
|
|
|
// Redirect function name
|
|
|
|
let fn_name = fn_ptr.fn_name();
|
|
|
|
let args_len = call_args.len() + fn_ptr.curry().len();
|
|
|
|
// Recalculate hash
|
2021-11-16 06:42:46 +01:00
|
|
|
let new_hash = FnCallHashes::from_all(
|
|
|
|
#[cfg(not(feature = "no_function"))]
|
2021-05-19 14:26:11 +02:00
|
|
|
calc_fn_hash(fn_name, args_len),
|
|
|
|
calc_fn_hash(fn_name, args_len + 1),
|
2021-03-08 08:30:32 +01:00
|
|
|
);
|
2021-03-01 15:44:56 +01:00
|
|
|
// Replace the first argument with the object pointer, adding the curried arguments
|
2021-12-27 05:27:44 +01:00
|
|
|
let mut curry = FnArgsVec::with_capacity(fn_ptr.num_curried());
|
2021-06-08 09:48:55 +02:00
|
|
|
curry.extend(fn_ptr.curry().iter().cloned());
|
2021-12-27 05:27:44 +01:00
|
|
|
let mut args = FnArgsVec::with_capacity(curry.len() + call_args.len() + 1);
|
2021-06-08 09:48:55 +02:00
|
|
|
args.push(target.as_mut());
|
|
|
|
args.extend(curry.iter_mut());
|
|
|
|
args.extend(call_args.iter_mut());
|
2021-03-01 15:44:56 +01:00
|
|
|
|
|
|
|
// Map it to name(args) in function-call style
|
|
|
|
self.exec_fn_call(
|
2022-02-02 15:42:33 +01:00
|
|
|
None, global, state, lib, fn_name, new_hash, &mut args, is_ref_mut, true, pos,
|
2021-06-17 03:50:32 +02:00
|
|
|
level,
|
2021-03-01 15:44:56 +01:00
|
|
|
)
|
|
|
|
}
|
2021-03-08 17:07:05 +01:00
|
|
|
KEYWORD_FN_PTR_CURRY => {
|
2021-05-29 12:33:29 +02:00
|
|
|
if !target.is::<FnPtr>() {
|
2021-03-08 17:07:05 +01:00
|
|
|
return Err(self.make_type_mismatch_err::<FnPtr>(
|
2021-05-29 12:33:29 +02:00
|
|
|
self.map_type_name(target.type_name()),
|
2021-03-08 17:07:05 +01:00
|
|
|
pos,
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
2021-11-13 05:23:35 +01:00
|
|
|
let fn_ptr = target.read_lock::<FnPtr>().expect("`FnPtr`");
|
2021-03-08 17:07:05 +01:00
|
|
|
|
|
|
|
// Curry call
|
2021-03-01 15:44:56 +01:00
|
|
|
Ok((
|
2021-03-08 17:07:05 +01:00
|
|
|
if call_args.is_empty() {
|
|
|
|
fn_ptr.clone()
|
|
|
|
} else {
|
|
|
|
FnPtr::new_unchecked(
|
2021-06-29 15:47:27 +02:00
|
|
|
fn_ptr.fn_name_raw().clone(),
|
2021-03-08 17:07:05 +01:00
|
|
|
fn_ptr
|
|
|
|
.curry()
|
|
|
|
.iter()
|
|
|
|
.cloned()
|
2021-06-08 17:40:10 +02:00
|
|
|
.chain(call_args.iter_mut().map(mem::take))
|
2021-03-08 17:07:05 +01:00
|
|
|
.collect(),
|
|
|
|
)
|
|
|
|
}
|
2021-03-01 15:44:56 +01:00
|
|
|
.into(),
|
|
|
|
false,
|
|
|
|
))
|
|
|
|
}
|
2020-07-23 12:40:42 +02:00
|
|
|
|
2021-03-01 15:44:56 +01:00
|
|
|
// Handle is_shared()
|
|
|
|
#[cfg(not(feature = "no_closure"))]
|
|
|
|
crate::engine::KEYWORD_IS_SHARED if call_args.is_empty() => {
|
|
|
|
return Ok((target.is_shared().into(), false));
|
2020-07-30 12:18:28 +02:00
|
|
|
}
|
|
|
|
|
2021-03-01 15:44:56 +01:00
|
|
|
_ => {
|
2021-05-29 12:33:29 +02:00
|
|
|
let mut fn_name = fn_name;
|
2021-03-01 15:44:56 +01:00
|
|
|
let _redirected;
|
|
|
|
|
|
|
|
// Check if it is a map method call in OOP style
|
|
|
|
#[cfg(not(feature = "no_object"))]
|
2021-12-06 13:52:47 +01:00
|
|
|
if let Some(map) = target.read_lock::<crate::Map>() {
|
2021-03-01 15:44:56 +01:00
|
|
|
if let Some(val) = map.get(fn_name) {
|
|
|
|
if let Some(fn_ptr) = val.read_lock::<FnPtr>() {
|
|
|
|
// Remap the function name
|
2021-06-29 15:47:27 +02:00
|
|
|
_redirected = fn_ptr.fn_name_raw().clone();
|
2021-03-01 15:44:56 +01:00
|
|
|
fn_name = &_redirected;
|
|
|
|
// Add curried arguments
|
2021-05-29 12:33:29 +02:00
|
|
|
if fn_ptr.is_curried() {
|
|
|
|
call_args.insert_many(0, fn_ptr.curry().iter().cloned());
|
|
|
|
}
|
2021-03-01 15:44:56 +01:00
|
|
|
// Recalculate the hash based on the new function name and new arguments
|
2021-11-16 06:42:46 +01:00
|
|
|
hash = FnCallHashes::from_all(
|
|
|
|
#[cfg(not(feature = "no_function"))]
|
2021-05-19 14:26:11 +02:00
|
|
|
calc_fn_hash(fn_name, call_args.len()),
|
|
|
|
calc_fn_hash(fn_name, call_args.len() + 1),
|
2021-03-08 08:30:32 +01:00
|
|
|
);
|
2021-03-01 15:44:56 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2020-07-23 12:40:42 +02:00
|
|
|
|
2021-03-01 15:44:56 +01:00
|
|
|
// Attached object pointer in front of the arguments
|
2021-12-27 05:27:44 +01:00
|
|
|
let mut args = FnArgsVec::with_capacity(call_args.len() + 1);
|
2021-06-08 09:48:55 +02:00
|
|
|
args.push(target.as_mut());
|
|
|
|
args.extend(call_args.iter_mut());
|
2021-03-01 15:44:56 +01:00
|
|
|
|
|
|
|
self.exec_fn_call(
|
2022-02-02 15:42:33 +01:00
|
|
|
None, global, state, lib, fn_name, hash, &mut args, is_ref_mut, true, pos,
|
2021-12-27 16:03:30 +01:00
|
|
|
level,
|
2021-03-01 15:44:56 +01:00
|
|
|
)
|
|
|
|
}
|
2020-07-27 06:52:32 +02:00
|
|
|
}?;
|
2020-07-23 12:40:42 +02:00
|
|
|
|
2020-10-04 04:40:44 +02:00
|
|
|
// Propagate the changed value back to the source if necessary
|
|
|
|
if updated {
|
2021-05-25 04:54:48 +02:00
|
|
|
target
|
|
|
|
.propagate_changed_value()
|
|
|
|
.map_err(|err| err.fill_position(pos))?;
|
2020-07-23 12:40:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok((result, updated))
|
|
|
|
}
|
|
|
|
|
2021-06-08 09:48:55 +02:00
|
|
|
/// Evaluate an argument.
|
2021-07-10 05:06:13 +02:00
|
|
|
#[inline]
|
2021-06-08 09:48:55 +02:00
|
|
|
pub(crate) fn get_arg_value(
|
2021-06-08 08:46:49 +02:00
|
|
|
&self,
|
|
|
|
scope: &mut Scope,
|
2021-12-27 16:03:30 +01:00
|
|
|
global: &mut GlobalRuntimeState,
|
2021-07-04 10:40:15 +02:00
|
|
|
state: &mut EvalState,
|
2021-06-08 08:46:49 +02:00
|
|
|
lib: &[&Module],
|
|
|
|
this_ptr: &mut Option<&mut Dynamic>,
|
2021-11-15 07:30:00 +01:00
|
|
|
arg_expr: &Expr,
|
2021-06-08 08:46:49 +02:00
|
|
|
constants: &[Dynamic],
|
2022-02-02 15:42:33 +01:00
|
|
|
level: usize,
|
2021-12-25 16:49:14 +01:00
|
|
|
) -> RhaiResultOf<(Dynamic, Position)> {
|
2022-01-08 11:40:19 +01:00
|
|
|
Ok((
|
2022-02-08 02:02:15 +01:00
|
|
|
if let Expr::Stack(slot, ..) = arg_expr {
|
2022-01-24 10:04:40 +01:00
|
|
|
#[cfg(feature = "debugging")]
|
2022-02-03 04:56:08 +01:00
|
|
|
self.run_debugger(scope, global, state, lib, this_ptr, arg_expr, level)?;
|
2022-01-08 11:40:19 +01:00
|
|
|
constants[*slot].clone()
|
|
|
|
} else if let Some(value) = arg_expr.get_literal_value() {
|
2022-01-24 10:04:40 +01:00
|
|
|
#[cfg(feature = "debugging")]
|
2022-02-03 04:56:08 +01:00
|
|
|
self.run_debugger(scope, global, state, lib, this_ptr, arg_expr, level)?;
|
2022-01-08 11:40:19 +01:00
|
|
|
value
|
|
|
|
} else {
|
2022-02-02 15:42:33 +01:00
|
|
|
// Do not match function exit for arguments
|
|
|
|
#[cfg(feature = "debugging")]
|
2022-02-03 04:56:08 +01:00
|
|
|
let reset_debugger = global.debugger.clear_status_if(|status| {
|
2022-02-08 02:46:14 +01:00
|
|
|
matches!(status, crate::eval::DebuggerStatus::FunctionExit(..))
|
2022-02-03 04:56:08 +01:00
|
|
|
});
|
2022-02-02 15:42:33 +01:00
|
|
|
|
|
|
|
let result = self.eval_expr(scope, global, state, lib, this_ptr, arg_expr, level);
|
|
|
|
|
2022-02-03 04:56:08 +01:00
|
|
|
// Restore function exit status
|
2022-02-02 15:42:33 +01:00
|
|
|
#[cfg(feature = "debugging")]
|
2022-02-03 04:56:08 +01:00
|
|
|
global.debugger.reset_status(reset_debugger);
|
2022-02-02 15:42:33 +01:00
|
|
|
|
|
|
|
result?
|
2022-01-08 11:40:19 +01:00
|
|
|
},
|
2022-02-04 05:04:33 +01:00
|
|
|
arg_expr.start_position(),
|
2022-01-08 11:40:19 +01:00
|
|
|
))
|
2021-06-08 08:46:49 +02:00
|
|
|
}
|
|
|
|
|
2020-07-23 12:40:42 +02:00
|
|
|
/// Call a function in normal function-call style.
|
|
|
|
pub(crate) fn make_function_call(
|
|
|
|
&self,
|
|
|
|
scope: &mut Scope,
|
2021-12-27 16:03:30 +01:00
|
|
|
global: &mut GlobalRuntimeState,
|
2021-07-04 10:40:15 +02:00
|
|
|
state: &mut EvalState,
|
2020-10-20 04:54:32 +02:00
|
|
|
lib: &[&Module],
|
2020-07-23 12:40:42 +02:00
|
|
|
this_ptr: &mut Option<&mut Dynamic>,
|
2022-01-04 08:22:48 +01:00
|
|
|
fn_name: &str,
|
2022-01-08 11:40:19 +01:00
|
|
|
first_arg: Option<&Expr>,
|
2021-03-01 08:58:11 +01:00
|
|
|
args_expr: &[Expr],
|
2021-06-08 08:46:49 +02:00
|
|
|
constants: &[Dynamic],
|
2021-11-15 07:30:00 +01:00
|
|
|
hashes: FnCallHashes,
|
2020-10-22 06:26:44 +02:00
|
|
|
capture_scope: bool,
|
2022-02-02 15:42:33 +01:00
|
|
|
pos: Position,
|
2020-07-23 12:40:42 +02:00
|
|
|
level: usize,
|
2021-03-02 08:02:28 +01:00
|
|
|
) -> RhaiResult {
|
2022-01-08 11:40:19 +01:00
|
|
|
let mut first_arg = first_arg;
|
2021-11-15 07:30:00 +01:00
|
|
|
let mut a_expr = args_expr;
|
2022-01-08 11:40:19 +01:00
|
|
|
let mut total_args = if first_arg.is_some() { 1 } else { 0 } + a_expr.len();
|
2021-12-27 05:27:44 +01:00
|
|
|
let mut curry = FnArgsVec::new_const();
|
2021-02-03 12:14:26 +01:00
|
|
|
let mut name = fn_name;
|
2021-11-15 07:30:00 +01:00
|
|
|
let mut hashes = hashes;
|
|
|
|
let redirected; // Handle call() - Redirect function call
|
2021-02-03 12:14:26 +01:00
|
|
|
|
2021-03-01 15:44:56 +01:00
|
|
|
match name {
|
|
|
|
// Handle call()
|
2021-03-28 13:04:25 +02:00
|
|
|
KEYWORD_FN_PTR_CALL if total_args >= 1 => {
|
2022-01-08 11:40:19 +01:00
|
|
|
let arg = first_arg.unwrap();
|
|
|
|
let (arg_value, arg_pos) =
|
2022-02-02 15:42:33 +01:00
|
|
|
self.get_arg_value(scope, global, state, lib, this_ptr, arg, constants, level)?;
|
2021-03-01 15:44:56 +01:00
|
|
|
|
2022-01-08 11:40:19 +01:00
|
|
|
if !arg_value.is::<FnPtr>() {
|
2021-03-01 15:44:56 +01:00
|
|
|
return Err(self.make_type_mismatch_err::<FnPtr>(
|
2022-01-08 11:40:19 +01:00
|
|
|
self.map_type_name(arg_value.type_name()),
|
2021-03-28 13:04:25 +02:00
|
|
|
arg_pos,
|
2021-03-01 15:44:56 +01:00
|
|
|
));
|
|
|
|
}
|
2021-02-03 12:14:26 +01:00
|
|
|
|
2022-01-08 11:40:19 +01:00
|
|
|
let fn_ptr = arg_value.cast::<FnPtr>();
|
2021-03-01 15:44:56 +01:00
|
|
|
curry.extend(fn_ptr.curry().iter().cloned());
|
|
|
|
|
|
|
|
// Redirect function name
|
|
|
|
redirected = fn_ptr.take_data().0;
|
|
|
|
name = &redirected;
|
|
|
|
|
2022-01-08 11:40:19 +01:00
|
|
|
// Shift the arguments
|
|
|
|
first_arg = a_expr.get(0);
|
|
|
|
if !a_expr.is_empty() {
|
|
|
|
a_expr = &a_expr[1..];
|
|
|
|
}
|
2021-03-28 13:04:25 +02:00
|
|
|
total_args -= 1;
|
2021-03-01 15:44:56 +01:00
|
|
|
|
|
|
|
// Recalculate hash
|
2021-03-28 13:04:25 +02:00
|
|
|
let args_len = total_args + curry.len();
|
2021-04-20 16:26:08 +02:00
|
|
|
hashes = if !hashes.is_native_only() {
|
2021-11-16 06:42:46 +01:00
|
|
|
calc_fn_hash(name, args_len).into()
|
2021-03-08 08:30:32 +01:00
|
|
|
} else {
|
2021-05-19 14:26:11 +02:00
|
|
|
FnCallHashes::from_native(calc_fn_hash(name, args_len))
|
2021-03-08 08:30:32 +01:00
|
|
|
};
|
2021-02-03 12:14:26 +01:00
|
|
|
}
|
2021-03-01 15:44:56 +01:00
|
|
|
// Handle Fn()
|
2021-03-28 13:04:25 +02:00
|
|
|
KEYWORD_FN_PTR if total_args == 1 => {
|
2022-01-08 11:40:19 +01:00
|
|
|
let arg = first_arg.unwrap();
|
|
|
|
let (arg_value, arg_pos) =
|
2022-02-02 15:42:33 +01:00
|
|
|
self.get_arg_value(scope, global, state, lib, this_ptr, arg, constants, level)?;
|
2021-03-28 13:04:25 +02:00
|
|
|
|
2021-03-01 15:44:56 +01:00
|
|
|
// Fn - only in function call style
|
2022-01-08 11:40:19 +01:00
|
|
|
return arg_value
|
2021-07-24 10:24:59 +02:00
|
|
|
.into_immutable_string()
|
2021-03-28 13:04:25 +02:00
|
|
|
.map_err(|typ| self.make_type_mismatch_err::<ImmutableString>(typ, arg_pos))
|
2021-07-24 08:11:16 +02:00
|
|
|
.and_then(FnPtr::try_from)
|
2021-12-27 09:59:05 +01:00
|
|
|
.map(Into::into)
|
2021-03-28 13:04:25 +02:00
|
|
|
.map_err(|err| err.fill_position(arg_pos));
|
2021-03-01 15:44:56 +01:00
|
|
|
}
|
2021-02-03 12:14:26 +01:00
|
|
|
|
2021-03-01 15:44:56 +01:00
|
|
|
// Handle curry()
|
2021-03-28 13:04:25 +02:00
|
|
|
KEYWORD_FN_PTR_CURRY if total_args > 1 => {
|
2022-01-08 11:40:19 +01:00
|
|
|
let first = first_arg.unwrap();
|
|
|
|
let (arg_value, arg_pos) = self
|
2022-02-02 15:42:33 +01:00
|
|
|
.get_arg_value(scope, global, state, lib, this_ptr, first, constants, level)?;
|
2021-02-03 12:14:26 +01:00
|
|
|
|
2022-01-08 11:40:19 +01:00
|
|
|
if !arg_value.is::<FnPtr>() {
|
2021-03-01 15:44:56 +01:00
|
|
|
return Err(self.make_type_mismatch_err::<FnPtr>(
|
2022-01-08 11:40:19 +01:00
|
|
|
self.map_type_name(arg_value.type_name()),
|
2021-03-28 13:04:25 +02:00
|
|
|
arg_pos,
|
2021-03-01 15:44:56 +01:00
|
|
|
));
|
|
|
|
}
|
2021-02-03 12:14:26 +01:00
|
|
|
|
2022-01-08 11:40:19 +01:00
|
|
|
let (name, fn_curry) = arg_value.cast::<FnPtr>().take_data();
|
2021-02-03 12:14:26 +01:00
|
|
|
|
2021-03-01 15:44:56 +01:00
|
|
|
// Append the new curried arguments to the existing list.
|
2022-01-08 11:40:19 +01:00
|
|
|
let fn_curry =
|
|
|
|
a_expr
|
|
|
|
.iter()
|
|
|
|
.try_fold(fn_curry, |mut curried, expr| -> RhaiResultOf<_> {
|
2022-02-08 02:02:15 +01:00
|
|
|
let (value, ..) = self.get_arg_value(
|
2022-02-02 15:42:33 +01:00
|
|
|
scope, global, state, lib, this_ptr, expr, constants, level,
|
2022-01-08 11:40:19 +01:00
|
|
|
)?;
|
|
|
|
curried.push(value);
|
|
|
|
Ok(curried)
|
|
|
|
})?;
|
2020-07-23 12:40:42 +02:00
|
|
|
|
2021-03-01 15:44:56 +01:00
|
|
|
return Ok(FnPtr::new_unchecked(name, fn_curry).into());
|
2020-07-23 12:40:42 +02:00
|
|
|
}
|
|
|
|
|
2021-03-01 15:44:56 +01:00
|
|
|
// Handle is_shared()
|
|
|
|
#[cfg(not(feature = "no_closure"))]
|
2021-03-28 13:04:25 +02:00
|
|
|
crate::engine::KEYWORD_IS_SHARED if total_args == 1 => {
|
2022-01-08 11:40:19 +01:00
|
|
|
let arg = first_arg.unwrap();
|
2022-02-08 02:02:15 +01:00
|
|
|
let (arg_value, ..) =
|
2022-02-02 15:42:33 +01:00
|
|
|
self.get_arg_value(scope, global, state, lib, this_ptr, arg, constants, level)?;
|
2022-01-08 11:40:19 +01:00
|
|
|
return Ok(arg_value.is_shared().into());
|
2021-03-01 15:44:56 +01:00
|
|
|
}
|
2020-10-17 07:49:16 +02:00
|
|
|
|
2021-03-01 15:44:56 +01:00
|
|
|
// Handle is_def_fn()
|
|
|
|
#[cfg(not(feature = "no_function"))]
|
2021-03-28 13:04:25 +02:00
|
|
|
crate::engine::KEYWORD_IS_DEF_FN if total_args == 2 => {
|
2022-01-08 11:40:19 +01:00
|
|
|
let first = first_arg.unwrap();
|
|
|
|
let (arg_value, arg_pos) = self
|
2022-02-02 15:42:33 +01:00
|
|
|
.get_arg_value(scope, global, state, lib, this_ptr, first, constants, level)?;
|
2021-03-28 13:04:25 +02:00
|
|
|
|
2022-01-08 11:40:19 +01:00
|
|
|
let fn_name = arg_value
|
2021-07-24 10:24:59 +02:00
|
|
|
.into_immutable_string()
|
2021-06-12 16:47:43 +02:00
|
|
|
.map_err(|typ| self.make_type_mismatch_err::<ImmutableString>(typ, arg_pos))?;
|
2021-03-28 13:04:25 +02:00
|
|
|
|
2022-01-08 11:40:19 +01:00
|
|
|
let (arg_value, arg_pos) = self.get_arg_value(
|
2022-02-02 15:42:33 +01:00
|
|
|
scope, global, state, lib, this_ptr, &a_expr[0], constants, level,
|
2021-06-08 08:46:49 +02:00
|
|
|
)?;
|
2021-03-28 13:04:25 +02:00
|
|
|
|
2022-01-08 11:40:19 +01:00
|
|
|
let num_params = arg_value
|
2021-03-06 03:44:55 +01:00
|
|
|
.as_int()
|
2021-06-12 16:47:43 +02:00
|
|
|
.map_err(|typ| self.make_type_mismatch_err::<crate::INT>(typ, arg_pos))?;
|
2020-07-23 12:40:42 +02:00
|
|
|
|
2021-03-02 15:31:07 +01:00
|
|
|
return Ok(if num_params < 0 {
|
2021-10-11 09:49:51 +02:00
|
|
|
false
|
2021-03-01 15:44:56 +01:00
|
|
|
} else {
|
2021-05-19 14:26:11 +02:00
|
|
|
let hash_script = calc_fn_hash(&fn_name, num_params as usize);
|
2021-12-27 16:03:30 +01:00
|
|
|
self.has_script_fn(Some(global), state, lib, hash_script)
|
2021-10-11 09:49:51 +02:00
|
|
|
}
|
|
|
|
.into());
|
2021-03-01 15:44:56 +01:00
|
|
|
}
|
2020-07-23 12:40:42 +02:00
|
|
|
|
2021-03-01 15:44:56 +01:00
|
|
|
// Handle is_def_var()
|
2021-03-28 13:04:25 +02:00
|
|
|
KEYWORD_IS_DEF_VAR if total_args == 1 => {
|
2022-01-08 11:40:19 +01:00
|
|
|
let arg = first_arg.unwrap();
|
|
|
|
let (arg_value, arg_pos) =
|
2022-02-02 15:42:33 +01:00
|
|
|
self.get_arg_value(scope, global, state, lib, this_ptr, arg, constants, level)?;
|
2022-01-08 11:40:19 +01:00
|
|
|
let var_name = arg_value
|
2021-07-24 10:24:59 +02:00
|
|
|
.into_immutable_string()
|
2021-06-12 16:47:43 +02:00
|
|
|
.map_err(|typ| self.make_type_mismatch_err::<ImmutableString>(typ, arg_pos))?;
|
2021-03-05 16:00:27 +01:00
|
|
|
return Ok(scope.contains(&var_name).into());
|
2021-03-01 15:44:56 +01:00
|
|
|
}
|
2020-07-23 12:40:42 +02:00
|
|
|
|
2021-03-01 15:44:56 +01:00
|
|
|
// Handle eval()
|
2021-03-28 13:04:25 +02:00
|
|
|
KEYWORD_EVAL if total_args == 1 => {
|
2021-03-01 15:44:56 +01:00
|
|
|
// eval - only in function call style
|
2021-11-27 07:24:36 +01:00
|
|
|
let orig_scope_len = scope.len();
|
2022-01-08 11:40:19 +01:00
|
|
|
let arg = first_arg.unwrap();
|
|
|
|
let (arg_value, pos) =
|
2022-02-02 15:42:33 +01:00
|
|
|
self.get_arg_value(scope, global, state, lib, this_ptr, arg, constants, level)?;
|
2022-01-08 11:40:19 +01:00
|
|
|
let script = &arg_value
|
2021-07-24 10:24:59 +02:00
|
|
|
.into_immutable_string()
|
2021-06-08 17:40:10 +02:00
|
|
|
.map_err(|typ| self.make_type_mismatch_err::<ImmutableString>(typ, pos))?;
|
2021-12-28 16:00:31 +01:00
|
|
|
let result = self.eval_script_expr_in_place(
|
|
|
|
scope,
|
|
|
|
global,
|
|
|
|
state,
|
|
|
|
lib,
|
|
|
|
script,
|
|
|
|
pos,
|
|
|
|
level + 1,
|
|
|
|
);
|
2021-03-01 15:44:56 +01:00
|
|
|
|
|
|
|
// IMPORTANT! If the eval defines new variables in the current scope,
|
|
|
|
// all variable offsets from this point on will be mis-aligned.
|
2021-11-27 07:24:36 +01:00
|
|
|
if scope.len() != orig_scope_len {
|
2021-12-28 05:19:20 +01:00
|
|
|
state.always_search_scope = true;
|
2021-03-01 15:44:56 +01:00
|
|
|
}
|
2020-10-03 10:25:58 +02:00
|
|
|
|
2021-03-01 15:44:56 +01:00
|
|
|
return result.map_err(|err| {
|
2021-12-27 05:27:31 +01:00
|
|
|
ERR::ErrorInFunctionCall(
|
2021-03-01 15:44:56 +01:00
|
|
|
KEYWORD_EVAL.to_string(),
|
2022-01-01 10:20:00 +01:00
|
|
|
global.source.to_string(),
|
2021-03-01 15:44:56 +01:00
|
|
|
err,
|
|
|
|
pos,
|
2021-06-29 12:25:20 +02:00
|
|
|
)
|
|
|
|
.into()
|
2021-03-01 15:44:56 +01:00
|
|
|
});
|
2020-07-30 12:18:28 +02:00
|
|
|
}
|
2021-03-01 10:17:13 +01:00
|
|
|
|
2021-03-01 15:44:56 +01:00
|
|
|
_ => (),
|
2020-07-30 12:18:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Normal function call - except for Fn, curry, call and eval (handled above)
|
2022-01-08 11:40:19 +01:00
|
|
|
let mut arg_values = FnArgsVec::with_capacity(total_args);
|
|
|
|
let mut args = FnArgsVec::with_capacity(total_args + curry.len());
|
2021-06-17 03:50:32 +02:00
|
|
|
let mut is_ref_mut = false;
|
2020-07-23 12:40:42 +02:00
|
|
|
|
2021-11-14 15:48:57 +01:00
|
|
|
// Capture parent scope?
|
2021-11-15 07:30:00 +01:00
|
|
|
//
|
|
|
|
// If so, do it separately because we cannot convert the first argument (if it is a simple
|
|
|
|
// variable access) to &mut because `scope` is needed.
|
2021-11-14 15:48:57 +01:00
|
|
|
if capture_scope && !scope.is_empty() {
|
2022-01-08 11:40:19 +01:00
|
|
|
first_arg
|
|
|
|
.iter()
|
|
|
|
.map(|&v| v)
|
|
|
|
.chain(a_expr.iter())
|
|
|
|
.try_for_each(|expr| {
|
2022-02-02 15:42:33 +01:00
|
|
|
self.get_arg_value(scope, global, state, lib, this_ptr, expr, constants, level)
|
2022-02-08 02:02:15 +01:00
|
|
|
.map(|(value, ..)| arg_values.push(value.flatten()))
|
2022-01-08 11:40:19 +01:00
|
|
|
})?;
|
2021-11-14 15:48:57 +01:00
|
|
|
args.extend(curry.iter_mut());
|
|
|
|
args.extend(arg_values.iter_mut());
|
|
|
|
|
|
|
|
// Use parent scope
|
|
|
|
let scope = Some(scope);
|
|
|
|
|
|
|
|
return self
|
|
|
|
.exec_fn_call(
|
2022-02-02 15:42:33 +01:00
|
|
|
scope, global, state, lib, name, hashes, &mut args, is_ref_mut, false, pos,
|
2021-12-27 16:03:30 +01:00
|
|
|
level,
|
2021-11-14 15:48:57 +01:00
|
|
|
)
|
2022-02-08 02:02:15 +01:00
|
|
|
.map(|(v, ..)| v);
|
2021-11-14 15:48:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Call with blank scope
|
2022-01-08 11:40:19 +01:00
|
|
|
if total_args == 0 && curry.is_empty() {
|
2020-07-23 12:40:42 +02:00
|
|
|
// No arguments
|
|
|
|
} else {
|
2021-02-03 12:14:26 +01:00
|
|
|
// If the first argument is a variable, and there is no curried arguments,
|
|
|
|
// convert to method-call style in order to leverage potential &mut first argument and
|
|
|
|
// avoid cloning the value
|
2022-01-08 11:40:19 +01:00
|
|
|
if curry.is_empty() && first_arg.map_or(false, |expr| expr.is_variable_access(false)) {
|
|
|
|
let first_expr = first_arg.unwrap();
|
2021-11-11 14:47:35 +01:00
|
|
|
|
2022-01-24 10:04:40 +01:00
|
|
|
#[cfg(feature = "debugging")]
|
2022-02-03 04:56:08 +01:00
|
|
|
self.run_debugger(scope, global, state, lib, this_ptr, first_expr, level)?;
|
2022-01-24 10:04:40 +01:00
|
|
|
|
|
|
|
// func(x, ...) -> x.func(...)
|
2022-01-08 11:40:19 +01:00
|
|
|
a_expr.iter().try_for_each(|expr| {
|
2022-02-02 15:42:33 +01:00
|
|
|
self.get_arg_value(scope, global, state, lib, this_ptr, expr, constants, level)
|
2022-02-08 02:02:15 +01:00
|
|
|
.map(|(value, ..)| arg_values.push(value.flatten()))
|
2021-11-15 07:30:00 +01:00
|
|
|
})?;
|
2020-07-23 12:40:42 +02:00
|
|
|
|
2021-04-25 09:27:58 +02:00
|
|
|
let (mut target, _pos) =
|
2022-02-04 15:16:12 +01:00
|
|
|
self.search_namespace(scope, global, state, lib, this_ptr, first_expr, level)?;
|
2020-07-23 12:40:42 +02:00
|
|
|
|
2020-12-08 16:09:12 +01:00
|
|
|
if target.as_ref().is_read_only() {
|
2020-12-08 15:47:38 +01:00
|
|
|
target = target.into_owned();
|
|
|
|
}
|
2020-11-14 09:08:48 +01:00
|
|
|
|
2021-04-25 09:27:58 +02:00
|
|
|
#[cfg(not(feature = "unchecked"))]
|
2021-12-27 16:03:30 +01:00
|
|
|
self.inc_operations(&mut global.num_operations, _pos)?;
|
2020-07-23 12:40:42 +02:00
|
|
|
|
2021-04-17 06:03:29 +02:00
|
|
|
#[cfg(not(feature = "no_closure"))]
|
|
|
|
let target_is_shared = target.is_shared();
|
|
|
|
#[cfg(feature = "no_closure")]
|
|
|
|
let target_is_shared = false;
|
|
|
|
|
2021-06-08 17:40:10 +02:00
|
|
|
if target_is_shared || target.is_temp_value() {
|
2020-10-17 07:49:16 +02:00
|
|
|
arg_values.insert(0, target.take_or_clone().flatten());
|
2021-06-08 09:48:55 +02:00
|
|
|
args.extend(arg_values.iter_mut())
|
2020-10-17 07:49:16 +02:00
|
|
|
} else {
|
|
|
|
// Turn it into a method call only if the object is not shared and not a simple value
|
2021-06-17 03:50:32 +02:00
|
|
|
is_ref_mut = true;
|
2022-01-04 15:16:20 +01:00
|
|
|
let obj_ref = target.take_ref().expect("ref");
|
2021-06-08 09:48:55 +02:00
|
|
|
args.push(obj_ref);
|
|
|
|
args.extend(arg_values.iter_mut());
|
|
|
|
}
|
2020-10-17 07:49:16 +02:00
|
|
|
} else {
|
2020-07-23 12:40:42 +02:00
|
|
|
// func(..., ...)
|
2022-01-08 11:40:19 +01:00
|
|
|
first_arg
|
|
|
|
.into_iter()
|
|
|
|
.chain(a_expr.iter())
|
|
|
|
.try_for_each(|expr| {
|
|
|
|
self.get_arg_value(
|
2022-02-02 15:42:33 +01:00
|
|
|
scope, global, state, lib, this_ptr, expr, constants, level,
|
2022-01-08 11:40:19 +01:00
|
|
|
)
|
2022-02-08 02:02:15 +01:00
|
|
|
.map(|(value, ..)| arg_values.push(value.flatten()))
|
2022-01-08 11:40:19 +01:00
|
|
|
})?;
|
2021-06-08 09:48:55 +02:00
|
|
|
args.extend(curry.iter_mut());
|
|
|
|
args.extend(arg_values.iter_mut());
|
2020-07-23 12:40:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
self.exec_fn_call(
|
2022-02-02 15:42:33 +01:00
|
|
|
None, global, state, lib, name, hashes, &mut args, is_ref_mut, false, pos, level,
|
2020-07-23 12:40:42 +02:00
|
|
|
)
|
2022-02-08 02:02:15 +01:00
|
|
|
.map(|(v, ..)| v)
|
2020-07-23 12:40:42 +02:00
|
|
|
}
|
|
|
|
|
2020-11-10 16:26:50 +01:00
|
|
|
/// Call a namespace-qualified function in normal function-call style.
|
2022-01-29 04:09:43 +01:00
|
|
|
#[cfg(not(feature = "no_module"))]
|
2020-07-23 12:40:42 +02:00
|
|
|
pub(crate) fn make_qualified_function_call(
|
|
|
|
&self,
|
|
|
|
scope: &mut Scope,
|
2021-12-27 16:03:30 +01:00
|
|
|
global: &mut GlobalRuntimeState,
|
2021-07-04 10:40:15 +02:00
|
|
|
state: &mut EvalState,
|
2020-10-20 04:54:32 +02:00
|
|
|
lib: &[&Module],
|
2020-07-23 12:40:42 +02:00
|
|
|
this_ptr: &mut Option<&mut Dynamic>,
|
2022-01-29 04:09:43 +01:00
|
|
|
namespace: &crate::module::Namespace,
|
2022-01-04 08:22:48 +01:00
|
|
|
fn_name: &str,
|
2021-03-01 08:58:11 +01:00
|
|
|
args_expr: &[Expr],
|
2021-06-08 08:46:49 +02:00
|
|
|
constants: &[Dynamic],
|
2021-03-08 08:30:32 +01:00
|
|
|
hash: u64,
|
2020-12-12 04:15:09 +01:00
|
|
|
pos: Position,
|
2020-07-23 12:40:42 +02:00
|
|
|
level: usize,
|
2021-03-02 08:02:28 +01:00
|
|
|
) -> RhaiResult {
|
2021-12-27 05:27:44 +01:00
|
|
|
let mut arg_values = FnArgsVec::with_capacity(args_expr.len());
|
|
|
|
let mut args = FnArgsVec::with_capacity(args_expr.len());
|
2020-08-20 10:26:10 +02:00
|
|
|
let mut first_arg_value = None;
|
2020-07-23 12:40:42 +02:00
|
|
|
|
2021-06-08 08:46:49 +02:00
|
|
|
if args_expr.is_empty() {
|
2020-07-23 12:40:42 +02:00
|
|
|
// No arguments
|
|
|
|
} else {
|
2020-11-10 16:26:50 +01:00
|
|
|
// See if the first argument is a variable (not namespace-qualified).
|
2020-07-23 12:40:42 +02:00
|
|
|
// If so, convert to method-call style in order to leverage potential
|
|
|
|
// &mut first argument and avoid cloning the value
|
2021-04-05 17:59:15 +02:00
|
|
|
if !args_expr.is_empty() && args_expr[0].is_variable_access(true) {
|
2022-01-24 10:04:40 +01:00
|
|
|
#[cfg(feature = "debugging")]
|
2022-02-03 04:56:08 +01:00
|
|
|
self.run_debugger(scope, global, state, lib, this_ptr, &args_expr[0], level)?;
|
2022-01-24 10:04:40 +01:00
|
|
|
|
2020-07-23 12:40:42 +02:00
|
|
|
// func(x, ...) -> x.func(...)
|
2021-11-15 07:30:00 +01:00
|
|
|
arg_values.push(Dynamic::UNIT);
|
|
|
|
|
|
|
|
args_expr.iter().skip(1).try_for_each(|expr| {
|
2022-02-02 15:42:33 +01:00
|
|
|
self.get_arg_value(scope, global, state, lib, this_ptr, expr, constants, level)
|
2022-02-08 02:02:15 +01:00
|
|
|
.map(|(value, ..)| arg_values.push(value.flatten()))
|
2021-11-15 07:30:00 +01:00
|
|
|
})?;
|
2020-10-17 07:49:16 +02:00
|
|
|
|
|
|
|
// Get target reference to first argument
|
2022-02-04 15:16:12 +01:00
|
|
|
let first_arg = &args_expr[0];
|
2021-04-25 09:27:58 +02:00
|
|
|
let (target, _pos) =
|
2022-02-04 15:16:12 +01:00
|
|
|
self.search_scope_only(scope, global, state, lib, this_ptr, first_arg, level)?;
|
2020-07-23 12:40:42 +02:00
|
|
|
|
2021-04-25 09:27:58 +02:00
|
|
|
#[cfg(not(feature = "unchecked"))]
|
2021-12-27 16:03:30 +01:00
|
|
|
self.inc_operations(&mut global.num_operations, _pos)?;
|
2020-10-17 07:49:16 +02:00
|
|
|
|
2021-04-17 06:03:29 +02:00
|
|
|
#[cfg(not(feature = "no_closure"))]
|
|
|
|
let target_is_shared = target.is_shared();
|
|
|
|
#[cfg(feature = "no_closure")]
|
|
|
|
let target_is_shared = false;
|
|
|
|
|
2021-06-08 17:40:10 +02:00
|
|
|
if target_is_shared || target.is_temp_value() {
|
2020-10-17 07:49:16 +02:00
|
|
|
arg_values[0] = target.take_or_clone().flatten();
|
2021-06-08 09:48:55 +02:00
|
|
|
args.extend(arg_values.iter_mut());
|
2020-10-17 07:49:16 +02:00
|
|
|
} else {
|
2021-06-02 08:29:18 +02:00
|
|
|
// Turn it into a method call only if the object is not shared and not a simple value
|
2022-01-06 04:07:52 +01:00
|
|
|
let (first, rest) = arg_values.split_first_mut().unwrap();
|
2020-10-17 07:49:16 +02:00
|
|
|
first_arg_value = Some(first);
|
2022-01-04 15:16:20 +01:00
|
|
|
let obj_ref = target.take_ref().expect("ref");
|
2021-06-08 09:48:55 +02:00
|
|
|
args.push(obj_ref);
|
|
|
|
args.extend(rest.iter_mut());
|
2020-07-23 12:40:42 +02:00
|
|
|
}
|
2020-10-17 07:49:16 +02:00
|
|
|
} else {
|
|
|
|
// func(..., ...) or func(mod::x, ...)
|
2021-11-15 07:30:00 +01:00
|
|
|
args_expr.iter().try_for_each(|expr| {
|
2022-02-02 15:42:33 +01:00
|
|
|
self.get_arg_value(scope, global, state, lib, this_ptr, expr, constants, level)
|
2022-02-08 02:02:15 +01:00
|
|
|
.map(|(value, ..)| arg_values.push(value.flatten()))
|
2021-11-15 07:30:00 +01:00
|
|
|
})?;
|
2021-06-08 09:48:55 +02:00
|
|
|
args.extend(arg_values.iter_mut());
|
2020-07-23 12:40:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-27 05:27:31 +01:00
|
|
|
let module = self
|
2021-12-27 16:03:30 +01:00
|
|
|
.search_imports(global, state, namespace)
|
2021-12-27 05:27:31 +01:00
|
|
|
.ok_or_else(|| ERR::ErrorModuleNotFound(namespace.to_string(), namespace[0].pos))?;
|
2020-07-23 12:40:42 +02:00
|
|
|
|
|
|
|
// First search in script-defined functions (can override built-in)
|
2021-03-08 08:30:32 +01:00
|
|
|
let func = match module.get_qualified_fn(hash) {
|
2020-07-27 06:52:32 +02:00
|
|
|
// Then search in Rust functions
|
|
|
|
None => {
|
2021-04-25 09:27:58 +02:00
|
|
|
#[cfg(not(feature = "unchecked"))]
|
2021-12-27 16:03:30 +01:00
|
|
|
self.inc_operations(&mut global.num_operations, pos)?;
|
2020-07-23 12:40:42 +02:00
|
|
|
|
2021-03-08 08:30:32 +01:00
|
|
|
let hash_params = calc_fn_params_hash(args.iter().map(|a| a.type_id()));
|
|
|
|
let hash_qualified_fn = combine_hashes(hash, hash_params);
|
2020-07-23 12:40:42 +02:00
|
|
|
|
|
|
|
module.get_qualified_fn(hash_qualified_fn)
|
|
|
|
}
|
|
|
|
r => r,
|
|
|
|
};
|
|
|
|
|
2021-01-23 02:37:27 +01:00
|
|
|
// Clone first argument if the function is not a method after-all
|
2021-05-25 04:54:48 +02:00
|
|
|
if !func.map(|f| f.is_method()).unwrap_or(true) {
|
2021-07-24 08:11:16 +02:00
|
|
|
if let Some(first) = first_arg_value {
|
2021-05-25 04:54:48 +02:00
|
|
|
*first = args[0].clone();
|
2021-01-23 02:37:27 +01:00
|
|
|
args[0] = first;
|
2021-07-24 08:11:16 +02:00
|
|
|
}
|
2021-01-23 02:37:27 +01:00
|
|
|
}
|
|
|
|
|
2022-02-02 07:47:35 +01:00
|
|
|
let level = level + 1;
|
|
|
|
|
2020-07-23 12:40:42 +02:00
|
|
|
match func {
|
|
|
|
#[cfg(not(feature = "no_function"))]
|
2020-07-27 06:52:32 +02:00
|
|
|
Some(f) if f.is_script() => {
|
2021-12-17 09:07:13 +01:00
|
|
|
let fn_def = f.get_script_fn_def().expect("script-defined function");
|
2022-02-04 05:04:33 +01:00
|
|
|
let new_scope = &mut Scope::new();
|
|
|
|
let mut source = module.id_raw().clone();
|
|
|
|
mem::swap(&mut global.source, &mut source);
|
2020-12-21 15:04:46 +01:00
|
|
|
|
2022-02-04 05:04:33 +01:00
|
|
|
let result = self.call_script_fn(
|
|
|
|
new_scope, global, state, lib, &mut None, fn_def, &mut args, true, pos, level,
|
|
|
|
);
|
2020-12-21 15:04:46 +01:00
|
|
|
|
2022-02-04 05:04:33 +01:00
|
|
|
global.source = source;
|
2021-03-10 15:12:48 +01:00
|
|
|
|
2022-02-04 05:04:33 +01:00
|
|
|
result
|
2020-07-23 12:40:42 +02:00
|
|
|
}
|
2021-02-27 08:06:57 +01:00
|
|
|
|
2021-11-05 12:35:33 +01:00
|
|
|
Some(f) if f.is_plugin_fn() => {
|
2022-02-02 07:47:35 +01:00
|
|
|
let context = (self, fn_name, module.id(), &*global, lib, pos, level).into();
|
2022-01-06 15:10:16 +01:00
|
|
|
let result = f
|
|
|
|
.get_plugin_fn()
|
2021-11-05 12:35:33 +01:00
|
|
|
.expect("plugin function")
|
|
|
|
.clone()
|
2022-01-06 15:10:16 +01:00
|
|
|
.call(context, &mut args);
|
|
|
|
self.check_return_value(result, pos)
|
2021-11-05 12:35:33 +01:00
|
|
|
}
|
2021-02-27 08:06:57 +01:00
|
|
|
|
2021-04-17 07:54:24 +02:00
|
|
|
Some(f) if f.is_native() => {
|
2021-08-26 17:58:41 +02:00
|
|
|
let func = f.get_native_fn().expect("native function");
|
2022-02-02 07:47:35 +01:00
|
|
|
let context = (self, fn_name, module.id(), &*global, lib, pos, level).into();
|
2022-01-06 15:10:16 +01:00
|
|
|
let result = func(context, &mut args);
|
|
|
|
self.check_return_value(result, pos)
|
2021-04-17 07:54:24 +02:00
|
|
|
}
|
2021-02-27 08:06:57 +01:00
|
|
|
|
2020-12-28 07:21:13 +01:00
|
|
|
Some(f) => unreachable!("unknown function type: {:?}", f),
|
2021-02-27 08:06:57 +01:00
|
|
|
|
2021-12-27 05:27:31 +01:00
|
|
|
None => Err(ERR::ErrorFunctionNotFound(
|
2021-06-21 13:12:28 +02:00
|
|
|
self.gen_call_signature(Some(namespace), fn_name, &args),
|
2020-12-12 04:15:09 +01:00
|
|
|
pos,
|
2020-08-06 04:17:32 +02:00
|
|
|
)
|
2021-10-19 17:52:58 +02:00
|
|
|
.into()),
|
2020-07-23 12:40:42 +02:00
|
|
|
}
|
|
|
|
}
|
2021-12-28 05:00:01 +01:00
|
|
|
|
|
|
|
/// Evaluate a text script in place - used primarily for 'eval'.
|
|
|
|
pub(crate) fn eval_script_expr_in_place(
|
|
|
|
&self,
|
|
|
|
scope: &mut Scope,
|
|
|
|
global: &mut GlobalRuntimeState,
|
|
|
|
state: &mut EvalState,
|
|
|
|
lib: &[&Module],
|
2022-01-04 08:22:48 +01:00
|
|
|
script: &str,
|
|
|
|
pos: Position,
|
2021-12-28 05:00:01 +01:00
|
|
|
level: usize,
|
|
|
|
) -> RhaiResult {
|
2022-01-04 08:22:48 +01:00
|
|
|
let _pos = pos;
|
|
|
|
|
2021-12-28 05:00:01 +01:00
|
|
|
#[cfg(not(feature = "unchecked"))]
|
|
|
|
self.inc_operations(&mut global.num_operations, _pos)?;
|
|
|
|
|
2022-01-04 08:22:48 +01:00
|
|
|
let script = script.trim();
|
|
|
|
|
2021-12-28 05:00:01 +01:00
|
|
|
if script.is_empty() {
|
|
|
|
return Ok(Dynamic::UNIT);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Compile the script text
|
|
|
|
// No optimizations because we only run it once
|
|
|
|
let ast = self.compile_with_scope_and_optimization_level(
|
|
|
|
&Scope::new(),
|
|
|
|
&[script],
|
|
|
|
#[cfg(not(feature = "no_optimize"))]
|
2022-02-07 14:03:39 +01:00
|
|
|
OptimizationLevel::None,
|
|
|
|
#[cfg(feature = "no_optimize")]
|
|
|
|
OptimizationLevel::default(),
|
2021-12-28 05:00:01 +01:00
|
|
|
)?;
|
|
|
|
|
|
|
|
// If new functions are defined within the eval string, it is an error
|
|
|
|
#[cfg(not(feature = "no_function"))]
|
|
|
|
if !ast.shared_lib().is_empty() {
|
|
|
|
return Err(crate::PERR::WrongFnDefinition.into());
|
|
|
|
}
|
|
|
|
|
|
|
|
let statements = ast.statements();
|
|
|
|
if statements.is_empty() {
|
|
|
|
return Ok(Dynamic::UNIT);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Evaluate the AST
|
2021-12-30 01:57:23 +01:00
|
|
|
self.eval_global_statements(scope, global, state, statements, lib, level)
|
2021-12-28 05:00:01 +01:00
|
|
|
}
|
2020-07-23 12:40:42 +02:00
|
|
|
}
|