Use fold.

This commit is contained in:
Stephen Chung 2021-11-16 13:15:43 +08:00
parent 2fffe31b59
commit c2c30f7711
7 changed files with 110 additions and 90 deletions

View File

@ -2200,12 +2200,11 @@ impl Expr {
#[cfg(not(feature = "no_object"))]
Self::Map(x, _) if self.is_constant() => {
let mut map = x.1.clone();
x.0.iter().for_each(|(k, v)| {
*map.get_mut(k.name.as_str()).expect("contains all keys") =
v.get_literal_value().expect("constant value")
});
Dynamic::from_map(map)
Dynamic::from_map(x.0.iter().fold(x.1.clone(), |mut map, (k, v)| {
let value_ref = map.get_mut(k.name.as_str()).expect("contains all keys");
*value_ref = v.get_literal_value().expect("constant value");
map
}))
}
_ => return None,

View File

@ -1893,20 +1893,22 @@ impl Engine {
let crate::ast::FnCallExpr {
args, constants, ..
} = x.as_ref();
let mut arg_values = StaticVec::with_capacity(args.len());
let mut first_arg_pos = Position::NONE;
args.iter().try_for_each(|expr| {
self.get_arg_value(scope, mods, state, lib, this_ptr, level, expr, constants)
.map(|(value, pos)| {
if arg_values.is_empty() {
first_arg_pos = pos
}
arg_values.push(value.flatten());
})
})?;
let (values, pos) = args.iter().try_fold(
(StaticVec::with_capacity(args.len()), Position::NONE),
|(mut values, mut pos), expr| -> Result<_, Box<EvalAltResult>> {
let (value, arg_pos) = self.get_arg_value(
scope, mods, state, lib, this_ptr, level, expr, constants,
)?;
if values.is_empty() {
pos = arg_pos;
}
values.push(value.flatten());
Ok((values, pos))
},
)?;
idx_values.push((arg_values, first_arg_pos).into());
idx_values.push((values, pos).into());
}
#[cfg(not(feature = "no_object"))]
Expr::FnCall(_, _) if _parent_chain_type == ChainType::Dotting => {
@ -1937,22 +1939,22 @@ impl Engine {
let crate::ast::FnCallExpr {
args, constants, ..
} = x.as_ref();
let mut arg_values = StaticVec::with_capacity(args.len());
let mut first_arg_pos = Position::NONE;
args.iter().try_for_each(|expr| {
self.get_arg_value(
scope, mods, state, lib, this_ptr, level, expr, constants,
)
.map(|(value, pos)| {
if arg_values.is_empty() {
first_arg_pos = pos
}
arg_values.push(value.flatten());
})
})?;
(arg_values, first_arg_pos).into()
args.iter()
.try_fold(
(StaticVec::with_capacity(args.len()), Position::NONE),
|(mut values, mut pos), expr| -> Result<_, Box<EvalAltResult>> {
let (value, arg_pos) = self.get_arg_value(
scope, mods, state, lib, this_ptr, level, expr, constants,
)?;
if values.is_empty() {
pos = arg_pos
}
values.push(value.flatten());
Ok((values, pos))
},
)?
.into()
}
#[cfg(not(feature = "no_object"))]
Expr::FnCall(_, _) if _parent_chain_type == ChainType::Dotting => {
@ -2255,25 +2257,35 @@ impl Engine {
}
#[cfg(not(feature = "no_index"))]
Expr::Array(x, _) => {
let mut arr = Array::with_capacity(x.len());
x.iter().try_for_each(|item| {
self.eval_expr(scope, mods, state, lib, this_ptr, item, level)
.map(|value| arr.push(value.flatten()))
})?;
Ok(arr.into())
}
Expr::Array(x, _) => Ok(x
.iter()
.try_fold(
Array::with_capacity(x.len()),
|mut arr, item| -> Result<_, Box<EvalAltResult>> {
arr.push(
self.eval_expr(scope, mods, state, lib, this_ptr, item, level)?
.flatten(),
);
Ok(arr)
},
)?
.into()),
#[cfg(not(feature = "no_object"))]
Expr::Map(x, _) => {
let mut map = x.1.clone();
x.0.iter().try_for_each(|(Ident { name: key, .. }, expr)| {
let value_ref = map.get_mut(key.as_str()).expect("contains all keys");
self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)
.map(|value| *value_ref = value.flatten())
})?;
Ok(map.into())
}
Expr::Map(x, _) => Ok(x
.0
.iter()
.try_fold(
x.1.clone(),
|mut map, (Ident { name: key, .. }, expr)| -> Result<_, Box<EvalAltResult>> {
let value_ref = map.get_mut(key.as_str()).expect("contains all keys");
*value_ref = self
.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?
.flatten();
Ok(map)
},
)?
.into()),
// Namespace-qualified function call
Expr::FnCall(x, pos) if x.is_qualified() => {

View File

@ -1153,13 +1153,19 @@ impl Engine {
));
}
let (name, mut fn_curry) = arg.cast::<FnPtr>().take_data();
let (name, fn_curry) = arg.cast::<FnPtr>().take_data();
// Append the new curried arguments to the existing list.
a_expr.iter().skip(1).try_for_each(|expr| {
self.get_arg_value(scope, mods, state, lib, this_ptr, level, expr, constants)
.map(|(value, _)| fn_curry.push(value))
})?;
let fn_curry = a_expr.iter().skip(1).try_fold(
fn_curry,
|mut curried, expr| -> Result<_, Box<EvalAltResult>> {
let (value, _) = self.get_arg_value(
scope, mods, state, lib, this_ptr, level, expr, constants,
)?;
curried.push(value);
Ok(curried)
},
)?;
return Ok(FnPtr::new_unchecked(name, fn_curry).into());
}

