Refine function call parameters size.

This commit is contained in:
Stephen Chung 2020-10-12 17:00:58 +08:00
parent c4f00afbee
commit 21b989afd5
3 changed files with 69 additions and 75 deletions

View File

@ -37,6 +37,7 @@ use crate::stdlib::{
collections::{HashMap, HashSet}, collections::{HashMap, HashSet},
fmt, format, fmt, format,
iter::{empty, once}, iter::{empty, once},
num::NonZeroUsize,
ops::DerefMut, ops::DerefMut,
string::{String, ToString}, string::{String, ToString},
vec::Vec, vec::Vec,
@ -250,8 +251,8 @@ impl<'a> Target<'a> {
Self::LockGuard(_) => (), Self::LockGuard(_) => (),
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
Self::StringChar(_, _, ch) => { Self::StringChar(_, _, ch) => {
let new_val = ch.clone(); let char_value = ch.clone();
self.set_value((new_val, Position::none()), Position::none()) self.set_value((char_value, Position::none()), Position::none())
.unwrap(); .unwrap();
} }
} }
@ -284,10 +285,9 @@ impl<'a> Target<'a> {
})?; })?;
let mut chars = s.chars().collect::<StaticVec<_>>(); let mut chars = s.chars().collect::<StaticVec<_>>();
let ch = chars[*index];
// See if changed - if so, update the String // See if changed - if so, update the String
if ch != new_ch { if chars[*index] != new_ch {
chars[*index] = new_ch; chars[*index] = new_ch;
*s = chars.iter().collect::<String>().into(); *s = chars.iter().collect::<String>().into();
} }
@ -520,13 +520,13 @@ pub fn search_imports<'s>(
// Qualified - check if the root module is directly indexed // Qualified - check if the root module is directly indexed
let index = if state.always_search { let index = if state.always_search {
None 0
} else { } else {
modules.index() modules.index().map_or(0, NonZeroUsize::get)
}; };
Ok(if let Some(index) = index { Ok(if index > 0 {
let offset = mods.len() - index.get(); let offset = mods.len() - index;
&mods.get(offset).unwrap().1 &mods.get(offset).unwrap().1
} else { } else {
mods.iter() mods.iter()
@ -548,13 +548,13 @@ pub fn search_imports_mut<'s>(
// Qualified - check if the root module is directly indexed // Qualified - check if the root module is directly indexed
let index = if state.always_search { let index = if state.always_search {
None 0
} else { } else {
modules.index() modules.index().map_or(0, NonZeroUsize::get)
}; };
Ok(if let Some(index) = index { Ok(if index > 0 {
let offset = mods.len() - index.get(); let offset = mods.len() - index;
&mut mods.get_mut(offset).unwrap().1 &mut mods.get_mut(offset).unwrap().1
} else { } else {
mods.iter_mut() mods.iter_mut()
@ -684,18 +684,14 @@ impl Engine {
// Qualified variable // Qualified variable
((name, pos), Some(modules), hash_var, _) => { ((name, pos), Some(modules), hash_var, _) => {
let module = search_imports_mut(mods, state, modules)?; let module = search_imports_mut(mods, state, modules)?;
let target = let target = module.get_qualified_var_mut(*hash_var).map_err(|mut err| {
module match *err {
.get_qualified_var_mut(*hash_var) EvalAltResult::ErrorVariableNotFound(ref mut err_name, _) => {
.map_err(|err| match *err { *err_name = format!("{}{}", modules, name);
EvalAltResult::ErrorVariableNotFound(_, _) => {
EvalAltResult::ErrorVariableNotFound(
format!("{}{}", modules, name),
*pos,
)
.into()
} }
_ => err.fill_position(*pos), _ => (),
}
err.fill_position(*pos)
})?; })?;
// Module variables are constant // Module variables are constant
@ -733,7 +729,11 @@ impl Engine {
} }
// Check if it is directly indexed // Check if it is directly indexed
let index = if state.always_search { None } else { *index }; let index = if state.always_search {
0
} else {
index.map_or(0, NonZeroUsize::get)
};
// Check the variable resolver, if any // Check the variable resolver, if any
if let Some(ref resolve_var) = self.resolve_var { if let Some(ref resolve_var) = self.resolve_var {
@ -745,15 +745,15 @@ impl Engine {
this_ptr, this_ptr,
level: 0, level: 0,
}; };
if let Some(result) = resolve_var(name, index.map_or(0, |v| v.get()), scope, &context) if let Some(result) =
.map_err(|err| err.fill_position(*pos))? resolve_var(name, index, scope, &context).map_err(|err| err.fill_position(*pos))?
{ {
return Ok((result.into(), name, ScopeEntryType::Constant, *pos)); return Ok((result.into(), name, ScopeEntryType::Constant, *pos));
} }
} }
let index = if let Some(index) = index { let index = if index > 0 {
scope.len() - index.get() scope.len() - index
} else { } else {
// Find the variable in the scope // Find the variable in the scope
scope scope

View File

@ -50,10 +50,6 @@ use crate::stdlib::{
vec::Vec, vec::Vec,
}; };
#[cfg(not(feature = "no_closure"))]
#[cfg(not(feature = "no_function"))]
use crate::stdlib::{collections::HashSet, string::String};
#[cfg(feature = "no_std")] #[cfg(feature = "no_std")]
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
use num_traits::float::Float; use num_traits::float::Float;
@ -146,29 +142,6 @@ impl Drop for ArgBackup<'_> {
} }
} }
// Add captured variables into scope
#[cfg(not(feature = "no_closure"))]
#[cfg(not(feature = "no_function"))]
fn add_captured_variables_into_scope<'s>(
externals: &HashSet<String>,
captured: Scope<'s>,
scope: &mut Scope<'s>,
) {
captured
.into_iter()
.filter(|ScopeEntry { name, .. }| externals.contains(name.as_ref()))
.for_each(
|ScopeEntry {
name, typ, value, ..
}| {
match typ {
ScopeEntryType::Normal => scope.push(name, value),
ScopeEntryType::Constant => scope.push_constant(name, value),
};
},
);
}
#[inline(always)] #[inline(always)]
pub fn ensure_no_data_race( pub fn ensure_no_data_race(
fn_name: &str, fn_name: &str,
@ -483,6 +456,8 @@ impl Engine {
/// Perform an actual function call, native Rust or scripted, taking care of special functions. /// Perform an actual function call, native Rust or scripted, taking care of special functions.
/// Position in `EvalAltResult` is `None` and must be set afterwards. /// Position in `EvalAltResult` is `None` and must be set afterwards.
/// ///
/// Capture `Scope` is consumed by this function.
///
/// ## WARNING /// ## WARNING
/// ///
/// Function call arguments may be _consumed_ when the function requires them to be passed by value. /// Function call arguments may be _consumed_ when the function requires them to be passed by value.
@ -498,7 +473,7 @@ impl Engine {
is_ref: bool, is_ref: bool,
_is_method: bool, _is_method: bool,
pub_only: bool, pub_only: bool,
_capture: Option<Scope>, _capture: Option<&mut Scope>, // `Scope` is consumed.
def_val: &Option<Dynamic>, def_val: &Option<Dynamic>,
_level: usize, _level: usize,
) -> Result<(Dynamic, bool), Box<EvalAltResult>> { ) -> Result<(Dynamic, bool), Box<EvalAltResult>> {
@ -574,10 +549,29 @@ impl Engine {
let scope = &mut Scope::new(); let scope = &mut Scope::new();
let mods = &mut Imports::new(); let mods = &mut Imports::new();
// Add captured variables into scope // Move captured variables into scope
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
if let Some(captured) = _capture { if let Some(captured) = _capture {
add_captured_variables_into_scope(&func.externals, captured, scope); captured
.iter_mut()
.filter(|ScopeEntry { name, .. }| {
func.externals.contains(name.as_ref())
})
.for_each(
|ScopeEntry {
name, typ, value, ..
}| {
// Consume the scope values.
match typ {
ScopeEntryType::Normal => {
scope.push(name.clone(), mem::take(value))
}
ScopeEntryType::Constant => {
scope.push_constant(name.clone(), mem::take(value))
}
};
},
);
} }
let result = if _is_method { let result = if _is_method {
@ -1019,11 +1013,13 @@ impl Engine {
let mut arg_values: StaticVec<_>; let mut arg_values: StaticVec<_>;
let mut args: StaticVec<_>; let mut args: StaticVec<_>;
let mut is_ref = false; let mut is_ref = false;
let capture = if cfg!(not(feature = "no_closure")) && capture && !scope.is_empty() { let mut capture_scope = if cfg!(not(feature = "no_closure")) && capture && !scope.is_empty()
Some(scope.flatten_clone()) {
Some(scope.clone_visible())
} else { } else {
None None
}; };
let capture = capture_scope.as_mut();
if args_expr.is_empty() && curry.is_empty() { if args_expr.is_empty() && curry.is_empty() {
// No arguments // No arguments
@ -1189,20 +1185,12 @@ impl Engine {
let args = args.as_mut(); let args = args.as_mut();
let func = f.get_fn_def(); let func = f.get_fn_def();
let scope = &mut Scope::new(); let new_scope = &mut Scope::new();
let mods = &mut Imports::new(); let mods = &mut Imports::new();
// Add captured variables into scope self.call_script_fn(
#[cfg(not(feature = "no_closure"))] new_scope, mods, state, lib, &mut None, name, func, args, level,
if _capture && !scope.is_empty() { )
add_captured_variables_into_scope(
&func.externals,
scope.flatten_clone(),
scope,
);
}
self.call_script_fn(scope, mods, state, lib, &mut None, name, func, args, level)
} }
Some(f) if f.is_plugin_fn() => f.get_plugin_fn().call(args.as_mut()), Some(f) if f.is_plugin_fn() => f.get_plugin_fn().call(args.as_mut()),
Some(f) if f.is_native() => { Some(f) if f.is_native() => {

View File

@ -420,7 +420,7 @@ impl<'a> Scope<'a> {
/// Clone the Scope, keeping only the last instances of each variable name. /// Clone the Scope, keeping only the last instances of each variable name.
/// Shadowed variables are omitted in the copy. /// Shadowed variables are omitted in the copy.
#[inline] #[inline]
pub(crate) fn flatten_clone(&self) -> Self { pub(crate) fn clone_visible(&self) -> Self {
let mut entries: Vec<Entry> = Default::default(); let mut entries: Vec<Entry> = Default::default();
self.0.iter().rev().for_each(|entry| { self.0.iter().rev().for_each(|entry| {
@ -488,6 +488,12 @@ impl<'a> Scope<'a> {
}| { (name.as_ref(), typ.is_constant(), value) }, }| { (name.as_ref(), typ.is_constant(), value) },
) )
} }
/// Get a mutable iterator to entries in the Scope.
#[inline(always)]
pub(crate) fn iter_mut(&mut self) -> impl Iterator<Item = &mut Entry<'a>> {
self.0.iter_mut()
}
} }
impl<'a, K: Into<Cow<'a, str>>> iter::Extend<(K, EntryType, Dynamic)> for Scope<'a> { impl<'a, K: Into<Cow<'a, str>>> iter::Extend<(K, EntryType, Dynamic)> for Scope<'a> {