Merge branch 'master' into plugins

This commit is contained in:
Stephen Chung
2020-08-06 10:31:15 +08:00
37 changed files with 431 additions and 404 deletions

View File

@@ -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(),
}
}
}