Allow access to scope by loaded module.
This commit is contained in:
parent
7fc72e8c28
commit
513a1ab435
@ -13,6 +13,12 @@ Bug fixes
|
||||
* `x += y` where `x` and `y` are `char` now works correctly.
|
||||
* Expressions such as `!inside` now parses correctly instead of as `!in` followed by `side`.
|
||||
|
||||
Potentially breaking changes
|
||||
----------------------------
|
||||
|
||||
* The trait method `ModuleResolver::resolve_raw` (which is a low-level API) now takes a `&mut Scope` parameter. This is a breaking change because the signature is modified, but this trait method has a default and is rarely called/implemented in practice.
|
||||
* `Module::eval_ast_as_new_raw` (a low-level API) now takes a `&mut Scope` instead of the `Scope` parameter. This is a breaking change because the `&mut` is now required.
|
||||
|
||||
Enhancements
|
||||
------------
|
||||
|
||||
|
@ -802,14 +802,16 @@ impl Engine {
|
||||
|
||||
let module = resolver
|
||||
.as_ref()
|
||||
.and_then(|r| match r.resolve_raw(self, global, &path, path_pos) {
|
||||
Err(err) if matches!(*err, ERR::ErrorModuleNotFound(..)) => None,
|
||||
result => Some(result),
|
||||
})
|
||||
.and_then(
|
||||
|r| match r.resolve_raw(self, global, scope, &path, path_pos) {
|
||||
Err(err) if matches!(*err, ERR::ErrorModuleNotFound(..)) => None,
|
||||
result => Some(result),
|
||||
},
|
||||
)
|
||||
.or_else(|| {
|
||||
Some(
|
||||
self.module_resolver
|
||||
.resolve_raw(self, global, &path, path_pos),
|
||||
.resolve_raw(self, global, scope, &path, path_pos),
|
||||
)
|
||||
})
|
||||
.unwrap_or_else(|| {
|
||||
|
@ -2083,9 +2083,10 @@ impl Module {
|
||||
ast: &crate::AST,
|
||||
engine: &crate::Engine,
|
||||
) -> RhaiResultOf<Self> {
|
||||
let mut scope = scope;
|
||||
let global = &mut crate::eval::GlobalRuntimeState::new(engine);
|
||||
|
||||
Self::eval_ast_as_new_raw(engine, scope, global, ast)
|
||||
Self::eval_ast_as_new_raw(engine, &mut scope, global, ast)
|
||||
}
|
||||
/// Create a new [`Module`] by evaluating an [`AST`][crate::AST].
|
||||
///
|
||||
@ -2101,13 +2102,12 @@ impl Module {
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
pub fn eval_ast_as_new_raw(
|
||||
engine: &crate::Engine,
|
||||
scope: crate::Scope,
|
||||
scope: &mut crate::Scope,
|
||||
global: &mut crate::eval::GlobalRuntimeState,
|
||||
ast: &crate::AST,
|
||||
) -> RhaiResultOf<Self> {
|
||||
let mut scope = scope;
|
||||
|
||||
// Save global state
|
||||
let orig_scope_len = scope.len();
|
||||
let orig_imports_len = global.num_imports();
|
||||
let orig_source = global.source.clone();
|
||||
|
||||
@ -2120,7 +2120,7 @@ impl Module {
|
||||
// Run the script
|
||||
let caches = &mut crate::eval::Caches::new();
|
||||
|
||||
let result = engine.eval_ast_with_scope_raw(global, caches, &mut scope, ast);
|
||||
let result = engine.eval_ast_with_scope_raw(global, caches, scope, ast);
|
||||
|
||||
// Create new module
|
||||
let mut module = Module::new();
|
||||
@ -2162,7 +2162,9 @@ impl Module {
|
||||
});
|
||||
|
||||
// Variables with an alias left in the scope become module variables
|
||||
for (_name, mut value, mut aliases) in scope {
|
||||
while scope.len() > orig_scope_len {
|
||||
let (_name, mut value, mut aliases) = scope.pop_entry().expect("not empty");
|
||||
|
||||
value.deep_scan(|v| {
|
||||
if let Some(fn_ptr) = v.downcast_mut::<crate::FnPtr>() {
|
||||
fn_ptr.set_encapsulated_environ(Some(environ.clone()));
|
||||
|
@ -290,15 +290,15 @@ impl FileModuleResolver {
|
||||
fn impl_resolve(
|
||||
&self,
|
||||
engine: &Engine,
|
||||
global: Option<&mut GlobalRuntimeState>,
|
||||
global: &mut GlobalRuntimeState,
|
||||
scope: &mut Scope,
|
||||
source: Option<&str>,
|
||||
path: &str,
|
||||
pos: Position,
|
||||
) -> Result<SharedModule, Box<crate::EvalAltResult>> {
|
||||
// Load relative paths from source if there is no base path specified
|
||||
let source_path = global
|
||||
.as_ref()
|
||||
.and_then(|g| g.source())
|
||||
.source()
|
||||
.or(source)
|
||||
.and_then(|p| Path::new(p).parent());
|
||||
|
||||
@ -321,14 +321,9 @@ impl FileModuleResolver {
|
||||
|
||||
ast.set_source(path);
|
||||
|
||||
let scope = Scope::new();
|
||||
|
||||
let m: Shared<_> = match global {
|
||||
Some(global) => Module::eval_ast_as_new_raw(engine, scope, global, &ast),
|
||||
None => Module::eval_ast_as_new(scope, &ast, engine),
|
||||
}
|
||||
.map_err(|err| Box::new(ERR::ErrorInModule(path.to_string(), err, pos)))?
|
||||
.into();
|
||||
let m: Shared<_> = Module::eval_ast_as_new_raw(engine, scope, global, &ast)
|
||||
.map_err(|err| Box::new(ERR::ErrorInModule(path.to_string(), err, pos)))?
|
||||
.into();
|
||||
|
||||
if self.is_cache_enabled() {
|
||||
locked_write(&self.cache).insert(file_path, m.clone());
|
||||
@ -343,10 +338,11 @@ impl ModuleResolver for FileModuleResolver {
|
||||
&self,
|
||||
engine: &Engine,
|
||||
global: &mut GlobalRuntimeState,
|
||||
scope: &mut Scope,
|
||||
path: &str,
|
||||
pos: Position,
|
||||
) -> RhaiResultOf<SharedModule> {
|
||||
self.impl_resolve(engine, Some(global), None, path, pos)
|
||||
self.impl_resolve(engine, global, scope, None, path, pos)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
@ -357,7 +353,9 @@ impl ModuleResolver for FileModuleResolver {
|
||||
path: &str,
|
||||
pos: Position,
|
||||
) -> RhaiResultOf<SharedModule> {
|
||||
self.impl_resolve(engine, None, source, path, pos)
|
||||
let global = &mut GlobalRuntimeState::new(engine);
|
||||
let scope = &mut Scope::new();
|
||||
self.impl_resolve(engine, global, scope, source, path, pos)
|
||||
}
|
||||
|
||||
/// Resolve an `AST` based on a path string.
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::eval::GlobalRuntimeState;
|
||||
use crate::func::SendSync;
|
||||
use crate::{Engine, Position, RhaiResultOf, SharedModule, AST};
|
||||
use crate::{Engine, Position, RhaiResultOf, Scope, SharedModule, AST};
|
||||
#[cfg(feature = "no_std")]
|
||||
use std::prelude::v1::*;
|
||||
|
||||
@ -27,15 +27,17 @@ pub trait ModuleResolver: SendSync {
|
||||
pos: Position,
|
||||
) -> RhaiResultOf<SharedModule>;
|
||||
|
||||
/// Resolve a module based on a path string, given a [`GlobalRuntimeState`].
|
||||
/// Resolve a module based on a path string, given a [`GlobalRuntimeState`] and the current [`Scope`].
|
||||
///
|
||||
/// # WARNING - Low Level API
|
||||
///
|
||||
/// This function is very low level.
|
||||
#[allow(unused_variables)]
|
||||
fn resolve_raw(
|
||||
&self,
|
||||
engine: &Engine,
|
||||
global: &mut GlobalRuntimeState,
|
||||
scope: &mut Scope,
|
||||
path: &str,
|
||||
pos: Position,
|
||||
) -> RhaiResultOf<SharedModule> {
|
||||
|
@ -385,11 +385,22 @@ impl Scope<'_> {
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn pop(&mut self) -> &mut Self {
|
||||
self.names.pop().expect("`Scope` must not be empty");
|
||||
let _ = self.values.pop().expect("`Scope` must not be empty");
|
||||
self.aliases.pop().expect("`Scope` must not be empty");
|
||||
self.names.pop().expect("not empty");
|
||||
let _ = self.values.pop().expect("not empty");
|
||||
self.aliases.pop().expect("not empty");
|
||||
self
|
||||
}
|
||||
/// Remove the last entry from the [`Scope`] and return it.
|
||||
#[inline(always)]
|
||||
pub(crate) fn pop_entry(&mut self) -> Option<(Identifier, Dynamic, Vec<ImmutableString>)> {
|
||||
self.values.pop().map(|value| {
|
||||
(
|
||||
self.names.pop().expect("not empty"),
|
||||
value,
|
||||
self.aliases.pop().expect("not empty"),
|
||||
)
|
||||
})
|
||||
}
|
||||
/// Truncate (rewind) the [`Scope`] to a previous size.
|
||||
///
|
||||
/// # Example
|
||||
|
Loading…
Reference in New Issue
Block a user