Fix bug with calling a pure function method-call style.
This commit is contained in:
parent
4a8710a4a9
commit
414f3d3c23
175
src/engine.rs
175
src/engine.rs
@ -3,7 +3,7 @@
|
|||||||
use crate::any::{Dynamic, Union};
|
use crate::any::{Dynamic, Union};
|
||||||
use crate::calc_fn_hash;
|
use crate::calc_fn_hash;
|
||||||
use crate::error::ParseErrorType;
|
use crate::error::ParseErrorType;
|
||||||
use crate::fn_native::{FnCallArgs, NativeFunction, SharedNativeFunction};
|
use crate::fn_native::{FnCallArgs, NativeFunction, NativeFunctionABI, SharedNativeFunction};
|
||||||
use crate::optimize::OptimizationLevel;
|
use crate::optimize::OptimizationLevel;
|
||||||
use crate::packages::{
|
use crate::packages::{
|
||||||
CorePackage, Package, PackageLibrary, PackageStore, PackagesCollection, StandardPackage,
|
CorePackage, Package, PackageLibrary, PackageStore, PackagesCollection, StandardPackage,
|
||||||
@ -544,13 +544,14 @@ impl Engine {
|
|||||||
scope: Option<&mut Scope>,
|
scope: Option<&mut Scope>,
|
||||||
state: &State,
|
state: &State,
|
||||||
fn_name: &str,
|
fn_name: &str,
|
||||||
|
is_protected: bool,
|
||||||
hash_fn_spec: u64,
|
hash_fn_spec: u64,
|
||||||
hash_fn_def: u64,
|
hash_fn_def: u64,
|
||||||
args: &mut FnCallArgs,
|
args: &mut FnCallArgs,
|
||||||
def_val: Option<&Dynamic>,
|
def_val: Option<&Dynamic>,
|
||||||
pos: Position,
|
pos: Position,
|
||||||
level: usize,
|
level: usize,
|
||||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
) -> Result<(Dynamic, bool), Box<EvalAltResult>> {
|
||||||
// Check for stack overflow
|
// Check for stack overflow
|
||||||
if level > self.max_call_stack_depth {
|
if level > self.max_call_stack_depth {
|
||||||
return Err(Box::new(EvalAltResult::ErrorStackOverflow(pos)));
|
return Err(Box::new(EvalAltResult::ErrorStackOverflow(pos)));
|
||||||
@ -559,7 +560,9 @@ impl Engine {
|
|||||||
// First search in script-defined functions (can override built-in)
|
// First search in script-defined functions (can override built-in)
|
||||||
if hash_fn_def > 0 {
|
if hash_fn_def > 0 {
|
||||||
if let Some(fn_def) = state.get_function(hash_fn_def) {
|
if let Some(fn_def) = state.get_function(hash_fn_def) {
|
||||||
return self.call_script_fn(scope, state, fn_def, args, pos, level);
|
return self
|
||||||
|
.call_script_fn(scope, state, fn_def, args, pos, level)
|
||||||
|
.map(|v| (v, false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -569,32 +572,61 @@ impl Engine {
|
|||||||
.get_function(hash_fn_spec)
|
.get_function(hash_fn_spec)
|
||||||
.or_else(|| self.packages.get_function(hash_fn_spec))
|
.or_else(|| self.packages.get_function(hash_fn_spec))
|
||||||
{
|
{
|
||||||
|
let mut backup: Dynamic = ().into();
|
||||||
|
let mut restore = false;
|
||||||
|
|
||||||
|
let updated = match func.abi() {
|
||||||
|
// Calling pure function in method-call
|
||||||
|
NativeFunctionABI::Pure if is_protected && args.len() > 0 => {
|
||||||
|
backup = args[0].clone();
|
||||||
|
restore = true;
|
||||||
|
false
|
||||||
|
}
|
||||||
|
NativeFunctionABI::Pure => false,
|
||||||
|
NativeFunctionABI::Method => true,
|
||||||
|
};
|
||||||
|
|
||||||
// Run external function
|
// Run external function
|
||||||
let result = func.call(args, pos)?;
|
let result = match func.call(args, pos) {
|
||||||
|
Ok(r) => {
|
||||||
|
// Restore the backup value for the first argument since it has been consumed!
|
||||||
|
if restore {
|
||||||
|
*args[0] = backup;
|
||||||
|
}
|
||||||
|
r
|
||||||
|
}
|
||||||
|
Err(err) => return Err(err),
|
||||||
|
};
|
||||||
|
|
||||||
// See if the function match print/debug (which requires special processing)
|
// See if the function match print/debug (which requires special processing)
|
||||||
return Ok(match fn_name {
|
return Ok(match fn_name {
|
||||||
KEYWORD_PRINT => (self.print)(result.as_str().map_err(|type_name| {
|
KEYWORD_PRINT => (
|
||||||
Box::new(EvalAltResult::ErrorMismatchOutputType(
|
(self.print)(result.as_str().map_err(|type_name| {
|
||||||
type_name.into(),
|
Box::new(EvalAltResult::ErrorMismatchOutputType(
|
||||||
pos,
|
type_name.into(),
|
||||||
))
|
pos,
|
||||||
})?)
|
))
|
||||||
.into(),
|
})?)
|
||||||
KEYWORD_DEBUG => (self.debug)(result.as_str().map_err(|type_name| {
|
.into(),
|
||||||
Box::new(EvalAltResult::ErrorMismatchOutputType(
|
false,
|
||||||
type_name.into(),
|
),
|
||||||
pos,
|
KEYWORD_DEBUG => (
|
||||||
))
|
(self.debug)(result.as_str().map_err(|type_name| {
|
||||||
})?)
|
Box::new(EvalAltResult::ErrorMismatchOutputType(
|
||||||
.into(),
|
type_name.into(),
|
||||||
_ => result,
|
pos,
|
||||||
|
))
|
||||||
|
})?)
|
||||||
|
.into(),
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
_ => (result, updated),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return default value (if any)
|
// Return default value (if any)
|
||||||
if let Some(val) = def_val {
|
if let Some(val) = def_val {
|
||||||
return Ok(val.clone());
|
return Ok((val.clone(), false));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Getter function not found?
|
// Getter function not found?
|
||||||
@ -730,12 +762,13 @@ impl Engine {
|
|||||||
&self,
|
&self,
|
||||||
state: &State,
|
state: &State,
|
||||||
fn_name: &str,
|
fn_name: &str,
|
||||||
|
is_protected: bool,
|
||||||
hash_fn_def: u64,
|
hash_fn_def: u64,
|
||||||
args: &mut FnCallArgs,
|
args: &mut FnCallArgs,
|
||||||
def_val: Option<&Dynamic>,
|
def_val: Option<&Dynamic>,
|
||||||
pos: Position,
|
pos: Position,
|
||||||
level: usize,
|
level: usize,
|
||||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
) -> Result<(Dynamic, bool), Box<EvalAltResult>> {
|
||||||
// Qualifiers (none) + function name + argument `TypeId`'s.
|
// Qualifiers (none) + function name + argument `TypeId`'s.
|
||||||
let hash_fn_spec = calc_fn_hash(empty(), fn_name, args.iter().map(|a| a.type_id()));
|
let hash_fn_spec = calc_fn_hash(empty(), fn_name, args.iter().map(|a| a.type_id()));
|
||||||
|
|
||||||
@ -744,7 +777,10 @@ impl Engine {
|
|||||||
KEYWORD_TYPE_OF
|
KEYWORD_TYPE_OF
|
||||||
if args.len() == 1 && !self.has_override(state, hash_fn_spec, hash_fn_def) =>
|
if args.len() == 1 && !self.has_override(state, hash_fn_spec, hash_fn_def) =>
|
||||||
{
|
{
|
||||||
Ok(self.map_type_name(args[0].type_name()).to_string().into())
|
Ok((
|
||||||
|
self.map_type_name(args[0].type_name()).to_string().into(),
|
||||||
|
false,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
// eval - reaching this point it must be a method-style call
|
// eval - reaching this point it must be a method-style call
|
||||||
@ -757,11 +793,12 @@ impl Engine {
|
|||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normal method call
|
// Normal function call
|
||||||
_ => self.call_fn_raw(
|
_ => self.call_fn_raw(
|
||||||
None,
|
None,
|
||||||
state,
|
state,
|
||||||
fn_name,
|
fn_name,
|
||||||
|
is_protected,
|
||||||
hash_fn_spec,
|
hash_fn_spec,
|
||||||
hash_fn_def,
|
hash_fn_def,
|
||||||
args,
|
args,
|
||||||
@ -820,10 +857,10 @@ impl Engine {
|
|||||||
mut new_val: Option<Dynamic>,
|
mut new_val: Option<Dynamic>,
|
||||||
) -> Result<(Dynamic, bool), Box<EvalAltResult>> {
|
) -> Result<(Dynamic, bool), Box<EvalAltResult>> {
|
||||||
// Get a reference to the mutation target Dynamic
|
// Get a reference to the mutation target Dynamic
|
||||||
let obj = match target {
|
let (obj, is_protected) = match target {
|
||||||
Target::Ref(r) => r,
|
Target::Ref(r) => (r, true),
|
||||||
Target::Value(ref mut r) => r.as_mut(),
|
Target::Value(ref mut r) => (r.as_mut(), false),
|
||||||
Target::StringChar(ref mut x) => &mut x.2,
|
Target::StringChar(ref mut x) => (&mut x.2, false),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Pop the last index value
|
// Pop the last index value
|
||||||
@ -835,8 +872,15 @@ impl Engine {
|
|||||||
Expr::Dot(x) | Expr::Index(x) => {
|
Expr::Dot(x) | Expr::Index(x) => {
|
||||||
let is_index = matches!(rhs, Expr::Index(_));
|
let is_index = matches!(rhs, Expr::Index(_));
|
||||||
|
|
||||||
let indexed_val =
|
let indexed_val = self.get_indexed_mut(
|
||||||
self.get_indexed_mut(state, obj, idx_val, x.0.position(), op_pos, false)?;
|
state,
|
||||||
|
obj,
|
||||||
|
is_protected,
|
||||||
|
idx_val,
|
||||||
|
x.0.position(),
|
||||||
|
op_pos,
|
||||||
|
false,
|
||||||
|
)?;
|
||||||
self.eval_dot_index_chain_helper(
|
self.eval_dot_index_chain_helper(
|
||||||
state,
|
state,
|
||||||
indexed_val,
|
indexed_val,
|
||||||
@ -850,14 +894,29 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
// xxx[rhs] = new_val
|
// xxx[rhs] = new_val
|
||||||
_ if new_val.is_some() => {
|
_ if new_val.is_some() => {
|
||||||
let mut indexed_val =
|
let mut indexed_val = self.get_indexed_mut(
|
||||||
self.get_indexed_mut(state, obj, idx_val, rhs.position(), op_pos, true)?;
|
state,
|
||||||
|
obj,
|
||||||
|
is_protected,
|
||||||
|
idx_val,
|
||||||
|
rhs.position(),
|
||||||
|
op_pos,
|
||||||
|
true,
|
||||||
|
)?;
|
||||||
indexed_val.set_value(new_val.unwrap(), rhs.position())?;
|
indexed_val.set_value(new_val.unwrap(), rhs.position())?;
|
||||||
Ok((Default::default(), true))
|
Ok((Default::default(), true))
|
||||||
}
|
}
|
||||||
// xxx[rhs]
|
// xxx[rhs]
|
||||||
_ => self
|
_ => self
|
||||||
.get_indexed_mut(state, obj, idx_val, rhs.position(), op_pos, false)
|
.get_indexed_mut(
|
||||||
|
state,
|
||||||
|
obj,
|
||||||
|
is_protected,
|
||||||
|
idx_val,
|
||||||
|
rhs.position(),
|
||||||
|
op_pos,
|
||||||
|
false,
|
||||||
|
)
|
||||||
.map(|v| (v.clone_into_dynamic(), false)),
|
.map(|v| (v.clone_into_dynamic(), false)),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -865,8 +924,9 @@ impl Engine {
|
|||||||
// xxx.fn_name(arg_expr_list)
|
// xxx.fn_name(arg_expr_list)
|
||||||
Expr::FnCall(x) if x.1.is_none() => {
|
Expr::FnCall(x) if x.1.is_none() => {
|
||||||
let ((name, pos), _, hash, _, def_val) = x.as_ref();
|
let ((name, pos), _, hash, _, def_val) = x.as_ref();
|
||||||
|
let def_val = def_val.as_ref();
|
||||||
|
|
||||||
let mut args: StaticVec<_> = once(obj)
|
let mut arg_values: StaticVec<_> = once(obj)
|
||||||
.chain(
|
.chain(
|
||||||
idx_val
|
idx_val
|
||||||
.downcast_mut::<StaticVec<Dynamic>>()
|
.downcast_mut::<StaticVec<Dynamic>>()
|
||||||
@ -874,10 +934,9 @@ impl Engine {
|
|||||||
.iter_mut(),
|
.iter_mut(),
|
||||||
)
|
)
|
||||||
.collect();
|
.collect();
|
||||||
// A function call is assumed to have side effects, so the value is changed
|
let args = arg_values.as_mut();
|
||||||
// TODO - Remove assumption of side effects by checking whether the first parameter is &mut
|
|
||||||
self.exec_fn_call(state, name, *hash, args.as_mut(), def_val.as_ref(), *pos, 0)
|
self.exec_fn_call(state, name, is_protected, *hash, args, def_val, *pos, 0)
|
||||||
.map(|v| (v, true))
|
|
||||||
}
|
}
|
||||||
// xxx.module::fn_name(...) - syntax error
|
// xxx.module::fn_name(...) - syntax error
|
||||||
Expr::FnCall(_) => unreachable!(),
|
Expr::FnCall(_) => unreachable!(),
|
||||||
@ -886,7 +945,7 @@ impl Engine {
|
|||||||
Expr::Property(x) if obj.is::<Map>() && new_val.is_some() => {
|
Expr::Property(x) if obj.is::<Map>() && new_val.is_some() => {
|
||||||
let index = x.0.clone().into();
|
let index = x.0.clone().into();
|
||||||
let mut indexed_val =
|
let mut indexed_val =
|
||||||
self.get_indexed_mut(state, obj, index, x.1, op_pos, true)?;
|
self.get_indexed_mut(state, obj, is_protected, index, x.1, op_pos, true)?;
|
||||||
indexed_val.set_value(new_val.unwrap(), rhs.position())?;
|
indexed_val.set_value(new_val.unwrap(), rhs.position())?;
|
||||||
Ok((Default::default(), true))
|
Ok((Default::default(), true))
|
||||||
}
|
}
|
||||||
@ -895,22 +954,22 @@ impl Engine {
|
|||||||
Expr::Property(x) if obj.is::<Map>() => {
|
Expr::Property(x) if obj.is::<Map>() => {
|
||||||
let index = x.0.clone().into();
|
let index = x.0.clone().into();
|
||||||
let indexed_val =
|
let indexed_val =
|
||||||
self.get_indexed_mut(state, obj, index, x.1, op_pos, false)?;
|
self.get_indexed_mut(state, obj, is_protected, index, x.1, op_pos, false)?;
|
||||||
Ok((indexed_val.clone_into_dynamic(), false))
|
Ok((indexed_val.clone_into_dynamic(), false))
|
||||||
}
|
}
|
||||||
// xxx.id = ??? a
|
// xxx.id = ??? a
|
||||||
Expr::Property(x) if new_val.is_some() => {
|
Expr::Property(x) if new_val.is_some() => {
|
||||||
let fn_name = make_setter(&x.0);
|
let fn_name = make_setter(&x.0);
|
||||||
let mut args = [obj, new_val.as_mut().unwrap()];
|
let mut args = [obj, new_val.as_mut().unwrap()];
|
||||||
self.exec_fn_call(state, &fn_name, 0, &mut args, None, x.1, 0)
|
self.exec_fn_call(state, &fn_name, is_protected, 0, &mut args, None, x.1, 0)
|
||||||
.map(|v| (v, true))
|
.map(|(v, _)| (v, true))
|
||||||
}
|
}
|
||||||
// xxx.id
|
// xxx.id
|
||||||
Expr::Property(x) => {
|
Expr::Property(x) => {
|
||||||
let fn_name = make_getter(&x.0);
|
let fn_name = make_getter(&x.0);
|
||||||
let mut args = [obj];
|
let mut args = [obj];
|
||||||
self.exec_fn_call(state, &fn_name, 0, &mut args, None, x.1, 0)
|
self.exec_fn_call(state, &fn_name, is_protected, 0, &mut args, None, x.1, 0)
|
||||||
.map(|v| (v, false))
|
.map(|(v, _)| (v, false))
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
// {xxx:map}.idx_lhs[idx_expr] | {xxx:map}.dot_lhs.rhs
|
// {xxx:map}.idx_lhs[idx_expr] | {xxx:map}.dot_lhs.rhs
|
||||||
@ -919,7 +978,7 @@ impl Engine {
|
|||||||
|
|
||||||
let indexed_val = if let Expr::Property(p) = &x.0 {
|
let indexed_val = if let Expr::Property(p) = &x.0 {
|
||||||
let index = p.0.clone().into();
|
let index = p.0.clone().into();
|
||||||
self.get_indexed_mut(state, obj, index, x.2, op_pos, false)?
|
self.get_indexed_mut(state, obj, is_protected, index, x.2, op_pos, false)?
|
||||||
} else {
|
} else {
|
||||||
// Syntax error
|
// Syntax error
|
||||||
return Err(Box::new(EvalAltResult::ErrorDotExpr(
|
return Err(Box::new(EvalAltResult::ErrorDotExpr(
|
||||||
@ -941,18 +1000,21 @@ impl Engine {
|
|||||||
// xxx.idx_lhs[idx_expr] | xxx.dot_lhs.rhs
|
// xxx.idx_lhs[idx_expr] | xxx.dot_lhs.rhs
|
||||||
Expr::Index(x) | Expr::Dot(x) => {
|
Expr::Index(x) | Expr::Dot(x) => {
|
||||||
let is_index = matches!(rhs, Expr::Index(_));
|
let is_index = matches!(rhs, Expr::Index(_));
|
||||||
let mut args = [obj, &mut Default::default()];
|
let mut arg_values = [obj, &mut Default::default()];
|
||||||
|
|
||||||
let indexed_val = &mut (if let Expr::Property(p) = &x.0 {
|
let (mut indexed_val, updated) = if let Expr::Property(p) = &x.0 {
|
||||||
let fn_name = make_getter(&p.0);
|
let fn_name = make_getter(&p.0);
|
||||||
self.exec_fn_call(state, &fn_name, 0, &mut args[..1], None, x.2, 0)?
|
let args = &mut arg_values[..1];
|
||||||
|
self.exec_fn_call(state, &fn_name, is_protected, 0, args, None, x.2, 0)?
|
||||||
} else {
|
} else {
|
||||||
// Syntax error
|
// Syntax error
|
||||||
return Err(Box::new(EvalAltResult::ErrorDotExpr(
|
return Err(Box::new(EvalAltResult::ErrorDotExpr(
|
||||||
"".to_string(),
|
"".to_string(),
|
||||||
rhs.position(),
|
rhs.position(),
|
||||||
)));
|
)));
|
||||||
});
|
};
|
||||||
|
let indexed_val = &mut indexed_val;
|
||||||
|
|
||||||
let (result, may_be_changed) = self.eval_dot_index_chain_helper(
|
let (result, may_be_changed) = self.eval_dot_index_chain_helper(
|
||||||
state,
|
state,
|
||||||
indexed_val.into(),
|
indexed_val.into(),
|
||||||
@ -965,12 +1027,13 @@ impl Engine {
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Feed the value back via a setter just in case it has been updated
|
// Feed the value back via a setter just in case it has been updated
|
||||||
if may_be_changed {
|
if updated || may_be_changed {
|
||||||
if let Expr::Property(p) = &x.0 {
|
if let Expr::Property(p) = &x.0 {
|
||||||
let fn_name = make_setter(&p.0);
|
let fn_name = make_setter(&p.0);
|
||||||
// Re-use args because the first &mut parameter will not be consumed
|
// Re-use args because the first &mut parameter will not be consumed
|
||||||
args[1] = indexed_val;
|
arg_values[1] = indexed_val;
|
||||||
self.exec_fn_call(state, &fn_name, 0, &mut args, None, x.2, 0)
|
let args = &mut arg_values;
|
||||||
|
self.exec_fn_call(state, &fn_name, is_protected, 0, args, None, x.2, 0)
|
||||||
.or_else(|err| match *err {
|
.or_else(|err| match *err {
|
||||||
// If there is no setter, no need to feed it back because the property is read-only
|
// If there is no setter, no need to feed it back because the property is read-only
|
||||||
EvalAltResult::ErrorDotExpr(_, _) => Ok(Default::default()),
|
EvalAltResult::ErrorDotExpr(_, _) => Ok(Default::default()),
|
||||||
@ -1099,6 +1162,7 @@ impl Engine {
|
|||||||
&self,
|
&self,
|
||||||
state: &State,
|
state: &State,
|
||||||
val: &'a mut Dynamic,
|
val: &'a mut Dynamic,
|
||||||
|
is_protected: bool,
|
||||||
mut idx: Dynamic,
|
mut idx: Dynamic,
|
||||||
idx_pos: Position,
|
idx_pos: Position,
|
||||||
op_pos: Position,
|
op_pos: Position,
|
||||||
@ -1177,8 +1241,8 @@ impl Engine {
|
|||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
let args = &mut [val, &mut idx];
|
let args = &mut [val, &mut idx];
|
||||||
self.exec_fn_call(state, FUNC_INDEXER, 0, args, None, op_pos, 0)
|
self.exec_fn_call(state, FUNC_INDEXER, is_protected, 0, args, None, op_pos, 0)
|
||||||
.map(|v| v.into())
|
.map(|(v, _)| v.into())
|
||||||
.map_err(|_| {
|
.map_err(|_| {
|
||||||
Box::new(EvalAltResult::ErrorIndexingType(
|
Box::new(EvalAltResult::ErrorIndexingType(
|
||||||
// Error - cannot be indexed
|
// Error - cannot be indexed
|
||||||
@ -1223,8 +1287,9 @@ impl Engine {
|
|||||||
|
|
||||||
if self
|
if self
|
||||||
.call_fn_raw(
|
.call_fn_raw(
|
||||||
None, state, op, fn_spec, fn_def, args, def_value, pos, level,
|
None, state, op, false, fn_spec, fn_def, args, def_value, pos, level,
|
||||||
)?
|
)?
|
||||||
|
.0
|
||||||
.as_bool()
|
.as_bool()
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
{
|
{
|
||||||
@ -1398,12 +1463,14 @@ impl Engine {
|
|||||||
self.exec_fn_call(
|
self.exec_fn_call(
|
||||||
state,
|
state,
|
||||||
name,
|
name,
|
||||||
|
false,
|
||||||
*hash_fn_def,
|
*hash_fn_def,
|
||||||
args.as_mut(),
|
args.as_mut(),
|
||||||
def_val.as_ref(),
|
def_val.as_ref(),
|
||||||
*pos,
|
*pos,
|
||||||
level,
|
level,
|
||||||
)
|
)
|
||||||
|
.map(|(v, _)| v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,30 +17,45 @@ pub type IteratorFn = dyn Fn(Dynamic) -> Box<dyn Iterator<Item = Dynamic>> + Sen
|
|||||||
#[cfg(not(feature = "sync"))]
|
#[cfg(not(feature = "sync"))]
|
||||||
pub type IteratorFn = dyn Fn(Dynamic) -> Box<dyn Iterator<Item = Dynamic>>;
|
pub type IteratorFn = dyn Fn(Dynamic) -> Box<dyn Iterator<Item = Dynamic>>;
|
||||||
|
|
||||||
|
/// A type representing the type of ABI of a native Rust function.
|
||||||
|
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
||||||
|
pub enum NativeFunctionABI {
|
||||||
|
/// A pure function where all arguments are passed by value.
|
||||||
|
Pure,
|
||||||
|
/// An object method where the first argument is the object passed by mutable reference.
|
||||||
|
/// All other arguments are passed by value.
|
||||||
|
Method,
|
||||||
|
}
|
||||||
|
|
||||||
/// A trait implemented by all native Rust functions that are callable by Rhai.
|
/// A trait implemented by all native Rust functions that are callable by Rhai.
|
||||||
pub trait NativeCallable {
|
pub trait NativeCallable {
|
||||||
|
/// Get the ABI type of a native Rust function.
|
||||||
|
fn abi(&self) -> NativeFunctionABI;
|
||||||
/// Call a native Rust function.
|
/// Call a native Rust function.
|
||||||
fn call(&self, args: &mut FnCallArgs, pos: Position) -> Result<Dynamic, Box<EvalAltResult>>;
|
fn call(&self, args: &mut FnCallArgs, pos: Position) -> Result<Dynamic, Box<EvalAltResult>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A type encapsulating a native Rust function callable by Rhai.
|
/// A type encapsulating a native Rust function callable by Rhai.
|
||||||
pub struct NativeFunction(Box<FnAny>);
|
pub struct NativeFunction(Box<FnAny>, NativeFunctionABI);
|
||||||
|
|
||||||
impl NativeCallable for NativeFunction {
|
impl NativeCallable for NativeFunction {
|
||||||
|
fn abi(&self) -> NativeFunctionABI {
|
||||||
|
self.1
|
||||||
|
}
|
||||||
fn call(&self, args: &mut FnCallArgs, pos: Position) -> Result<Dynamic, Box<EvalAltResult>> {
|
fn call(&self, args: &mut FnCallArgs, pos: Position) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
(self.0)(args, pos)
|
(self.0)(args, pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Box<FnAny>> for NativeFunction {
|
impl From<(Box<FnAny>, NativeFunctionABI)> for NativeFunction {
|
||||||
fn from(func: Box<FnAny>) -> Self {
|
fn from(func: (Box<FnAny>, NativeFunctionABI)) -> Self {
|
||||||
Self::new(func)
|
Self::new(func.0, func.1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl NativeFunction {
|
impl NativeFunction {
|
||||||
/// Create a new `NativeFunction`.
|
/// Create a new `NativeFunction`.
|
||||||
pub fn new(func: Box<FnAny>) -> Self {
|
pub fn new(func: Box<FnAny>, abi: NativeFunctionABI) -> Self {
|
||||||
Self(func)
|
Self(func, abi)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
use crate::any::{Dynamic, Variant};
|
use crate::any::{Dynamic, Variant};
|
||||||
use crate::engine::Engine;
|
use crate::engine::Engine;
|
||||||
use crate::fn_native::{FnCallArgs, NativeFunction};
|
use crate::fn_native::{FnCallArgs, NativeFunction, NativeFunctionABI::*};
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::token::Position;
|
use crate::token::Position;
|
||||||
use crate::utils::calc_fn_spec;
|
use crate::utils::calc_fn_spec;
|
||||||
@ -134,11 +134,12 @@ pub fn by_value<T: Clone + 'static>(data: &mut Dynamic) -> T {
|
|||||||
|
|
||||||
/// This macro creates a closure wrapping a registered function.
|
/// This macro creates a closure wrapping a registered function.
|
||||||
macro_rules! make_func {
|
macro_rules! make_func {
|
||||||
($fn:ident : $map:expr ; $($par:ident => $convert:expr),*) => {
|
($fn:ident : $abi:expr ; $map:expr ; $($par:ident => $convert:expr),*) => {
|
||||||
// ^ function pointer
|
// ^ function pointer
|
||||||
// ^ result mapping function
|
// ^ function ABI type
|
||||||
// ^ function parameter generic type name (A, B, C etc.)
|
// ^ result mapping function
|
||||||
// ^ dereferencing function
|
// ^ function parameter generic type name (A, B, C etc.)
|
||||||
|
// ^ dereferencing function
|
||||||
|
|
||||||
NativeFunction::new(Box::new(move |args: &mut FnCallArgs, pos: Position| {
|
NativeFunction::new(Box::new(move |args: &mut FnCallArgs, pos: Position| {
|
||||||
// The arguments are assumed to be of the correct number and types!
|
// The arguments are assumed to be of the correct number and types!
|
||||||
@ -156,7 +157,7 @@ macro_rules! make_func {
|
|||||||
|
|
||||||
// Map the result
|
// Map the result
|
||||||
$map(r, pos)
|
$map(r, pos)
|
||||||
}));
|
}), $abi);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,13 +188,14 @@ pub fn map_result<T: Variant + Clone>(
|
|||||||
|
|
||||||
macro_rules! def_register {
|
macro_rules! def_register {
|
||||||
() => {
|
() => {
|
||||||
def_register!(imp);
|
def_register!(imp Pure;);
|
||||||
};
|
};
|
||||||
(imp $($par:ident => $mark:ty => $param:ty => $clone:expr),*) => {
|
(imp $abi:expr ; $($par:ident => $mark:ty => $param:ty => $clone:expr),*) => {
|
||||||
// ^ function parameter generic type name (A, B, C etc.)
|
// ^ function ABI type
|
||||||
// ^ function parameter marker type (T, Ref<T> or Mut<T>)
|
// ^ function parameter generic type name (A, B, C etc.)
|
||||||
// ^ function parameter actual type (T, &T or &mut T)
|
// ^ function parameter marker type (T, Ref<T> or Mut<T>)
|
||||||
// ^ dereferencing function
|
// ^ function parameter actual type (T, &T or &mut T)
|
||||||
|
// ^ dereferencing function
|
||||||
impl<
|
impl<
|
||||||
$($par: Variant + Clone,)*
|
$($par: Variant + Clone,)*
|
||||||
|
|
||||||
@ -207,7 +209,7 @@ macro_rules! def_register {
|
|||||||
> RegisterFn<FN, ($($mark,)*), RET> for Engine
|
> RegisterFn<FN, ($($mark,)*), RET> for Engine
|
||||||
{
|
{
|
||||||
fn register_fn(&mut self, name: &str, f: FN) {
|
fn register_fn(&mut self, name: &str, f: FN) {
|
||||||
let func = make_func!(f : map_dynamic ; $($par => $clone),*);
|
let func = make_func!(f : $abi ; map_dynamic ; $($par => $clone),*);
|
||||||
let hash = calc_fn_spec(empty(), name, [$(TypeId::of::<$par>()),*].iter().cloned());
|
let hash = calc_fn_spec(empty(), name, [$(TypeId::of::<$par>()),*].iter().cloned());
|
||||||
self.base_package.functions.insert(hash, Box::new(func));
|
self.base_package.functions.insert(hash, Box::new(func));
|
||||||
}
|
}
|
||||||
@ -224,7 +226,7 @@ macro_rules! def_register {
|
|||||||
> RegisterDynamicFn<FN, ($($mark,)*)> for Engine
|
> RegisterDynamicFn<FN, ($($mark,)*)> for Engine
|
||||||
{
|
{
|
||||||
fn register_dynamic_fn(&mut self, name: &str, f: FN) {
|
fn register_dynamic_fn(&mut self, name: &str, f: FN) {
|
||||||
let func = make_func!(f : map_identity ; $($par => $clone),*);
|
let func = make_func!(f : $abi ; map_identity ; $($par => $clone),*);
|
||||||
let hash = calc_fn_spec(empty(), name, [$(TypeId::of::<$par>()),*].iter().cloned());
|
let hash = calc_fn_spec(empty(), name, [$(TypeId::of::<$par>()),*].iter().cloned());
|
||||||
self.base_package.functions.insert(hash, Box::new(func));
|
self.base_package.functions.insert(hash, Box::new(func));
|
||||||
}
|
}
|
||||||
@ -242,7 +244,7 @@ macro_rules! def_register {
|
|||||||
> RegisterResultFn<FN, ($($mark,)*), RET> for Engine
|
> RegisterResultFn<FN, ($($mark,)*), RET> for Engine
|
||||||
{
|
{
|
||||||
fn register_result_fn(&mut self, name: &str, f: FN) {
|
fn register_result_fn(&mut self, name: &str, f: FN) {
|
||||||
let func = make_func!(f : map_result ; $($par => $clone),*);
|
let func = make_func!(f : $abi ; map_result ; $($par => $clone),*);
|
||||||
let hash = calc_fn_spec(empty(), name, [$(TypeId::of::<$par>()),*].iter().cloned());
|
let hash = calc_fn_spec(empty(), name, [$(TypeId::of::<$par>()),*].iter().cloned());
|
||||||
self.base_package.functions.insert(hash, Box::new(func));
|
self.base_package.functions.insert(hash, Box::new(func));
|
||||||
}
|
}
|
||||||
@ -251,10 +253,10 @@ macro_rules! def_register {
|
|||||||
//def_register!(imp_pop $($par => $mark => $param),*);
|
//def_register!(imp_pop $($par => $mark => $param),*);
|
||||||
};
|
};
|
||||||
($p0:ident $(, $p:ident)*) => {
|
($p0:ident $(, $p:ident)*) => {
|
||||||
def_register!(imp $p0 => $p0 => $p0 => by_value $(, $p => $p => $p => by_value)*);
|
def_register!(imp Pure ; $p0 => $p0 => $p0 => by_value $(, $p => $p => $p => by_value)*);
|
||||||
def_register!(imp $p0 => Mut<$p0> => &mut $p0 => by_ref $(, $p => $p => $p => by_value)*);
|
def_register!(imp Method ; $p0 => Mut<$p0> => &mut $p0 => by_ref $(, $p => $p => $p => by_value)*);
|
||||||
// handle the first parameter ^ first parameter passed through
|
// handle the first parameter ^ first parameter passed through
|
||||||
// ^ others passed by value (by_value)
|
// ^ others passed by value (by_value)
|
||||||
|
|
||||||
// Currently does not support first argument which is a reference, as there will be
|
// Currently does not support first argument which is a reference, as there will be
|
||||||
// conflicting implementations since &T: Any and T: Any cannot be distinguished
|
// conflicting implementations since &T: Any and T: Any cannot be distinguished
|
||||||
|
@ -4,7 +4,10 @@
|
|||||||
use crate::any::{Dynamic, Variant};
|
use crate::any::{Dynamic, Variant};
|
||||||
use crate::calc_fn_hash;
|
use crate::calc_fn_hash;
|
||||||
use crate::engine::{Engine, FunctionsLib};
|
use crate::engine::{Engine, FunctionsLib};
|
||||||
use crate::fn_native::{FnAny, FnCallArgs, NativeCallable, NativeFunction, SharedNativeFunction};
|
use crate::fn_native::{
|
||||||
|
FnAny, FnCallArgs, NativeCallable, NativeFunction, NativeFunctionABI, NativeFunctionABI::*,
|
||||||
|
SharedNativeFunction,
|
||||||
|
};
|
||||||
use crate::parser::{FnAccess, FnDef, SharedFnDef, AST};
|
use crate::parser::{FnAccess, FnDef, SharedFnDef, AST};
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::scope::{Entry as ScopeEntry, EntryType as ScopeEntryType, Scope};
|
use crate::scope::{Entry as ScopeEntry, EntryType as ScopeEntryType, Scope};
|
||||||
@ -39,6 +42,9 @@ pub trait ModuleResolver {
|
|||||||
) -> Result<Module, Box<EvalAltResult>>;
|
) -> Result<Module, Box<EvalAltResult>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Default function access mode.
|
||||||
|
const DEF_ACCESS: FnAccess = FnAccess::Public;
|
||||||
|
|
||||||
/// Return type of module-level Rust function.
|
/// Return type of module-level Rust function.
|
||||||
type FuncReturn<T> = Result<T, Box<EvalAltResult>>;
|
type FuncReturn<T> = Result<T, Box<EvalAltResult>>;
|
||||||
|
|
||||||
@ -263,21 +269,22 @@ impl Module {
|
|||||||
/// If there is an existing Rust function of the same hash, it is replaced.
|
/// If there is an existing Rust function of the same hash, it is replaced.
|
||||||
pub fn set_fn(
|
pub fn set_fn(
|
||||||
&mut self,
|
&mut self,
|
||||||
fn_name: String,
|
name: String,
|
||||||
|
abi: NativeFunctionABI,
|
||||||
access: FnAccess,
|
access: FnAccess,
|
||||||
params: Vec<TypeId>,
|
params: Vec<TypeId>,
|
||||||
func: Box<FnAny>,
|
func: Box<FnAny>,
|
||||||
) -> u64 {
|
) -> u64 {
|
||||||
let hash = calc_fn_hash(empty(), &fn_name, params.iter().cloned());
|
let hash = calc_fn_hash(empty(), &name, params.iter().cloned());
|
||||||
|
|
||||||
let f = Box::new(NativeFunction::from(func)) as Box<dyn NativeCallable>;
|
let f = Box::new(NativeFunction::from((func, abi))) as Box<dyn NativeCallable>;
|
||||||
|
|
||||||
#[cfg(not(feature = "sync"))]
|
#[cfg(not(feature = "sync"))]
|
||||||
let func = Rc::new(f);
|
let func = Rc::new(f);
|
||||||
#[cfg(feature = "sync")]
|
#[cfg(feature = "sync")]
|
||||||
let func = Arc::new(f);
|
let func = Arc::new(f);
|
||||||
|
|
||||||
self.functions.insert(hash, (fn_name, access, params, func));
|
self.functions.insert(hash, (name, access, params, func));
|
||||||
|
|
||||||
hash
|
hash
|
||||||
}
|
}
|
||||||
@ -297,7 +304,7 @@ impl Module {
|
|||||||
/// ```
|
/// ```
|
||||||
pub fn set_fn_0<K: Into<String>, T: Into<Dynamic>>(
|
pub fn set_fn_0<K: Into<String>, T: Into<Dynamic>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
fn_name: K,
|
name: K,
|
||||||
#[cfg(not(feature = "sync"))] func: impl Fn() -> FuncReturn<T> + 'static,
|
#[cfg(not(feature = "sync"))] func: impl Fn() -> FuncReturn<T> + 'static,
|
||||||
#[cfg(feature = "sync")] func: impl Fn() -> FuncReturn<T> + Send + Sync + 'static,
|
#[cfg(feature = "sync")] func: impl Fn() -> FuncReturn<T> + Send + Sync + 'static,
|
||||||
) -> u64 {
|
) -> u64 {
|
||||||
@ -307,7 +314,7 @@ impl Module {
|
|||||||
.map_err(|err| EvalAltResult::set_position(err, pos))
|
.map_err(|err| EvalAltResult::set_position(err, pos))
|
||||||
};
|
};
|
||||||
let arg_types = vec![];
|
let arg_types = vec![];
|
||||||
self.set_fn(fn_name.into(), FnAccess::Public, arg_types, Box::new(f))
|
self.set_fn(name.into(), Pure, DEF_ACCESS, arg_types, Box::new(f))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a Rust function taking one parameter into the module, returning a hash key.
|
/// Set a Rust function taking one parameter into the module, returning a hash key.
|
||||||
@ -325,7 +332,7 @@ impl Module {
|
|||||||
/// ```
|
/// ```
|
||||||
pub fn set_fn_1<K: Into<String>, A: Variant + Clone, T: Into<Dynamic>>(
|
pub fn set_fn_1<K: Into<String>, A: Variant + Clone, T: Into<Dynamic>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
fn_name: K,
|
name: K,
|
||||||
#[cfg(not(feature = "sync"))] func: impl Fn(A) -> FuncReturn<T> + 'static,
|
#[cfg(not(feature = "sync"))] func: impl Fn(A) -> FuncReturn<T> + 'static,
|
||||||
#[cfg(feature = "sync")] func: impl Fn(A) -> FuncReturn<T> + Send + Sync + 'static,
|
#[cfg(feature = "sync")] func: impl Fn(A) -> FuncReturn<T> + Send + Sync + 'static,
|
||||||
) -> u64 {
|
) -> u64 {
|
||||||
@ -335,7 +342,7 @@ impl Module {
|
|||||||
.map_err(|err| EvalAltResult::set_position(err, pos))
|
.map_err(|err| EvalAltResult::set_position(err, pos))
|
||||||
};
|
};
|
||||||
let arg_types = vec![TypeId::of::<A>()];
|
let arg_types = vec![TypeId::of::<A>()];
|
||||||
self.set_fn(fn_name.into(), FnAccess::Public, arg_types, Box::new(f))
|
self.set_fn(name.into(), Pure, DEF_ACCESS, arg_types, Box::new(f))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a Rust function taking one mutable parameter into the module, returning a hash key.
|
/// Set a Rust function taking one mutable parameter into the module, returning a hash key.
|
||||||
@ -353,7 +360,7 @@ impl Module {
|
|||||||
/// ```
|
/// ```
|
||||||
pub fn set_fn_1_mut<K: Into<String>, A: Variant + Clone, T: Into<Dynamic>>(
|
pub fn set_fn_1_mut<K: Into<String>, A: Variant + Clone, T: Into<Dynamic>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
fn_name: K,
|
name: K,
|
||||||
#[cfg(not(feature = "sync"))] func: impl Fn(&mut A) -> FuncReturn<T> + 'static,
|
#[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,
|
#[cfg(feature = "sync")] func: impl Fn(&mut A) -> FuncReturn<T> + Send + Sync + 'static,
|
||||||
) -> u64 {
|
) -> u64 {
|
||||||
@ -363,7 +370,7 @@ impl Module {
|
|||||||
.map_err(|err| EvalAltResult::set_position(err, pos))
|
.map_err(|err| EvalAltResult::set_position(err, pos))
|
||||||
};
|
};
|
||||||
let arg_types = vec![TypeId::of::<A>()];
|
let arg_types = vec![TypeId::of::<A>()];
|
||||||
self.set_fn(fn_name.into(), FnAccess::Public, arg_types, Box::new(f))
|
self.set_fn(name.into(), Method, DEF_ACCESS, arg_types, Box::new(f))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a Rust function taking two parameters into the module, returning a hash key.
|
/// Set a Rust function taking two parameters into the module, returning a hash key.
|
||||||
@ -383,7 +390,7 @@ impl Module {
|
|||||||
/// ```
|
/// ```
|
||||||
pub fn set_fn_2<K: Into<String>, A: Variant + Clone, B: Variant + Clone, T: Into<Dynamic>>(
|
pub fn set_fn_2<K: Into<String>, A: Variant + Clone, B: Variant + Clone, T: Into<Dynamic>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
fn_name: K,
|
name: K,
|
||||||
#[cfg(not(feature = "sync"))] func: impl Fn(A, B) -> FuncReturn<T> + 'static,
|
#[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,
|
#[cfg(feature = "sync")] func: impl Fn(A, B) -> FuncReturn<T> + Send + Sync + 'static,
|
||||||
) -> u64 {
|
) -> u64 {
|
||||||
@ -396,7 +403,7 @@ impl Module {
|
|||||||
.map_err(|err| EvalAltResult::set_position(err, pos))
|
.map_err(|err| EvalAltResult::set_position(err, pos))
|
||||||
};
|
};
|
||||||
let arg_types = vec![TypeId::of::<A>(), TypeId::of::<B>()];
|
let arg_types = vec![TypeId::of::<A>(), TypeId::of::<B>()];
|
||||||
self.set_fn(fn_name.into(), FnAccess::Public, arg_types, Box::new(f))
|
self.set_fn(name.into(), Pure, DEF_ACCESS, arg_types, Box::new(f))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a Rust function taking two parameters (the first one mutable) into the module,
|
/// Set a Rust function taking two parameters (the first one mutable) into the module,
|
||||||
@ -420,7 +427,7 @@ impl Module {
|
|||||||
T: Into<Dynamic>,
|
T: Into<Dynamic>,
|
||||||
>(
|
>(
|
||||||
&mut self,
|
&mut self,
|
||||||
fn_name: K,
|
name: K,
|
||||||
#[cfg(not(feature = "sync"))] func: impl Fn(&mut A, B) -> FuncReturn<T> + 'static,
|
#[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,
|
#[cfg(feature = "sync")] func: impl Fn(&mut A, B) -> FuncReturn<T> + Send + Sync + 'static,
|
||||||
) -> u64 {
|
) -> u64 {
|
||||||
@ -433,7 +440,7 @@ impl Module {
|
|||||||
.map_err(|err| EvalAltResult::set_position(err, pos))
|
.map_err(|err| EvalAltResult::set_position(err, pos))
|
||||||
};
|
};
|
||||||
let arg_types = vec![TypeId::of::<A>(), TypeId::of::<B>()];
|
let arg_types = vec![TypeId::of::<A>(), TypeId::of::<B>()];
|
||||||
self.set_fn(fn_name.into(), FnAccess::Public, arg_types, Box::new(f))
|
self.set_fn(name.into(), Method, DEF_ACCESS, arg_types, Box::new(f))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a Rust function taking three parameters into the module, returning a hash key.
|
/// Set a Rust function taking three parameters into the module, returning a hash key.
|
||||||
@ -459,7 +466,7 @@ impl Module {
|
|||||||
T: Into<Dynamic>,
|
T: Into<Dynamic>,
|
||||||
>(
|
>(
|
||||||
&mut self,
|
&mut self,
|
||||||
fn_name: K,
|
name: K,
|
||||||
#[cfg(not(feature = "sync"))] func: impl Fn(A, B, C) -> FuncReturn<T> + 'static,
|
#[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,
|
#[cfg(feature = "sync")] func: impl Fn(A, B, C) -> FuncReturn<T> + Send + Sync + 'static,
|
||||||
) -> u64 {
|
) -> u64 {
|
||||||
@ -473,7 +480,7 @@ impl Module {
|
|||||||
.map_err(|err| EvalAltResult::set_position(err, pos))
|
.map_err(|err| EvalAltResult::set_position(err, pos))
|
||||||
};
|
};
|
||||||
let arg_types = vec![TypeId::of::<A>(), TypeId::of::<B>(), TypeId::of::<C>()];
|
let arg_types = vec![TypeId::of::<A>(), TypeId::of::<B>(), TypeId::of::<C>()];
|
||||||
self.set_fn(fn_name.into(), FnAccess::Public, arg_types, Box::new(f))
|
self.set_fn(name.into(), Pure, DEF_ACCESS, arg_types, Box::new(f))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a Rust function taking three parameters (the first one mutable) into the module,
|
/// Set a Rust function taking three parameters (the first one mutable) into the module,
|
||||||
@ -500,7 +507,7 @@ impl Module {
|
|||||||
T: Into<Dynamic>,
|
T: Into<Dynamic>,
|
||||||
>(
|
>(
|
||||||
&mut self,
|
&mut self,
|
||||||
fn_name: K,
|
name: K,
|
||||||
#[cfg(not(feature = "sync"))] func: impl Fn(&mut A, B, C) -> FuncReturn<T> + 'static,
|
#[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,
|
#[cfg(feature = "sync")] func: impl Fn(&mut A, B, C) -> FuncReturn<T> + Send + Sync + 'static,
|
||||||
) -> u64 {
|
) -> u64 {
|
||||||
@ -514,7 +521,7 @@ impl Module {
|
|||||||
.map_err(|err| EvalAltResult::set_position(err, pos))
|
.map_err(|err| EvalAltResult::set_position(err, pos))
|
||||||
};
|
};
|
||||||
let arg_types = vec![TypeId::of::<A>(), TypeId::of::<B>(), TypeId::of::<C>()];
|
let arg_types = vec![TypeId::of::<A>(), TypeId::of::<B>(), TypeId::of::<C>()];
|
||||||
self.set_fn(fn_name.into(), FnAccess::Public, arg_types, Box::new(f))
|
self.set_fn(name.into(), Method, DEF_ACCESS, arg_types, Box::new(f))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a Rust function.
|
/// Get a Rust function.
|
||||||
@ -646,7 +653,7 @@ impl Module {
|
|||||||
variables.push((hash, value.clone()));
|
variables.push((hash, value.clone()));
|
||||||
}
|
}
|
||||||
// Index all Rust functions
|
// Index all Rust functions
|
||||||
for (fn_name, access, params, func) in module.functions.values() {
|
for (name, access, params, func) in module.functions.values() {
|
||||||
match access {
|
match access {
|
||||||
// Private functions are not exported
|
// Private functions are not exported
|
||||||
FnAccess::Private => continue,
|
FnAccess::Private => continue,
|
||||||
@ -657,7 +664,7 @@ impl Module {
|
|||||||
// i.e. qualifiers + function name + dummy parameter types (one for each parameter).
|
// i.e. qualifiers + function name + dummy parameter types (one for each parameter).
|
||||||
let hash_fn_def = calc_fn_hash(
|
let hash_fn_def = calc_fn_hash(
|
||||||
qualifiers.iter().map(|&v| v),
|
qualifiers.iter().map(|&v| v),
|
||||||
fn_name,
|
name,
|
||||||
repeat(EMPTY_TYPE_ID()).take(params.len()),
|
repeat(EMPTY_TYPE_ID()).take(params.len()),
|
||||||
);
|
);
|
||||||
// 2) Calculate a second hash with no qualifiers, empty function name, and
|
// 2) Calculate a second hash with no qualifiers, empty function name, and
|
||||||
@ -673,7 +680,7 @@ impl Module {
|
|||||||
match fn_def.access {
|
match fn_def.access {
|
||||||
// Private functions are not exported
|
// Private functions are not exported
|
||||||
FnAccess::Private => continue,
|
FnAccess::Private => continue,
|
||||||
FnAccess::Public => (),
|
DEF_ACCESS => (),
|
||||||
}
|
}
|
||||||
// Qualifiers + function name + placeholders (one for each parameter)
|
// Qualifiers + function name + placeholders (one for each parameter)
|
||||||
let hash = calc_fn_hash(
|
let hash = calc_fn_hash(
|
||||||
|
@ -118,9 +118,8 @@ def_package!(crate:BasicArrayPackage:"Basic array utilities.", lib, {
|
|||||||
// Register array iterator
|
// Register array iterator
|
||||||
lib.type_iterators.insert(
|
lib.type_iterators.insert(
|
||||||
TypeId::of::<Array>(),
|
TypeId::of::<Array>(),
|
||||||
Box::new(|a: Dynamic| {
|
Box::new(|arr| Box::new(
|
||||||
Box::new(a.cast::<Array>().into_iter())
|
arr.cast::<Array>().into_iter()) as Box<dyn Iterator<Item = Dynamic>>
|
||||||
as Box<dyn Iterator<Item = Dynamic>>
|
),
|
||||||
}),
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -18,7 +18,7 @@ where
|
|||||||
{
|
{
|
||||||
lib.type_iterators.insert(
|
lib.type_iterators.insert(
|
||||||
TypeId::of::<Range<T>>(),
|
TypeId::of::<Range<T>>(),
|
||||||
Box::new(|source: Dynamic| {
|
Box::new(|source| {
|
||||||
Box::new(source.cast::<Range<T>>().map(|x| x.into_dynamic()))
|
Box::new(source.cast::<Range<T>>().map(|x| x.into_dynamic()))
|
||||||
as Box<dyn Iterator<Item = Dynamic>>
|
as Box<dyn Iterator<Item = Dynamic>>
|
||||||
}),
|
}),
|
||||||
@ -58,7 +58,7 @@ where
|
|||||||
{
|
{
|
||||||
lib.type_iterators.insert(
|
lib.type_iterators.insert(
|
||||||
TypeId::of::<StepRange<T>>(),
|
TypeId::of::<StepRange<T>>(),
|
||||||
Box::new(|source: Dynamic| {
|
Box::new(|source| {
|
||||||
Box::new(source.cast::<StepRange<T>>().map(|x| x.into_dynamic()))
|
Box::new(source.cast::<StepRange<T>>().map(|x| x.into_dynamic()))
|
||||||
as Box<dyn Iterator<Item = Dynamic>>
|
as Box<dyn Iterator<Item = Dynamic>>
|
||||||
}),
|
}),
|
||||||
|
@ -2,7 +2,7 @@ use super::PackageStore;
|
|||||||
|
|
||||||
use crate::any::{Dynamic, Variant};
|
use crate::any::{Dynamic, Variant};
|
||||||
use crate::calc_fn_hash;
|
use crate::calc_fn_hash;
|
||||||
use crate::fn_native::{FnCallArgs, NativeFunction};
|
use crate::fn_native::{FnCallArgs, NativeFunction, NativeFunctionABI::*};
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::token::Position;
|
use crate::token::Position;
|
||||||
|
|
||||||
@ -106,7 +106,8 @@ pub fn reg_none<R>(
|
|||||||
map_result(r, pos)
|
map_result(r, pos)
|
||||||
});
|
});
|
||||||
|
|
||||||
lib.functions.insert(hash, Box::new(NativeFunction::new(f)));
|
lib.functions
|
||||||
|
.insert(hash, Box::new(NativeFunction::new(f, Pure)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a function with one parameter to the package.
|
/// Add a function with one parameter to the package.
|
||||||
@ -157,7 +158,8 @@ pub fn reg_unary<T: Variant + Clone, R>(
|
|||||||
map_result(r, pos)
|
map_result(r, pos)
|
||||||
});
|
});
|
||||||
|
|
||||||
lib.functions.insert(hash, Box::new(NativeFunction::new(f)));
|
lib.functions
|
||||||
|
.insert(hash, Box::new(NativeFunction::new(f, Pure)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a function with one mutable reference parameter to the package.
|
/// Add a function with one mutable reference parameter to the package.
|
||||||
@ -215,7 +217,8 @@ pub fn reg_unary_mut<T: Variant + Clone, R>(
|
|||||||
map_result(r, pos)
|
map_result(r, pos)
|
||||||
});
|
});
|
||||||
|
|
||||||
lib.functions.insert(hash, Box::new(NativeFunction::new(f)));
|
lib.functions
|
||||||
|
.insert(hash, Box::new(NativeFunction::new(f, Method)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a function with two parameters to the package.
|
/// Add a function with two parameters to the package.
|
||||||
@ -271,7 +274,8 @@ pub fn reg_binary<A: Variant + Clone, B: Variant + Clone, R>(
|
|||||||
map_result(r, pos)
|
map_result(r, pos)
|
||||||
});
|
});
|
||||||
|
|
||||||
lib.functions.insert(hash, Box::new(NativeFunction::new(f)));
|
lib.functions
|
||||||
|
.insert(hash, Box::new(NativeFunction::new(f, Pure)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a function with two parameters (the first one being a mutable reference) to the package.
|
/// Add a function with two parameters (the first one being a mutable reference) to the package.
|
||||||
@ -334,7 +338,8 @@ pub fn reg_binary_mut<A: Variant + Clone, B: Variant + Clone, R>(
|
|||||||
map_result(r, pos)
|
map_result(r, pos)
|
||||||
});
|
});
|
||||||
|
|
||||||
lib.functions.insert(hash, Box::new(NativeFunction::new(f)));
|
lib.functions
|
||||||
|
.insert(hash, Box::new(NativeFunction::new(f, Method)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a function with three parameters to the package.
|
/// Add a function with three parameters to the package.
|
||||||
@ -374,7 +379,8 @@ pub fn reg_trinary<A: Variant + Clone, B: Variant + Clone, C: Variant + Clone, R
|
|||||||
map_result(r, pos)
|
map_result(r, pos)
|
||||||
});
|
});
|
||||||
|
|
||||||
lib.functions.insert(hash, Box::new(NativeFunction::new(f)));
|
lib.functions
|
||||||
|
.insert(hash, Box::new(NativeFunction::new(f, Pure)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a function with three parameters (the first one is a mutable reference) to the package.
|
/// Add a function with three parameters (the first one is a mutable reference) to the package.
|
||||||
@ -414,5 +420,6 @@ pub fn reg_trinary_mut<A: Variant + Clone, B: Variant + Clone, C: Variant + Clon
|
|||||||
map_result(r, pos)
|
map_result(r, pos)
|
||||||
});
|
});
|
||||||
|
|
||||||
lib.functions.insert(hash, Box::new(NativeFunction::new(f)));
|
lib.functions
|
||||||
|
.insert(hash, Box::new(NativeFunction::new(f, Method)));
|
||||||
}
|
}
|
||||||
|
@ -38,3 +38,12 @@ fn test_method_call() -> Result<(), Box<EvalAltResult>> {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_method_call_style() -> Result<(), Box<EvalAltResult>> {
|
||||||
|
let mut engine = Engine::new();
|
||||||
|
|
||||||
|
assert_eq!(engine.eval::<INT>("let x = -123; x.abs(); x")?, -123);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user