Encode pure in CallableFunction variant.
This commit is contained in:
parent
8662ffec62
commit
407d376a61
@ -90,15 +90,15 @@ impl Engine {
|
|||||||
let param_type_names: Option<&[&str]> = None;
|
let param_type_names: Option<&[&str]> = None;
|
||||||
|
|
||||||
let fn_name = name.as_ref();
|
let fn_name = name.as_ref();
|
||||||
let no_const = false;
|
let is_pure = true;
|
||||||
|
|
||||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||||
let no_const = no_const || (F::num_params() == 3 && fn_name == crate::engine::FN_IDX_SET);
|
let is_pure = is_pure && (F::num_params() != 3 || fn_name != crate::engine::FN_IDX_SET);
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
let no_const =
|
let is_pure =
|
||||||
no_const || (F::num_params() == 2 && fn_name.starts_with(crate::engine::FN_SET));
|
is_pure && (F::num_params() != 2 || !fn_name.starts_with(crate::engine::FN_SET));
|
||||||
|
|
||||||
let func = func.into_callable_function(fn_name.into(), no_const);
|
let func = func.into_callable_function(fn_name.into(), is_pure);
|
||||||
|
|
||||||
self.global_namespace_mut().set_fn(
|
self.global_namespace_mut().set_fn(
|
||||||
name,
|
name,
|
||||||
|
@ -276,6 +276,7 @@ impl Engine {
|
|||||||
func: CallableFunction::Method {
|
func: CallableFunction::Method {
|
||||||
func: Shared::new(f),
|
func: Shared::new(f),
|
||||||
has_context,
|
has_context,
|
||||||
|
is_pure: false,
|
||||||
},
|
},
|
||||||
source: None,
|
source: None,
|
||||||
})
|
})
|
||||||
@ -285,6 +286,7 @@ impl Engine {
|
|||||||
func: CallableFunction::Method {
|
func: CallableFunction::Method {
|
||||||
func: Shared::new(f),
|
func: Shared::new(f),
|
||||||
has_context,
|
has_context,
|
||||||
|
is_pure: true,
|
||||||
},
|
},
|
||||||
source: None,
|
source: None,
|
||||||
}),
|
}),
|
||||||
@ -372,8 +374,8 @@ impl Engine {
|
|||||||
|
|
||||||
let backup = &mut ArgBackup::new();
|
let backup = &mut ArgBackup::new();
|
||||||
|
|
||||||
// Calling pure function but the first argument is a reference?
|
// Calling non-method function but the first argument is a reference?
|
||||||
let swap = is_ref_mut && func.is_pure() && !args.is_empty();
|
let swap = is_ref_mut && !func.is_method() && !args.is_empty();
|
||||||
|
|
||||||
if swap {
|
if swap {
|
||||||
// Clone the first argument
|
// Clone the first argument
|
||||||
@ -400,12 +402,11 @@ impl Engine {
|
|||||||
.has_context()
|
.has_context()
|
||||||
.then(|| (self, name, src, &*global, pos).into());
|
.then(|| (self, name, src, &*global, pos).into());
|
||||||
|
|
||||||
let mut _result = if let Some(f) = func.get_plugin_fn() {
|
let mut _result = if !func.is_pure() && !args.is_empty() && args[0].is_read_only() {
|
||||||
if !f.is_pure() && !args.is_empty() && args[0].is_read_only() {
|
// If function is not pure, there must be at least one argument
|
||||||
Err(ERR::ErrorNonPureMethodCallOnConstant(name.to_string(), pos).into())
|
Err(ERR::ErrorNonPureMethodCallOnConstant(name.to_string(), pos).into())
|
||||||
} else {
|
} else if let Some(f) = func.get_plugin_fn() {
|
||||||
f.call(context, args)
|
f.call(context, args)
|
||||||
}
|
|
||||||
} else if let Some(f) = func.get_native_fn() {
|
} else if let Some(f) = func.get_native_fn() {
|
||||||
f(context, args)
|
f(context, args)
|
||||||
} else {
|
} else {
|
||||||
@ -1493,18 +1494,19 @@ impl Engine {
|
|||||||
self.call_script_fn(global, caches, scope, None, environ, f, args, true, pos)
|
self.call_script_fn(global, caches, scope, None, environ, f, args, true, pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some(f) if !f.is_pure() && args[0].is_read_only() => {
|
||||||
|
// If function is not pure, there must be at least one argument
|
||||||
|
Err(ERR::ErrorNonPureMethodCallOnConstant(fn_name.to_string(), pos).into())
|
||||||
|
}
|
||||||
|
|
||||||
Some(f) if f.is_plugin_fn() => {
|
Some(f) if f.is_plugin_fn() => {
|
||||||
let f = f.get_plugin_fn().expect("plugin function");
|
let f = f.get_plugin_fn().expect("plugin function");
|
||||||
let context = f
|
let context = f
|
||||||
.has_context()
|
.has_context()
|
||||||
.then(|| (self, fn_name, module.id(), &*global, pos).into());
|
.then(|| (self, fn_name, module.id(), &*global, pos).into());
|
||||||
if !f.is_pure() && !args.is_empty() && args[0].is_read_only() {
|
|
||||||
Err(ERR::ErrorNonPureMethodCallOnConstant(fn_name.to_string(), pos).into())
|
|
||||||
} else {
|
|
||||||
f.call(context, args)
|
f.call(context, args)
|
||||||
.and_then(|r| self.check_data_size(r, pos))
|
.and_then(|r| self.check_data_size(r, pos))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Some(f) if f.is_native() => {
|
Some(f) if f.is_native() => {
|
||||||
let func = f.get_native_fn().expect("native function");
|
let func = f.get_native_fn().expect("native function");
|
||||||
|
@ -39,6 +39,8 @@ pub enum CallableFunction {
|
|||||||
func: Shared<FnAny>,
|
func: Shared<FnAny>,
|
||||||
/// Does the function take a [`NativeCallContext`][crate::NativeCallContext] parameter?
|
/// Does the function take a [`NativeCallContext`][crate::NativeCallContext] parameter?
|
||||||
has_context: bool,
|
has_context: bool,
|
||||||
|
/// This is a dummy field and is not used.
|
||||||
|
is_pure: bool,
|
||||||
},
|
},
|
||||||
/// A native Rust object method with the first argument passed by reference,
|
/// A native Rust object method with the first argument passed by reference,
|
||||||
/// and the rest passed by value.
|
/// and the rest passed by value.
|
||||||
@ -47,6 +49,8 @@ pub enum CallableFunction {
|
|||||||
func: Shared<FnAny>,
|
func: Shared<FnAny>,
|
||||||
/// Does the function take a [`NativeCallContext`][crate::NativeCallContext] parameter?
|
/// Does the function take a [`NativeCallContext`][crate::NativeCallContext] parameter?
|
||||||
has_context: bool,
|
has_context: bool,
|
||||||
|
/// Allow operating on constants?
|
||||||
|
is_pure: bool,
|
||||||
},
|
},
|
||||||
/// An iterator function.
|
/// An iterator function.
|
||||||
Iterator {
|
Iterator {
|
||||||
@ -105,9 +109,10 @@ impl CallableFunction {
|
|||||||
pub fn is_pure(&self) -> bool {
|
pub fn is_pure(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::Pure { .. } => true,
|
Self::Pure { .. } => true,
|
||||||
Self::Method { .. } | Self::Iterator { .. } => false,
|
Self::Method { is_pure, .. } => *is_pure,
|
||||||
|
Self::Iterator { .. } => true,
|
||||||
|
|
||||||
Self::Plugin { func, .. } => !func.is_method_call(),
|
Self::Plugin { func, .. } => func.is_pure(),
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
Self::Script { .. } => false,
|
Self::Script { .. } => false,
|
||||||
|
@ -84,7 +84,7 @@ pub trait RegisterNativeFunction<
|
|||||||
{
|
{
|
||||||
/// Convert this function into a [`CallableFunction`].
|
/// Convert this function into a [`CallableFunction`].
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn into_callable_function(self, name: Identifier, no_const: bool) -> CallableFunction;
|
fn into_callable_function(self, name: Identifier, is_pure: bool) -> CallableFunction;
|
||||||
/// Get the type ID's of this function's parameters.
|
/// Get the type ID's of this function's parameters.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn param_types() -> [TypeId; N];
|
fn param_types() -> [TypeId; N];
|
||||||
@ -127,19 +127,6 @@ pub trait RegisterNativeFunction<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! check_constant {
|
|
||||||
($abi:ident, $n:expr, $fn_name:ident, $no_const:ident, $args:ident) => {
|
|
||||||
#[cfg(any(not(feature = "no_object"), not(feature = "no_index")))]
|
|
||||||
if stringify!($abi) == "Method" && $no_const && $args[0].is_read_only() {
|
|
||||||
return Err(crate::ERR::ErrorNonPureMethodCallOnConstant(
|
|
||||||
$fn_name.to_string(),
|
|
||||||
crate::Position::NONE,
|
|
||||||
)
|
|
||||||
.into());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! def_register {
|
macro_rules! def_register {
|
||||||
() => {
|
() => {
|
||||||
def_register!(imp Pure : 0;);
|
def_register!(imp Pure : 0;);
|
||||||
@ -160,11 +147,9 @@ macro_rules! def_register {
|
|||||||
> RegisterNativeFunction<($($mark,)*), $n, false, RET, false> for FN {
|
> RegisterNativeFunction<($($mark,)*), $n, false, RET, false> for FN {
|
||||||
#[inline(always)] fn param_types() -> [TypeId;$n] { [$(TypeId::of::<$par>()),*] }
|
#[inline(always)] fn param_types() -> [TypeId;$n] { [$(TypeId::of::<$par>()),*] }
|
||||||
#[cfg(feature = "metadata")] #[inline(always)] fn param_names() -> [&'static str;$n] { [$(type_name::<$param>()),*] }
|
#[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 {
|
#[inline(always)] fn into_callable_function(self, fn_name: Identifier, is_pure: bool) -> CallableFunction {
|
||||||
CallableFunction::$abi { func: 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!
|
// The arguments are assumed to be of the correct number and types!
|
||||||
check_constant!($abi, $n, fn_name, no_const, args);
|
|
||||||
|
|
||||||
let mut drain = args.iter_mut();
|
let mut drain = args.iter_mut();
|
||||||
$(let mut $par = $clone(drain.next().unwrap()); )*
|
$(let mut $par = $clone(drain.next().unwrap()); )*
|
||||||
|
|
||||||
@ -173,7 +158,7 @@ macro_rules! def_register {
|
|||||||
|
|
||||||
// Map the result
|
// Map the result
|
||||||
Ok(Dynamic::from(r))
|
Ok(Dynamic::from(r))
|
||||||
}), has_context: false }
|
}), has_context: false, is_pure }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,13 +169,11 @@ macro_rules! def_register {
|
|||||||
> RegisterNativeFunction<($($mark,)*), $n, true, RET, false> for FN {
|
> RegisterNativeFunction<($($mark,)*), $n, true, RET, false> for FN {
|
||||||
#[inline(always)] fn param_types() -> [TypeId;$n] { [$(TypeId::of::<$par>()),*] }
|
#[inline(always)] fn param_types() -> [TypeId;$n] { [$(TypeId::of::<$par>()),*] }
|
||||||
#[cfg(feature = "metadata")] #[inline(always)] fn param_names() -> [&'static str;$n] { [$(type_name::<$param>()),*] }
|
#[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 {
|
#[inline(always)] fn into_callable_function(self, fn_name: Identifier, is_pure: bool) -> CallableFunction {
|
||||||
CallableFunction::$abi { func: Shared::new(move |ctx: Option<NativeCallContext>, args: &mut FnCallArgs| {
|
CallableFunction::$abi { func: Shared::new(move |ctx: Option<NativeCallContext>, args: &mut FnCallArgs| {
|
||||||
let ctx = ctx.unwrap();
|
let ctx = ctx.unwrap();
|
||||||
|
|
||||||
// The arguments are assumed to be of the correct number and types!
|
// The arguments are assumed to be of the correct number and types!
|
||||||
check_constant!($abi, $n, fn_name, no_const, args);
|
|
||||||
|
|
||||||
let mut drain = args.iter_mut();
|
let mut drain = args.iter_mut();
|
||||||
$(let mut $par = $clone(drain.next().unwrap()); )*
|
$(let mut $par = $clone(drain.next().unwrap()); )*
|
||||||
|
|
||||||
@ -199,7 +182,7 @@ macro_rules! def_register {
|
|||||||
|
|
||||||
// Map the result
|
// Map the result
|
||||||
Ok(Dynamic::from(r))
|
Ok(Dynamic::from(r))
|
||||||
}), has_context: true }
|
}), has_context: true, is_pure }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,17 +194,15 @@ macro_rules! def_register {
|
|||||||
#[inline(always)] fn param_types() -> [TypeId;$n] { [$(TypeId::of::<$par>()),*] }
|
#[inline(always)] fn param_types() -> [TypeId;$n] { [$(TypeId::of::<$par>()),*] }
|
||||||
#[cfg(feature = "metadata")] #[inline(always)] fn param_names() -> [&'static str;$n] { [$(type_name::<$param>()),*] }
|
#[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::<RhaiResultOf<RET>>() }
|
#[cfg(feature = "metadata")] #[inline(always)] fn return_type_name() -> &'static str { type_name::<RhaiResultOf<RET>>() }
|
||||||
#[inline(always)] fn into_callable_function(self, fn_name: Identifier, no_const: bool) -> CallableFunction {
|
#[inline(always)] fn into_callable_function(self, fn_name: Identifier, is_pure: bool) -> CallableFunction {
|
||||||
CallableFunction::$abi { func: 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!
|
// The arguments are assumed to be of the correct number and types!
|
||||||
check_constant!($abi, $n, fn_name, no_const, args);
|
|
||||||
|
|
||||||
let mut drain = args.iter_mut();
|
let mut drain = args.iter_mut();
|
||||||
$(let mut $par = $clone(drain.next().unwrap()); )*
|
$(let mut $par = $clone(drain.next().unwrap()); )*
|
||||||
|
|
||||||
// Call the function with each argument value
|
// Call the function with each argument value
|
||||||
self($($arg),*).map(Dynamic::from)
|
self($($arg),*).map(Dynamic::from)
|
||||||
}), has_context: false }
|
}), has_context: false, is_pure }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,19 +214,17 @@ macro_rules! def_register {
|
|||||||
#[inline(always)] fn param_types() -> [TypeId;$n] { [$(TypeId::of::<$par>()),*] }
|
#[inline(always)] fn param_types() -> [TypeId;$n] { [$(TypeId::of::<$par>()),*] }
|
||||||
#[cfg(feature = "metadata")] #[inline(always)] fn param_names() -> [&'static str;$n] { [$(type_name::<$param>()),*] }
|
#[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::<RhaiResultOf<RET>>() }
|
#[cfg(feature = "metadata")] #[inline(always)] fn return_type_name() -> &'static str { type_name::<RhaiResultOf<RET>>() }
|
||||||
#[inline(always)] fn into_callable_function(self, fn_name: Identifier, no_const: bool) -> CallableFunction {
|
#[inline(always)] fn into_callable_function(self, fn_name: Identifier, is_pure: bool) -> CallableFunction {
|
||||||
CallableFunction::$abi { func: Shared::new(move |ctx: Option<NativeCallContext>, args: &mut FnCallArgs| {
|
CallableFunction::$abi { func: Shared::new(move |ctx: Option<NativeCallContext>, args: &mut FnCallArgs| {
|
||||||
let ctx = ctx.unwrap();
|
let ctx = ctx.unwrap();
|
||||||
|
|
||||||
// The arguments are assumed to be of the correct number and types!
|
// The arguments are assumed to be of the correct number and types!
|
||||||
check_constant!($abi, $n, fn_name, no_const, args);
|
|
||||||
|
|
||||||
let mut drain = args.iter_mut();
|
let mut drain = args.iter_mut();
|
||||||
$(let mut $par = $clone(drain.next().unwrap()); )*
|
$(let mut $par = $clone(drain.next().unwrap()); )*
|
||||||
|
|
||||||
// Call the function with each argument value
|
// Call the function with each argument value
|
||||||
self(ctx, $($arg),*).map(Dynamic::from)
|
self(ctx, $($arg),*).map(Dynamic::from)
|
||||||
}), has_context: true }
|
}), has_context: true, is_pure }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1266,6 +1266,7 @@ impl Module {
|
|||||||
CallableFunction::Method {
|
CallableFunction::Method {
|
||||||
func: Shared::new(f),
|
func: Shared::new(f),
|
||||||
has_context: true,
|
has_context: true,
|
||||||
|
is_pure: false,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -1303,15 +1304,15 @@ impl Module {
|
|||||||
F: RegisterNativeFunction<A, N, C, T, true>,
|
F: RegisterNativeFunction<A, N, C, T, true>,
|
||||||
{
|
{
|
||||||
let fn_name = name.into();
|
let fn_name = name.into();
|
||||||
let no_const = false;
|
let is_pure = true;
|
||||||
|
|
||||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||||
let no_const = no_const || (F::num_params() == 3 && fn_name == crate::engine::FN_IDX_SET);
|
let is_pure = is_pure && (F::num_params() != 3 || fn_name != crate::engine::FN_IDX_SET);
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
let no_const =
|
let is_pure =
|
||||||
no_const || (F::num_params() == 2 && fn_name.starts_with(crate::engine::FN_SET));
|
is_pure && (F::num_params() != 2 || !fn_name.starts_with(crate::engine::FN_SET));
|
||||||
|
|
||||||
let func = func.into_callable_function(fn_name.clone(), no_const);
|
let func = func.into_callable_function(fn_name.clone(), is_pure);
|
||||||
|
|
||||||
self.set_fn(
|
self.set_fn(
|
||||||
fn_name,
|
fn_name,
|
||||||
@ -1350,7 +1351,7 @@ impl Module {
|
|||||||
F: RegisterNativeFunction<(Mut<A>,), 1, C, T, true> + SendSync + 'static,
|
F: RegisterNativeFunction<(Mut<A>,), 1, C, T, true> + SendSync + 'static,
|
||||||
{
|
{
|
||||||
let fn_name = crate::engine::make_getter(name.as_ref());
|
let fn_name = crate::engine::make_getter(name.as_ref());
|
||||||
let func = func.into_callable_function(fn_name.clone(), false);
|
let func = func.into_callable_function(fn_name.clone(), true);
|
||||||
|
|
||||||
self.set_fn(
|
self.set_fn(
|
||||||
fn_name,
|
fn_name,
|
||||||
@ -1394,7 +1395,7 @@ impl Module {
|
|||||||
F: RegisterNativeFunction<(Mut<A>, T), 2, C, (), true> + SendSync + 'static,
|
F: RegisterNativeFunction<(Mut<A>, T), 2, C, (), true> + SendSync + 'static,
|
||||||
{
|
{
|
||||||
let fn_name = crate::engine::make_setter(name.as_ref());
|
let fn_name = crate::engine::make_setter(name.as_ref());
|
||||||
let func = func.into_callable_function(fn_name.clone(), true);
|
let func = func.into_callable_function(fn_name.clone(), false);
|
||||||
|
|
||||||
self.set_fn(
|
self.set_fn(
|
||||||
fn_name,
|
fn_name,
|
||||||
@ -1510,7 +1511,7 @@ impl Module {
|
|||||||
FnAccess::Public,
|
FnAccess::Public,
|
||||||
None,
|
None,
|
||||||
F::param_types(),
|
F::param_types(),
|
||||||
func.into_callable_function(crate::engine::FN_IDX_GET.into(), false),
|
func.into_callable_function(crate::engine::FN_IDX_GET.into(), true),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1571,7 +1572,7 @@ impl Module {
|
|||||||
FnAccess::Public,
|
FnAccess::Public,
|
||||||
None,
|
None,
|
||||||
F::param_types(),
|
F::param_types(),
|
||||||
func.into_callable_function(crate::engine::FN_IDX_SET.into(), true),
|
func.into_callable_function(crate::engine::FN_IDX_SET.into(), false),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user