Merge branch 'master' into plugins
This commit is contained in:
122
src/fn_call.rs
122
src/fn_call.rs
@@ -34,6 +34,7 @@ use crate::engine::{FN_IDX_GET, FN_IDX_SET};
|
||||
use crate::engine::{Map, Target, FN_GET, FN_SET};
|
||||
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
use crate::scope::Entry as ScopeEntry;
|
||||
|
||||
use crate::stdlib::{
|
||||
@@ -48,6 +49,7 @@ use crate::stdlib::{
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
use crate::stdlib::{collections::HashSet, string::String};
|
||||
|
||||
/// Extract the property name from a getter function name.
|
||||
@@ -140,6 +142,7 @@ impl Drop for ArgBackup<'_> {
|
||||
|
||||
// Add captured variables into scope
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
fn add_captured_variables_into_scope<'s>(
|
||||
externals: &HashSet<String>,
|
||||
captured: Scope<'s>,
|
||||
@@ -175,10 +178,11 @@ pub fn ensure_no_data_race(
|
||||
.enumerate()
|
||||
.find(|(_, a)| a.is_locked())
|
||||
{
|
||||
return Err(Box::new(EvalAltResult::ErrorDataRace(
|
||||
return EvalAltResult::ErrorDataRace(
|
||||
format!("argument #{} of function '{}'", n + 1 + skip, fn_name),
|
||||
Position::none(),
|
||||
)));
|
||||
)
|
||||
.into();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,22 +242,22 @@ impl Engine {
|
||||
return Ok(match fn_name {
|
||||
KEYWORD_PRINT => (
|
||||
(self.print)(result.as_str().map_err(|typ| {
|
||||
Box::new(EvalAltResult::ErrorMismatchOutputType(
|
||||
EvalAltResult::ErrorMismatchOutputType(
|
||||
self.map_type_name(type_name::<ImmutableString>()).into(),
|
||||
typ.into(),
|
||||
Position::none(),
|
||||
))
|
||||
)
|
||||
})?)
|
||||
.into(),
|
||||
false,
|
||||
),
|
||||
KEYWORD_DEBUG => (
|
||||
(self.debug)(result.as_str().map_err(|typ| {
|
||||
Box::new(EvalAltResult::ErrorMismatchOutputType(
|
||||
EvalAltResult::ErrorMismatchOutputType(
|
||||
self.map_type_name(type_name::<ImmutableString>()).into(),
|
||||
typ.into(),
|
||||
Position::none(),
|
||||
))
|
||||
)
|
||||
})?)
|
||||
.into(),
|
||||
false,
|
||||
@@ -277,56 +281,60 @@ impl Engine {
|
||||
|
||||
// Getter function not found?
|
||||
if let Some(prop) = extract_prop_from_getter(fn_name) {
|
||||
return Err(Box::new(EvalAltResult::ErrorDotExpr(
|
||||
return EvalAltResult::ErrorDotExpr(
|
||||
format!(
|
||||
"Unknown property '{}' for {}, or it is write-only",
|
||||
prop,
|
||||
self.map_type_name(args[0].type_name())
|
||||
),
|
||||
Position::none(),
|
||||
)));
|
||||
)
|
||||
.into();
|
||||
}
|
||||
|
||||
// Setter function not found?
|
||||
if let Some(prop) = extract_prop_from_setter(fn_name) {
|
||||
return Err(Box::new(EvalAltResult::ErrorDotExpr(
|
||||
return EvalAltResult::ErrorDotExpr(
|
||||
format!(
|
||||
"Unknown property '{}' for {}, or it is read-only",
|
||||
prop,
|
||||
self.map_type_name(args[0].type_name())
|
||||
),
|
||||
Position::none(),
|
||||
)));
|
||||
)
|
||||
.into();
|
||||
}
|
||||
|
||||
// index getter function not found?
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
if fn_name == FN_IDX_GET && args.len() == 2 {
|
||||
return Err(Box::new(EvalAltResult::ErrorFunctionNotFound(
|
||||
return EvalAltResult::ErrorFunctionNotFound(
|
||||
format!(
|
||||
"{} [{}]",
|
||||
self.map_type_name(args[0].type_name()),
|
||||
self.map_type_name(args[1].type_name()),
|
||||
),
|
||||
Position::none(),
|
||||
)));
|
||||
)
|
||||
.into();
|
||||
}
|
||||
|
||||
// index setter function not found?
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
if fn_name == FN_IDX_SET {
|
||||
return Err(Box::new(EvalAltResult::ErrorFunctionNotFound(
|
||||
return EvalAltResult::ErrorFunctionNotFound(
|
||||
format!(
|
||||
"{} [{}]=",
|
||||
self.map_type_name(args[0].type_name()),
|
||||
self.map_type_name(args[1].type_name()),
|
||||
),
|
||||
Position::none(),
|
||||
)));
|
||||
)
|
||||
.into();
|
||||
}
|
||||
|
||||
// Raise error
|
||||
Err(Box::new(EvalAltResult::ErrorFunctionNotFound(
|
||||
EvalAltResult::ErrorFunctionNotFound(
|
||||
format!(
|
||||
"{} ({})",
|
||||
fn_name,
|
||||
@@ -340,7 +348,8 @@ impl Engine {
|
||||
.join(", ")
|
||||
),
|
||||
Position::none(),
|
||||
)))
|
||||
)
|
||||
.into()
|
||||
}
|
||||
|
||||
/// Call a script-defined function.
|
||||
@@ -401,17 +410,15 @@ impl Engine {
|
||||
// Convert return statement to return value
|
||||
EvalAltResult::Return(x, _) => Ok(x),
|
||||
EvalAltResult::ErrorInFunctionCall(name, err, _) => {
|
||||
Err(Box::new(EvalAltResult::ErrorInFunctionCall(
|
||||
EvalAltResult::ErrorInFunctionCall(
|
||||
format!("{} > {}", fn_name, name),
|
||||
err,
|
||||
Position::none(),
|
||||
)))
|
||||
)
|
||||
.into()
|
||||
}
|
||||
_ => Err(Box::new(EvalAltResult::ErrorInFunctionCall(
|
||||
fn_name.to_string(),
|
||||
err,
|
||||
Position::none(),
|
||||
))),
|
||||
_ => EvalAltResult::ErrorInFunctionCall(fn_name.to_string(), err, Position::none())
|
||||
.into(),
|
||||
});
|
||||
|
||||
// Remove all local variables
|
||||
@@ -453,11 +460,11 @@ impl Engine {
|
||||
hash_script: u64,
|
||||
args: &mut FnCallArgs,
|
||||
is_ref: bool,
|
||||
is_method: bool,
|
||||
_is_method: bool,
|
||||
pub_only: bool,
|
||||
_capture: Option<Scope>,
|
||||
def_val: Option<bool>,
|
||||
level: usize,
|
||||
_level: usize,
|
||||
) -> Result<(Dynamic, bool), Box<EvalAltResult>> {
|
||||
// Check for data race.
|
||||
if cfg!(not(feature = "no_closure")) {
|
||||
@@ -483,20 +490,22 @@ impl Engine {
|
||||
KEYWORD_FN_PTR
|
||||
if args.len() == 1 && !self.has_override(lib, hash_fn, hash_script, pub_only) =>
|
||||
{
|
||||
Err(Box::new(EvalAltResult::ErrorRuntime(
|
||||
EvalAltResult::ErrorRuntime(
|
||||
"'Fn' should not be called in method style. Try Fn(...);".into(),
|
||||
Position::none(),
|
||||
)))
|
||||
)
|
||||
.into()
|
||||
}
|
||||
|
||||
// eval - reaching this point it must be a method-style call
|
||||
KEYWORD_EVAL
|
||||
if args.len() == 1 && !self.has_override(lib, hash_fn, hash_script, pub_only) =>
|
||||
{
|
||||
Err(Box::new(EvalAltResult::ErrorRuntime(
|
||||
EvalAltResult::ErrorRuntime(
|
||||
"'eval' should not be called in method style. Try eval(...);".into(),
|
||||
Position::none(),
|
||||
)))
|
||||
)
|
||||
.into()
|
||||
}
|
||||
|
||||
// Normal script function call
|
||||
@@ -514,7 +523,7 @@ impl Engine {
|
||||
add_captured_variables_into_scope(&func.externals, captured, scope);
|
||||
}
|
||||
|
||||
let result = if is_method {
|
||||
let result = if _is_method {
|
||||
// Method call of script function - map first argument to `this`
|
||||
let (first, rest) = args.split_at_mut(1);
|
||||
self.call_script_fn(
|
||||
@@ -526,7 +535,7 @@ impl Engine {
|
||||
fn_name,
|
||||
func,
|
||||
rest,
|
||||
level,
|
||||
_level,
|
||||
)?
|
||||
} else {
|
||||
// Normal call of script function - map first argument to `this`
|
||||
@@ -535,7 +544,7 @@ impl Engine {
|
||||
backup.change_first_arg_to_copy(is_ref, args);
|
||||
|
||||
let result = self.call_script_fn(
|
||||
scope, mods, state, lib, &mut None, fn_name, func, args, level,
|
||||
scope, mods, state, lib, &mut None, fn_name, func, args, _level,
|
||||
);
|
||||
|
||||
// Restore the original reference
|
||||
@@ -698,29 +707,42 @@ impl Engine {
|
||||
&& _fn_name == KEYWORD_IS_SHARED
|
||||
&& idx.is_empty()
|
||||
{
|
||||
// take call
|
||||
// is_shared call
|
||||
Ok((target.is_shared().into(), false))
|
||||
} else {
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
let redirected;
|
||||
let mut _hash = hash_script;
|
||||
let mut hash = hash_script;
|
||||
|
||||
// Check if it is a map method call in OOP style
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
if let Some(map) = obj.read_lock::<Map>() {
|
||||
if let Some(val) = map.get(_fn_name) {
|
||||
if let Some(f) = val.read_lock::<FnPtr>() {
|
||||
if let Some(fn_ptr) = val.read_lock::<FnPtr>() {
|
||||
// Remap the function name
|
||||
redirected = f.get_fn_name().clone();
|
||||
redirected = fn_ptr.get_fn_name().clone();
|
||||
_fn_name = &redirected;
|
||||
// Recalculate the hash based on the new function name
|
||||
_hash = calc_fn_hash(empty(), _fn_name, idx.len(), empty());
|
||||
// Add curried arguments
|
||||
if !fn_ptr.curry().is_empty() {
|
||||
fn_ptr
|
||||
.curry()
|
||||
.iter()
|
||||
.cloned()
|
||||
.enumerate()
|
||||
.for_each(|(i, v)| idx.insert(i, v));
|
||||
}
|
||||
// Recalculate the hash based on the new function name and new arguments
|
||||
hash = if native {
|
||||
0
|
||||
} else {
|
||||
calc_fn_hash(empty(), _fn_name, idx.len(), empty())
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if native {
|
||||
_hash = 0;
|
||||
hash = 0;
|
||||
}
|
||||
|
||||
// Attached object pointer in front of the arguments
|
||||
@@ -728,7 +750,7 @@ impl Engine {
|
||||
let args = arg_values.as_mut();
|
||||
|
||||
self.exec_fn_call(
|
||||
state, lib, _fn_name, _hash, args, is_ref, true, pub_only, None, def_val, level,
|
||||
state, lib, _fn_name, hash, args, is_ref, true, pub_only, None, def_val, level,
|
||||
)
|
||||
}?;
|
||||
|
||||
@@ -771,11 +793,12 @@ impl Engine {
|
||||
return arg_value
|
||||
.take_immutable_string()
|
||||
.map_err(|typ| {
|
||||
Box::new(EvalAltResult::ErrorMismatchOutputType(
|
||||
EvalAltResult::ErrorMismatchOutputType(
|
||||
self.map_type_name(type_name::<ImmutableString>()).into(),
|
||||
typ.into(),
|
||||
expr.position(),
|
||||
))
|
||||
)
|
||||
.into()
|
||||
})
|
||||
.and_then(|s| FnPtr::try_from(s))
|
||||
.map(Into::<Dynamic>::into)
|
||||
@@ -789,11 +812,12 @@ impl Engine {
|
||||
let fn_ptr = self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?;
|
||||
|
||||
if !fn_ptr.is::<FnPtr>() {
|
||||
return Err(Box::new(EvalAltResult::ErrorMismatchOutputType(
|
||||
return EvalAltResult::ErrorMismatchOutputType(
|
||||
self.map_type_name(type_name::<FnPtr>()).into(),
|
||||
self.map_type_name(fn_ptr.type_name()).into(),
|
||||
expr.position(),
|
||||
)));
|
||||
)
|
||||
.into();
|
||||
}
|
||||
|
||||
let (fn_name, fn_curry) = fn_ptr.cast::<FnPtr>().take_data();
|
||||
@@ -843,11 +867,12 @@ impl Engine {
|
||||
// Recalculate hash
|
||||
hash_script = calc_fn_hash(empty(), name, curry.len() + args_expr.len(), empty());
|
||||
} else {
|
||||
return Err(Box::new(EvalAltResult::ErrorMismatchOutputType(
|
||||
return EvalAltResult::ErrorMismatchOutputType(
|
||||
self.map_type_name(type_name::<FnPtr>()).into(),
|
||||
fn_name.type_name().into(),
|
||||
expr.position(),
|
||||
)));
|
||||
)
|
||||
.into();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1037,7 +1062,7 @@ impl Engine {
|
||||
Some(f) if f.is_plugin_fn() => f.get_plugin_fn().call(args.as_mut(), Position::none()),
|
||||
Some(f) => f.get_native_fn()(self, lib, args.as_mut()),
|
||||
None if def_val.is_some() => Ok(def_val.unwrap().into()),
|
||||
None => Err(Box::new(EvalAltResult::ErrorFunctionNotFound(
|
||||
None => EvalAltResult::ErrorFunctionNotFound(
|
||||
format!(
|
||||
"{}{} ({})",
|
||||
modules,
|
||||
@@ -1052,7 +1077,8 @@ impl Engine {
|
||||
.join(", ")
|
||||
),
|
||||
Position::none(),
|
||||
))),
|
||||
)
|
||||
.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user