Implement closures.
This commit is contained in:
146
src/any.rs
146
src/any.rs
@@ -4,7 +4,7 @@ use crate::fn_native::{FnPtr, SendSync};
|
||||
use crate::parser::{ImmutableString, INT};
|
||||
use crate::r#unsafe::{unsafe_cast_box, unsafe_try_cast};
|
||||
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
use crate::fn_native::SharedMut;
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
@@ -24,14 +24,14 @@ use crate::stdlib::{
|
||||
string::String,
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
#[cfg(not(feature = "sync"))]
|
||||
use crate::stdlib::{
|
||||
cell::{Ref, RefCell, RefMut},
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
#[cfg(feature = "sync")]
|
||||
use crate::stdlib::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||
|
||||
@@ -159,7 +159,7 @@ pub enum Union {
|
||||
Map(Box<Map>),
|
||||
FnPtr(Box<FnPtr>),
|
||||
Variant(Box<Box<dyn Variant>>),
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
Shared(SharedMut<Dynamic>),
|
||||
}
|
||||
|
||||
@@ -176,11 +176,11 @@ enum DynamicReadLockInner<'d, T: Variant + Clone> {
|
||||
/// A simple reference to a non-shared value.
|
||||
Reference(&'d T),
|
||||
/// A read guard to a shared `RefCell`.
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
#[cfg(not(feature = "sync"))]
|
||||
Guard(Ref<'d, Dynamic>),
|
||||
/// A read guard to a shared `RwLock`.
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
#[cfg(feature = "sync")]
|
||||
Guard(RwLockReadGuard<'d, Dynamic>),
|
||||
}
|
||||
@@ -193,7 +193,7 @@ impl<'d, T: Variant + Clone> Deref for DynamicReadLock<'d, T> {
|
||||
match &self.0 {
|
||||
DynamicReadLockInner::Reference(reference) => *reference,
|
||||
// Unwrapping is safe because all checking is already done in its constructor
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
DynamicReadLockInner::Guard(guard) => guard.downcast_ref().unwrap(),
|
||||
}
|
||||
}
|
||||
@@ -212,11 +212,11 @@ enum DynamicWriteLockInner<'d, T: Variant + Clone> {
|
||||
/// A simple mutable reference to a non-shared value.
|
||||
Reference(&'d mut T),
|
||||
/// A write guard to a shared `RefCell`.
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
#[cfg(not(feature = "sync"))]
|
||||
Guard(RefMut<'d, Dynamic>),
|
||||
/// A write guard to a shared `RwLock`.
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
#[cfg(feature = "sync")]
|
||||
Guard(RwLockWriteGuard<'d, Dynamic>),
|
||||
}
|
||||
@@ -229,7 +229,7 @@ impl<'d, T: Variant + Clone> Deref for DynamicWriteLock<'d, T> {
|
||||
match &self.0 {
|
||||
DynamicWriteLockInner::Reference(reference) => *reference,
|
||||
// Unwrapping is safe because all checking is already done in its constructor
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
DynamicWriteLockInner::Guard(guard) => guard.downcast_ref().unwrap(),
|
||||
}
|
||||
}
|
||||
@@ -241,7 +241,7 @@ impl<'d, T: Variant + Clone> DerefMut for DynamicWriteLock<'d, T> {
|
||||
match &mut self.0 {
|
||||
DynamicWriteLockInner::Reference(reference) => *reference,
|
||||
// Unwrapping is safe because all checking is already done in its constructor
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
DynamicWriteLockInner::Guard(guard) => guard.downcast_mut().unwrap(),
|
||||
}
|
||||
}
|
||||
@@ -261,7 +261,7 @@ impl Dynamic {
|
||||
/// instead of one of the supported system primitive types?
|
||||
pub fn is_shared(&self) -> bool {
|
||||
match self.0 {
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
Union::Shared(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
@@ -302,10 +302,10 @@ impl Dynamic {
|
||||
Union::Map(_) => TypeId::of::<Map>(),
|
||||
Union::FnPtr(_) => TypeId::of::<FnPtr>(),
|
||||
Union::Variant(value) => (***value).type_id(),
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
#[cfg(not(feature = "sync"))]
|
||||
Union::Shared(cell) => (*cell.borrow()).type_id(),
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
#[cfg(feature = "sync")]
|
||||
Union::Shared(cell) => (*cell.read().unwrap()).type_id(),
|
||||
}
|
||||
@@ -335,10 +335,10 @@ impl Dynamic {
|
||||
#[cfg(not(feature = "no_std"))]
|
||||
Union::Variant(value) if value.is::<Instant>() => "timestamp",
|
||||
Union::Variant(value) => (***value).type_name(),
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
#[cfg(not(feature = "sync"))]
|
||||
Union::Shared(cell) => (*cell.borrow()).type_name(),
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
#[cfg(feature = "sync")]
|
||||
Union::Shared(cell) => (*cell.read().unwrap()).type_name(),
|
||||
}
|
||||
@@ -396,7 +396,7 @@ impl fmt::Display for Dynamic {
|
||||
#[cfg(not(feature = "no_std"))]
|
||||
Union::Variant(value) if value.is::<Instant>() => write!(f, "<timestamp>"),
|
||||
Union::Variant(value) => write!(f, "{}", (*value).type_name()),
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
Union::Shared(_) => f.write_str("<shared>"),
|
||||
}
|
||||
}
|
||||
@@ -424,7 +424,7 @@ impl fmt::Debug for Dynamic {
|
||||
#[cfg(not(feature = "no_std"))]
|
||||
Union::Variant(value) if value.is::<Instant>() => write!(f, "<timestamp>"),
|
||||
Union::Variant(value) => write!(f, "{}", (*value).type_name()),
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
Union::Shared(_) => f.write_str("<shared>"),
|
||||
}
|
||||
}
|
||||
@@ -446,7 +446,7 @@ impl Clone for Dynamic {
|
||||
Union::Map(ref value) => Self(Union::Map(value.clone())),
|
||||
Union::FnPtr(ref value) => Self(Union::FnPtr(value.clone())),
|
||||
Union::Variant(ref value) => (***value).clone_into_dynamic(),
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
Union::Shared(ref cell) => Self(Union::Shared(cell.clone())),
|
||||
}
|
||||
}
|
||||
@@ -571,9 +571,9 @@ impl Dynamic {
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics under the `no_shared` feature.
|
||||
/// Panics under the `no_closure` feature.
|
||||
pub fn into_shared(self) -> Self {
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
return match self.0 {
|
||||
Union::Shared(..) => self,
|
||||
#[cfg(not(feature = "sync"))]
|
||||
@@ -582,7 +582,7 @@ impl Dynamic {
|
||||
_ => Self(Union::Shared(Arc::new(RwLock::new(self)))),
|
||||
};
|
||||
|
||||
#[cfg(feature = "no_shared")]
|
||||
#[cfg(feature = "no_closure")]
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
@@ -614,11 +614,11 @@ impl Dynamic {
|
||||
let type_id = TypeId::of::<T>();
|
||||
|
||||
match self.0 {
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
#[cfg(not(feature = "sync"))]
|
||||
Union::Shared(cell) => return cell.borrow().clone().try_cast(),
|
||||
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
#[cfg(feature = "sync")]
|
||||
Union::Shared(cell) => return cell.read().unwrap().clone().try_cast(),
|
||||
_ => (),
|
||||
@@ -703,7 +703,7 @@ impl Dynamic {
|
||||
|
||||
match self.0 {
|
||||
Union::Variant(value) => (*value).as_box_any().downcast().map(|x| *x).ok(),
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
Union::Shared(_) => unreachable!(),
|
||||
_ => None,
|
||||
}
|
||||
@@ -748,17 +748,17 @@ impl Dynamic {
|
||||
///
|
||||
/// Returns `None` if the cast fails.
|
||||
#[inline(always)]
|
||||
pub fn clone_inner_data<T: Variant + Clone>(&self) -> Option<T> {
|
||||
pub fn clone_inner_data<T: Variant + Clone>(self) -> Option<T> {
|
||||
match self.0 {
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
Union::Shared(ref cell) => {
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
Union::Shared(cell) => {
|
||||
#[cfg(not(feature = "sync"))]
|
||||
return Some(cell.borrow().downcast_ref::<T>().unwrap().clone());
|
||||
|
||||
#[cfg(feature = "sync")]
|
||||
return Some(cell.read().unwrap().downcast_ref::<T>().unwrap().clone());
|
||||
}
|
||||
_ => self.downcast_ref().cloned(),
|
||||
_ => self.try_cast(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -772,7 +772,7 @@ impl Dynamic {
|
||||
#[inline(always)]
|
||||
pub fn is_locked(&self) -> bool {
|
||||
match self.0 {
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
Union::Shared(ref _cell) => {
|
||||
#[cfg(not(feature = "sync"))]
|
||||
return _cell.try_borrow().is_err();
|
||||
@@ -788,22 +788,33 @@ impl Dynamic {
|
||||
/// Casting to `Dynamic` just returns a reference to it.
|
||||
///
|
||||
/// Returns `None` if the cast fails.
|
||||
///
|
||||
/// # Panics and Deadlocks When Value is Shared
|
||||
///
|
||||
/// Under the `sync` feature, this call may deadlock.
|
||||
/// Otherwise, this call panics if the data is currently borrowed for write.
|
||||
#[inline(always)]
|
||||
pub fn read_lock<T: Variant + Clone>(&self) -> Option<DynamicReadLock<T>> {
|
||||
match self.0 {
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
Union::Shared(ref cell) => {
|
||||
#[cfg(not(feature = "sync"))]
|
||||
return Some(DynamicReadLock(DynamicReadLockInner::Guard(cell.borrow())));
|
||||
let data = cell.borrow();
|
||||
|
||||
#[cfg(feature = "sync")]
|
||||
return Some(DynamicReadLock(DynamicReadLockInner::Guard(
|
||||
cell.read().unwrap(),
|
||||
)));
|
||||
let data = cell.read().unwrap();
|
||||
|
||||
let type_id = (*data).type_id();
|
||||
|
||||
if type_id != TypeId::of::<T>() && TypeId::of::<Dynamic>() != TypeId::of::<T>() {
|
||||
None
|
||||
} else {
|
||||
Some(DynamicReadLock(DynamicReadLockInner::Guard(data)))
|
||||
}
|
||||
}
|
||||
_ => self
|
||||
.downcast_ref()
|
||||
.map(|reference| DynamicReadLock(DynamicReadLockInner::Reference(reference))),
|
||||
.map(|r| DynamicReadLock(DynamicReadLockInner::Reference(r))),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -811,24 +822,33 @@ impl Dynamic {
|
||||
/// Casting to `Dynamic` just returns a mutable reference to it.
|
||||
///
|
||||
/// Returns `None` if the cast fails.
|
||||
///
|
||||
/// # Panics and Deadlocks When Value is Shared
|
||||
///
|
||||
/// Under the `sync` feature, this call may deadlock.
|
||||
/// Otherwise, this call panics if the data is currently borrowed for write.
|
||||
#[inline(always)]
|
||||
pub fn write_lock<T: Variant + Clone>(&mut self) -> Option<DynamicWriteLock<T>> {
|
||||
match self.0 {
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
Union::Shared(ref cell) => {
|
||||
#[cfg(not(feature = "sync"))]
|
||||
return Some(DynamicWriteLock(DynamicWriteLockInner::Guard(
|
||||
cell.borrow_mut(),
|
||||
)));
|
||||
let data = cell.borrow_mut();
|
||||
|
||||
#[cfg(feature = "sync")]
|
||||
return Some(DynamicWriteLock(DynamicWriteLockInner::Guard(
|
||||
cell.write().unwrap(),
|
||||
)));
|
||||
let data = cell.write().unwrap();
|
||||
|
||||
let type_id = (*data).type_id();
|
||||
|
||||
if type_id != TypeId::of::<T>() && TypeId::of::<Dynamic>() != TypeId::of::<T>() {
|
||||
None
|
||||
} else {
|
||||
Some(DynamicWriteLock(DynamicWriteLockInner::Guard(data)))
|
||||
}
|
||||
}
|
||||
_ => self
|
||||
.downcast_mut()
|
||||
.map(|reference| DynamicWriteLock(DynamicWriteLockInner::Reference(reference))),
|
||||
.map(|r| DynamicWriteLock(DynamicWriteLockInner::Reference(r))),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -836,6 +856,10 @@ impl Dynamic {
|
||||
/// Casting to `Dynamic` just returns a reference to it.
|
||||
///
|
||||
/// Returns `None` if the cast fails.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the value is shared.
|
||||
#[inline(always)]
|
||||
fn downcast_ref<T: Variant + Clone>(&self) -> Option<&T> {
|
||||
let type_id = TypeId::of::<T>();
|
||||
@@ -909,7 +933,7 @@ impl Dynamic {
|
||||
|
||||
match &self.0 {
|
||||
Union::Variant(value) => value.as_ref().as_ref().as_any().downcast_ref::<T>(),
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
Union::Shared(_) => unreachable!(),
|
||||
_ => None,
|
||||
}
|
||||
@@ -919,6 +943,10 @@ impl Dynamic {
|
||||
/// Casting to `Dynamic` just returns a mutable reference to it.
|
||||
///
|
||||
/// Returns `None` if the cast fails.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the value is shared.
|
||||
#[inline(always)]
|
||||
fn downcast_mut<T: Variant + Clone>(&mut self) -> Option<&mut T> {
|
||||
let type_id = TypeId::of::<T>();
|
||||
@@ -986,7 +1014,7 @@ impl Dynamic {
|
||||
|
||||
match &mut self.0 {
|
||||
Union::Variant(value) => value.as_mut().as_mut_any().downcast_mut::<T>(),
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
Union::Shared(_) => unreachable!(),
|
||||
_ => None,
|
||||
}
|
||||
@@ -997,10 +1025,8 @@ impl Dynamic {
|
||||
pub fn as_int(&self) -> Result<INT, &'static str> {
|
||||
match self.0 {
|
||||
Union::Int(n) => Ok(n),
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
Union::Shared(_) => self
|
||||
.clone_inner_data::<INT>()
|
||||
.ok_or_else(|| self.type_name()),
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
Union::Shared(_) => self.read_lock().map(|v| *v).ok_or_else(|| self.type_name()),
|
||||
_ => Err(self.type_name()),
|
||||
}
|
||||
}
|
||||
@@ -1011,10 +1037,8 @@ impl Dynamic {
|
||||
pub fn as_float(&self) -> Result<FLOAT, &'static str> {
|
||||
match self.0 {
|
||||
Union::Float(n) => Ok(n),
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
Union::Shared(_) => self
|
||||
.clone_inner_data::<FLOAT>()
|
||||
.ok_or_else(|| self.type_name()),
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
Union::Shared(_) => self.read_lock().map(|v| *v).ok_or_else(|| self.type_name()),
|
||||
_ => Err(self.type_name()),
|
||||
}
|
||||
}
|
||||
@@ -1024,10 +1048,8 @@ impl Dynamic {
|
||||
pub fn as_bool(&self) -> Result<bool, &'static str> {
|
||||
match self.0 {
|
||||
Union::Bool(b) => Ok(b),
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
Union::Shared(_) => self
|
||||
.clone_inner_data::<bool>()
|
||||
.ok_or_else(|| self.type_name()),
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
Union::Shared(_) => self.read_lock().map(|v| *v).ok_or_else(|| self.type_name()),
|
||||
_ => Err(self.type_name()),
|
||||
}
|
||||
}
|
||||
@@ -1037,10 +1059,8 @@ impl Dynamic {
|
||||
pub fn as_char(&self) -> Result<char, &'static str> {
|
||||
match self.0 {
|
||||
Union::Char(n) => Ok(n),
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
Union::Shared(_) => self
|
||||
.clone_inner_data::<char>()
|
||||
.ok_or_else(|| self.type_name()),
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
Union::Shared(_) => self.read_lock().map(|v| *v).ok_or_else(|| self.type_name()),
|
||||
_ => Err(self.type_name()),
|
||||
}
|
||||
}
|
||||
@@ -1070,7 +1090,7 @@ impl Dynamic {
|
||||
match self.0 {
|
||||
Union::Str(s) => Ok(s),
|
||||
Union::FnPtr(f) => Ok(f.take_data().0),
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
Union::Shared(cell) => {
|
||||
#[cfg(not(feature = "sync"))]
|
||||
{
|
||||
|
@@ -1284,7 +1284,7 @@ impl Engine {
|
||||
let args = args.as_mut();
|
||||
|
||||
// Check for data race.
|
||||
if cfg!(not(feature = "no_shared")) {
|
||||
if cfg!(not(feature = "no_closure")) {
|
||||
ensure_no_data_race(name, args, false)?;
|
||||
}
|
||||
|
||||
|
@@ -31,7 +31,7 @@ use crate::module::resolvers;
|
||||
#[cfg(any(not(feature = "no_object"), not(feature = "no_module")))]
|
||||
use crate::utils::ImmutableString;
|
||||
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
use crate::any::DynamicWriteLock;
|
||||
|
||||
@@ -49,6 +49,9 @@ use crate::stdlib::{
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
use crate::stdlib::any::TypeId;
|
||||
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
use crate::stdlib::mem;
|
||||
|
||||
/// Variable-sized array of `Dynamic` values.
|
||||
///
|
||||
/// Not available under the `no_index` feature.
|
||||
@@ -96,8 +99,6 @@ pub const KEYWORD_EVAL: &str = "eval";
|
||||
pub const KEYWORD_FN_PTR: &str = "Fn";
|
||||
pub const KEYWORD_FN_PTR_CALL: &str = "call";
|
||||
pub const KEYWORD_FN_PTR_CURRY: &str = "curry";
|
||||
pub const KEYWORD_SHARED: &str = "shared";
|
||||
pub const KEYWORD_TAKE: &str = "take";
|
||||
pub const KEYWORD_IS_SHARED: &str = "is_shared";
|
||||
pub const KEYWORD_THIS: &str = "this";
|
||||
pub const FN_TO_STRING: &str = "to_string";
|
||||
@@ -132,7 +133,7 @@ pub enum Target<'a> {
|
||||
Ref(&'a mut Dynamic),
|
||||
/// The target is a mutable reference to a Shared `Dynamic` value.
|
||||
/// It holds both the access guard and the original shared value.
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
LockGuard((DynamicWriteLock<'a, Dynamic>, Dynamic)),
|
||||
/// The target is a temporary `Dynamic` value (i.e. the mutation can cause no side effects).
|
||||
@@ -149,7 +150,7 @@ impl Target<'_> {
|
||||
pub fn is_ref(&self) -> bool {
|
||||
match self {
|
||||
Self::Ref(_) => true,
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
Self::LockGuard(_) => true,
|
||||
Self::Value(_) => false,
|
||||
@@ -161,7 +162,7 @@ impl Target<'_> {
|
||||
pub fn is_value(&self) -> bool {
|
||||
match self {
|
||||
Self::Ref(_) => false,
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
Self::LockGuard(_) => false,
|
||||
Self::Value(_) => true,
|
||||
@@ -173,7 +174,7 @@ impl Target<'_> {
|
||||
pub fn is_shared(&self) -> bool {
|
||||
match self {
|
||||
Self::Ref(r) => r.is_shared(),
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
Self::LockGuard(_) => true,
|
||||
Self::Value(r) => r.is_shared(),
|
||||
@@ -186,7 +187,7 @@ impl Target<'_> {
|
||||
pub fn is<T: Variant + Clone>(&self) -> bool {
|
||||
match self {
|
||||
Target::Ref(r) => r.is::<T>(),
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
Target::LockGuard((r, _)) => r.is::<T>(),
|
||||
Target::Value(r) => r.is::<T>(),
|
||||
@@ -198,7 +199,7 @@ impl Target<'_> {
|
||||
pub fn clone_into_dynamic(self) -> Dynamic {
|
||||
match self {
|
||||
Self::Ref(r) => r.clone(), // Referenced value is cloned
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
Self::LockGuard((_, orig)) => orig, // Original value is simply taken
|
||||
Self::Value(v) => v, // Owned value is simply taken
|
||||
@@ -210,7 +211,7 @@ impl Target<'_> {
|
||||
pub fn as_mut(&mut self) -> &mut Dynamic {
|
||||
match self {
|
||||
Self::Ref(r) => *r,
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
Self::LockGuard((r, _)) => r.deref_mut(),
|
||||
Self::Value(ref mut r) => r,
|
||||
@@ -223,7 +224,7 @@ impl Target<'_> {
|
||||
pub fn set_value(&mut self, new_val: Dynamic) -> Result<(), Box<EvalAltResult>> {
|
||||
match self {
|
||||
Self::Ref(r) => **r = new_val,
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
Self::LockGuard((r, _)) => **r = new_val,
|
||||
Self::Value(_) => {
|
||||
@@ -260,7 +261,7 @@ impl Target<'_> {
|
||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||
impl<'a> From<&'a mut Dynamic> for Target<'a> {
|
||||
fn from(value: &'a mut Dynamic) -> Self {
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
if value.is_shared() {
|
||||
// Cloning is cheap for a shared value
|
||||
@@ -632,7 +633,7 @@ pub fn search_scope_only<'s, 'a>(
|
||||
|
||||
// Check for data race - probably not necessary because the only place it should conflict is in a method call
|
||||
// when the object variable is also used as a parameter.
|
||||
// if cfg!(not(feature = "no_shared")) && val.is_locked() {
|
||||
// if cfg!(not(feature = "no_closure")) && val.is_locked() {
|
||||
// return Err(Box::new(EvalAltResult::ErrorDataRace(name.into(), *pos)));
|
||||
// }
|
||||
|
||||
@@ -1351,12 +1352,9 @@ impl Engine {
|
||||
)),
|
||||
// Normal assignment
|
||||
ScopeEntryType::Normal if op.is_empty() => {
|
||||
if cfg!(not(feature = "no_shared")) && lhs_ptr.is_shared() {
|
||||
*lhs_ptr.write_lock::<Dynamic>().unwrap() = if rhs_val.is_shared() {
|
||||
rhs_val.clone_inner_data().unwrap()
|
||||
} else {
|
||||
rhs_val
|
||||
};
|
||||
let rhs_val = rhs_val.clone_inner_data().unwrap();
|
||||
if cfg!(not(feature = "no_closure")) && lhs_ptr.is_shared() {
|
||||
*lhs_ptr.write_lock::<Dynamic>().unwrap() = rhs_val;
|
||||
} else {
|
||||
*lhs_ptr = rhs_val;
|
||||
}
|
||||
@@ -1377,7 +1375,7 @@ impl Engine {
|
||||
.get_fn(hash_fn, false)
|
||||
.or_else(|| self.packages.get_fn(hash_fn, false))
|
||||
{
|
||||
if cfg!(not(feature = "no_shared")) && lhs_ptr.is_shared() {
|
||||
if cfg!(not(feature = "no_closure")) && lhs_ptr.is_shared() {
|
||||
let mut lock_guard = lhs_ptr.write_lock::<Dynamic>().unwrap();
|
||||
let lhs_ptr_inner = lock_guard.deref_mut();
|
||||
|
||||
@@ -1401,12 +1399,9 @@ impl Engine {
|
||||
)
|
||||
.map_err(|err| err.new_position(*op_pos))?;
|
||||
|
||||
if cfg!(not(feature = "no_shared")) && lhs_ptr.is_shared() {
|
||||
*lhs_ptr.write_lock::<Dynamic>().unwrap() = if value.is_shared() {
|
||||
value.clone_inner_data().unwrap()
|
||||
} else {
|
||||
value
|
||||
};
|
||||
let value = value.clone_inner_data().unwrap();
|
||||
if cfg!(not(feature = "no_closure")) && lhs_ptr.is_shared() {
|
||||
*lhs_ptr.write_lock::<Dynamic>().unwrap() = value;
|
||||
} else {
|
||||
*lhs_ptr = value;
|
||||
}
|
||||
@@ -1845,6 +1840,25 @@ impl Engine {
|
||||
}
|
||||
Ok(Default::default())
|
||||
}
|
||||
|
||||
// Share statement
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
Stmt::Share(x) => {
|
||||
let (var_name, _) = x.as_ref();
|
||||
|
||||
match scope.get_index(var_name) {
|
||||
Some((index, ScopeEntryType::Normal)) => {
|
||||
let (val, _) = scope.get_mut(index);
|
||||
|
||||
if !val.is_shared() {
|
||||
// Replace the variable with a shared value.
|
||||
*val = mem::take(val).into_shared();
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
Ok(Default::default())
|
||||
}
|
||||
};
|
||||
|
||||
self.check_data_size(result)
|
||||
|
@@ -93,7 +93,7 @@ pub enum ParseErrorType {
|
||||
MalformedInExpr(String),
|
||||
/// A capturing has syntax error. Wrapped value is the error description (if any).
|
||||
///
|
||||
/// Never appears under the `no_capture` feature.
|
||||
/// Never appears under the `no_closure` feature.
|
||||
MalformedCapture(String),
|
||||
/// A map definition has duplicated property names. Wrapped value is the property name.
|
||||
///
|
||||
|
@@ -5,7 +5,7 @@ use crate::calc_fn_hash;
|
||||
use crate::engine::{
|
||||
search_imports, search_namespace, search_scope_only, Engine, Imports, State, KEYWORD_DEBUG,
|
||||
KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_FN_PTR_CALL, KEYWORD_FN_PTR_CURRY, KEYWORD_IS_SHARED,
|
||||
KEYWORD_PRINT, KEYWORD_SHARED, KEYWORD_TAKE, KEYWORD_TYPE_OF,
|
||||
KEYWORD_PRINT, KEYWORD_TYPE_OF,
|
||||
};
|
||||
use crate::error::ParseErrorType;
|
||||
use crate::fn_native::{FnCallArgs, FnPtr};
|
||||
@@ -33,7 +33,7 @@ use crate::engine::{FN_IDX_GET, FN_IDX_SET};
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
use crate::engine::{Map, Target, FN_GET, FN_SET};
|
||||
|
||||
#[cfg(not(feature = "no_capture"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
use crate::scope::Entry as ScopeEntry;
|
||||
|
||||
use crate::stdlib::{
|
||||
@@ -47,7 +47,7 @@ use crate::stdlib::{
|
||||
vec::Vec,
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "no_capture"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
use crate::stdlib::{collections::HashSet, string::String};
|
||||
|
||||
/// Extract the property name from a getter function name.
|
||||
@@ -139,7 +139,7 @@ impl Drop for ArgBackup<'_> {
|
||||
}
|
||||
|
||||
// Add captured variables into scope
|
||||
#[cfg(not(feature = "no_capture"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
fn add_captured_variables_into_scope<'s>(
|
||||
externals: &HashSet<String>,
|
||||
captured: Scope<'s>,
|
||||
@@ -166,7 +166,7 @@ pub fn ensure_no_data_race(
|
||||
args: &FnCallArgs,
|
||||
is_ref: bool,
|
||||
) -> Result<(), Box<EvalAltResult>> {
|
||||
if cfg!(not(feature = "no_shared")) {
|
||||
if cfg!(not(feature = "no_closure")) {
|
||||
let skip = if is_ref { 1 } else { 0 };
|
||||
|
||||
if let Some((n, _)) = args
|
||||
@@ -456,7 +456,7 @@ impl Engine {
|
||||
level: usize,
|
||||
) -> Result<(Dynamic, bool), Box<EvalAltResult>> {
|
||||
// Check for data race.
|
||||
if cfg!(not(feature = "no_shared")) {
|
||||
if cfg!(not(feature = "no_closure")) {
|
||||
ensure_no_data_race(fn_name, args, is_ref)?;
|
||||
}
|
||||
|
||||
@@ -505,7 +505,7 @@ impl Engine {
|
||||
let mods = &mut Imports::new();
|
||||
|
||||
// Add captured variables into scope
|
||||
#[cfg(not(feature = "no_capture"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
if let Some(captured) = _capture {
|
||||
add_captured_variables_into_scope(&func.externals, captured, scope);
|
||||
}
|
||||
@@ -690,18 +690,12 @@ impl Engine {
|
||||
.into(),
|
||||
false,
|
||||
))
|
||||
} else if cfg!(not(feature = "no_shared"))
|
||||
} else if cfg!(not(feature = "no_closure"))
|
||||
&& _fn_name == KEYWORD_IS_SHARED
|
||||
&& idx.is_empty()
|
||||
{
|
||||
// take call
|
||||
Ok((target.is_shared().into(), false))
|
||||
} else if cfg!(not(feature = "no_shared")) && _fn_name == KEYWORD_SHARED && idx.is_empty() {
|
||||
// take call
|
||||
Ok((obj.clone().into_shared(), false))
|
||||
} else if cfg!(not(feature = "no_shared")) && _fn_name == KEYWORD_TAKE && idx.is_empty() {
|
||||
// take call
|
||||
Ok((obj.clone_inner_data::<Dynamic>().unwrap(), false))
|
||||
} else {
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
let redirected;
|
||||
@@ -814,29 +808,13 @@ impl Engine {
|
||||
}
|
||||
|
||||
// Handle is_shared()
|
||||
if cfg!(not(feature = "no_shared")) && name == KEYWORD_IS_SHARED && args_expr.len() == 1 {
|
||||
if cfg!(not(feature = "no_closure")) && name == KEYWORD_IS_SHARED && args_expr.len() == 1 {
|
||||
let expr = args_expr.get(0).unwrap();
|
||||
let value = self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?;
|
||||
|
||||
return Ok(value.is_shared().into());
|
||||
}
|
||||
|
||||
// Handle shared()
|
||||
if cfg!(not(feature = "no_shared")) && name == KEYWORD_SHARED && args_expr.len() == 1 {
|
||||
let expr = args_expr.get(0).unwrap();
|
||||
let value = self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?;
|
||||
|
||||
return Ok(value.into_shared());
|
||||
}
|
||||
|
||||
// Handle take()
|
||||
if cfg!(not(feature = "no_shared")) && name == KEYWORD_TAKE && args_expr.len() == 1 {
|
||||
let expr = args_expr.get(0).unwrap();
|
||||
let value = self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?;
|
||||
|
||||
return Ok(value.clone_inner_data::<Dynamic>().unwrap());
|
||||
}
|
||||
|
||||
// Handle call() - Redirect function call
|
||||
let redirected;
|
||||
let mut args_expr = args_expr.as_ref();
|
||||
@@ -896,7 +874,7 @@ impl Engine {
|
||||
let mut arg_values: StaticVec<_>;
|
||||
let mut args: StaticVec<_>;
|
||||
let mut is_ref = false;
|
||||
let capture = if cfg!(not(feature = "no_capture")) && capture && !scope.is_empty() {
|
||||
let capture = if cfg!(not(feature = "no_closure")) && capture && !scope.is_empty() {
|
||||
Some(scope.flatten_clone())
|
||||
} else {
|
||||
None
|
||||
@@ -924,7 +902,7 @@ impl Engine {
|
||||
|
||||
// Turn it into a method call only if the object is not shared
|
||||
args = if target.is_shared() {
|
||||
arg_values.insert(0, target.clone_inner_data().unwrap());
|
||||
arg_values.insert(0, target.clone().clone_inner_data().unwrap());
|
||||
arg_values.iter_mut().collect()
|
||||
} else {
|
||||
is_ref = true;
|
||||
@@ -1041,7 +1019,7 @@ impl Engine {
|
||||
let mods = &mut Imports::new();
|
||||
|
||||
// Add captured variables into scope
|
||||
#[cfg(not(feature = "no_capture"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
if _capture && !scope.is_empty() {
|
||||
add_captured_variables_into_scope(
|
||||
&func.externals,
|
||||
|
@@ -22,10 +22,10 @@ use crate::stdlib::rc::Rc;
|
||||
#[cfg(feature = "sync")]
|
||||
use crate::stdlib::sync::Arc;
|
||||
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
#[cfg(not(feature = "sync"))]
|
||||
use crate::stdlib::cell::RefCell;
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
#[cfg(feature = "sync")]
|
||||
use crate::stdlib::sync::RwLock;
|
||||
|
||||
@@ -51,11 +51,11 @@ pub type Shared<T> = Rc<T>;
|
||||
pub type Shared<T> = Arc<T>;
|
||||
|
||||
/// Mutable reference-counted container (read-write lock)
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
#[cfg(not(feature = "sync"))]
|
||||
pub type SharedMut<T> = Shared<RefCell<T>>;
|
||||
/// Mutable reference-counted container (read-write lock)
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
#[cfg(feature = "sync")]
|
||||
pub type SharedMut<T> = Shared<RwLock<T>>;
|
||||
|
||||
|
@@ -765,7 +765,7 @@ pub fn optimize_into_ast(
|
||||
access: fn_def.access,
|
||||
body: Default::default(),
|
||||
params: fn_def.params.clone(),
|
||||
#[cfg(not(feature = "no_capture"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
externals: fn_def.externals.clone(),
|
||||
pos: fn_def.pos,
|
||||
}
|
||||
|
@@ -39,7 +39,7 @@ use crate::stdlib::{
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
use crate::stdlib::collections::hash_map::DefaultHasher;
|
||||
|
||||
#[cfg(not(feature = "no_capture"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
use crate::stdlib::collections::HashSet;
|
||||
|
||||
#[cfg(feature = "no_std")]
|
||||
@@ -366,7 +366,7 @@ pub struct ScriptFnDef {
|
||||
/// Names of function parameters.
|
||||
pub params: StaticVec<String>,
|
||||
/// Access to external variables.
|
||||
#[cfg(not(feature = "no_capture"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
pub externals: HashSet<String>,
|
||||
/// Function body.
|
||||
pub body: Stmt,
|
||||
@@ -414,13 +414,13 @@ struct ParseState<'e> {
|
||||
/// Encapsulates a local stack with variable names to simulate an actual runtime scope.
|
||||
stack: Vec<(String, ScopeEntryType)>,
|
||||
/// Tracks a list of external variables (variables that are not explicitly declared in the scope).
|
||||
#[cfg(not(feature = "no_capture"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
externals: HashMap<String, Position>,
|
||||
/// An indicator that prevents variables capturing into externals one time.
|
||||
/// If set to true the next call of `access_var` will not capture the variable.
|
||||
/// An indicator that disables variable capturing into externals one single time.
|
||||
/// If set to false the next call to `access_var` will not capture the variable.
|
||||
/// All consequent calls to `access_var` will not be affected
|
||||
#[cfg(not(feature = "no_capture"))]
|
||||
capture: bool,
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
allow_capture: bool,
|
||||
/// Encapsulates a local stack with variable names to simulate an actual runtime scope.
|
||||
modules: Vec<String>,
|
||||
/// Maximum levels of expression nesting.
|
||||
@@ -444,10 +444,10 @@ impl<'e> ParseState<'e> {
|
||||
max_expr_depth,
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
max_function_expr_depth,
|
||||
#[cfg(not(feature = "no_capture"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
externals: Default::default(),
|
||||
#[cfg(not(feature = "no_capture"))]
|
||||
capture: true,
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
allow_capture: true,
|
||||
stack: Default::default(),
|
||||
modules: Default::default(),
|
||||
}
|
||||
@@ -469,13 +469,13 @@ impl<'e> ParseState<'e> {
|
||||
.find(|(_, (n, _))| *n == name)
|
||||
.and_then(|(i, _)| NonZeroUsize::new(i + 1));
|
||||
|
||||
#[cfg(not(feature = "no_capture"))]
|
||||
if self.capture {
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
if self.allow_capture {
|
||||
if index.is_none() && !self.externals.contains_key(name) {
|
||||
self.externals.insert(name.to_string(), _pos);
|
||||
}
|
||||
} else {
|
||||
self.capture = true
|
||||
self.allow_capture = true
|
||||
}
|
||||
|
||||
index
|
||||
@@ -579,6 +579,9 @@ pub enum Stmt {
|
||||
Position,
|
||||
)>,
|
||||
),
|
||||
/// Convert a variable to shared.
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
Share(Box<(String, Position)>),
|
||||
}
|
||||
|
||||
impl Default for Stmt {
|
||||
@@ -606,6 +609,9 @@ impl Stmt {
|
||||
Stmt::Import(x) => x.2,
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
Stmt::Export(x) => x.1,
|
||||
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
Stmt::Share(x) => x.1,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -629,6 +635,9 @@ impl Stmt {
|
||||
Stmt::Import(x) => x.2 = new_pos,
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
Stmt::Export(x) => x.1 = new_pos,
|
||||
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
Stmt::Share(x) => x.1 = new_pos,
|
||||
}
|
||||
|
||||
self
|
||||
@@ -655,6 +664,9 @@ impl Stmt {
|
||||
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
Stmt::Import(_) | Stmt::Export(_) => false,
|
||||
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
Stmt::Share(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -678,6 +690,9 @@ impl Stmt {
|
||||
Stmt::Import(_) => false,
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
Stmt::Export(_) => false,
|
||||
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
Stmt::Share(_) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1671,7 +1686,7 @@ fn parse_primary(
|
||||
|
||||
root_expr = match (root_expr, token) {
|
||||
// Function call
|
||||
#[cfg(not(feature = "no_capture"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
(Expr::Variable(x), Token::Bang) => {
|
||||
if !match_token(input, Token::LeftParen)? {
|
||||
return Err(PERR::MissingToken(
|
||||
@@ -1855,7 +1870,7 @@ fn parse_unary(
|
||||
|
||||
let (expr, func) = parse_anon_fn(input, &mut new_state, lib, settings)?;
|
||||
|
||||
#[cfg(not(feature = "no_capture"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
new_state.externals.iter().for_each(|(closure, pos)| {
|
||||
state.access_var(closure, *pos);
|
||||
});
|
||||
@@ -2216,9 +2231,9 @@ fn parse_binary_op(
|
||||
if cfg!(not(feature = "no_object")) && op_token == Token::Period {
|
||||
if let (Token::Identifier(_), _) = input.peek().unwrap() {
|
||||
// prevents capturing of the object properties as vars: xxx.<var>
|
||||
#[cfg(not(feature = "no_capture"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
{
|
||||
state.capture = false;
|
||||
state.allow_capture = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3095,7 +3110,7 @@ fn parse_fn(
|
||||
|
||||
let params: StaticVec<_> = params.into_iter().map(|(p, _)| p).collect();
|
||||
|
||||
#[cfg(not(feature = "no_capture"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
let externals = state
|
||||
.externals
|
||||
.iter()
|
||||
@@ -3108,7 +3123,7 @@ fn parse_fn(
|
||||
name: name.into(),
|
||||
access,
|
||||
params,
|
||||
#[cfg(not(feature = "no_capture"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
externals,
|
||||
body,
|
||||
pos: settings.pos,
|
||||
@@ -3128,6 +3143,17 @@ fn make_curry_from_externals(
|
||||
let num_externals = externals.len();
|
||||
let mut args: StaticVec<_> = Default::default();
|
||||
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
externals.iter().for_each(|(var_name, pos)| {
|
||||
args.push(Expr::Variable(Box::new((
|
||||
(var_name.into(), *pos),
|
||||
None,
|
||||
0,
|
||||
None,
|
||||
))));
|
||||
});
|
||||
|
||||
#[cfg(feature = "no_closure")]
|
||||
externals.into_iter().for_each(|(var_name, pos)| {
|
||||
args.push(Expr::Variable(Box::new(((var_name, pos), None, 0, None))));
|
||||
});
|
||||
@@ -3142,7 +3168,23 @@ fn make_curry_from_externals(
|
||||
None,
|
||||
)));
|
||||
|
||||
Expr::Dot(Box::new((fn_expr, fn_call, pos)))
|
||||
let expr = Expr::Dot(Box::new((fn_expr, fn_call, pos)));
|
||||
|
||||
// If there are captured variables, convert the entire expression into a statement block,
|
||||
// then insert the relevant `Share` statements.
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
{
|
||||
// Statement block
|
||||
let mut statements: StaticVec<_> = Default::default();
|
||||
// Insert `Share` statements
|
||||
statements.extend(externals.into_iter().map(|x| Stmt::Share(Box::new(x))));
|
||||
// Final expression
|
||||
statements.push(Stmt::Expr(Box::new(expr)));
|
||||
Expr::Stmt(Box::new((Stmt::Block(Box::new((statements, pos))), pos)))
|
||||
}
|
||||
|
||||
#[cfg(feature = "no_closure")]
|
||||
return expr;
|
||||
}
|
||||
|
||||
/// Parse an anonymous function definition.
|
||||
@@ -3215,7 +3257,7 @@ fn parse_anon_fn(
|
||||
// External variables may need to be processed in a consistent order,
|
||||
// so extract them into a list.
|
||||
let externals: StaticVec<_> = {
|
||||
#[cfg(not(feature = "no_capture"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
{
|
||||
state
|
||||
.externals
|
||||
@@ -3223,11 +3265,11 @@ fn parse_anon_fn(
|
||||
.map(|(k, &v)| (k.clone(), v))
|
||||
.collect()
|
||||
}
|
||||
#[cfg(feature = "no_capture")]
|
||||
#[cfg(feature = "no_closure")]
|
||||
Default::default()
|
||||
};
|
||||
|
||||
let params: StaticVec<_> = if cfg!(not(feature = "no_capture")) {
|
||||
let params: StaticVec<_> = if cfg!(not(feature = "no_closure")) {
|
||||
externals
|
||||
.iter()
|
||||
.map(|(k, _)| k)
|
||||
@@ -3257,7 +3299,7 @@ fn parse_anon_fn(
|
||||
name: fn_name.clone(),
|
||||
access: FnAccess::Public,
|
||||
params,
|
||||
#[cfg(not(feature = "no_capture"))]
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
externals: Default::default(),
|
||||
body,
|
||||
pos: settings.pos,
|
||||
@@ -3265,7 +3307,7 @@ fn parse_anon_fn(
|
||||
|
||||
let expr = Expr::FnPointer(Box::new((fn_name, settings.pos)));
|
||||
|
||||
let expr = if cfg!(not(feature = "no_capture")) {
|
||||
let expr = if cfg!(not(feature = "no_closure")) {
|
||||
make_curry_from_externals(expr, externals, settings.pos)
|
||||
} else {
|
||||
expr
|
||||
|
69
src/scope.rs
69
src/scope.rs
@@ -158,32 +158,6 @@ impl<'a> Scope<'a> {
|
||||
self.push_dynamic_value(name, EntryType::Normal, Dynamic::from(value), false)
|
||||
}
|
||||
|
||||
/// Add (push) a new shared entry to the Scope.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use rhai::Scope;
|
||||
///
|
||||
/// let mut my_scope = Scope::new();
|
||||
///
|
||||
/// my_scope.push_shared("x", 42_i64);
|
||||
/// assert_eq!(my_scope.get_value::<i64>("x").unwrap(), 42);
|
||||
/// ```
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
pub fn push_shared<K: Into<Cow<'a, str>>, T: Variant + Clone>(
|
||||
&mut self,
|
||||
name: K,
|
||||
value: T,
|
||||
) -> &mut Self {
|
||||
self.push_dynamic_value(
|
||||
name,
|
||||
EntryType::Normal,
|
||||
Dynamic::from(value).into_shared(),
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
||||
/// Add (push) a new `Dynamic` entry to the Scope.
|
||||
///
|
||||
/// # Examples
|
||||
@@ -226,34 +200,6 @@ impl<'a> Scope<'a> {
|
||||
self.push_dynamic_value(name, EntryType::Constant, Dynamic::from(value), true)
|
||||
}
|
||||
|
||||
/// Add (push) a new shared constant to the Scope.
|
||||
///
|
||||
/// Shared constants are immutable and cannot be assigned to, but their shared values can change.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use rhai::Scope;
|
||||
///
|
||||
/// let mut my_scope = Scope::new();
|
||||
///
|
||||
/// my_scope.push_constant_shared("x", 42_i64);
|
||||
/// assert_eq!(my_scope.get_value::<i64>("x").unwrap(), 42);
|
||||
/// ```
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
pub fn push_constant_shared<K: Into<Cow<'a, str>>, T: Variant + Clone>(
|
||||
&mut self,
|
||||
name: K,
|
||||
value: T,
|
||||
) -> &mut Self {
|
||||
self.push_dynamic_value(
|
||||
name,
|
||||
EntryType::Constant,
|
||||
Dynamic::from(value).into_shared(),
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
||||
/// Add (push) a new constant with a `Dynamic` value to the Scope.
|
||||
///
|
||||
/// Constants are immutable and cannot be assigned to. Their values never change.
|
||||
@@ -394,7 +340,7 @@ impl<'a> Scope<'a> {
|
||||
/// ```
|
||||
pub fn get_value<T: Variant + Clone>(&self, name: &str) -> Option<T> {
|
||||
self.get_entry(name)
|
||||
.and_then(|Entry { value, .. }| value.clone_inner_data::<T>())
|
||||
.and_then(|Entry { value, .. }| value.clone().clone_inner_data::<T>())
|
||||
}
|
||||
|
||||
/// Update the value of the named entry.
|
||||
@@ -485,13 +431,20 @@ impl<'a> Scope<'a> {
|
||||
///
|
||||
/// let (name, value) = iter.next().unwrap();
|
||||
/// assert_eq!(name, "x");
|
||||
/// assert_eq!(value.clone().cast::<i64>(), 42);
|
||||
/// assert_eq!(value.cast::<i64>(), 42);
|
||||
///
|
||||
/// let (name, value) = iter.next().unwrap();
|
||||
/// assert_eq!(name, "foo");
|
||||
/// assert_eq!(value.clone().cast::<String>(), "hello");
|
||||
/// assert_eq!(value.cast::<String>(), "hello");
|
||||
/// ```
|
||||
pub fn iter(&self) -> impl Iterator<Item = (&str, &Dynamic)> {
|
||||
pub fn iter(&self) -> impl Iterator<Item = (&str, Dynamic)> {
|
||||
self.iter_raw()
|
||||
.map(|(name, value)| (name, value.clone().clone_inner_data().unwrap()))
|
||||
}
|
||||
|
||||
/// Get an iterator to entries in the Scope.
|
||||
/// Shared values are not expanded.
|
||||
pub fn iter_raw(&self) -> impl Iterator<Item = (&str, &Dynamic)> {
|
||||
self.0
|
||||
.iter()
|
||||
.map(|Entry { name, value, .. }| (name.as_ref(), value))
|
||||
|
19
src/token.rs
19
src/token.rs
@@ -2,7 +2,7 @@
|
||||
|
||||
use crate::engine::{
|
||||
Engine, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_FN_PTR_CALL, KEYWORD_FN_PTR_CURRY,
|
||||
KEYWORD_IS_SHARED, KEYWORD_PRINT, KEYWORD_SHARED, KEYWORD_TAKE, KEYWORD_THIS, KEYWORD_TYPE_OF,
|
||||
KEYWORD_IS_SHARED, KEYWORD_PRINT, KEYWORD_THIS, KEYWORD_TYPE_OF,
|
||||
};
|
||||
|
||||
use crate::error::LexError;
|
||||
@@ -501,14 +501,15 @@ impl Token {
|
||||
"import" | "export" | "as" => Reserved(syntax.into()),
|
||||
|
||||
"===" | "!==" | "->" | "<-" | "=>" | ":=" | "::<" | "(*" | "*)" | "#" | "public"
|
||||
| "new" | "use" | "module" | "package" | "var" | "static" | "with" | "do" | "each"
|
||||
| "then" | "goto" | "exit" | "switch" | "match" | "case" | "try" | "catch"
|
||||
| "default" | "void" | "null" | "nil" | "spawn" | "go" | "sync" | "async" | "await"
|
||||
| "yield" => Reserved(syntax.into()),
|
||||
| "new" | "use" | "module" | "package" | "var" | "static" | "shared" | "with"
|
||||
| "do" | "each" | "then" | "goto" | "exit" | "switch" | "match" | "case" | "try"
|
||||
| "catch" | "default" | "void" | "null" | "nil" | "spawn" | "go" | "sync" | "async"
|
||||
| "await" | "yield" => Reserved(syntax.into()),
|
||||
|
||||
KEYWORD_PRINT | KEYWORD_DEBUG | KEYWORD_TYPE_OF | KEYWORD_EVAL | KEYWORD_FN_PTR
|
||||
| KEYWORD_FN_PTR_CALL | KEYWORD_FN_PTR_CURRY | KEYWORD_IS_SHARED | KEYWORD_SHARED
|
||||
| KEYWORD_TAKE | KEYWORD_THIS => Reserved(syntax.into()),
|
||||
| KEYWORD_FN_PTR_CALL | KEYWORD_FN_PTR_CURRY | KEYWORD_IS_SHARED | KEYWORD_THIS => {
|
||||
Reserved(syntax.into())
|
||||
}
|
||||
|
||||
_ => return None,
|
||||
})
|
||||
@@ -1432,8 +1433,8 @@ fn get_identifier(
|
||||
#[inline(always)]
|
||||
pub fn is_keyword_function(name: &str) -> bool {
|
||||
match name {
|
||||
#[cfg(not(feature = "no_shared"))]
|
||||
KEYWORD_SHARED | KEYWORD_TAKE | KEYWORD_IS_SHARED => true,
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
KEYWORD_IS_SHARED => true,
|
||||
KEYWORD_PRINT | KEYWORD_DEBUG | KEYWORD_TYPE_OF | KEYWORD_EVAL | KEYWORD_FN_PTR
|
||||
| KEYWORD_FN_PTR_CALL | KEYWORD_FN_PTR_CURRY => true,
|
||||
_ => false,
|
||||
|
Reference in New Issue
Block a user