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.
|
* `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`.
|
* 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
|
Enhancements
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
@ -802,14 +802,16 @@ impl Engine {
|
|||||||
|
|
||||||
let module = resolver
|
let module = resolver
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|r| match r.resolve_raw(self, global, &path, path_pos) {
|
.and_then(
|
||||||
Err(err) if matches!(*err, ERR::ErrorModuleNotFound(..)) => None,
|
|r| match r.resolve_raw(self, global, scope, &path, path_pos) {
|
||||||
result => Some(result),
|
Err(err) if matches!(*err, ERR::ErrorModuleNotFound(..)) => None,
|
||||||
})
|
result => Some(result),
|
||||||
|
},
|
||||||
|
)
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
Some(
|
Some(
|
||||||
self.module_resolver
|
self.module_resolver
|
||||||
.resolve_raw(self, global, &path, path_pos),
|
.resolve_raw(self, global, scope, &path, path_pos),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
|
@ -2083,9 +2083,10 @@ impl Module {
|
|||||||
ast: &crate::AST,
|
ast: &crate::AST,
|
||||||
engine: &crate::Engine,
|
engine: &crate::Engine,
|
||||||
) -> RhaiResultOf<Self> {
|
) -> RhaiResultOf<Self> {
|
||||||
|
let mut scope = scope;
|
||||||
let global = &mut crate::eval::GlobalRuntimeState::new(engine);
|
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].
|
/// Create a new [`Module`] by evaluating an [`AST`][crate::AST].
|
||||||
///
|
///
|
||||||
@ -2101,13 +2102,12 @@ impl Module {
|
|||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
pub fn eval_ast_as_new_raw(
|
pub fn eval_ast_as_new_raw(
|
||||||
engine: &crate::Engine,
|
engine: &crate::Engine,
|
||||||
scope: crate::Scope,
|
scope: &mut crate::Scope,
|
||||||
global: &mut crate::eval::GlobalRuntimeState,
|
global: &mut crate::eval::GlobalRuntimeState,
|
||||||
ast: &crate::AST,
|
ast: &crate::AST,
|
||||||
) -> RhaiResultOf<Self> {
|
) -> RhaiResultOf<Self> {
|
||||||
let mut scope = scope;
|
|
||||||
|
|
||||||
// Save global state
|
// Save global state
|
||||||
|
let orig_scope_len = scope.len();
|
||||||
let orig_imports_len = global.num_imports();
|
let orig_imports_len = global.num_imports();
|
||||||
let orig_source = global.source.clone();
|
let orig_source = global.source.clone();
|
||||||
|
|
||||||
@ -2120,7 +2120,7 @@ impl Module {
|
|||||||
// Run the script
|
// Run the script
|
||||||
let caches = &mut crate::eval::Caches::new();
|
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
|
// Create new module
|
||||||
let mut module = Module::new();
|
let mut module = Module::new();
|
||||||
@ -2162,7 +2162,9 @@ impl Module {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Variables with an alias left in the scope become module variables
|
// 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| {
|
value.deep_scan(|v| {
|
||||||
if let Some(fn_ptr) = v.downcast_mut::<crate::FnPtr>() {
|
if let Some(fn_ptr) = v.downcast_mut::<crate::FnPtr>() {
|
||||||
fn_ptr.set_encapsulated_environ(Some(environ.clone()));
|
fn_ptr.set_encapsulated_environ(Some(environ.clone()));
|
||||||
|
@ -290,15 +290,15 @@ impl FileModuleResolver {
|
|||||||
fn impl_resolve(
|
fn impl_resolve(
|
||||||
&self,
|
&self,
|
||||||
engine: &Engine,
|
engine: &Engine,
|
||||||
global: Option<&mut GlobalRuntimeState>,
|
global: &mut GlobalRuntimeState,
|
||||||
|
scope: &mut Scope,
|
||||||
source: Option<&str>,
|
source: Option<&str>,
|
||||||
path: &str,
|
path: &str,
|
||||||
pos: Position,
|
pos: Position,
|
||||||
) -> Result<SharedModule, Box<crate::EvalAltResult>> {
|
) -> Result<SharedModule, Box<crate::EvalAltResult>> {
|
||||||
// Load relative paths from source if there is no base path specified
|
// Load relative paths from source if there is no base path specified
|
||||||
let source_path = global
|
let source_path = global
|
||||||
.as_ref()
|
.source()
|
||||||
.and_then(|g| g.source())
|
|
||||||
.or(source)
|
.or(source)
|
||||||
.and_then(|p| Path::new(p).parent());
|
.and_then(|p| Path::new(p).parent());
|
||||||
|
|
||||||
@ -321,14 +321,9 @@ impl FileModuleResolver {
|
|||||||
|
|
||||||
ast.set_source(path);
|
ast.set_source(path);
|
||||||
|
|
||||||
let scope = Scope::new();
|
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)))?
|
||||||
let m: Shared<_> = match global {
|
.into();
|
||||||
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();
|
|
||||||
|
|
||||||
if self.is_cache_enabled() {
|
if self.is_cache_enabled() {
|
||||||
locked_write(&self.cache).insert(file_path, m.clone());
|
locked_write(&self.cache).insert(file_path, m.clone());
|
||||||
@ -343,10 +338,11 @@ impl ModuleResolver for FileModuleResolver {
|
|||||||
&self,
|
&self,
|
||||||
engine: &Engine,
|
engine: &Engine,
|
||||||
global: &mut GlobalRuntimeState,
|
global: &mut GlobalRuntimeState,
|
||||||
|
scope: &mut Scope,
|
||||||
path: &str,
|
path: &str,
|
||||||
pos: Position,
|
pos: Position,
|
||||||
) -> RhaiResultOf<SharedModule> {
|
) -> RhaiResultOf<SharedModule> {
|
||||||
self.impl_resolve(engine, Some(global), None, path, pos)
|
self.impl_resolve(engine, global, scope, None, path, pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
@ -357,7 +353,9 @@ impl ModuleResolver for FileModuleResolver {
|
|||||||
path: &str,
|
path: &str,
|
||||||
pos: Position,
|
pos: Position,
|
||||||
) -> RhaiResultOf<SharedModule> {
|
) -> 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.
|
/// Resolve an `AST` based on a path string.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::eval::GlobalRuntimeState;
|
use crate::eval::GlobalRuntimeState;
|
||||||
use crate::func::SendSync;
|
use crate::func::SendSync;
|
||||||
use crate::{Engine, Position, RhaiResultOf, SharedModule, AST};
|
use crate::{Engine, Position, RhaiResultOf, Scope, SharedModule, AST};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
|
|
||||||
@ -27,15 +27,17 @@ pub trait ModuleResolver: SendSync {
|
|||||||
pos: Position,
|
pos: Position,
|
||||||
) -> RhaiResultOf<SharedModule>;
|
) -> 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
|
/// # WARNING - Low Level API
|
||||||
///
|
///
|
||||||
/// This function is very low level.
|
/// This function is very low level.
|
||||||
|
#[allow(unused_variables)]
|
||||||
fn resolve_raw(
|
fn resolve_raw(
|
||||||
&self,
|
&self,
|
||||||
engine: &Engine,
|
engine: &Engine,
|
||||||
global: &mut GlobalRuntimeState,
|
global: &mut GlobalRuntimeState,
|
||||||
|
scope: &mut Scope,
|
||||||
path: &str,
|
path: &str,
|
||||||
pos: Position,
|
pos: Position,
|
||||||
) -> RhaiResultOf<SharedModule> {
|
) -> RhaiResultOf<SharedModule> {
|
||||||
|
@ -385,11 +385,22 @@ impl Scope<'_> {
|
|||||||
/// ```
|
/// ```
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn pop(&mut self) -> &mut Self {
|
pub fn pop(&mut self) -> &mut Self {
|
||||||
self.names.pop().expect("`Scope` must not be empty");
|
self.names.pop().expect("not empty");
|
||||||
let _ = self.values.pop().expect("`Scope` must not be empty");
|
let _ = self.values.pop().expect("not empty");
|
||||||
self.aliases.pop().expect("`Scope` must not be empty");
|
self.aliases.pop().expect("not empty");
|
||||||
self
|
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.
|
/// Truncate (rewind) the [`Scope`] to a previous size.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
|
Loading…
Reference in New Issue
Block a user