diff --git a/src/engine.rs b/src/engine.rs index ec3365ab..127a4277 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -1611,10 +1611,10 @@ impl Engine { // Module-qualified function call Expr::FnCall(x) if x.1.is_some() => { - let ((name, _, capture, pos), modules, hash, args_expr, def_val) = x.as_ref(); + let ((name, _, _, pos), modules, hash, args_expr, def_val) = x.as_ref(); self.make_qualified_function_call( scope, mods, state, lib, this_ptr, modules, name, args_expr, *def_val, *hash, - *capture, level, + level, ) .map_err(|err| err.fill_position(*pos)) } diff --git a/src/fn_call.rs b/src/fn_call.rs index 1357e7fa..437a86dc 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -384,9 +384,27 @@ impl Engine { }), ); + // Merge in encapsulated environment, if any + let mut lib_merged; + + let unified_lib = if let Some(ref env_lib) = fn_def.lib { + if !lib.is_empty() { + // In the special case of the main script not defining any function + env_lib + } else { + lib_merged = lib.clone(); + lib_merged.merge(env_lib); + &lib_merged + } + } else { + lib + }; + // Evaluate the function at one higher level of call depth + let stmt = &fn_def.body; + let result = self - .eval_stmt(scope, mods, state, lib, this_ptr, &fn_def.body, level + 1) + .eval_stmt(scope, mods, state, unified_lib, this_ptr, stmt, level + 1) .or_else(|err| match *err { // Convert return statement to return value EvalAltResult::Return(x, _) => Ok(x), @@ -1082,7 +1100,6 @@ impl Engine { args_expr: &[Expr], def_val: Option, hash_script: u64, - _capture: bool, level: usize, ) -> Result> { let modules = modules.as_ref().unwrap(); diff --git a/src/module/mod.rs b/src/module/mod.rs index fa509656..f98d1f89 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -288,7 +288,7 @@ impl Module { /// If there is an existing function of the same name and number of arguments, it is replaced. #[cfg(not(feature = "no_function"))] #[inline] - pub(crate) fn set_script_fn(&mut self, fn_def: ScriptFnDef) -> u64 { + pub(crate) fn set_script_fn(&mut self, fn_def: Shared) -> u64 { // None + function name + number of arguments. let num_params = fn_def.params.len(); let hash_script = calc_fn_hash(empty(), &fn_def.name, num_params, empty()); @@ -1392,53 +1392,18 @@ impl Module { module.modules.insert(alias.to_string(), m); }); + // Non-private functions defined become module functions #[cfg(not(feature = "no_function"))] { let ast_lib: Shared = ast.lib().clone().into(); ast.iter_functions() - .filter(|(access, _, _, _)| access.is_public()) - .for_each(|(_, name, num_params, func)| { - let ast_lib = ast_lib.clone(); - - module.set_raw_fn_as_scripted( - name, - num_params, - move |engine: &Engine, lib: &Module, args: &mut [&mut Dynamic]| { - let mut lib_merged; - - let unified_lib = if lib.is_empty() { - // In the special case of the main script not defining any function - &ast_lib - } else { - lib_merged = lib.clone(); - lib_merged.merge(&ast_lib); - &lib_merged - }; - - engine - .call_script_fn( - &mut Default::default(), - &mut Default::default(), - &mut Default::default(), - unified_lib, - &mut None, - &func.name, - func.as_ref(), - args, - 0, - ) - .map_err(|err| { - // Wrap the error in a module-error - EvalAltResult::ErrorInModule( - "".to_string(), - err, - Position::none(), - ) - .into() - }) - }, - ); + .filter(|(access, _, _, _)| !access.is_private()) + .for_each(|(_, _, _, func)| { + // Encapsulate AST environment + let mut func = func.as_ref().clone(); + func.lib = Some(ast_lib.clone()); + module.set_script_fn(func.into()); }); } diff --git a/src/optimize.rs b/src/optimize.rs index a314cdac..631f68d6 100644 --- a/src/optimize.rs +++ b/src/optimize.rs @@ -823,6 +823,7 @@ pub fn optimize_into_ast( #[cfg(not(feature = "no_closure"))] externals: fn_def.externals.clone(), pos: fn_def.pos, + lib: None, } .into() }) @@ -862,7 +863,7 @@ pub fn optimize_into_ast( }); } else { _functions.into_iter().for_each(|fn_def| { - module.set_script_fn(fn_def); + module.set_script_fn(fn_def.into()); }); } diff --git a/src/parser.rs b/src/parser.rs index 12f8660a..77b460f7 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -549,6 +549,8 @@ pub struct ScriptFnDef { pub body: Stmt, /// Position of the function definition. pub pos: Position, + /// Encapsulated running environment, if any. + pub lib: Option>, } impl fmt::Display for ScriptFnDef { @@ -3373,6 +3375,7 @@ fn parse_fn( externals, body, pos: settings.pos, + lib: None, }) } @@ -3550,6 +3553,7 @@ fn parse_anon_fn( externals: Default::default(), body, pos: settings.pos, + lib: None, }; let expr = Expr::FnPointer(Box::new((fn_name, settings.pos)));