Use Scope::flatten_clone for capturing.

This commit is contained in:
Stephen Chung 2020-07-30 23:29:30 +08:00
parent 7d4620d0d9
commit a7ff207636
3 changed files with 34 additions and 18 deletions

View File

@ -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);
}

View File

@ -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.

View File

@ -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
}