Recursively store encapsulated environment into values.
This commit is contained in:
parent
d350a948e7
commit
db7410776a
@ -834,13 +834,13 @@ impl Engine {
|
|||||||
let fn_ptr = mem::take(&mut call_args[0]).cast::<FnPtr>();
|
let fn_ptr = mem::take(&mut call_args[0]).cast::<FnPtr>();
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
let (fn_name, is_anon, fn_curry, environ, fn_def) = {
|
let (fn_name, is_anon, fn_curry, _environ, fn_def) = {
|
||||||
let is_anon = fn_ptr.is_anonymous();
|
let is_anon = fn_ptr.is_anonymous();
|
||||||
let (fn_name, fn_curry, environ, fn_def) = fn_ptr.take_data();
|
let (fn_name, fn_curry, environ, fn_def) = fn_ptr.take_data();
|
||||||
(fn_name, is_anon, fn_curry, environ, fn_def)
|
(fn_name, is_anon, fn_curry, environ, fn_def)
|
||||||
};
|
};
|
||||||
#[cfg(feature = "no_function")]
|
#[cfg(feature = "no_function")]
|
||||||
let (fn_name, is_anon, environ, fn_curry) = {
|
let (fn_name, is_anon, fn_curry, _environ) = {
|
||||||
let (fn_name, fn_curry, environ) = fn_ptr.take_data();
|
let (fn_name, fn_curry, environ) = fn_ptr.take_data();
|
||||||
(fn_name, false, fn_curry, environ)
|
(fn_name, false, fn_curry, environ)
|
||||||
};
|
};
|
||||||
@ -868,7 +868,7 @@ impl Engine {
|
|||||||
caches,
|
caches,
|
||||||
&mut Scope::new(),
|
&mut Scope::new(),
|
||||||
target,
|
target,
|
||||||
environ.as_deref(),
|
_environ.as_deref(),
|
||||||
&fn_def,
|
&fn_def,
|
||||||
args,
|
args,
|
||||||
true,
|
true,
|
||||||
@ -1043,13 +1043,13 @@ impl Engine {
|
|||||||
let fn_ptr = arg_value.cast::<FnPtr>();
|
let fn_ptr = arg_value.cast::<FnPtr>();
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
let (fn_name, is_anon, fn_curry, environ, fn_def) = {
|
let (fn_name, is_anon, fn_curry, _environ, fn_def) = {
|
||||||
let is_anon = fn_ptr.is_anonymous();
|
let is_anon = fn_ptr.is_anonymous();
|
||||||
let (fn_name, fn_curry, environ, fn_def) = fn_ptr.take_data();
|
let (fn_name, fn_curry, environ, fn_def) = fn_ptr.take_data();
|
||||||
(fn_name, is_anon, fn_curry, environ, fn_def)
|
(fn_name, is_anon, fn_curry, environ, fn_def)
|
||||||
};
|
};
|
||||||
#[cfg(feature = "no_function")]
|
#[cfg(feature = "no_function")]
|
||||||
let (fn_name, is_anon, fn_curry, environ) = {
|
let (fn_name, is_anon, fn_curry, _environ) = {
|
||||||
let (fn_name, fn_curry, environ) = fn_ptr.take_data();
|
let (fn_name, fn_curry, environ) = fn_ptr.take_data();
|
||||||
(fn_name, false, fn_curry, environ)
|
(fn_name, false, fn_curry, environ)
|
||||||
};
|
};
|
||||||
@ -1077,7 +1077,7 @@ impl Engine {
|
|||||||
caches,
|
caches,
|
||||||
&mut Scope::new(),
|
&mut Scope::new(),
|
||||||
&mut this_ptr,
|
&mut this_ptr,
|
||||||
environ.as_deref(),
|
_environ.as_deref(),
|
||||||
&fn_def,
|
&fn_def,
|
||||||
args,
|
args,
|
||||||
true,
|
true,
|
||||||
|
@ -2139,19 +2139,37 @@ impl Module {
|
|||||||
let _ = result?;
|
let _ = result?;
|
||||||
|
|
||||||
// Encapsulated environment
|
// Encapsulated environment
|
||||||
#[cfg(not(feature = "no_function"))]
|
|
||||||
let environ = Shared::new(crate::func::EncapsulatedEnviron {
|
let environ = Shared::new(crate::func::EncapsulatedEnviron {
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
lib: ast.shared_lib().clone(),
|
lib: ast.shared_lib().clone(),
|
||||||
imports: imports.into_boxed_slice(),
|
imports: imports.into_boxed_slice(),
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
constants,
|
constants,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
fn update_encapsulated_environ(
|
||||||
|
value: &mut Dynamic,
|
||||||
|
environ: &Shared<crate::func::EncapsulatedEnviron>,
|
||||||
|
) {
|
||||||
|
match value.0 {
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
crate::types::dynamic::Union::Array(ref mut a, _, _) => a
|
||||||
|
.iter_mut()
|
||||||
|
.for_each(|v| update_encapsulated_environ(v, environ)),
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
crate::types::dynamic::Union::Map(ref mut map, _, _) => map
|
||||||
|
.values_mut()
|
||||||
|
.for_each(|v| update_encapsulated_environ(v, environ)),
|
||||||
|
crate::types::dynamic::Union::FnPtr(ref mut fn_ptr, _, _) => {
|
||||||
|
fn_ptr.set_encapsulated_environ(Some(environ.clone()))
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Variables with an alias left in the scope become module variables
|
// Variables with an alias left in the scope become module variables
|
||||||
for (_name, mut value, mut aliases) in scope {
|
for (_name, mut value, mut aliases) in scope {
|
||||||
#[cfg(not(feature = "no_function"))]
|
update_encapsulated_environ(&mut value, &environ);
|
||||||
if let Some(mut fn_ptr) = value.write_lock::<crate::FnPtr>() {
|
|
||||||
fn_ptr.set_encapsulated_environ(Some(environ.clone()));
|
|
||||||
}
|
|
||||||
|
|
||||||
match aliases.len() {
|
match aliases.len() {
|
||||||
0 => (),
|
0 => (),
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
//! The `FnPtr` type.
|
//! The `FnPtr` type.
|
||||||
|
|
||||||
use crate::eval::GlobalRuntimeState;
|
use crate::eval::GlobalRuntimeState;
|
||||||
|
use crate::func::EncapsulatedEnviron;
|
||||||
use crate::tokenizer::is_valid_function_name;
|
use crate::tokenizer::is_valid_function_name;
|
||||||
use crate::types::dynamic::Variant;
|
use crate::types::dynamic::Variant;
|
||||||
use crate::{
|
use crate::{
|
||||||
Dynamic, Engine, FnArgsVec, FuncArgs, ImmutableString, NativeCallContext, Position, RhaiError,
|
Dynamic, Engine, FnArgsVec, FuncArgs, ImmutableString, NativeCallContext, Position, RhaiError,
|
||||||
RhaiResult, RhaiResultOf, StaticVec, AST, ERR,
|
RhaiResult, RhaiResultOf, Shared, StaticVec, AST, ERR,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
@ -13,7 +14,7 @@ use std::{
|
|||||||
any::{type_name, TypeId},
|
any::{type_name, TypeId},
|
||||||
convert::{TryFrom, TryInto},
|
convert::{TryFrom, TryInto},
|
||||||
fmt,
|
fmt,
|
||||||
hash::Hash,
|
hash::{Hash, Hasher},
|
||||||
mem,
|
mem,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -23,23 +24,23 @@ use std::{
|
|||||||
pub struct FnPtr {
|
pub struct FnPtr {
|
||||||
name: ImmutableString,
|
name: ImmutableString,
|
||||||
curry: StaticVec<Dynamic>,
|
curry: StaticVec<Dynamic>,
|
||||||
environ: Option<crate::Shared<crate::func::EncapsulatedEnviron>>,
|
environ: Option<Shared<EncapsulatedEnviron>>,
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
fn_def: Option<crate::Shared<crate::ast::ScriptFnDef>>,
|
fn_def: Option<Shared<crate::ast::ScriptFnDef>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Hash for FnPtr {
|
impl Hash for FnPtr {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
self.name.hash(state);
|
self.name.hash(state);
|
||||||
self.curry.hash(state);
|
self.curry.hash(state);
|
||||||
|
|
||||||
|
// Hash the shared [`EncapsulatedEnviron`] by hashing its shared pointer.
|
||||||
|
self.environ.as_ref().map(|e| Shared::as_ptr(e)).hash(state);
|
||||||
|
|
||||||
// Hash the linked [`ScriptFnDef`][crate::ast::ScriptFnDef] by hashing its shared pointer.
|
// Hash the linked [`ScriptFnDef`][crate::ast::ScriptFnDef] by hashing its shared pointer.
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
self.fn_def
|
self.fn_def.as_ref().map(|f| Shared::as_ptr(f)).hash(state);
|
||||||
.as_ref()
|
|
||||||
.map(|f| crate::Shared::as_ptr(f))
|
|
||||||
.hash(state);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,8 +103,8 @@ impl FnPtr {
|
|||||||
) -> (
|
) -> (
|
||||||
ImmutableString,
|
ImmutableString,
|
||||||
StaticVec<Dynamic>,
|
StaticVec<Dynamic>,
|
||||||
Option<crate::Shared<crate::func::EncapsulatedEnviron>>,
|
Option<Shared<EncapsulatedEnviron>>,
|
||||||
Option<crate::Shared<crate::ast::ScriptFnDef>>,
|
Option<Shared<crate::ast::ScriptFnDef>>,
|
||||||
) {
|
) {
|
||||||
(self.name, self.curry, self.environ, self.fn_def)
|
(self.name, self.curry, self.environ, self.fn_def)
|
||||||
}
|
}
|
||||||
@ -116,7 +117,7 @@ impl FnPtr {
|
|||||||
) -> (
|
) -> (
|
||||||
ImmutableString,
|
ImmutableString,
|
||||||
StaticVec<Dynamic>,
|
StaticVec<Dynamic>,
|
||||||
Option<crate::Shared<crate::func::EncapsulatedEnviron>>,
|
Option<Shared<EncapsulatedEnviron>>,
|
||||||
) {
|
) {
|
||||||
(self.name, self.curry, self.environ)
|
(self.name, self.curry, self.environ)
|
||||||
}
|
}
|
||||||
@ -192,7 +193,7 @@ impl FnPtr {
|
|||||||
args: impl FuncArgs,
|
args: impl FuncArgs,
|
||||||
) -> RhaiResultOf<T> {
|
) -> RhaiResultOf<T> {
|
||||||
let _ast = ast;
|
let _ast = ast;
|
||||||
let mut arg_values = crate::StaticVec::new_const();
|
let mut arg_values = StaticVec::new_const();
|
||||||
args.parse(&mut arg_values);
|
args.parse(&mut arg_values);
|
||||||
|
|
||||||
let global = &mut GlobalRuntimeState::new(engine);
|
let global = &mut GlobalRuntimeState::new(engine);
|
||||||
@ -228,7 +229,7 @@ impl FnPtr {
|
|||||||
context: &NativeCallContext,
|
context: &NativeCallContext,
|
||||||
args: impl FuncArgs,
|
args: impl FuncArgs,
|
||||||
) -> RhaiResultOf<T> {
|
) -> RhaiResultOf<T> {
|
||||||
let mut arg_values = crate::StaticVec::new_const();
|
let mut arg_values = StaticVec::new_const();
|
||||||
args.parse(&mut arg_values);
|
args.parse(&mut arg_values);
|
||||||
|
|
||||||
self.call_raw(context, None, arg_values).and_then(|result| {
|
self.call_raw(context, None, arg_values).and_then(|result| {
|
||||||
@ -316,17 +317,19 @@ impl FnPtr {
|
|||||||
|
|
||||||
context.call_fn_raw(self.fn_name(), is_method, is_method, args)
|
context.call_fn_raw(self.fn_name(), is_method, is_method, args)
|
||||||
}
|
}
|
||||||
/// Get a reference to the [encapsulated environment][crate::func::EncapsulatedEnviron].
|
/// Get a reference to the [encapsulated environment][EncapsulatedEnviron].
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn encapsulated_environ(&self) -> Option<&crate::func::EncapsulatedEnviron> {
|
#[allow(dead_code)]
|
||||||
|
pub(crate) fn encapsulated_environ(&self) -> Option<&EncapsulatedEnviron> {
|
||||||
self.environ.as_deref()
|
self.environ.as_deref()
|
||||||
}
|
}
|
||||||
/// Set a reference to the [encapsulated environment][crate::func::EncapsulatedEnviron].
|
/// Set a reference to the [encapsulated environment][EncapsulatedEnviron].
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
#[allow(dead_code)]
|
||||||
pub(crate) fn set_encapsulated_environ(
|
pub(crate) fn set_encapsulated_environ(
|
||||||
&mut self,
|
&mut self,
|
||||||
value: Option<impl Into<crate::Shared<crate::func::EncapsulatedEnviron>>>,
|
value: Option<impl Into<Shared<EncapsulatedEnviron>>>,
|
||||||
) {
|
) {
|
||||||
self.environ = value.map(Into::into);
|
self.environ = value.map(Into::into);
|
||||||
}
|
}
|
||||||
@ -334,16 +337,13 @@ impl FnPtr {
|
|||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn fn_def(&self) -> Option<&crate::Shared<crate::ast::ScriptFnDef>> {
|
pub(crate) fn fn_def(&self) -> Option<&Shared<crate::ast::ScriptFnDef>> {
|
||||||
self.fn_def.as_ref()
|
self.fn_def.as_ref()
|
||||||
}
|
}
|
||||||
/// Set a reference to the linked [`ScriptFnDef`][crate::ast::ScriptFnDef].
|
/// Set a reference to the linked [`ScriptFnDef`][crate::ast::ScriptFnDef].
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn set_fn_def(
|
pub(crate) fn set_fn_def(&mut self, value: Option<impl Into<Shared<crate::ast::ScriptFnDef>>>) {
|
||||||
&mut self,
|
|
||||||
value: Option<impl Into<crate::Shared<crate::ast::ScriptFnDef>>>,
|
|
||||||
) {
|
|
||||||
self.fn_def = value.map(Into::into);
|
self.fn_def = value.map(Into::into);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -374,7 +374,7 @@ impl TryFrom<ImmutableString> for FnPtr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
impl<T: Into<crate::Shared<crate::ast::ScriptFnDef>>> From<T> for FnPtr {
|
impl<T: Into<Shared<crate::ast::ScriptFnDef>>> From<T> for FnPtr {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn from(value: T) -> Self {
|
fn from(value: T) -> Self {
|
||||||
let fn_def = value.into();
|
let fn_def = value.into();
|
||||||
|
Loading…
Reference in New Issue
Block a user