Automatic global module.

This commit is contained in:
Stephen Chung 2021-04-17 17:25:35 +08:00
parent 9a409b5b49
commit 1be7e60be2
4 changed files with 52 additions and 2 deletions

View File

@ -4,12 +4,24 @@ Rhai Release Notes
Version 0.20.1 Version 0.20.1
============== ==============
This version enables functions to access constants declared at global level via the special `global` module.
Breaking changes Breaking changes
---------------- ----------------
* `Dynamic::is_shared` and `Dynamic::is_locked` are removed under the `no_closure` feature. They used to always return `false`. * `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. * `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 Version 0.20.0
============== ==============

View File

@ -52,7 +52,10 @@ pub type Precedence = NonZeroU8;
// the module name will live beyond the AST of the eval script text. // the module name will live beyond the AST of the eval script text.
// The best we can do is a shared reference. // The best we can do is a shared reference.
#[derive(Clone, Default)] #[derive(Clone, Default)]
pub struct Imports(StaticVec<Identifier>, StaticVec<Shared<Module>>); pub struct Imports(
smallvec::SmallVec<[Identifier; 8]>,
smallvec::SmallVec<[Shared<Module>; 8]>,
);
impl Imports { impl Imports {
/// Get the length of this stack of imported [modules][Module]. /// Get the length of this stack of imported [modules][Module].
@ -70,6 +73,12 @@ impl Imports {
pub fn get(&self, index: usize) -> Option<Shared<Module>> { pub fn get(&self, index: usize) -> Option<Shared<Module>> {
self.1.get(index).cloned() 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<Module>> {
self.1.get_mut(index)
}
/// Get the index of an imported [modules][Module] by name. /// Get the index of an imported [modules][Module] by name.
#[inline(always)] #[inline(always)]
pub fn find(&self, name: &str) -> Option<usize> { pub fn find(&self, name: &str) -> Option<usize> {
@ -199,6 +208,8 @@ pub const KEYWORD_IS_DEF_VAR: &str = "is_def_var";
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
pub const KEYWORD_IS_DEF_FN: &str = "is_def_fn"; pub const KEYWORD_IS_DEF_FN: &str = "is_def_fn";
pub const KEYWORD_THIS: &str = "this"; pub const KEYWORD_THIS: &str = "this";
#[cfg(not(feature = "no_function"))]
pub const KEYWORD_GLOBAL: &str = "global";
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
pub const FN_GET: &str = "get$"; pub const FN_GET: &str = "get$";
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
@ -2504,6 +2515,14 @@ impl Engine {
.flatten(); .flatten();
let (var_name, _alias): (Cow<'_, str>, _) = if state.is_global() { 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(), name.to_string().into(),
if *export { Some(name.clone()) } else { None }, if *export { Some(name.clone()) } else { None },

View File

@ -826,6 +826,10 @@ impl Engine {
lib: &[&Module], lib: &[&Module],
level: usize, level: usize,
) -> RhaiResult { ) -> 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) self.eval_stmt_block(scope, mods, state, lib, &mut None, statements, false, level)
.or_else(|err| match *err { .or_else(|err| match *err {
EvalAltResult::Return(out, _) => Ok(out), EvalAltResult::Return(out, _) => Ok(out),

View File

@ -62,7 +62,22 @@ fn test_functions_namespaces() -> Result<(), Box<EvalAltResult>> {
assert_eq!(engine.eval::<INT>("test()")?, 42); assert_eq!(engine.eval::<INT>("test()")?, 42);
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
assert_eq!(engine.eval::<INT>("fn test() { 123 } test()")?, 123); {
assert_eq!(engine.eval::<INT>("fn test() { 123 } test()")?, 123);
assert_eq!(
engine.eval::<INT>(
r"
const ANSWER = 42;
fn foo() { global::ANSWER }
foo()
"
)?,
42
);
}
Ok(()) Ok(())
} }