Implement closures.

This commit is contained in:
Stephen Chung
2020-08-03 12:10:20 +08:00
parent 747c0345f2
commit 4079164bfd
24 changed files with 340 additions and 588 deletions

View File

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