Use Scope::flatten_clone for capturing.
This commit is contained in:
parent
7d4620d0d9
commit
a7ff207636
@ -36,6 +36,7 @@ use crate::engine::{Map, Target, FN_GET, FN_SET};
|
||||
use crate::stdlib::{
|
||||
any::{type_name, TypeId},
|
||||
boxed::Box,
|
||||
collections::HashSet,
|
||||
convert::TryFrom,
|
||||
format,
|
||||
iter::{empty, once},
|
||||
@ -109,22 +110,20 @@ fn restore_first_arg<'a>(old_this_ptr: Option<&'a mut Dynamic>, args: &mut FnCal
|
||||
// Add captured variables into scope
|
||||
#[cfg(not(feature = "no_capture"))]
|
||||
fn add_captured_variables_into_scope<'s>(
|
||||
externals: &[String],
|
||||
captured: &'s Scope<'s>,
|
||||
externals: &HashSet<String>,
|
||||
captured: Scope<'s>,
|
||||
scope: &mut Scope<'s>,
|
||||
) {
|
||||
externals
|
||||
.iter()
|
||||
.map(|var_name| captured.get_entry(var_name))
|
||||
.filter(Option::is_some)
|
||||
.map(Option::unwrap)
|
||||
captured
|
||||
.into_iter()
|
||||
.filter(|ScopeEntry { name, .. }| externals.contains(name.as_ref()))
|
||||
.for_each(
|
||||
|ScopeEntry {
|
||||
name, typ, value, ..
|
||||
}| {
|
||||
match typ {
|
||||
ScopeEntryType::Normal => scope.push(name.clone(), value.clone()),
|
||||
ScopeEntryType::Constant => scope.push_constant(name.clone(), value.clone()),
|
||||
ScopeEntryType::Normal => scope.push(name, value),
|
||||
ScopeEntryType::Constant => scope.push_constant(name, value),
|
||||
};
|
||||
},
|
||||
);
|
||||
@ -451,7 +450,7 @@ impl Engine {
|
||||
|
||||
// Add captured variables into scope
|
||||
#[cfg(not(feature = "no_capture"))]
|
||||
if let Some(captured) = &capture {
|
||||
if let Some(captured) = capture {
|
||||
add_captured_variables_into_scope(&func.externals, captured, scope);
|
||||
}
|
||||
|
||||
@ -801,7 +800,7 @@ impl Engine {
|
||||
let mut args: StaticVec<_>;
|
||||
let mut is_ref = false;
|
||||
let capture = if capture && !scope.is_empty() {
|
||||
Some(scope.clone())
|
||||
Some(scope.flatten_clone())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
@ -875,7 +874,7 @@ impl Engine {
|
||||
|
||||
#[cfg(not(feature = "no_capture"))]
|
||||
let capture = if capture && !scope.is_empty() {
|
||||
Some(scope.clone())
|
||||
Some(scope.flatten_clone())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
@ -952,7 +951,7 @@ impl Engine {
|
||||
|
||||
// Add captured variables into scope
|
||||
#[cfg(not(feature = "no_capture"))]
|
||||
if let Some(captured) = &capture {
|
||||
if let Some(captured) = capture {
|
||||
add_captured_variables_into_scope(&func.externals, captured, scope);
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,7 @@ use crate::stdlib::{
|
||||
borrow::Cow,
|
||||
boxed::Box,
|
||||
char,
|
||||
collections::HashMap,
|
||||
collections::{HashMap, HashSet},
|
||||
fmt, format,
|
||||
hash::{Hash, Hasher},
|
||||
iter::empty,
|
||||
@ -355,7 +355,7 @@ impl fmt::Display for FnAccess {
|
||||
/// ## WARNING
|
||||
///
|
||||
/// This type is volatile and may change.
|
||||
#[derive(Debug, Clone, Hash)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ScriptFnDef {
|
||||
/// Function name.
|
||||
pub name: ImmutableString,
|
||||
@ -365,7 +365,7 @@ pub struct ScriptFnDef {
|
||||
pub params: StaticVec<String>,
|
||||
/// Access to external variables.
|
||||
#[cfg(not(feature = "no_capture"))]
|
||||
pub externals: StaticVec<String>,
|
||||
pub externals: HashSet<String>,
|
||||
/// Function body.
|
||||
pub body: Stmt,
|
||||
/// Position of the function definition.
|
||||
|
21
src/scope.rs
21
src/scope.rs
@ -4,7 +4,9 @@ use crate::any::{Dynamic, Variant};
|
||||
use crate::parser::{map_dynamic_to_expr, Expr};
|
||||
use crate::token::Position;
|
||||
|
||||
use crate::stdlib::{borrow::Cow, boxed::Box, iter, string::String, vec::Vec};
|
||||
use crate::stdlib::{
|
||||
borrow::Cow, boxed::Box, collections::HashMap, iter, string::String, vec::Vec,
|
||||
};
|
||||
|
||||
/// Type of an entry in the Scope.
|
||||
#[derive(Debug, Eq, PartialEq, Hash, Copy, Clone)]
|
||||
@ -389,13 +391,28 @@ impl<'a> Scope<'a> {
|
||||
self
|
||||
}
|
||||
|
||||
/// Clone the Scope, keeping only the last instances of each variable name.
|
||||
/// Shadowed variables are omitted in the copy.
|
||||
#[cfg(not(feature = "no_capture"))]
|
||||
pub(crate) fn flatten_clone(&self) -> Self {
|
||||
let mut entries: HashMap<&str, Entry> = Default::default();
|
||||
|
||||
self.0.iter().rev().for_each(|entry| {
|
||||
entries
|
||||
.entry(entry.name.as_ref())
|
||||
.or_insert_with(|| entry.clone());
|
||||
});
|
||||
|
||||
Self(entries.into_iter().map(|(_, v)| v).collect())
|
||||
}
|
||||
|
||||
/// Get an iterator to entries in the Scope.
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
pub(crate) fn into_iter(self) -> impl Iterator<Item = Entry<'a>> {
|
||||
self.0.into_iter()
|
||||
}
|
||||
|
||||
/// Get an iterator to entries in the Scope.
|
||||
/// Get an iterator to entries in the Scope in reverse order.
|
||||
pub(crate) fn to_iter(&self) -> impl Iterator<Item = &Entry> {
|
||||
self.0.iter().rev() // Always search a Scope in reverse order
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user