Code refactor.

This commit is contained in:
Stephen Chung 2023-04-28 15:05:31 +08:00
parent ceb5b3718d
commit 72cfd42ab7
6 changed files with 163 additions and 198 deletions

View File

@ -576,39 +576,32 @@ impl Engine {
) -> RhaiResultOf<(Dynamic, bool)> { ) -> RhaiResultOf<(Dynamic, bool)> {
// These may be redirected from method style calls. // These may be redirected from method style calls.
if hashes.is_native_only() { if hashes.is_native_only() {
let error = match fn_name { loop {
// Handle type_of() match fn_name {
KEYWORD_TYPE_OF => { // Handle type_of()
if args.len() == 1 { KEYWORD_TYPE_OF if args.len() == 1 => {
let typ = self.get_interned_string(self.map_type_name(args[0].type_name())); let typ = self.get_interned_string(self.map_type_name(args[0].type_name()));
return Ok((typ.into(), false)); return Ok((typ.into(), false));
} }
true
}
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
crate::engine::KEYWORD_IS_SHARED => { crate::engine::KEYWORD_IS_SHARED if args.len() == 1 => {
if args.len() == 1 { return Ok((args[0].is_shared().into(), false))
return Ok((args[0].is_shared().into(), false));
} }
true #[cfg(not(feature = "no_closure"))]
crate::engine::KEYWORD_IS_SHARED => (),
#[cfg(not(feature = "no_function"))]
crate::engine::KEYWORD_IS_DEF_FN => (),
KEYWORD_TYPE_OF | KEYWORD_FN_PTR | KEYWORD_EVAL | KEYWORD_IS_DEF_VAR
| KEYWORD_FN_PTR_CALL | KEYWORD_FN_PTR_CURRY => (),
_ => break,
} }
#[cfg(not(feature = "no_function"))] let sig = self.gen_fn_call_signature(fn_name, args);
crate::engine::KEYWORD_IS_DEF_FN => true, return Err(ERR::ErrorFunctionNotFound(sig, pos).into());
KEYWORD_FN_PTR | KEYWORD_EVAL | KEYWORD_IS_DEF_VAR | KEYWORD_FN_PTR_CALL
| KEYWORD_FN_PTR_CURRY => true,
_ => false,
};
if error {
return Err(ERR::ErrorFunctionNotFound(
self.gen_fn_call_signature(fn_name, args),
pos,
)
.into());
} }
} }
@ -624,31 +617,27 @@ impl Engine {
let hash = hashes.script(); let hash = hashes.script();
let local_entry = &mut None; let local_entry = &mut None;
let mut resolved = None;
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
let resolved = if _is_method_call && !args.is_empty() { if _is_method_call && !args.is_empty() {
let typed_hash = let typed_hash =
crate::calc_typed_method_hash(hash, self.map_type_name(args[0].type_name())); crate::calc_typed_method_hash(hash, self.map_type_name(args[0].type_name()));
self.resolve_fn(global, caches, local_entry, None, typed_hash, None, false) resolved =
} else { self.resolve_fn(global, caches, local_entry, None, typed_hash, None, false);
None }
};
#[cfg(feature = "no_object")]
let resolved = None;
let resolved = if resolved.is_none() { if resolved.is_none() {
self.resolve_fn(global, caches, local_entry, None, hash, None, false) resolved = self.resolve_fn(global, caches, local_entry, None, hash, None, false);
} else { }
resolved
};
if let Some(FnResolutionCacheEntry { func, ref source }) = resolved.cloned() { if let Some(FnResolutionCacheEntry { func, source }) = resolved.cloned() {
// Script function call // Script function call
debug_assert!(func.is_script()); debug_assert!(func.is_script());
let f = func.get_script_fn_def().expect("script-defined function");
let environ = func.get_encapsulated_environ(); let environ = func.get_encapsulated_environ();
let func = func.get_script_fn_def().expect("script-defined function");
if f.body.is_empty() { if func.body.is_empty() {
return Ok((Dynamic::UNIT, false)); return Ok((Dynamic::UNIT, false));
} }
@ -660,23 +649,17 @@ impl Engine {
&mut empty_scope &mut empty_scope
}; };
let orig_source = mem::replace(&mut global.source, source.clone()); let orig_source = mem::replace(&mut global.source, source);
defer! { global => move |g| g.source = orig_source } defer! { global => move |g| g.source = orig_source }
return if _is_method_call { return if _is_method_call {
// Method call of script function - map first argument to `this` use std::ops::DerefMut;
let (first_arg, rest_args) = args.split_first_mut().unwrap();
// Method call of script function - map first argument to `this`
let (first_arg, args) = args.split_first_mut().unwrap();
let this_ptr = Some(first_arg.deref_mut());
self.call_script_fn( self.call_script_fn(
global, global, caches, scope, this_ptr, environ, func, args, true, pos,
caches,
scope,
Some(first_arg),
environ,
f,
rest_args,
true,
pos,
) )
} else { } else {
// Normal call of script function // Normal call of script function
@ -691,7 +674,7 @@ impl Engine {
defer! { args = (args) if swap => move |a| backup.restore_first_arg(a) } defer! { args = (args) if swap => move |a| backup.restore_first_arg(a) }
self.call_script_fn(global, caches, scope, None, environ, f, args, true, pos) self.call_script_fn(global, caches, scope, None, environ, func, args, true, pos)
} }
.map(|r| (r, false)); .map(|r| (r, false));
} }
@ -748,31 +731,28 @@ impl Engine {
fn_name: &str, fn_name: &str,
mut hash: FnCallHashes, mut hash: FnCallHashes,
target: &mut crate::eval::Target, target: &mut crate::eval::Target,
mut call_args: &mut [Dynamic], call_args: &mut [Dynamic],
first_arg_pos: Position, first_arg_pos: Position,
pos: Position, pos: Position,
) -> RhaiResultOf<(Dynamic, bool)> { ) -> RhaiResultOf<(Dynamic, bool)> {
let is_ref_mut = target.is_ref();
let (result, updated) = match fn_name { let (result, updated) = match fn_name {
// Handle fn_ptr.call(...) // Handle fn_ptr.call(...)
KEYWORD_FN_PTR_CALL if target.is_fnptr() => { KEYWORD_FN_PTR_CALL if target.is_fnptr() => {
let fn_ptr = target.read_lock::<FnPtr>().expect("`FnPtr`"); let fn_ptr = target.read_lock::<FnPtr>().expect("`FnPtr`");
// Arguments are passed as-is, adding the curried arguments // Arguments are passed as-is, adding the curried arguments
let mut curry = FnArgsVec::with_capacity(fn_ptr.curry().len()); let mut curry = fn_ptr.curry().iter().cloned().collect::<FnArgsVec<_>>();
curry.extend(fn_ptr.curry().iter().cloned()); let args = &mut curry
let args = &mut FnArgsVec::with_capacity(curry.len() + call_args.len()); .iter_mut()
args.extend(curry.iter_mut()); .chain(call_args.iter_mut())
args.extend(call_args.iter_mut()); .collect::<FnArgsVec<_>>();
// Linked to scripted function? let _fn_def = ();
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
let fn_def = fn_ptr.fn_def(); let _fn_def = fn_ptr.fn_def();
#[cfg(feature = "no_function")]
let fn_def = ();
match fn_def { match _fn_def {
// Linked to scripted function - short-circuit
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
Some(fn_def) if fn_def.params.len() == args.len() => { Some(fn_def) if fn_def.params.len() == args.len() => {
let scope = &mut Scope::new(); let scope = &mut Scope::new();
@ -805,23 +785,21 @@ impl Engine {
} }
} }
// Handle obj.call()
KEYWORD_FN_PTR_CALL if call_args.is_empty() => {
return Err(self
.make_type_mismatch_err::<FnPtr>(self.map_type_name(target.type_name()), pos))
}
// Handle obj.call(fn_ptr, ...) // Handle obj.call(fn_ptr, ...)
KEYWORD_FN_PTR_CALL => { KEYWORD_FN_PTR_CALL => {
if call_args.is_empty() { debug_assert!(!call_args.is_empty());
return Err(self.make_type_mismatch_err::<FnPtr>(
self.map_type_name(target.type_name()),
pos,
));
}
if !call_args[0].is_fnptr() {
return Err(self.make_type_mismatch_err::<FnPtr>(
self.map_type_name(call_args[0].type_name()),
first_arg_pos,
));
}
// FnPtr call on object // FnPtr call on object
let fn_ptr = call_args[0].take().cast::<FnPtr>(); let typ = call_args[0].type_name();
let fn_ptr = call_args[0].take().try_cast::<FnPtr>().ok_or_else(|| {
self.make_type_mismatch_err::<FnPtr>(self.map_type_name(typ), first_arg_pos)
})?;
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
let (is_anon, (fn_name, fn_curry, environ, fn_def)) = let (is_anon, (fn_name, fn_curry, environ, fn_def)) =
@ -829,17 +807,14 @@ impl Engine {
#[cfg(feature = "no_function")] #[cfg(feature = "no_function")]
let (is_anon, (fn_name, fn_curry, _), fn_def) = (false, fn_ptr.take_data(), ()); let (is_anon, (fn_name, fn_curry, _), fn_def) = (false, fn_ptr.take_data(), ());
// Replace the first argument with the object pointer, adding the curried arguments // Adding the curried arguments and the remaining arguments
call_args = &mut call_args[1..]; let mut curry = fn_curry.into_iter().collect::<FnArgsVec<_>>();
let args = &mut FnArgsVec::with_capacity(curry.len() + call_args.len());
let mut curry = FnArgsVec::with_capacity(fn_curry.len());
curry.extend(fn_curry.into_iter());
let args = &mut FnArgsVec::with_capacity(curry.len() + call_args.len() + 1);
args.extend(curry.iter_mut()); args.extend(curry.iter_mut());
args.extend(call_args.iter_mut()); args.extend(call_args.iter_mut().skip(1));
// Linked to scripted function?
match fn_def { match fn_def {
// Linked to scripted function - short-circuit
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
Some(fn_def) if fn_def.params.len() == args.len() => { Some(fn_def) if fn_def.params.len() == args.len() => {
// Check for data race. // Check for data race.
@ -856,58 +831,53 @@ impl Engine {
.map(|v| (v, false)) .map(|v| (v, false))
} }
_ => { _ => {
let name = fn_name.as_str();
let is_ref_mut = target.is_ref();
// Add the first argument with the object pointer // Add the first argument with the object pointer
args.insert(0, target.as_mut()); args.insert(0, target.as_mut());
// Recalculate hash // Recalculate hash
let num_args = args.len();
let new_hash = match is_anon { let new_hash = match is_anon {
false if !is_valid_function_name(&fn_name) => { false if !is_valid_function_name(name) => {
FnCallHashes::from_native_only(calc_fn_hash( FnCallHashes::from_native_only(calc_fn_hash(None, name, num_args))
None,
&fn_name,
args.len(),
))
} }
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
_ => FnCallHashes::from_script_and_native( _ => FnCallHashes::from_script_and_native(
calc_fn_hash(None, &fn_name, args.len() - 1), calc_fn_hash(None, name, num_args - 1),
calc_fn_hash(None, &fn_name, args.len()), calc_fn_hash(None, name, num_args),
), ),
#[cfg(feature = "no_function")] #[cfg(feature = "no_function")]
_ => FnCallHashes::from_native_only(calc_fn_hash( _ => FnCallHashes::from_native_only(calc_fn_hash(None, name, num_args)),
None,
&fn_name,
args.len(),
)),
}; };
// Map it to name(args) in function-call style // Map it to name(args) in function-call style
self.exec_fn_call( self.exec_fn_call(
global, caches, None, &fn_name, None, new_hash, args, is_ref_mut, true, global, caches, None, name, None, new_hash, args, is_ref_mut, true, pos,
pos,
) )
} }
} }
} }
KEYWORD_FN_PTR_CURRY => {
if !target.is_fnptr() {
return Err(self.make_type_mismatch_err::<FnPtr>(
self.map_type_name(target.type_name()),
pos,
));
}
let mut fn_ptr = target.read_lock::<FnPtr>().expect("`FnPtr`").clone(); // Handle fn_ptr.curry(...)
KEYWORD_FN_PTR_CURRY => {
let typ = target.type_name();
let mut fn_ptr = target
.read_lock::<FnPtr>()
.ok_or_else(|| {
self.make_type_mismatch_err::<FnPtr>(self.map_type_name(typ), pos)
})?
.clone();
// Append the new curried arguments to the existing list. // Append the new curried arguments to the existing list.
call_args.iter_mut().map(mem::take).for_each(|value| { fn_ptr.extend(call_args.iter_mut().map(mem::take));
fn_ptr.add_curry(value);
});
Ok((fn_ptr.into(), false)) Ok((fn_ptr.into(), false))
} }
// Handle is_shared() // Handle var.is_shared()
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
crate::engine::KEYWORD_IS_SHARED if call_args.is_empty() => { crate::engine::KEYWORD_IS_SHARED if call_args.is_empty() => {
return Ok((target.is_shared().into(), false)); return Ok((target.is_shared().into(), false));
@ -917,7 +887,7 @@ impl Engine {
let mut fn_name = fn_name; let mut fn_name = fn_name;
let _redirected; let _redirected;
let mut _linked = None; let mut _linked = None;
let mut _arg_values: FnArgsVec<_>; let mut _arg_values;
let mut call_args = call_args; let mut call_args = call_args;
// Check if it is a map method call in OOP style // Check if it is a map method call in OOP style
@ -936,17 +906,16 @@ impl Engine {
.iter() .iter()
.cloned() .cloned()
.chain(call_args.iter_mut().map(mem::take)) .chain(call_args.iter_mut().map(mem::take))
.collect(); .collect::<FnArgsVec<_>>();
call_args = &mut _arg_values; call_args = &mut _arg_values;
} }
// Linked to scripted function? let _fn_def = ();
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
let fn_def = fn_ptr.fn_def(); let _fn_def = fn_ptr.fn_def();
#[cfg(feature = "no_function")]
let fn_def = ();
match fn_def { match _fn_def {
// Linked to scripted function
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
Some(fn_def) if fn_def.params.len() == call_args.len() => { Some(fn_def) if fn_def.params.len() == call_args.len() => {
_linked = Some(( _linked = Some((
@ -960,21 +929,22 @@ impl Engine {
let _is_anon = fn_ptr.is_anonymous(); let _is_anon = fn_ptr.is_anonymous();
// Recalculate the hash based on the new function name and new arguments // Recalculate the hash based on the new function name and new arguments
let args_len = call_args.len() + 1; let num_args = call_args.len() + 1;
hash = match _is_anon { hash = match _is_anon {
false if !is_valid_function_name(fn_name) => { false if !is_valid_function_name(fn_name) => {
FnCallHashes::from_native_only(calc_fn_hash( FnCallHashes::from_native_only(calc_fn_hash(
None, fn_name, args_len, None, fn_name, num_args,
)) ))
} }
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
_ => FnCallHashes::from_script_and_native( _ => FnCallHashes::from_script_and_native(
calc_fn_hash(None, fn_name, args_len - 1), calc_fn_hash(None, fn_name, num_args - 1),
calc_fn_hash(None, fn_name, args_len), calc_fn_hash(None, fn_name, num_args),
), ),
#[cfg(feature = "no_function")] #[cfg(feature = "no_function")]
_ => FnCallHashes::from_native_only(calc_fn_hash( _ => FnCallHashes::from_native_only(calc_fn_hash(
None, fn_name, args_len, None, fn_name, num_args,
)), )),
}; };
} }
@ -986,7 +956,7 @@ impl Engine {
match _linked { match _linked {
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
Some((fn_def, environ)) => { Some((fn_def, environ)) => {
// Linked to scripted function // Linked to scripted function - short-circuit
let scope = &mut Scope::new(); let scope = &mut Scope::new();
let environ = environ.as_deref(); let environ = environ.as_deref();
let this_ptr = Some(target.as_mut()); let this_ptr = Some(target.as_mut());
@ -1000,14 +970,15 @@ impl Engine {
#[cfg(feature = "no_function")] #[cfg(feature = "no_function")]
Some(()) => unreachable!(), Some(()) => unreachable!(),
None => { None => {
let is_ref_mut = target.is_ref();
// Attached object pointer in front of the arguments // Attached object pointer in front of the arguments
let mut args = FnArgsVec::with_capacity(call_args.len() + 1); let args = &mut std::iter::once(target.as_mut())
args.push(target.as_mut()); .chain(call_args.iter_mut())
args.extend(call_args.iter_mut()); .collect::<FnArgsVec<_>>();
self.exec_fn_call( self.exec_fn_call(
global, caches, None, fn_name, None, hash, &mut args, is_ref_mut, true, global, caches, None, fn_name, None, hash, args, is_ref_mut, true, pos,
pos,
) )
} }
} }
@ -1039,7 +1010,7 @@ impl Engine {
) -> RhaiResult { ) -> RhaiResult {
let mut first_arg = first_arg; let mut first_arg = first_arg;
let mut args_expr = args_expr; let mut args_expr = args_expr;
let mut total_args = usize::from(first_arg.is_some()) + args_expr.len(); let mut num_args = usize::from(first_arg.is_some()) + args_expr.len();
let mut curry = FnArgsVec::new_const(); let mut curry = FnArgsVec::new_const();
let mut name = fn_name; let mut name = fn_name;
let mut hashes = hashes; let mut hashes = hashes;
@ -1049,19 +1020,15 @@ impl Engine {
_ if op_token.is_some() => (), _ if op_token.is_some() => (),
// Handle call(fn_ptr, ...) // Handle call(fn_ptr, ...)
KEYWORD_FN_PTR_CALL if total_args >= 1 => { KEYWORD_FN_PTR_CALL if num_args >= 1 => {
let arg = first_arg.unwrap(); let arg = first_arg.unwrap();
let (arg_value, arg_pos) = let (first_arg_value, first_arg_pos) =
self.get_arg_value(global, caches, scope, this_ptr.as_deref_mut(), arg)?; self.get_arg_value(global, caches, scope, this_ptr.as_deref_mut(), arg)?;
if !arg_value.is_fnptr() { let typ = first_arg_value.type_name();
return Err(self.make_type_mismatch_err::<FnPtr>( let fn_ptr = first_arg_value.try_cast::<FnPtr>().ok_or_else(|| {
self.map_type_name(arg_value.type_name()), self.make_type_mismatch_err::<FnPtr>(self.map_type_name(typ), first_arg_pos)
arg_pos, })?;
));
}
let fn_ptr = arg_value.cast::<FnPtr>();
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
let (is_anon, (fn_name, fn_curry, _environ, fn_def)) = let (is_anon, (fn_name, fn_curry, _environ, fn_def)) =
@ -1071,20 +1038,20 @@ impl Engine {
curry.extend(fn_curry.into_iter()); curry.extend(fn_curry.into_iter());
// Linked to scripted function? // Linked to scripted function - short-circuit
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
if let Some(fn_def) = fn_def { if let Some(fn_def) = fn_def {
if fn_def.params.len() == curry.len() + args_expr.len() { if fn_def.params.len() == curry.len() + args_expr.len() {
// Evaluate arguments // Evaluate arguments
let mut arg_values = curry let mut arg_values =
.into_iter() FnArgsVec::with_capacity(curry.len() + args_expr.len());
.map(Ok) arg_values.extend(curry);
.chain(args_expr.iter().map(|expr| -> Result<_, crate::RhaiError> { for expr in args_expr {
let this_ptr = this_ptr.as_deref_mut(); let this_ptr = this_ptr.as_deref_mut();
self.get_arg_value(global, caches, scope, this_ptr, expr) let (value, _) =
.map(|(v, ..)| v) self.get_arg_value(global, caches, scope, this_ptr, expr)?;
})) arg_values.push(value);
.collect::<RhaiResultOf<FnArgsVec<_>>>()?; }
let args = &mut arg_values.iter_mut().collect::<FnArgsVec<_>>(); let args = &mut arg_values.iter_mut().collect::<FnArgsVec<_>>();
let scope = &mut Scope::new(); let scope = &mut Scope::new();
let environ = _environ.as_deref(); let environ = _environ.as_deref();
@ -1104,10 +1071,10 @@ impl Engine {
if !args_expr.is_empty() { if !args_expr.is_empty() {
args_expr = &args_expr[1..]; args_expr = &args_expr[1..];
} }
total_args -= 1; num_args -= 1;
// Recalculate hash // Recalculate hash
let args_len = total_args + curry.len(); let args_len = num_args + curry.len();
hashes = if !is_anon && !is_valid_function_name(name) { hashes = if !is_anon && !is_valid_function_name(name) {
FnCallHashes::from_native_only(calc_fn_hash(None, name, args_len)) FnCallHashes::from_native_only(calc_fn_hash(None, name, args_len))
@ -1115,8 +1082,9 @@ impl Engine {
FnCallHashes::from_hash(calc_fn_hash(None, name, args_len)) FnCallHashes::from_hash(calc_fn_hash(None, name, args_len))
}; };
} }
// Handle Fn(fn_name) // Handle Fn(fn_name)
KEYWORD_FN_PTR if total_args == 1 => { KEYWORD_FN_PTR if num_args == 1 => {
let arg = first_arg.unwrap(); let arg = first_arg.unwrap();
let (arg_value, arg_pos) = let (arg_value, arg_pos) =
self.get_arg_value(global, caches, scope, this_ptr, arg)?; self.get_arg_value(global, caches, scope, this_ptr, arg)?;
@ -1131,19 +1099,15 @@ impl Engine {
} }
// Handle curry(x, ...) // Handle curry(x, ...)
KEYWORD_FN_PTR_CURRY if total_args > 1 => { KEYWORD_FN_PTR_CURRY if num_args > 1 => {
let first = first_arg.unwrap(); let first = first_arg.unwrap();
let (arg_value, arg_pos) = let (first_arg_value, first_arg_pos) =
self.get_arg_value(global, caches, scope, this_ptr.as_deref_mut(), first)?; self.get_arg_value(global, caches, scope, this_ptr.as_deref_mut(), first)?;
if !arg_value.is_fnptr() { let typ = first_arg_value.type_name();
return Err(self.make_type_mismatch_err::<FnPtr>( let mut fn_ptr = first_arg_value.try_cast::<FnPtr>().ok_or_else(|| {
self.map_type_name(arg_value.type_name()), self.make_type_mismatch_err::<FnPtr>(self.map_type_name(typ), first_arg_pos)
arg_pos, })?;
));
}
let mut fn_ptr = arg_value.cast::<FnPtr>();
// Append the new curried arguments to the existing list. // Append the new curried arguments to the existing list.
for expr in args_expr { for expr in args_expr {
@ -1157,7 +1121,7 @@ impl Engine {
// Handle is_shared(var) // Handle is_shared(var)
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
crate::engine::KEYWORD_IS_SHARED if total_args == 1 => { crate::engine::KEYWORD_IS_SHARED if num_args == 1 => {
let arg = first_arg.unwrap(); let arg = first_arg.unwrap();
let (arg_value, ..) = let (arg_value, ..) =
self.get_arg_value(global, caches, scope, this_ptr.as_deref_mut(), arg)?; self.get_arg_value(global, caches, scope, this_ptr.as_deref_mut(), arg)?;
@ -1166,7 +1130,7 @@ impl Engine {
// Handle is_def_fn(fn_name, arity) // Handle is_def_fn(fn_name, arity)
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
crate::engine::KEYWORD_IS_DEF_FN if total_args == 2 => { crate::engine::KEYWORD_IS_DEF_FN if num_args == 2 => {
let first = first_arg.unwrap(); let first = first_arg.unwrap();
let (arg_value, arg_pos) = let (arg_value, arg_pos) =
self.get_arg_value(global, caches, scope, this_ptr.as_deref_mut(), first)?; self.get_arg_value(global, caches, scope, this_ptr.as_deref_mut(), first)?;
@ -1194,7 +1158,7 @@ impl Engine {
// Handle is_def_fn(this_type, fn_name, arity) // Handle is_def_fn(this_type, fn_name, arity)
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
crate::engine::KEYWORD_IS_DEF_FN if total_args == 3 => { crate::engine::KEYWORD_IS_DEF_FN if num_args == 3 => {
let first = first_arg.unwrap(); let first = first_arg.unwrap();
let (arg_value, arg_pos) = let (arg_value, arg_pos) =
self.get_arg_value(global, caches, scope, this_ptr.as_deref_mut(), first)?; self.get_arg_value(global, caches, scope, this_ptr.as_deref_mut(), first)?;
@ -1235,7 +1199,7 @@ impl Engine {
} }
// Handle is_def_var(fn_name) // Handle is_def_var(fn_name)
KEYWORD_IS_DEF_VAR if total_args == 1 => { KEYWORD_IS_DEF_VAR if num_args == 1 => {
let arg = first_arg.unwrap(); let arg = first_arg.unwrap();
let (arg_value, arg_pos) = let (arg_value, arg_pos) =
self.get_arg_value(global, caches, scope, this_ptr, arg)?; self.get_arg_value(global, caches, scope, this_ptr, arg)?;
@ -1246,7 +1210,7 @@ impl Engine {
} }
// Handle eval(script) // Handle eval(script)
KEYWORD_EVAL if total_args == 1 => { KEYWORD_EVAL if num_args == 1 => {
// eval - only in function call style // eval - only in function call style
let orig_scope_len = scope.len(); let orig_scope_len = scope.len();
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
@ -1289,8 +1253,8 @@ impl Engine {
} }
// Normal function call - except for Fn, curry, call and eval (handled above) // Normal function call - except for Fn, curry, call and eval (handled above)
let mut arg_values = FnArgsVec::with_capacity(total_args); let mut arg_values = FnArgsVec::with_capacity(num_args);
let mut args = FnArgsVec::with_capacity(total_args + curry.len()); let mut args = FnArgsVec::with_capacity(num_args + curry.len());
let mut is_ref_mut = false; let mut is_ref_mut = false;
// Capture parent scope? // Capture parent scope?
@ -1318,7 +1282,7 @@ impl Engine {
} }
// Call with blank scope // Call with blank scope
if total_args > 0 || !curry.is_empty() { if num_args > 0 || !curry.is_empty() {
// If the first argument is a variable, and there is no curried arguments, // If the first argument is a variable, and there is no curried arguments,
// convert to method-call style in order to leverage potential &mut first argument and // convert to method-call style in order to leverage potential &mut first argument and
// avoid cloning the value // avoid cloning the value

View File

@ -7,8 +7,8 @@ use crate::plugin::PluginFunction;
use crate::tokenizer::{is_valid_function_name, Token, TokenizeState}; use crate::tokenizer::{is_valid_function_name, Token, TokenizeState};
use crate::types::dynamic::Variant; use crate::types::dynamic::Variant;
use crate::{ use crate::{
calc_fn_hash, Dynamic, Engine, EvalContext, FuncArgs, Position, RhaiResult, RhaiResultOf, calc_fn_hash, Dynamic, Engine, EvalContext, FnArgsVec, FuncArgs, Position, RhaiResult,
StaticVec, VarDefInfo, ERR, RhaiResultOf, StaticVec, VarDefInfo, ERR,
}; };
use std::any::{type_name, TypeId}; use std::any::{type_name, TypeId};
#[cfg(feature = "no_std")] #[cfg(feature = "no_std")]
@ -309,9 +309,9 @@ impl<'a> NativeCallContext<'a> {
let mut arg_values = StaticVec::new_const(); let mut arg_values = StaticVec::new_const();
args.parse(&mut arg_values); args.parse(&mut arg_values);
let mut args: StaticVec<_> = arg_values.iter_mut().collect(); let args = &mut arg_values.iter_mut().collect::<FnArgsVec<_>>();
self._call_fn_raw(fn_name, &mut args, false, false, false) self._call_fn_raw(fn_name, args, false, false, false)
.and_then(|result| { .and_then(|result| {
// Bail out early if the return type needs no cast // Bail out early if the return type needs no cast
if TypeId::of::<T>() == TypeId::of::<Dynamic>() { if TypeId::of::<T>() == TypeId::of::<Dynamic>() {
@ -340,9 +340,9 @@ impl<'a> NativeCallContext<'a> {
let mut arg_values = StaticVec::new_const(); let mut arg_values = StaticVec::new_const();
args.parse(&mut arg_values); args.parse(&mut arg_values);
let mut args: StaticVec<_> = arg_values.iter_mut().collect(); let args = &mut arg_values.iter_mut().collect::<FnArgsVec<_>>();
self._call_fn_raw(fn_name, &mut args, true, false, false) self._call_fn_raw(fn_name, args, true, false, false)
.and_then(|result| { .and_then(|result| {
// Bail out early if the return type needs no cast // Bail out early if the return type needs no cast
if TypeId::of::<T>() == TypeId::of::<Dynamic>() { if TypeId::of::<T>() == TypeId::of::<Dynamic>() {

View File

@ -118,7 +118,7 @@ impl FuncInfo {
} }
} }
} else { } else {
let params: FnArgsVec<_> = self let params = self
.metadata .metadata
.params_info .params_info
.iter() .iter()
@ -134,7 +134,7 @@ impl FuncInfo {
}; };
result result
}) })
.collect(); .collect::<FnArgsVec<_>>();
signature.push_str(&params.join(", ")); signature.push_str(&params.join(", "));
} }
signature.push(')'); signature.push(')');
@ -932,7 +932,10 @@ impl Module {
hash_fn: u64, hash_fn: u64,
arg_names: impl IntoIterator<Item = S>, arg_names: impl IntoIterator<Item = S>,
) -> &mut Self { ) -> &mut Self {
let mut param_names: FnArgsVec<_> = arg_names.into_iter().map(Into::into).collect(); let mut param_names = arg_names
.into_iter()
.map(Into::into)
.collect::<FnArgsVec<_>>();
if let Some(f) = self.functions.as_mut().and_then(|m| m.get_mut(&hash_fn)) { if let Some(f) = self.functions.as_mut().and_then(|m| m.get_mut(&hash_fn)) {
let (param_names, return_type_name) = if param_names.len() > f.metadata.num_params { let (param_names, return_type_name) = if param_names.len() > f.metadata.num_params {
@ -1053,13 +1056,12 @@ impl Module {
let _arg_names = arg_names; let _arg_names = arg_names;
let is_method = func.is_method(); let is_method = func.is_method();
let mut param_types: FnArgsVec<_> = arg_types let param_types = arg_types
.as_ref() .as_ref()
.iter() .iter()
.enumerate() .enumerate()
.map(|(i, &type_id)| Self::map_type(!is_method || i > 0, type_id)) .map(|(i, &type_id)| Self::map_type(!is_method || i > 0, type_id))
.collect(); .collect::<FnArgsVec<_>>();
param_types.shrink_to_fit();
let is_dynamic = param_types let is_dynamic = param_types
.iter() .iter()

View File

@ -1195,12 +1195,11 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, _chaining: bool) {
&& x.constant_args() // all arguments are constants && x.constant_args() // all arguments are constants
=> { => {
// First search for script-defined functions (can override built-in) // First search for script-defined functions (can override built-in)
let _has_script_fn = false;
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
let has_script_fn = !x.hashes.is_native_only() && state.global.lib.iter().find_map(|m| m.get_script_fn(&x.name, x.args.len())).is_some(); let _has_script_fn = !x.hashes.is_native_only() && state.global.lib.iter().find_map(|m| m.get_script_fn(&x.name, x.args.len())).is_some();
#[cfg(feature = "no_function")]
let has_script_fn = false;
if !has_script_fn { if !_has_script_fn {
let arg_values = &mut x.args.iter().map(Expr::get_literal_value).collect::<Option<FnArgsVec<_>>>().unwrap(); let arg_values = &mut x.args.iter().map(Expr::get_literal_value).collect::<Option<FnArgsVec<_>>>().unwrap();
let result = match x.name.as_str() { let result = match x.name.as_str() {

View File

@ -265,7 +265,7 @@ mod string_functions {
/// ///
/// print(text); // prints "hello, world!" /// print(text); // prints "hello, world!"
/// ///
/// x.truncate(10); /// text.truncate(10);
/// ///
/// print(text); // prints "hello, world!" /// print(text); // prints "hello, world!"
/// ``` /// ```
@ -273,10 +273,10 @@ mod string_functions {
if len > 0 { if len > 0 {
#[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)] #[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)]
let len = len.min(MAX_USIZE_INT) as usize; let len = len.min(MAX_USIZE_INT) as usize;
let chars: StaticVec<_> = string.chars().collect(); if let Some((index, _)) = string.char_indices().nth(len) {
let copy = string.make_mut(); let copy = string.make_mut();
copy.clear(); copy.truncate(index);
copy.extend(chars.into_iter().take(len)); }
} else { } else {
clear(string); clear(string);
} }
@ -1109,7 +1109,7 @@ mod string_functions {
copy.clear(); copy.clear();
copy.extend(chars.iter().skip(offset).take(len)); copy.extend(chars.iter().skip(offset).take(len));
} }
/// Remove all characters from the string except until the `start` position. /// Remove all characters from the string up to the `start` position.
/// ///
/// * If `start` < 0, position counts from the end of the string (`-1` is the last character). /// * If `start` < 0, position counts from the end of the string (`-1` is the last character).
/// * If `start` < -length of string, the string is not modified. /// * If `start` < -length of string, the string is not modified.

View File

@ -156,7 +156,7 @@ impl ModuleMetadata<'_> {
impl<'a> From<&'a crate::Module> for ModuleMetadata<'a> { impl<'a> From<&'a crate::Module> for ModuleMetadata<'a> {
fn from(module: &'a crate::Module) -> Self { fn from(module: &'a crate::Module) -> Self {
let mut functions: StaticVec<_> = module.iter_fn().map(Into::into).collect(); let mut functions = module.iter_fn().map(Into::into).collect::<StaticVec<_>>();
functions.sort(); functions.sort();
Self { Self {