From 67a7ab40691f21dc35de596ad333df6e27c787d4 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Mon, 12 Dec 2022 16:06:24 +0800 Subject: [PATCH] Move encapsulated environment out of ScriptFnDef. --- src/api/call_fn.rs | 1 + src/ast/ast.rs | 12 +++------ src/ast/mod.rs | 3 --- src/ast/script_fn.rs | 22 --------------- src/func/call.rs | 40 +++++++++++++++++++++++----- src/func/callable_function.rs | 50 ++++++++++++++++++++++++++++++----- src/func/mod.rs | 2 +- src/func/script.rs | 17 ++++++------ src/lib.rs | 4 +-- src/module/mod.rs | 29 ++++++++++---------- src/optimizer.rs | 2 -- src/parser.rs | 4 --- src/tests.rs | 8 ++++++ src/types/fn_ptr.rs | 1 + 14 files changed, 116 insertions(+), 79 deletions(-) diff --git a/src/api/call_fn.rs b/src/api/call_fn.rs index 5c48712f..680b7a7e 100644 --- a/src/api/call_fn.rs +++ b/src/api/call_fn.rs @@ -265,6 +265,7 @@ impl Engine { caches, scope, this_ptr, + None, fn_def, args, rewind_scope, diff --git a/src/ast/ast.rs b/src/ast/ast.rs index 3609064d..ea5e05e6 100644 --- a/src/ast/ast.rs +++ b/src/ast/ast.rs @@ -750,10 +750,8 @@ impl AST { #[cfg(feature = "internals")] #[cfg(not(feature = "no_function"))] #[inline] - pub fn iter_fn_def(&self) -> impl Iterator { - self.lib - .iter_script_fn() - .map(|(.., fn_def)| fn_def.as_ref()) + pub fn iter_fn_def(&self) -> impl Iterator> { + self.lib.iter_script_fn().map(|(.., fn_def)| fn_def) } /// Iterate through all function definitions. /// @@ -762,10 +760,8 @@ impl AST { #[cfg(not(feature = "no_function"))] #[allow(dead_code)] #[inline] - pub(crate) fn iter_fn_def(&self) -> impl Iterator { - self.lib - .iter_script_fn() - .map(|(.., fn_def)| fn_def.as_ref()) + pub(crate) fn iter_fn_def(&self) -> impl Iterator> { + self.lib.iter_script_fn().map(|(.., fn_def)| fn_def) } /// Iterate through all function definitions. /// diff --git a/src/ast/mod.rs b/src/ast/mod.rs index b64ef8a0..1e63aa4b 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -19,9 +19,6 @@ pub use ident::Ident; pub use namespace::Namespace; #[cfg(feature = "no_module")] pub use namespace_none::Namespace; -#[cfg(not(feature = "no_module"))] -#[cfg(not(feature = "no_function"))] -pub use script_fn::EncapsulatedEnviron; #[cfg(not(feature = "no_function"))] pub use script_fn::{ScriptFnDef, ScriptFnMetadata}; pub use stmt::{ diff --git a/src/ast/script_fn.rs b/src/ast/script_fn.rs index bf2398d0..e42e1b8c 100644 --- a/src/ast/script_fn.rs +++ b/src/ast/script_fn.rs @@ -7,34 +7,12 @@ use crate::{FnArgsVec, ImmutableString}; use std::prelude::v1::*; use std::{fmt, hash::Hash}; -/// _(internals)_ Encapsulated AST environment. -/// Exported under the `internals` feature only. -/// -/// 1) other functions defined within the same AST -/// 2) the stack of imported [modules][crate::Module] -/// 3) global constants -/// -/// Not available under `no_module` or `no_function`. -#[cfg(not(feature = "no_module"))] -#[derive(Debug, Clone)] -pub struct EncapsulatedEnviron { - /// Functions defined within the same [`AST`][crate::AST]. - pub lib: crate::SharedModule, - /// Imported [modules][crate::Module]. - pub imports: Box<[(ImmutableString, crate::SharedModule)]>, - /// Globally-defined constants. - pub constants: Option, -} - /// _(internals)_ A type containing information on a script-defined function. /// Exported under the `internals` feature only. #[derive(Debug, Clone)] pub struct ScriptFnDef { /// Function body. pub body: StmtBlock, - /// Encapsulated AST environment, if any. - #[cfg(not(feature = "no_module"))] - pub environ: Option>, /// Function name. pub name: ImmutableString, /// Function access mode. diff --git a/src/func/call.rs b/src/func/call.rs index 5b738743..4d4bd0b8 100644 --- a/src/func/call.rs +++ b/src/func/call.rs @@ -644,9 +644,10 @@ impl Engine { // Script function call assert!(func.is_script()); - let func = func.get_script_fn_def().expect("script-defined function"); + let f = func.get_script_fn_def().expect("script-defined function"); + let environ = func.get_encapsulated_environ(); - if func.body.is_empty() { + if f.body.is_empty() { return Ok((Dynamic::UNIT, false)); } @@ -666,7 +667,7 @@ impl Engine { let (first_arg, rest_args) = _args.split_first_mut().unwrap(); self.call_script_fn( - global, caches, scope, first_arg, func, rest_args, true, pos, + global, caches, scope, first_arg, environ, f, rest_args, true, pos, ) } else { // Normal call of script function @@ -683,7 +684,17 @@ impl Engine { let mut this_ptr = Dynamic::NULL; - self.call_script_fn(global, caches, scope, &mut this_ptr, func, args, true, pos) + self.call_script_fn( + global, + caches, + scope, + &mut this_ptr, + environ, + f, + args, + true, + pos, + ) } .map(|r| (r, false)); } @@ -770,6 +781,7 @@ impl Engine { caches, &mut Scope::new(), &mut this_ptr, + None, fn_def, args, true, @@ -856,6 +868,7 @@ impl Engine { caches, &mut Scope::new(), target, + None, &fn_def, args, true, @@ -1064,6 +1077,7 @@ impl Engine { caches, &mut Scope::new(), &mut this_ptr, + None, &fn_def, args, true, @@ -1441,15 +1455,27 @@ impl Engine { match func { #[cfg(not(feature = "no_function"))] - Some(f) if f.is_script() => { - let f = f.get_script_fn_def().expect("script-defined function"); + Some(func) if func.is_script() => { + let f = func.get_script_fn_def().expect("script-defined function"); + let environ = func.get_encapsulated_environ(); + let scope = &mut Scope::new(); let mut this_ptr = Dynamic::NULL; let orig_source = mem::replace(&mut global.source, module.id_raw().cloned()); auto_restore!(global => move |g| g.source = orig_source); - self.call_script_fn(global, caches, scope, &mut this_ptr, f, args, true, pos) + self.call_script_fn( + global, + caches, + scope, + &mut this_ptr, + environ, + f, + args, + true, + pos, + ) } Some(f) if f.is_plugin_fn() => { diff --git a/src/func/callable_function.rs b/src/func/callable_function.rs index e3cebc7a..ff7a1509 100644 --- a/src/func/callable_function.rs +++ b/src/func/callable_function.rs @@ -8,6 +8,26 @@ use std::fmt; #[cfg(feature = "no_std")] use std::prelude::v1::*; +/// _(internals)_ Encapsulated AST environment. +/// Exported under the `internals` feature only. +/// +/// 1) functions defined within the same AST +/// 2) the stack of imported [modules][crate::Module] +/// 3) global constants +#[derive(Debug, Clone)] +pub struct EncapsulatedEnviron { + /// Functions defined within the same [`AST`][crate::AST]. + #[cfg(not(feature = "no_function"))] + pub lib: crate::SharedModule, + /// Imported [modules][crate::Module]. + #[cfg(not(feature = "no_module"))] + pub imports: Box<[(crate::ImmutableString, crate::SharedModule)]>, + /// Globally-defined constants. + #[cfg(not(feature = "no_module"))] + #[cfg(not(feature = "no_function"))] + pub constants: Option, +} + /// _(internals)_ A type encapsulating a function callable by Rhai. /// Exported under the `internals` feature only. #[derive(Clone)] @@ -24,7 +44,10 @@ pub enum CallableFunction { Plugin(Shared), /// A script-defined function. #[cfg(not(feature = "no_function"))] - Script(Shared), + Script( + Shared, + Option>, + ), } impl fmt::Debug for CallableFunction { @@ -38,7 +61,7 @@ impl fmt::Debug for CallableFunction { Self::Plugin(..) => f.write_str("PluginFunction"), #[cfg(not(feature = "no_function"))] - Self::Script(fn_def) => fmt::Debug::fmt(fn_def, f), + Self::Script(fn_def, ..) => fmt::Debug::fmt(fn_def, f), } } } @@ -52,7 +75,7 @@ impl fmt::Display for CallableFunction { Self::Plugin(..) => f.write_str("PluginFunction"), #[cfg(not(feature = "no_function"))] - Self::Script(s) => fmt::Display::fmt(s, f), + Self::Script(fn_def, ..) => fmt::Display::fmt(fn_def, f), } } } @@ -160,7 +183,7 @@ impl CallableFunction { Self::Plugin(..) | Self::Pure(..) | Self::Method(..) | Self::Iterator(..) => { FnAccess::Public } - Self::Script(f) => f.access, + Self::Script(f, ..) => f.access, } } /// Get a shared reference to a native Rust function. @@ -184,7 +207,20 @@ impl CallableFunction { pub const fn get_script_fn_def(&self) -> Option<&Shared> { match self { Self::Pure(..) | Self::Method(..) | Self::Iterator(..) | Self::Plugin(..) => None, - Self::Script(f) => Some(f), + Self::Script(f, ..) => Some(f), + } + } + /// Get a reference to the shared encapsulated environment of the function definition. + /// + /// Not available under `no_function` or `no_module`. + #[inline] + #[must_use] + pub fn get_encapsulated_environ(&self) -> Option<&EncapsulatedEnviron> { + match self { + Self::Pure(..) | Self::Method(..) | Self::Iterator(..) | Self::Plugin(..) => None, + + #[cfg(not(feature = "no_function"))] + Self::Script(.., environ) => environ.as_deref(), } } /// Get a reference to an iterator function. @@ -217,7 +253,7 @@ impl CallableFunction { impl From for CallableFunction { #[inline(always)] fn from(func: crate::ast::ScriptFnDef) -> Self { - Self::Script(func.into()) + Self::Script(func.into(), None) } } @@ -225,7 +261,7 @@ impl From for CallableFunction { impl From> for CallableFunction { #[inline(always)] fn from(func: Shared) -> Self { - Self::Script(func) + Self::Script(func, None) } } diff --git a/src/func/mod.rs b/src/func/mod.rs index 0b31f72b..b726b5ac 100644 --- a/src/func/mod.rs +++ b/src/func/mod.rs @@ -18,7 +18,7 @@ pub use call::ensure_no_data_race; #[cfg(not(feature = "no_function"))] pub use call::is_anonymous_fn; pub use call::FnCallArgs; -pub use callable_function::CallableFunction; +pub use callable_function::{CallableFunction, EncapsulatedEnviron}; #[cfg(not(feature = "no_function"))] pub use func::Func; pub use hashing::{calc_fn_hash, calc_fn_hash_full, calc_var_hash, get_hasher, StraightHashMap}; diff --git a/src/func/script.rs b/src/func/script.rs index ea7cb0f7..03482ffc 100644 --- a/src/func/script.rs +++ b/src/func/script.rs @@ -4,6 +4,7 @@ use super::call::FnCallArgs; use crate::ast::ScriptFnDef; use crate::eval::{Caches, GlobalRuntimeState}; +use crate::func::EncapsulatedEnviron; use crate::{Dynamic, Engine, Position, RhaiResult, Scope, ERR}; use std::mem; #[cfg(feature = "no_std")] @@ -28,6 +29,7 @@ impl Engine { caches: &mut Caches, scope: &mut Scope, this_ptr: &mut Dynamic, + _environ: Option<&EncapsulatedEnviron>, fn_def: &ScriptFnDef, args: &mut FnCallArgs, rewind_scope: bool, @@ -84,12 +86,12 @@ impl Engine { let orig_fn_resolution_caches_len = caches.fn_resolution_caches_len(); #[cfg(not(feature = "no_module"))] - let orig_constants = if let Some(ref environ) = fn_def.environ { - let crate::ast::EncapsulatedEnviron { - ref lib, - ref imports, - ref constants, - } = **environ; + let orig_constants = if let Some(environ) = _environ { + let EncapsulatedEnviron { + lib, + imports, + constants, + } = environ; imports .iter() @@ -124,8 +126,7 @@ impl Engine { _ => Err(ERR::ErrorInFunctionCall( fn_def.name.to_string(), #[cfg(not(feature = "no_module"))] - fn_def - .environ + _environ .as_deref() .and_then(|environ| environ.lib.id()) .unwrap_or_else(|| global.source().unwrap_or("")) diff --git a/src/lib.rs b/src/lib.rs index 5423f9be..6368156a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -338,9 +338,7 @@ pub use ast::CustomExpr; pub use ast::Namespace; #[cfg(feature = "internals")] -#[cfg(not(feature = "no_module"))] -#[cfg(not(feature = "no_function"))] -pub use ast::EncapsulatedEnviron; +pub use func::EncapsulatedEnviron; #[cfg(feature = "internals")] pub use eval::{Caches, FnResolutionCache, FnResolutionCacheEntry, GlobalRuntimeState}; diff --git a/src/module/mod.rs b/src/module/mod.rs index 24ac305b..61d568ce 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -2184,31 +2184,32 @@ impl Module { // Non-private functions defined become module functions #[cfg(not(feature = "no_function"))] { - let environ = Shared::new(crate::ast::EncapsulatedEnviron { + let environ = Shared::new(crate::func::EncapsulatedEnviron { lib: ast.shared_lib().clone(), imports: imports.into_boxed_slice(), constants, }); - ast.shared_lib() - .iter_fn() - .filter(|&f| match f.metadata.access { + ast.iter_fn_def() + .filter(|&f| match f.access { FnAccess::Public => true, FnAccess::Private => false, }) - .filter(|&f| f.func.is_script()) .for_each(|f| { - let mut func = f - .func - .get_script_fn_def() - .expect("script-defined function") - .as_ref() - .clone(); + let hash = module.set_script_fn(f.clone()); // Encapsulate AST environment - func.environ = Some(environ.clone()); - - module.set_script_fn(func); + match module + .functions + .as_mut() + .unwrap() + .get_mut(&hash) + .unwrap() + .func + { + CallableFunction::Script(.., ref mut e) => *e = Some(environ.clone()), + _ => (), + } }); } diff --git a/src/optimizer.rs b/src/optimizer.rs index a534e75a..6c7cc76f 100644 --- a/src/optimizer.rs +++ b/src/optimizer.rs @@ -1344,8 +1344,6 @@ impl Engine { access: fn_def.access, body: crate::ast::StmtBlock::NONE, params: fn_def.params.clone(), - #[cfg(not(feature = "no_module"))] - environ: None, #[cfg(not(feature = "no_function"))] #[cfg(feature = "metadata")] comments: Box::default(), diff --git a/src/parser.rs b/src/parser.rs index 92da6876..8dceca1b 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -3629,8 +3629,6 @@ impl Engine { access, params, body, - #[cfg(not(feature = "no_module"))] - environ: None, #[cfg(feature = "metadata")] comments: comments.into_iter().collect(), }) @@ -3791,8 +3789,6 @@ impl Engine { access: crate::FnAccess::Public, params, body: body.into(), - #[cfg(not(feature = "no_module"))] - environ: None, #[cfg(not(feature = "no_function"))] #[cfg(feature = "metadata")] comments: Box::default(), diff --git a/src/tests.rs b/src/tests.rs index f80e3e49..ebf6ebee 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -31,6 +31,14 @@ fn check_struct_sizes() { size_of::>(), if IS_32_BIT { 12 } else { 16 } ); + assert_eq!( + size_of::(), + if IS_32_BIT { 12 } else { 24 } + ); + assert_eq!( + size_of::(), + if IS_32_BIT { 16 } else { 32 } + ); #[cfg(target_pointer_width = "64")] { diff --git a/src/types/fn_ptr.rs b/src/types/fn_ptr.rs index 5c71bf62..135bfbe5 100644 --- a/src/types/fn_ptr.rs +++ b/src/types/fn_ptr.rs @@ -290,6 +290,7 @@ impl FnPtr { caches, &mut crate::Scope::new(), this_ptr.unwrap_or(&mut null_ptr), + None, &fn_def, args, true,