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::{
|
use crate::stdlib::{
|
||||||
any::{type_name, TypeId},
|
any::{type_name, TypeId},
|
||||||
boxed::Box,
|
boxed::Box,
|
||||||
|
collections::HashSet,
|
||||||
convert::TryFrom,
|
convert::TryFrom,
|
||||||
format,
|
format,
|
||||||
iter::{empty, once},
|
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
|
// Add captured variables into scope
|
||||||
#[cfg(not(feature = "no_capture"))]
|
#[cfg(not(feature = "no_capture"))]
|
||||||
fn add_captured_variables_into_scope<'s>(
|
fn add_captured_variables_into_scope<'s>(
|
||||||
externals: &[String],
|
externals: &HashSet<String>,
|
||||||
captured: &'s Scope<'s>,
|
captured: Scope<'s>,
|
||||||
scope: &mut Scope<'s>,
|
scope: &mut Scope<'s>,
|
||||||
) {
|
) {
|
||||||
externals
|
captured
|
||||||
.iter()
|
.into_iter()
|
||||||
.map(|var_name| captured.get_entry(var_name))
|
.filter(|ScopeEntry { name, .. }| externals.contains(name.as_ref()))
|
||||||
.filter(Option::is_some)
|
|
||||||
.map(Option::unwrap)
|
|
||||||
.for_each(
|
.for_each(
|
||||||
|ScopeEntry {
|
|ScopeEntry {
|
||||||
name, typ, value, ..
|
name, typ, value, ..
|
||||||
}| {
|
}| {
|
||||||
match typ {
|
match typ {
|
||||||
ScopeEntryType::Normal => scope.push(name.clone(), value.clone()),
|
ScopeEntryType::Normal => scope.push(name, value),
|
||||||
ScopeEntryType::Constant => scope.push_constant(name.clone(), value.clone()),
|
ScopeEntryType::Constant => scope.push_constant(name, value),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -451,7 +450,7 @@ impl Engine {
|
|||||||
|
|
||||||
// Add captured variables into scope
|
// Add captured variables into scope
|
||||||
#[cfg(not(feature = "no_capture"))]
|
#[cfg(not(feature = "no_capture"))]
|
||||||
if let Some(captured) = &capture {
|
if let Some(captured) = capture {
|
||||||
add_captured_variables_into_scope(&func.externals, captured, scope);
|
add_captured_variables_into_scope(&func.externals, captured, scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -801,7 +800,7 @@ impl Engine {
|
|||||||
let mut args: StaticVec<_>;
|
let mut args: StaticVec<_>;
|
||||||
let mut is_ref = false;
|
let mut is_ref = false;
|
||||||
let capture = if capture && !scope.is_empty() {
|
let capture = if capture && !scope.is_empty() {
|
||||||
Some(scope.clone())
|
Some(scope.flatten_clone())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
@ -875,7 +874,7 @@ impl Engine {
|
|||||||
|
|
||||||
#[cfg(not(feature = "no_capture"))]
|
#[cfg(not(feature = "no_capture"))]
|
||||||
let capture = if capture && !scope.is_empty() {
|
let capture = if capture && !scope.is_empty() {
|
||||||
Some(scope.clone())
|
Some(scope.flatten_clone())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
@ -952,7 +951,7 @@ impl Engine {
|
|||||||
|
|
||||||
// Add captured variables into scope
|
// Add captured variables into scope
|
||||||
#[cfg(not(feature = "no_capture"))]
|
#[cfg(not(feature = "no_capture"))]
|
||||||
if let Some(captured) = &capture {
|
if let Some(captured) = capture {
|
||||||
add_captured_variables_into_scope(&func.externals, captured, scope);
|
add_captured_variables_into_scope(&func.externals, captured, scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ use crate::stdlib::{
|
|||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
boxed::Box,
|
boxed::Box,
|
||||||
char,
|
char,
|
||||||
collections::HashMap,
|
collections::{HashMap, HashSet},
|
||||||
fmt, format,
|
fmt, format,
|
||||||
hash::{Hash, Hasher},
|
hash::{Hash, Hasher},
|
||||||
iter::empty,
|
iter::empty,
|
||||||
@ -355,7 +355,7 @@ impl fmt::Display for FnAccess {
|
|||||||
/// ## WARNING
|
/// ## WARNING
|
||||||
///
|
///
|
||||||
/// This type is volatile and may change.
|
/// This type is volatile and may change.
|
||||||
#[derive(Debug, Clone, Hash)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ScriptFnDef {
|
pub struct ScriptFnDef {
|
||||||
/// Function name.
|
/// Function name.
|
||||||
pub name: ImmutableString,
|
pub name: ImmutableString,
|
||||||
@ -365,7 +365,7 @@ pub struct ScriptFnDef {
|
|||||||
pub params: StaticVec<String>,
|
pub params: StaticVec<String>,
|
||||||
/// Access to external variables.
|
/// Access to external variables.
|
||||||
#[cfg(not(feature = "no_capture"))]
|
#[cfg(not(feature = "no_capture"))]
|
||||||
pub externals: StaticVec<String>,
|
pub externals: HashSet<String>,
|
||||||
/// Function body.
|
/// Function body.
|
||||||
pub body: Stmt,
|
pub body: Stmt,
|
||||||
/// Position of the function definition.
|
/// 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::parser::{map_dynamic_to_expr, Expr};
|
||||||
use crate::token::Position;
|
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.
|
/// Type of an entry in the Scope.
|
||||||
#[derive(Debug, Eq, PartialEq, Hash, Copy, Clone)]
|
#[derive(Debug, Eq, PartialEq, Hash, Copy, Clone)]
|
||||||
@ -389,13 +391,28 @@ impl<'a> Scope<'a> {
|
|||||||
self
|
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.
|
/// Get an iterator to entries in the Scope.
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
pub(crate) fn into_iter(self) -> impl Iterator<Item = Entry<'a>> {
|
pub(crate) fn into_iter(self) -> impl Iterator<Item = Entry<'a>> {
|
||||||
self.0.into_iter()
|
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> {
|
pub(crate) fn to_iter(&self) -> impl Iterator<Item = &Entry> {
|
||||||
self.0.iter().rev() // Always search a Scope in reverse order
|
self.0.iter().rev() // Always search a Scope in reverse order
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user