From 1be7e60be2e3ae002a52f068c820ad6bd8a2dd8b Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Sat, 17 Apr 2021 17:25:35 +0800 Subject: [PATCH] Automatic global module. --- CHANGELOG.md | 12 ++++++++++++ src/engine.rs | 21 ++++++++++++++++++++- src/fn_call.rs | 4 ++++ tests/functions.rs | 17 ++++++++++++++++- 4 files changed, 52 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 50328aab..3ede0882 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,12 +4,24 @@ Rhai Release Notes Version 0.20.1 ============== +This version enables functions to access constants declared at global level via the special `global` module. + Breaking changes ---------------- * `Dynamic::is_shared` and `Dynamic::is_locked` are removed under the `no_closure` feature. They used to always return `false`. * `Engine::call_fn` now evaluates the `AST` before calling the function. +Enhancements +------------ + +* The crate [`no-std-compat`](https://crates.io/crates/no_std_compat) is used to compile for `no-std`. This removes the need to use a special `crate::stdlib` namespace for `std` imports. + +New features +------------ + +* A module called `global` is automatically created to hold global-level constants, which can then be accessed from functions. + Version 0.20.0 ============== diff --git a/src/engine.rs b/src/engine.rs index 7541a56a..8196d18d 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -52,7 +52,10 @@ pub type Precedence = NonZeroU8; // the module name will live beyond the AST of the eval script text. // The best we can do is a shared reference. #[derive(Clone, Default)] -pub struct Imports(StaticVec, StaticVec>); +pub struct Imports( + smallvec::SmallVec<[Identifier; 8]>, + smallvec::SmallVec<[Shared; 8]>, +); impl Imports { /// Get the length of this stack of imported [modules][Module]. @@ -70,6 +73,12 @@ impl Imports { pub fn get(&self, index: usize) -> Option> { self.1.get(index).cloned() } + /// Get the imported [modules][Module] at a particular index. + #[cfg(not(feature = "no_function"))] + #[inline(always)] + pub(crate) fn get_mut(&mut self, index: usize) -> Option<&mut Shared> { + self.1.get_mut(index) + } /// Get the index of an imported [modules][Module] by name. #[inline(always)] pub fn find(&self, name: &str) -> Option { @@ -199,6 +208,8 @@ pub const KEYWORD_IS_DEF_VAR: &str = "is_def_var"; #[cfg(not(feature = "no_function"))] pub const KEYWORD_IS_DEF_FN: &str = "is_def_fn"; pub const KEYWORD_THIS: &str = "this"; +#[cfg(not(feature = "no_function"))] +pub const KEYWORD_GLOBAL: &str = "global"; #[cfg(not(feature = "no_object"))] pub const FN_GET: &str = "get$"; #[cfg(not(feature = "no_object"))] @@ -2504,6 +2515,14 @@ impl Engine { .flatten(); let (var_name, _alias): (Cow<'_, str>, _) = if state.is_global() { + #[cfg(not(feature = "no_function"))] + if entry_type == AccessMode::ReadOnly { + let global = mods.get_mut(mods.find(KEYWORD_GLOBAL).unwrap()).unwrap(); + let global = Shared::get_mut(global).unwrap(); + global.set_var(name.clone(), value.clone()); + global.build_index(); + } + ( name.to_string().into(), if *export { Some(name.clone()) } else { None }, diff --git a/src/fn_call.rs b/src/fn_call.rs index 2a5c904c..3840c587 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -826,6 +826,10 @@ impl Engine { lib: &[&Module], level: usize, ) -> RhaiResult { + // Create the global module + #[cfg(not(feature = "no_function"))] + mods.push(crate::engine::KEYWORD_GLOBAL, Module::new()); + self.eval_stmt_block(scope, mods, state, lib, &mut None, statements, false, level) .or_else(|err| match *err { EvalAltResult::Return(out, _) => Ok(out), diff --git a/tests/functions.rs b/tests/functions.rs index 05805a9e..1387f3eb 100644 --- a/tests/functions.rs +++ b/tests/functions.rs @@ -62,7 +62,22 @@ fn test_functions_namespaces() -> Result<(), Box> { assert_eq!(engine.eval::("test()")?, 42); #[cfg(not(feature = "no_function"))] - assert_eq!(engine.eval::("fn test() { 123 } test()")?, 123); + { + assert_eq!(engine.eval::("fn test() { 123 } test()")?, 123); + + assert_eq!( + engine.eval::( + r" + const ANSWER = 42; + + fn foo() { global::ANSWER } + + foo() + " + )?, + 42 + ); + } Ok(()) }