diff --git a/src/ast/stmt.rs b/src/ast/stmt.rs index 8dba2bca..d3f11a46 100644 --- a/src/ast/stmt.rs +++ b/src/ast/stmt.rs @@ -573,8 +573,8 @@ pub enum Stmt { Assignment(Box<(OpAssignment, BinaryExpr)>), /// func `(` expr `,` ... `)` /// - /// Note - this is a duplicate of [`Expr::FnCall`] to cover the very common pattern of a single - /// function call forming one statement. + /// This is a duplicate of [`Expr::FnCall`] to cover the very common pattern of a single + /// function call forming one statement. FnCall(Box, Position), /// `{` stmt`;` ... `}` Block(Box), diff --git a/src/func/call.rs b/src/func/call.rs index 1d770324..4f68b776 100644 --- a/src/func/call.rs +++ b/src/func/call.rs @@ -270,25 +270,31 @@ impl Engine { } // Try to find a built-in version - let builtin = - args.and_then(|args| match op_token { - Token::NONE => None, - token if token.is_op_assignment() => { - let (first_arg, rest_args) = args.split_first().unwrap(); + let builtin = args.and_then(|args| match op_token { + Token::NONE => None, + token if token.is_op_assignment() => { + let (first_arg, rest_args) = args.split_first().unwrap(); - get_builtin_op_assignment_fn(token, first_arg, rest_args[0]) - .map(|(f, ctx)| FnResolutionCacheEntry { - func: CallableFunction::Method(Shared::new(f), ctx), - source: None, - }) - } - token => get_builtin_binary_op_fn(token, args[0], args[1]).map( - |(f, ctx)| FnResolutionCacheEntry { - func: CallableFunction::Method(Shared::new(f), ctx), + get_builtin_op_assignment_fn(token, first_arg, rest_args[0]).map( + |(f, has_context)| FnResolutionCacheEntry { + func: CallableFunction::Method { + func: Shared::new(f), + has_context, + }, source: None, }, - ), - }); + ) + } + token => get_builtin_binary_op_fn(token, args[0], args[1]).map( + |(f, has_context)| FnResolutionCacheEntry { + func: CallableFunction::Method { + func: Shared::new(f), + has_context, + }, + source: None, + }, + ), + }); return if cache.filter.is_absent_and_set(hash) { // Do not cache "one-hit wonders" diff --git a/src/func/callable_function.rs b/src/func/callable_function.rs index ff7a1509..21a7ae4d 100644 --- a/src/func/callable_function.rs +++ b/src/func/callable_function.rs @@ -21,7 +21,7 @@ pub struct EncapsulatedEnviron { pub lib: crate::SharedModule, /// Imported [modules][crate::Module]. #[cfg(not(feature = "no_module"))] - pub imports: Box<[(crate::ImmutableString, crate::SharedModule)]>, + pub imports: Box>, /// Globally-defined constants. #[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_function"))] @@ -34,20 +34,38 @@ pub struct EncapsulatedEnviron { #[non_exhaustive] pub enum CallableFunction { /// A pure native Rust function with all arguments passed by value. - Pure(Shared, bool), + Pure { + /// Shared function pointer. + func: Shared, + /// Does the function take a [`NativeCallContext`][crate::NativeCallContext] parameter? + has_context: bool, + }, /// A native Rust object method with the first argument passed by reference, /// and the rest passed by value. - Method(Shared, bool), + Method { + /// Shared function pointer. + func: Shared, + /// Does the function take a [`NativeCallContext`][crate::NativeCallContext] parameter? + has_context: bool, + }, /// An iterator function. - Iterator(Shared), + Iterator { + /// Shared function pointer. + func: Shared, + }, /// A plugin function, - Plugin(Shared), + Plugin { + /// Shared function pointer. + func: Shared, + }, /// A script-defined function. #[cfg(not(feature = "no_function"))] - Script( - Shared, - Option>, - ), + Script { + /// Shared reference to the [`ScriptFnDef`][crate::ast::ScriptFnDef] function definition. + fn_def: Shared, + /// Encapsulated environment, if any. + environ: Option>, + }, } impl fmt::Debug for CallableFunction { @@ -55,13 +73,13 @@ impl fmt::Debug for CallableFunction { #[inline(never)] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Self::Pure(..) => f.write_str("NativePureFunction"), - Self::Method(..) => f.write_str("NativeMethod"), - Self::Iterator(..) => f.write_str("NativeIterator"), - Self::Plugin(..) => f.write_str("PluginFunction"), + Self::Pure { .. } => f.write_str("NativePureFunction"), + Self::Method { .. } => f.write_str("NativeMethod"), + Self::Iterator { .. } => f.write_str("NativeIterator"), + Self::Plugin { .. } => f.write_str("PluginFunction"), #[cfg(not(feature = "no_function"))] - Self::Script(fn_def, ..) => fmt::Debug::fmt(fn_def, f), + Self::Script { fn_def, .. } => fmt::Debug::fmt(fn_def, f), } } } @@ -69,13 +87,13 @@ impl fmt::Debug for CallableFunction { impl fmt::Display for CallableFunction { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Self::Pure(..) => f.write_str("NativePureFunction"), - Self::Method(..) => f.write_str("NativeMethod"), - Self::Iterator(..) => f.write_str("NativeIterator"), - Self::Plugin(..) => f.write_str("PluginFunction"), + Self::Pure { .. } => f.write_str("NativePureFunction"), + Self::Method { .. } => f.write_str("NativeMethod"), + Self::Iterator { .. } => f.write_str("NativeIterator"), + Self::Plugin { .. } => f.write_str("PluginFunction"), #[cfg(not(feature = "no_function"))] - Self::Script(fn_def, ..) => fmt::Display::fmt(fn_def, f), + Self::Script { fn_def, .. } => fmt::Display::fmt(fn_def, f), } } } @@ -86,13 +104,13 @@ impl CallableFunction { #[must_use] pub fn is_pure(&self) -> bool { match self { - Self::Pure(..) => true, - Self::Method(..) | Self::Iterator(..) => false, + Self::Pure { .. } => true, + Self::Method { .. } | Self::Iterator { .. } => false, - Self::Plugin(p) => !p.is_method_call(), + Self::Plugin { func, .. } => !func.is_method_call(), #[cfg(not(feature = "no_function"))] - Self::Script(..) => false, + Self::Script { .. } => false, } } /// Is this a native Rust method function? @@ -100,13 +118,13 @@ impl CallableFunction { #[must_use] pub fn is_method(&self) -> bool { match self { - Self::Method(..) => true, - Self::Pure(..) | Self::Iterator(..) => false, + Self::Method { .. } => true, + Self::Pure { .. } | Self::Iterator { .. } => false, - Self::Plugin(p) => p.is_method_call(), + Self::Plugin { func, .. } => func.is_method_call(), #[cfg(not(feature = "no_function"))] - Self::Script(..) => false, + Self::Script { .. } => false, } } /// Is this an iterator function? @@ -114,11 +132,11 @@ impl CallableFunction { #[must_use] pub const fn is_iter(&self) -> bool { match self { - Self::Iterator(..) => true, - Self::Pure(..) | Self::Method(..) | Self::Plugin(..) => false, + Self::Iterator { .. } => true, + Self::Pure { .. } | Self::Method { .. } | Self::Plugin { .. } => false, #[cfg(not(feature = "no_function"))] - Self::Script(..) => false, + Self::Script { .. } => false, } } /// Is this a script-defined function? @@ -130,8 +148,11 @@ impl CallableFunction { #[cfg(not(feature = "no_function"))] match self { - Self::Script(..) => true, - Self::Pure(..) | Self::Method(..) | Self::Iterator(..) | Self::Plugin(..) => false, + Self::Script { .. } => true, + Self::Pure { .. } + | Self::Method { .. } + | Self::Iterator { .. } + | Self::Plugin { .. } => false, } } /// Is this a plugin function? @@ -139,11 +160,11 @@ impl CallableFunction { #[must_use] pub const fn is_plugin_fn(&self) -> bool { match self { - Self::Plugin(..) => true, - Self::Pure(..) | Self::Method(..) | Self::Iterator(..) => false, + Self::Plugin { .. } => true, + Self::Pure { .. } | Self::Method { .. } | Self::Iterator { .. } => false, #[cfg(not(feature = "no_function"))] - Self::Script(..) => false, + Self::Script { .. } => false, } } /// Is this a native Rust function? @@ -155,8 +176,11 @@ impl CallableFunction { #[cfg(not(feature = "no_function"))] match self { - Self::Pure(..) | Self::Method(..) | Self::Plugin(..) | Self::Iterator(..) => true, - Self::Script(..) => false, + Self::Pure { .. } + | Self::Method { .. } + | Self::Plugin { .. } + | Self::Iterator { .. } => true, + Self::Script { .. } => false, } } /// Is there a [`NativeCallContext`][crate::NativeCallContext] parameter? @@ -164,11 +188,11 @@ impl CallableFunction { #[must_use] pub fn has_context(&self) -> bool { match self { - Self::Pure(.., ctx) | Self::Method(.., ctx) => *ctx, - Self::Plugin(f) => f.has_context(), - Self::Iterator(..) => false, + Self::Pure { has_context, .. } | Self::Method { has_context, .. } => *has_context, + Self::Plugin { func, .. } => func.has_context(), + Self::Iterator { .. } => false, #[cfg(not(feature = "no_function"))] - Self::Script(..) => false, + Self::Script { .. } => false, } } /// Get the access mode. @@ -180,10 +204,11 @@ impl CallableFunction { #[cfg(not(feature = "no_function"))] match self { - Self::Plugin(..) | Self::Pure(..) | Self::Method(..) | Self::Iterator(..) => { - FnAccess::Public - } - Self::Script(f, ..) => f.access, + Self::Plugin { .. } + | Self::Pure { .. } + | Self::Method { .. } + | Self::Iterator { .. } => FnAccess::Public, + Self::Script { fn_def, .. } => fn_def.access, } } /// Get a shared reference to a native Rust function. @@ -191,11 +216,11 @@ impl CallableFunction { #[must_use] pub fn get_native_fn(&self) -> Option<&Shared> { match self { - Self::Pure(f, ..) | Self::Method(f, ..) => Some(f), - Self::Iterator(..) | Self::Plugin(..) => None, + Self::Pure { func, .. } | Self::Method { func, .. } => Some(func), + Self::Iterator { .. } | Self::Plugin { .. } => None, #[cfg(not(feature = "no_function"))] - Self::Script(..) => None, + Self::Script { .. } => None, } } /// Get a shared reference to a script-defined function definition. @@ -206,8 +231,11 @@ impl CallableFunction { #[must_use] pub const fn get_script_fn_def(&self) -> Option<&Shared> { match self { - Self::Pure(..) | Self::Method(..) | Self::Iterator(..) | Self::Plugin(..) => None, - Self::Script(f, ..) => Some(f), + Self::Pure { .. } + | Self::Method { .. } + | Self::Iterator { .. } + | Self::Plugin { .. } => None, + Self::Script { fn_def, .. } => Some(fn_def), } } /// Get a reference to the shared encapsulated environment of the function definition. @@ -217,10 +245,13 @@ impl CallableFunction { #[must_use] pub fn get_encapsulated_environ(&self) -> Option<&EncapsulatedEnviron> { match self { - Self::Pure(..) | Self::Method(..) | Self::Iterator(..) | Self::Plugin(..) => None, + Self::Pure { .. } + | Self::Method { .. } + | Self::Iterator { .. } + | Self::Plugin { .. } => None, #[cfg(not(feature = "no_function"))] - Self::Script(.., environ) => environ.as_deref(), + Self::Script { environ, .. } => environ.as_deref(), } } /// Get a reference to an iterator function. @@ -228,11 +259,11 @@ impl CallableFunction { #[must_use] pub fn get_iter_fn(&self) -> Option<&IteratorFn> { match self { - Self::Iterator(f) => Some(&**f), - Self::Pure(..) | Self::Method(..) | Self::Plugin(..) => None, + Self::Iterator { func, .. } => Some(&**func), + Self::Pure { .. } | Self::Method { .. } | Self::Plugin { .. } => None, #[cfg(not(feature = "no_function"))] - Self::Script(..) => None, + Self::Script { .. } => None, } } /// Get a shared reference to a plugin function. @@ -240,11 +271,11 @@ impl CallableFunction { #[must_use] pub fn get_plugin_fn(&self) -> Option<&Shared> { match self { - Self::Plugin(f) => Some(f), - Self::Pure(..) | Self::Method(..) | Self::Iterator(..) => None, + Self::Plugin { func, .. } => Some(func), + Self::Pure { .. } | Self::Method { .. } | Self::Iterator { .. } => None, #[cfg(not(feature = "no_function"))] - Self::Script(..) => None, + Self::Script { .. } => None, } } } @@ -252,29 +283,37 @@ impl CallableFunction { #[cfg(not(feature = "no_function"))] impl From for CallableFunction { #[inline(always)] - fn from(func: crate::ast::ScriptFnDef) -> Self { - Self::Script(func.into(), None) + fn from(fn_def: crate::ast::ScriptFnDef) -> Self { + Self::Script { + fn_def: fn_def.into(), + environ: None, + } } } #[cfg(not(feature = "no_function"))] impl From> for CallableFunction { #[inline(always)] - fn from(func: Shared) -> Self { - Self::Script(func, None) + fn from(fn_def: Shared) -> Self { + Self::Script { + fn_def, + environ: None, + } } } impl From for CallableFunction { #[inline(always)] fn from(func: T) -> Self { - Self::Plugin(Shared::new(func)) + Self::Plugin { + func: Shared::new(func), + } } } impl From> for CallableFunction { #[inline(always)] fn from(func: Shared) -> Self { - Self::Plugin(func) + Self::Plugin { func } } } diff --git a/src/func/register.rs b/src/func/register.rs index 822d8bad..ee309f47 100644 --- a/src/func/register.rs +++ b/src/func/register.rs @@ -162,7 +162,7 @@ macro_rules! def_register { #[inline(always)] fn param_types() -> [TypeId;$n] { [$(TypeId::of::<$par>()),*] } #[cfg(feature = "metadata")] #[inline(always)] fn param_names() -> [&'static str;$n] { [$(type_name::<$param>()),*] } #[inline(always)] fn into_callable_function(self, fn_name: Identifier, no_const: bool) -> CallableFunction { - CallableFunction::$abi(Shared::new(move |_, args: &mut FnCallArgs| { + CallableFunction::$abi { func: Shared::new(move |_, args: &mut FnCallArgs| { // The arguments are assumed to be of the correct number and types! check_constant!($abi, $n, fn_name, no_const, args); @@ -174,7 +174,7 @@ macro_rules! def_register { // Map the result Ok(Dynamic::from(r)) - }), false) + }), has_context: false } } } @@ -186,7 +186,7 @@ macro_rules! def_register { #[inline(always)] fn param_types() -> [TypeId;$n] { [$(TypeId::of::<$par>()),*] } #[cfg(feature = "metadata")] #[inline(always)] fn param_names() -> [&'static str;$n] { [$(type_name::<$param>()),*] } #[inline(always)] fn into_callable_function(self, fn_name: Identifier, no_const: bool) -> CallableFunction { - CallableFunction::$abi(Shared::new(move |ctx: Option, args: &mut FnCallArgs| { + CallableFunction::$abi { func: Shared::new(move |ctx: Option, args: &mut FnCallArgs| { let ctx = ctx.unwrap(); // The arguments are assumed to be of the correct number and types! @@ -200,7 +200,7 @@ macro_rules! def_register { // Map the result Ok(Dynamic::from(r)) - }), true) + }), has_context: true } } } @@ -213,7 +213,7 @@ macro_rules! def_register { #[cfg(feature = "metadata")] #[inline(always)] fn param_names() -> [&'static str;$n] { [$(type_name::<$param>()),*] } #[cfg(feature = "metadata")] #[inline(always)] fn return_type_name() -> &'static str { type_name::>() } #[inline(always)] fn into_callable_function(self, fn_name: Identifier, no_const: bool) -> CallableFunction { - CallableFunction::$abi(Shared::new(move |_, args: &mut FnCallArgs| { + CallableFunction::$abi { func: Shared::new(move |_, args: &mut FnCallArgs| { // The arguments are assumed to be of the correct number and types! check_constant!($abi, $n, fn_name, no_const, args); @@ -222,7 +222,7 @@ macro_rules! def_register { // Call the function with each argument value self($($arg),*).map(Dynamic::from) - }), false) + }), has_context: false } } } @@ -235,7 +235,7 @@ macro_rules! def_register { #[cfg(feature = "metadata")] #[inline(always)] fn param_names() -> [&'static str;$n] { [$(type_name::<$param>()),*] } #[cfg(feature = "metadata")] #[inline(always)] fn return_type_name() -> &'static str { type_name::>() } #[inline(always)] fn into_callable_function(self, fn_name: Identifier, no_const: bool) -> CallableFunction { - CallableFunction::$abi(Shared::new(move |ctx: Option, args: &mut FnCallArgs| { + CallableFunction::$abi { func: Shared::new(move |ctx: Option, args: &mut FnCallArgs| { let ctx = ctx.unwrap(); // The arguments are assumed to be of the correct number and types! @@ -246,7 +246,7 @@ macro_rules! def_register { // Call the function with each argument value self(ctx, $($arg),*).map(Dynamic::from) - }), true) + }), has_context: true } } } diff --git a/src/module/mod.rs b/src/module/mod.rs index c1f8f54f..26c3dcbb 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -9,7 +9,7 @@ use crate::func::{ }; use crate::types::{dynamic::Variant, BloomFilterU64, CustomTypesCollection}; use crate::{ - calc_fn_hash, calc_fn_hash_full, Dynamic, FnArgsVec, FnPtr, Identifier, ImmutableString, + calc_fn_hash, calc_fn_hash_full, Dynamic, FnArgsVec, Identifier, ImmutableString, NativeCallContext, RhaiResultOf, Shared, SharedModule, SmartString, }; use bitflags::bitflags; @@ -1221,7 +1221,10 @@ impl Module { access, None, arg_types, - CallableFunction::Method(Shared::new(f), true), + CallableFunction::Method { + func: Shared::new(f), + has_context: true, + }, ) } @@ -2142,7 +2145,7 @@ impl Module { let environ = Shared::new(crate::func::EncapsulatedEnviron { #[cfg(not(feature = "no_function"))] lib: ast.shared_lib().clone(), - imports: imports.into_boxed_slice(), + imports: imports.into(), #[cfg(not(feature = "no_function"))] constants, }); @@ -2150,7 +2153,7 @@ impl Module { // Variables with an alias left in the scope become module variables for (_name, mut value, mut aliases) in scope { value.deep_scan(|v| { - if let Some(fn_ptr) = v.downcast_mut::() { + if let Some(fn_ptr) = v.downcast_mut::() { fn_ptr.set_encapsulated_environ(Some(environ.clone())); } }); @@ -2184,8 +2187,8 @@ impl Module { let f = module.functions.as_mut().unwrap().get_mut(&hash).unwrap(); // Encapsulate AST environment - match f.func { - CallableFunction::Script(.., ref mut e) => *e = Some(environ.clone()), + match &mut f.func { + CallableFunction::Script { environ: e, .. } => *e = Some(environ.clone()), _ => (), } });