rhai/src/func/call.rs

1492 lines
55 KiB
Rust
Raw Normal View History

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