View File

@ -124,10 +124,7 @@ pub fn calc_fn_hash(fn_name: &str, num: usize) -> u64 {
pub fn calc_fn_params_hash(params: impl Iterator<Item = TypeId>) -> u64 {
let s = &mut get_hasher();
let mut len = 0;
params.for_each(|t| {
len += 1;
t.hash(s);
});
params.inspect(|_| len += 1).for_each(|t| t.hash(s));
len.hash(s);
s.finish()
}

View File

@ -1409,10 +1409,11 @@ impl Module {
/// ```
#[cfg(not(feature = "no_module"))]
pub fn eval_ast_as_new(
mut scope: crate::Scope,
scope: crate::Scope,
ast: &crate::AST,
engine: &crate::Engine,
) -> Result<Self, Box<EvalAltResult>> {
let mut scope = scope;
let mut mods = crate::engine::Imports::new();
let orig_mods_len = mods.len();
@ -1420,21 +1421,28 @@ impl Module {
engine.eval_ast_with_scope_raw(&mut scope, &mut mods, &ast, 0)?;
// Create new module
let mut module = Module::new();
scope.into_iter().for_each(|(_, value, mut aliases)| {
// Variables with an alias left in the scope become module variables
match aliases.len() {
0 => (),
1 => {
let alias = aliases.pop().expect("not empty");
module.set_var(alias, value);
}
_ => aliases.into_iter().for_each(|alias| {
module.set_var(alias, value.clone());
}),
}
});
let mut module =
scope
.into_iter()
.fold(Module::new(), |mut module, (_, value, mut aliases)| {
// Variables with an alias left in the scope become module variables
match aliases.len() {
0 => (),
1 => {
let alias = aliases.pop().expect("not empty");
module.set_var(alias, value);
}
_ => {
let last_alias = aliases.pop().expect("not empty");
aliases.into_iter().for_each(|alias| {
module.set_var(alias, value.clone());
});
// Avoid cloning the last value
module.set_var(last_alias, value);
}
}
module
});
// Extra modules left in the scope become sub-modules
let mut func_mods = crate::engine::Imports::new();

View File

@ -90,11 +90,13 @@ fn collect_fn_metadata(ctx: NativeCallContext) -> crate::Array {
.map(|&s| s.into())
.collect();
let mut list = Array::new();
ctx.iter_namespaces()
.flat_map(|m| m.iter_script_fn())
.for_each(|(_, _, _, _, f)| list.push(make_metadata(&dict, None, f).into()));
let mut list = ctx.iter_namespaces().flat_map(Module::iter_script_fn).fold(
Array::new(),
|mut list, (_, _, _, _, f)| {
list.push(make_metadata(&dict, None, f).into());
list
},
);
#[cfg(not(feature = "no_module"))]
{

View File

@ -518,22 +518,18 @@ impl<'a> Scope<'a> {
#[inline]
#[must_use]
pub fn clone_visible(&self) -> Self {
let mut entries = Self::new();
self.names
.iter()
.rev()
.enumerate()
.for_each(|(index, (name, alias))| {
self.names.iter().rev().enumerate().fold(
Self::new(),
|mut entries, (index, (name, alias))| {
if !entries.names.iter().any(|(key, _)| key == name) {
entries.names.push((name.clone(), alias.clone()));
entries
.values
.push(self.values[self.len() - 1 - index].clone());
}
});
entries
entries
},
)
}
/// Get an iterator to entries in the [`Scope`].
#[inline]