Merge branch 'master' into plugins

This commit is contained in:
Stephen Chung
2020-06-11 22:45:20 +08:00
14 changed files with 467 additions and 492 deletions

View File

@@ -1,5 +1,6 @@
//! Helper module which defines the `Any` trait to to allow dynamic value handling.
use crate::fn_native::SendSync;
use crate::module::Module;
use crate::parser::{ImmutableString, INT};
use crate::r#unsafe::{unsafe_cast_box, unsafe_try_cast};
@@ -54,31 +55,6 @@ pub trait Variant: Any {
fn _closed(&self) -> _Private;
}
#[cfg(not(feature = "sync"))]
impl<T: Any + Clone> Variant for T {
fn as_any(&self) -> &dyn Any {
self as &dyn Any
}
fn as_mut_any(&mut self) -> &mut dyn Any {
self as &mut dyn Any
}
fn as_box_any(self: Box<Self>) -> Box<dyn Any> {
self as Box<dyn Any>
}
fn type_name(&self) -> &'static str {
type_name::<T>()
}
fn into_dynamic(self) -> Dynamic {
Dynamic::from(self)
}
fn clone_into_dynamic(&self) -> Dynamic {
Dynamic::from(self.clone())
}
fn _closed(&self) -> _Private {
_Private
}
}
/// Trait to represent any type.
///
/// `From<_>` is implemented for `i64` (`i32` if `only_i32`), `f64` (if not `no_float`),
@@ -108,8 +84,7 @@ pub trait Variant: Any + Send + Sync {
fn _closed(&self) -> _Private;
}
#[cfg(feature = "sync")]
impl<T: Any + Clone + Send + Sync> Variant for T {
impl<T: Any + Clone + SendSync> Variant for T {
fn as_any(&self) -> &dyn Any {
self as &dyn Any
}
@@ -227,17 +202,17 @@ impl fmt::Display for Dynamic {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.0 {
Union::Unit(_) => write!(f, ""),
Union::Bool(value) => write!(f, "{}", value),
Union::Str(value) => write!(f, "{}", value),
Union::Char(value) => write!(f, "{}", value),
Union::Int(value) => write!(f, "{}", value),
Union::Bool(value) => fmt::Display::fmt(value, f),
Union::Str(value) => fmt::Display::fmt(value, f),
Union::Char(value) => fmt::Display::fmt(value, f),
Union::Int(value) => fmt::Display::fmt(value, f),
#[cfg(not(feature = "no_float"))]
Union::Float(value) => write!(f, "{}", value),
Union::Float(value) => fmt::Display::fmt(value, f),
#[cfg(not(feature = "no_index"))]
Union::Array(value) => write!(f, "{:?}", value),
Union::Array(value) => fmt::Debug::fmt(value, f),
#[cfg(not(feature = "no_object"))]
Union::Map(value) => write!(f, "#{:?}", value),
Union::Module(value) => write!(f, "{:?}", value),
Union::Module(value) => fmt::Debug::fmt(value, f),
#[cfg(not(feature = "no_std"))]
Union::Variant(value) if value.is::<Instant>() => write!(f, "<timestamp>"),
@@ -249,18 +224,18 @@ impl fmt::Display for Dynamic {
impl fmt::Debug for Dynamic {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.0 {
Union::Unit(value) => write!(f, "{:?}", value),
Union::Bool(value) => write!(f, "{:?}", value),
Union::Str(value) => write!(f, "{:?}", value),
Union::Char(value) => write!(f, "{:?}", value),
Union::Int(value) => write!(f, "{:?}", value),
Union::Unit(value) => fmt::Debug::fmt(value, f),
Union::Bool(value) => fmt::Debug::fmt(value, f),
Union::Str(value) => fmt::Debug::fmt(value, f),
Union::Char(value) => fmt::Debug::fmt(value, f),
Union::Int(value) => fmt::Debug::fmt(value, f),
#[cfg(not(feature = "no_float"))]
Union::Float(value) => write!(f, "{:?}", value),
Union::Float(value) => fmt::Debug::fmt(value, f),
#[cfg(not(feature = "no_index"))]
Union::Array(value) => write!(f, "{:?}", value),
Union::Array(value) => fmt::Debug::fmt(value, f),
#[cfg(not(feature = "no_object"))]
Union::Map(value) => write!(f, "#{:?}", value),
Union::Module(value) => write!(f, "{:?}", value),
Union::Module(value) => fmt::Debug::fmt(value, f),
#[cfg(not(feature = "no_std"))]
Union::Variant(value) if value.is::<Instant>() => write!(f, "<timestamp>"),

View File

@@ -200,8 +200,8 @@ pub fn get_script_function_by_signature<'a>(
public_only: bool,
) -> Option<&'a ScriptFnDef> {
// Qualifiers (none) + function name + number of arguments.
let hash_fn_def = calc_fn_hash(empty(), name, params, empty());
let func = module.get_fn(hash_fn_def)?;
let hash_script = calc_fn_hash(empty(), name, params, empty());
let func = module.get_fn(hash_script)?;
if !func.is_script() {
return None;
}
@@ -228,7 +228,7 @@ pub fn get_script_function_by_signature<'a>(
/// # }
/// ```
///
/// Currently, `Engine` is neither `Send` nor `Sync`. Turn on the `sync` feature to make it `Send + Sync`.
/// Currently, `Engine` is neither `Send` nor `Sync`. Use the `sync` feature to make it `Send + Sync`.
pub struct Engine {
/// A module containing all functions directly loaded into the Engine.
pub(crate) global_module: Module,
@@ -524,7 +524,7 @@ impl Engine {
state: &mut State,
lib: &Module,
fn_name: &str,
hashes: (u64, u64),
(hash_fn, hash_script): (u64, u64),
args: &mut FnCallArgs,
is_ref: bool,
def_val: Option<&Dynamic>,
@@ -532,7 +532,7 @@ impl Engine {
) -> Result<(Dynamic, bool), Box<EvalAltResult>> {
self.inc_operations(state)?;
let native_only = hashes.1 == 0;
let native_only = hash_script == 0;
// Check for stack overflow
#[cfg(not(feature = "no_function"))]
@@ -587,14 +587,14 @@ impl Engine {
// Then search packages
// NOTE: We skip script functions for global_module and packages, and native functions for lib
let func = if !native_only {
lib.get_fn(hashes.1) //.or_else(|| lib.get_fn(hashes.0))
lib.get_fn(hash_script) //.or_else(|| lib.get_fn(hash_fn))
} else {
None
}
//.or_else(|| self.global_module.get_fn(hashes.1))
.or_else(|| self.global_module.get_fn(hashes.0))
//.or_else(|| self.packages.get_fn(hashes.1))
.or_else(|| self.packages.get_fn(hashes.0));
//.or_else(|| self.global_module.get_fn(hash_script))
.or_else(|| self.global_module.get_fn(hash_fn))
//.or_else(|| self.packages.get_fn(hash_script))
.or_else(|| self.packages.get_fn(hash_fn));
if let Some(func) = func {
// Calling pure function in method-call?
@@ -784,18 +784,18 @@ impl Engine {
}
// Has a system function an override?
fn has_override(&self, lib: &Module, hashes: (u64, u64)) -> bool {
fn has_override(&self, lib: &Module, (hash_fn, hash_script): (u64, u64)) -> bool {
// NOTE: We skip script functions for global_module and packages, and native functions for lib
// First check script-defined functions
lib.contains_fn(hashes.1)
//|| lib.contains_fn(hashes.0)
lib.contains_fn(hash_script)
//|| lib.contains_fn(hash_fn)
// Then check registered functions
//|| self.global_module.contains_fn(hashes.1)
|| self.global_module.contains_fn(hashes.0)
//|| self.global_module.contains_fn(hash_script)
|| self.global_module.contains_fn(hash_fn)
// Then check packages
//|| self.packages.contains_fn(hashes.1)
|| self.packages.contains_fn(hashes.0)
//|| self.packages.contains_fn(hash_script)
|| self.packages.contains_fn(hash_fn)
}
/// Perform an actual function call, taking care of special functions
@@ -812,7 +812,7 @@ impl Engine {
lib: &Module,
fn_name: &str,
native_only: bool,
hash_fn_def: u64,
hash_script: u64,
args: &mut FnCallArgs,
is_ref: bool,
def_val: Option<&Dynamic>,
@@ -821,7 +821,7 @@ impl Engine {
// Qualifiers (none) + function name + number of arguments + argument `TypeId`'s.
let arg_types = args.iter().map(|a| a.type_id());
let hash_fn = calc_fn_hash(empty(), fn_name, args.len(), arg_types);
let hashes = (hash_fn, if native_only { 0 } else { hash_fn_def });
let hashes = (hash_fn, if native_only { 0 } else { hash_script });
match fn_name {
// type_of
@@ -1412,7 +1412,7 @@ impl Engine {
Expr::Property(_) => unreachable!(),
// Statement block
Expr::Stmt(stmt) => self.eval_stmt(scope, state, lib, &stmt.0, level),
Expr::Stmt(x) => self.eval_stmt(scope, state, lib, &x.0, level),
// var op= rhs
Expr::Assignment(x) if matches!(x.0, Expr::Variable(_)) => {
@@ -1625,7 +1625,7 @@ impl Engine {
// Module-qualified function call
Expr::FnCall(x) if x.1.is_some() => {
let ((name, _, pos), modules, hash_fn_def, args_expr, def_val) = x.as_ref();
let ((name, _, pos), modules, hash_script, args_expr, def_val) = x.as_ref();
let modules = modules.as_ref().unwrap();
let mut arg_values = args_expr
@@ -1650,13 +1650,13 @@ impl Engine {
};
// First search in script-defined functions (can override built-in)
let func = match module.get_qualified_fn(name, *hash_fn_def) {
let func = match module.get_qualified_fn(name, *hash_script) {
Err(err) if matches!(*err, EvalAltResult::ErrorFunctionNotFound(_, _)) => {
// Then search in Rust functions
self.inc_operations(state)
.map_err(|err| EvalAltResult::new_position(err, *pos))?;
// Rust functions are indexed in two steps:
// Qualified Rust functions are indexed in two steps:
// 1) Calculate a hash in a similar manner to script-defined functions,
// i.e. qualifiers + function name + number of arguments.
// 2) Calculate a second hash with no qualifiers, empty function name,
@@ -1664,9 +1664,9 @@ impl Engine {
let hash_fn_args =
calc_fn_hash(empty(), "", 0, args.iter().map(|a| a.type_id()));
// 3) The final hash is the XOR of the two hashes.
let hash_fn_native = *hash_fn_def ^ hash_fn_args;
let hash_qualified_fn = *hash_script ^ hash_fn_args;
module.get_qualified_fn(name, hash_fn_native)
module.get_qualified_fn(name, hash_qualified_fn)
}
r => r,
};

View File

@@ -89,9 +89,9 @@ impl fmt::Debug for CallableFunction {
match self {
Self::Pure(_) => write!(f, "NativePureFunction"),
Self::Method(_) => write!(f, "NativeMethod"),
Self::Iterator(_) => write!(f, "IteratorFunction"),
Self::Iterator(_) => write!(f, "NativeIterator"),
Self::Plugin(_) => write!(f, "PluginFunction"),
Self::Script(fn_def) => write!(f, "{:?}", fn_def),
Self::Script(fn_def) => fmt::Debug::fmt(fn_def, f),
}
}
}

View File

@@ -4,7 +4,7 @@
use crate::any::{Dynamic, Variant};
use crate::engine::Engine;
use crate::fn_native::{CallableFunction, FnAny, FnCallArgs};
use crate::fn_native::{CallableFunction, FnAny, FnCallArgs, SendSync};
use crate::parser::FnAccess;
use crate::plugin::Plugin;
use crate::result::EvalAltResult;
@@ -264,13 +264,7 @@ macro_rules! def_register {
// ^ dereferencing function
impl<
$($par: Variant + Clone,)*
#[cfg(feature = "sync")]
FN: Fn($($param),*) -> RET + Send + Sync + 'static,
#[cfg(not(feature = "sync"))]
FN: Fn($($param),*) -> RET + 'static,
FN: Fn($($param),*) -> RET + SendSync + 'static,
RET: Variant + Clone
> RegisterFn<FN, ($($mark,)*), RET> for Engine
{
@@ -284,11 +278,7 @@ macro_rules! def_register {
impl<
$($par: Variant + Clone,)*
#[cfg(feature = "sync")]
FN: Fn($($param),*) -> Result<Dynamic, Box<EvalAltResult>> + Send + Sync + 'static,
#[cfg(not(feature = "sync"))]
FN: Fn($($param),*) -> Result<Dynamic, Box<EvalAltResult>> + 'static,
FN: Fn($($param),*) -> Result<Dynamic, Box<EvalAltResult>> + SendSync + 'static,
> RegisterResultFn<FN, ($($mark,)*)> for Engine
{
fn register_result_fn(&mut self, name: &str, f: FN) {

View File

@@ -65,7 +65,7 @@ impl fmt::Debug for Module {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"<module {:?}, functions={}>",
"<module vars={:?}, functions={}>",
self.variables,
self.functions.len(),
)
@@ -187,9 +187,9 @@ impl Module {
/// If there is an existing function of the same name and number of arguments, it is replaced.
pub(crate) fn set_script_fn(&mut self, fn_def: ScriptFnDef) {
// None + function name + number of arguments.
let hash_fn_def = calc_fn_hash(empty(), &fn_def.name, fn_def.params.len(), empty());
let hash_script = calc_fn_hash(empty(), &fn_def.name, fn_def.params.len(), empty());
self.functions.insert(
hash_fn_def,
hash_script,
(
fn_def.name.to_string(),
fn_def.access,
@@ -321,8 +321,7 @@ impl Module {
pub fn set_fn_0<T: Variant + Clone>(
&mut self,
name: impl Into<String>,
#[cfg(not(feature = "sync"))] func: impl Fn() -> FuncReturn<T> + 'static,
#[cfg(feature = "sync")] func: impl Fn() -> FuncReturn<T> + Send + Sync + 'static,
func: impl Fn() -> FuncReturn<T> + SendSync + 'static,
) -> u64 {
let f = move |_: &mut FnCallArgs| func().map(Dynamic::from);
let args = [];
@@ -350,8 +349,7 @@ impl Module {
pub fn set_fn_1<A: Variant + Clone, T: Variant + Clone>(
&mut self,
name: impl Into<String>,
#[cfg(not(feature = "sync"))] func: impl Fn(A) -> FuncReturn<T> + 'static,
#[cfg(feature = "sync")] func: impl Fn(A) -> FuncReturn<T> + Send + Sync + 'static,
func: impl Fn(A) -> FuncReturn<T> + SendSync + 'static,
) -> u64 {
let f =
move |args: &mut FnCallArgs| func(mem::take(args[0]).cast::<A>()).map(Dynamic::from);
@@ -380,8 +378,7 @@ impl Module {
pub fn set_fn_1_mut<A: Variant + Clone, T: Variant + Clone>(
&mut self,
name: impl Into<String>,
#[cfg(not(feature = "sync"))] func: impl Fn(&mut A) -> FuncReturn<T> + 'static,
#[cfg(feature = "sync")] func: impl Fn(&mut A) -> FuncReturn<T> + Send + Sync + 'static,
func: impl Fn(&mut A) -> FuncReturn<T> + SendSync + 'static,
) -> u64 {
let f = move |args: &mut FnCallArgs| {
func(args[0].downcast_mut::<A>().unwrap()).map(Dynamic::from)
@@ -412,8 +409,7 @@ impl Module {
pub fn set_getter_fn<A: Variant + Clone, T: Variant + Clone>(
&mut self,
name: impl Into<String>,
#[cfg(not(feature = "sync"))] func: impl Fn(&mut A) -> FuncReturn<T> + 'static,
#[cfg(feature = "sync")] func: impl Fn(&mut A) -> FuncReturn<T> + Send + Sync + 'static,
func: impl Fn(&mut A) -> FuncReturn<T> + SendSync + 'static,
) -> u64 {
self.set_fn_1_mut(make_getter(&name.into()), func)
}
@@ -436,8 +432,7 @@ impl Module {
pub fn set_fn_2<A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>(
&mut self,
name: impl Into<String>,
#[cfg(not(feature = "sync"))] func: impl Fn(A, B) -> FuncReturn<T> + 'static,
#[cfg(feature = "sync")] func: impl Fn(A, B) -> FuncReturn<T> + Send + Sync + 'static,
func: impl Fn(A, B) -> FuncReturn<T> + SendSync + 'static,
) -> u64 {
let f = move |args: &mut FnCallArgs| {
let a = mem::take(args[0]).cast::<A>();
@@ -473,8 +468,7 @@ impl Module {
pub fn set_fn_2_mut<A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>(
&mut self,
name: impl Into<String>,
#[cfg(not(feature = "sync"))] func: impl Fn(&mut A, B) -> FuncReturn<T> + 'static,
#[cfg(feature = "sync")] func: impl Fn(&mut A, B) -> FuncReturn<T> + Send + Sync + 'static,
func: impl Fn(&mut A, B) -> FuncReturn<T> + SendSync + 'static,
) -> u64 {
let f = move |args: &mut FnCallArgs| {
let b = mem::take(args[1]).cast::<B>();
@@ -512,8 +506,7 @@ impl Module {
pub fn set_setter_fn<A: Variant + Clone, B: Variant + Clone>(
&mut self,
name: impl Into<String>,
#[cfg(not(feature = "sync"))] func: impl Fn(&mut A, B) -> FuncReturn<()> + 'static,
#[cfg(feature = "sync")] func: impl Fn(&mut A, B) -> FuncReturn<()> + Send + Sync + 'static,
func: impl Fn(&mut A, B) -> FuncReturn<()> + SendSync + 'static,
) -> u64 {
self.set_fn_2_mut(make_setter(&name.into()), func)
}
@@ -538,8 +531,7 @@ impl Module {
#[cfg(not(feature = "no_index"))]
pub fn set_indexer_get_fn<A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>(
&mut self,
#[cfg(not(feature = "sync"))] func: impl Fn(&mut A, B) -> FuncReturn<T> + 'static,
#[cfg(feature = "sync")] func: impl Fn(&mut A, B) -> FuncReturn<T> + Send + Sync + 'static,
func: impl Fn(&mut A, B) -> FuncReturn<T> + SendSync + 'static,
) -> u64 {
self.set_fn_2_mut(FUNC_INDEXER_GET, func)
}
@@ -567,8 +559,7 @@ impl Module {
>(
&mut self,
name: impl Into<String>,
#[cfg(not(feature = "sync"))] func: impl Fn(A, B, C) -> FuncReturn<T> + 'static,
#[cfg(feature = "sync")] func: impl Fn(A, B, C) -> FuncReturn<T> + Send + Sync + 'static,
func: impl Fn(A, B, C) -> FuncReturn<T> + SendSync + 'static,
) -> u64 {
let f = move |args: &mut FnCallArgs| {
let a = mem::take(args[0]).cast::<A>();
@@ -610,8 +601,7 @@ impl Module {
>(
&mut self,
name: impl Into<String>,
#[cfg(not(feature = "sync"))] func: impl Fn(&mut A, B, C) -> FuncReturn<T> + 'static,
#[cfg(feature = "sync")] func: impl Fn(&mut A, B, C) -> FuncReturn<T> + Send + Sync + 'static,
func: impl Fn(&mut A, B, C) -> FuncReturn<T> + SendSync + 'static,
) -> u64 {
let f = move |args: &mut FnCallArgs| {
let b = mem::take(args[1]).cast::<B>();
@@ -648,8 +638,7 @@ impl Module {
/// ```
pub fn set_indexer_set_fn<A: Variant + Clone, B: Variant + Clone>(
&mut self,
#[cfg(not(feature = "sync"))] func: impl Fn(&mut A, B, A) -> FuncReturn<()> + 'static,
#[cfg(feature = "sync")] func: impl Fn(&mut A, B, A) -> FuncReturn<()> + Send + Sync + 'static,
func: impl Fn(&mut A, B, A) -> FuncReturn<()> + SendSync + 'static,
) -> u64 {
let f = move |args: &mut FnCallArgs| {
let b = mem::take(args[1]).cast::<B>();
@@ -691,8 +680,7 @@ impl Module {
>(
&mut self,
name: impl Into<String>,
#[cfg(not(feature = "sync"))] func: impl Fn(A, B, C, D) -> FuncReturn<T> + 'static,
#[cfg(feature = "sync")] func: impl Fn(A, B, C, D) -> FuncReturn<T> + Send + Sync + 'static,
func: impl Fn(A, B, C, D) -> FuncReturn<T> + SendSync + 'static,
) -> u64 {
let f = move |args: &mut FnCallArgs| {
let a = mem::take(args[0]).cast::<A>();
@@ -741,8 +729,7 @@ impl Module {
>(
&mut self,
name: impl Into<String>,
#[cfg(not(feature = "sync"))] func: impl Fn(&mut A, B, C, D) -> FuncReturn<T> + 'static,
#[cfg(feature = "sync")] func: impl Fn(&mut A, B, C, D) -> FuncReturn<T> + Send + Sync + 'static,
func: impl Fn(&mut A, B, C, D) -> FuncReturn<T> + SendSync + 'static,
) -> u64 {
let f = move |args: &mut FnCallArgs| {
let b = mem::take(args[1]).cast::<B>();
@@ -791,9 +778,9 @@ impl Module {
pub(crate) fn get_qualified_fn(
&mut self,
name: &str,
hash_fn_native: u64,
hash_qualified_fn: u64,
) -> Result<&CallableFunction, Box<EvalAltResult>> {
self.all_functions.get(&hash_fn_native).ok_or_else(|| {
self.all_functions.get(&hash_qualified_fn).ok_or_else(|| {
Box::new(EvalAltResult::ErrorFunctionNotFound(
name.to_string(),
Position::none(),
@@ -920,26 +907,26 @@ impl Module {
if func.is_script() {
let fn_def = func.get_shared_fn_def();
// Qualifiers + function name + number of arguments.
let hash_fn_def = calc_fn_hash(
let hash_qualified_script = calc_fn_hash(
qualifiers.iter().map(|&v| v),
&fn_def.name,
fn_def.params.len(),
empty(),
);
functions.push((hash_fn_def, fn_def.into()));
functions.push((hash_qualified_script, fn_def.into()));
} else {
// Rust functions are indexed in two steps:
// Qualified Rust functions are indexed in two steps:
// 1) Calculate a hash in a similar manner to script-defined functions,
// i.e. qualifiers + function name + number of arguments.
let hash_fn_def =
let hash_qualified_script =
calc_fn_hash(qualifiers.iter().map(|&v| v), name, params.len(), empty());
// 2) Calculate a second hash with no qualifiers, empty function name,
// zero number of arguments, and the actual list of argument `TypeId`'.s
let hash_fn_args = calc_fn_hash(empty(), "", 0, params.iter().cloned());
// 3) The final hash is the XOR of the two hashes.
let hash_fn_native = hash_fn_def ^ hash_fn_args;
let hash_qualified_fn = hash_qualified_script ^ hash_fn_args;
functions.push((hash_fn_native, func.clone()));
functions.push((hash_qualified_fn, func.clone()));
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -19,6 +19,8 @@ use crate::stdlib::{
type LERR = LexError;
pub type TokenStream<'a> = Peekable<TokenIterator<'a>>;
/// A location (line number + character position) in the input script.
///
/// In order to keep footprint small, both line number and character position have 16-bit unsigned resolution,

View File

@@ -542,9 +542,7 @@ impl<T: Default> StaticVec<T> {
impl<T: fmt::Debug> fmt::Debug for StaticVec<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "[ ")?;
self.iter().try_for_each(|v| write!(f, "{:?}, ", v))?;
write!(f, "]")
fmt::Debug::fmt(&self.iter().collect::<Vec<_>>(), f)
}
}