Refactor and add state to debugger.
This commit is contained in:
@@ -1401,9 +1401,9 @@ impl Module {
|
||||
/// Sub-modules are flattened onto the root [`Module`], with higher level overriding lower level.
|
||||
#[inline]
|
||||
pub fn combine_flatten(&mut self, other: Self) -> &mut Self {
|
||||
other.modules.into_iter().for_each(|(_, m)| {
|
||||
for (_, m) in other.modules.into_iter() {
|
||||
self.combine_flatten(shared_take_or_clone(m));
|
||||
});
|
||||
}
|
||||
self.variables.extend(other.variables.into_iter());
|
||||
self.functions.extend(other.functions.into_iter());
|
||||
self.type_iterators.extend(other.type_iterators.into_iter());
|
||||
@@ -1419,22 +1419,22 @@ impl Module {
|
||||
/// Only items not existing in this [`Module`] are added.
|
||||
#[inline]
|
||||
pub fn fill_with(&mut self, other: &Self) -> &mut Self {
|
||||
other.modules.iter().for_each(|(k, v)| {
|
||||
for (k, v) in &other.modules {
|
||||
if !self.modules.contains_key(k) {
|
||||
self.modules.insert(k.clone(), v.clone());
|
||||
}
|
||||
});
|
||||
other.variables.iter().for_each(|(k, v)| {
|
||||
}
|
||||
for (k, v) in &other.variables {
|
||||
if !self.variables.contains_key(k) {
|
||||
self.variables.insert(k.clone(), v.clone());
|
||||
}
|
||||
});
|
||||
other.functions.iter().for_each(|(&k, v)| {
|
||||
}
|
||||
for (&k, v) in &other.functions {
|
||||
self.functions.entry(k).or_insert_with(|| v.clone());
|
||||
});
|
||||
other.type_iterators.iter().for_each(|(&k, v)| {
|
||||
}
|
||||
for (&k, v) in &other.type_iterators {
|
||||
self.type_iterators.entry(k).or_insert(v.clone());
|
||||
});
|
||||
}
|
||||
self.all_functions.clear();
|
||||
self.all_variables.clear();
|
||||
self.all_type_iterators.clear();
|
||||
@@ -1455,12 +1455,11 @@ impl Module {
|
||||
other: &Self,
|
||||
_filter: impl Fn(FnNamespace, FnAccess, bool, &str, usize) -> bool + Copy,
|
||||
) -> &mut Self {
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
other.modules.iter().for_each(|(k, v)| {
|
||||
for (k, v) in &other.modules {
|
||||
let mut m = Self::new();
|
||||
m.merge_filtered(v, _filter);
|
||||
self.set_sub_module(k.clone(), m);
|
||||
});
|
||||
}
|
||||
#[cfg(feature = "no_function")]
|
||||
self.modules
|
||||
.extend(other.modules.iter().map(|(k, v)| (k.clone(), v.clone())));
|
||||
@@ -1658,60 +1657,90 @@ impl Module {
|
||||
/// # }
|
||||
/// ```
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
#[inline(always)]
|
||||
pub fn eval_ast_as_new(
|
||||
scope: crate::Scope,
|
||||
ast: &crate::AST,
|
||||
engine: &crate::Engine,
|
||||
) -> RhaiResultOf<Self> {
|
||||
let global = &mut crate::eval::GlobalRuntimeState::new(engine);
|
||||
|
||||
Self::eval_ast_as_new_raw(engine, scope, global, ast)
|
||||
}
|
||||
/// Create a new [`Module`] by evaluating an [`AST`][crate::AST].
|
||||
///
|
||||
/// The entire [`AST`][crate::AST] is encapsulated into each function, allowing functions
|
||||
/// to cross-call each other. Functions in the global namespace, plus all functions
|
||||
/// defined in the [`Module`], are _merged_ into a _unified_ namespace before each call.
|
||||
/// Therefore, all functions will be found.
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
pub(crate) fn eval_ast_as_new_raw(
|
||||
engine: &crate::Engine,
|
||||
scope: crate::Scope,
|
||||
global: &mut crate::eval::GlobalRuntimeState,
|
||||
ast: &crate::AST,
|
||||
) -> RhaiResultOf<Self> {
|
||||
let mut scope = scope;
|
||||
let mut global = crate::eval::GlobalRuntimeState::new();
|
||||
|
||||
#[cfg(feature = "debugging")]
|
||||
global.debugger.activate(engine.debugger.is_some());
|
||||
|
||||
// Save global state
|
||||
let orig_imports_len = global.num_imports();
|
||||
let orig_source = global.source.clone();
|
||||
let orig_constants = std::mem::take(&mut global.constants);
|
||||
|
||||
// Run the script
|
||||
engine.eval_ast_with_scope_raw(&mut scope, &mut global, &ast, 0)?;
|
||||
let result = engine.eval_ast_with_scope_raw(&mut scope, global, &ast, 0);
|
||||
|
||||
// Create new module
|
||||
let mut module =
|
||||
scope
|
||||
.into_iter()
|
||||
.fold(Module::new(), |mut module, (_, value, mut aliases)| {
|
||||
// Variables with an alias left in the scope become module variables
|
||||
match aliases.len() {
|
||||
0 => (),
|
||||
1 => {
|
||||
let alias = aliases.pop().unwrap();
|
||||
module.set_var(alias, value);
|
||||
}
|
||||
_ => {
|
||||
let last_alias = aliases.pop().unwrap();
|
||||
aliases.into_iter().for_each(|alias| {
|
||||
module.set_var(alias, value.clone());
|
||||
});
|
||||
// Avoid cloning the last value
|
||||
module.set_var(last_alias, value);
|
||||
}
|
||||
}
|
||||
module
|
||||
});
|
||||
let mut module = Module::new();
|
||||
|
||||
// Extra modules left in the scope become sub-modules
|
||||
// Extra modules left become sub-modules
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
let mut func_global = None;
|
||||
|
||||
global.into_iter().skip(orig_imports_len).for_each(|kv| {
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
if func_global.is_none() {
|
||||
func_global = Some(StaticVec::new());
|
||||
}
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
func_global.as_mut().expect("`Some`").push(kv.clone());
|
||||
if result.is_ok() {
|
||||
global
|
||||
.scan_imports_raw()
|
||||
.skip(orig_imports_len)
|
||||
.for_each(|(k, m)| {
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
if func_global.is_none() {
|
||||
func_global = Some(StaticVec::new());
|
||||
}
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
func_global
|
||||
.as_mut()
|
||||
.expect("`Some`")
|
||||
.push((k.clone(), m.clone()));
|
||||
|
||||
module.set_sub_module(kv.0, kv.1);
|
||||
});
|
||||
module.set_sub_module(k.clone(), m.clone());
|
||||
});
|
||||
}
|
||||
|
||||
// Restore global state
|
||||
global.constants = orig_constants;
|
||||
global.truncate_imports(orig_imports_len);
|
||||
global.source = orig_source;
|
||||
|
||||
result?;
|
||||
|
||||
// Variables with an alias left in the scope become module variables
|
||||
for (_, value, mut aliases) in scope {
|
||||
match aliases.len() {
|
||||
0 => (),
|
||||
1 => {
|
||||
let alias = aliases.pop().unwrap();
|
||||
module.set_var(alias, value);
|
||||
}
|
||||
_ => {
|
||||
let last_alias = aliases.pop().unwrap();
|
||||
for alias in aliases {
|
||||
module.set_var(alias, value.clone());
|
||||
}
|
||||
// Avoid cloning the last value
|
||||
module.set_var(last_alias, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
let func_global = func_global.map(|v| v.into_boxed_slice());
|
||||
@@ -1773,29 +1802,29 @@ impl Module {
|
||||
) -> bool {
|
||||
let mut contains_indexed_global_functions = false;
|
||||
|
||||
module.modules.iter().for_each(|(name, m)| {
|
||||
for (name, m) in &module.modules {
|
||||
// Index all the sub-modules first.
|
||||
path.push(name);
|
||||
if index_module(m, path, variables, functions, type_iterators) {
|
||||
contains_indexed_global_functions = true;
|
||||
}
|
||||
path.pop();
|
||||
});
|
||||
}
|
||||
|
||||
// Index all variables
|
||||
module.variables.iter().for_each(|(var_name, value)| {
|
||||
for (var_name, value) in &module.variables {
|
||||
let hash_var = crate::calc_qualified_var_hash(path.iter().copied(), var_name);
|
||||
variables.insert(hash_var, value.clone());
|
||||
});
|
||||
}
|
||||
|
||||
// Index type iterators
|
||||
module.type_iterators.iter().for_each(|(&type_id, func)| {
|
||||
for (&type_id, func) in &module.type_iterators {
|
||||
type_iterators.insert(type_id, func.clone());
|
||||
contains_indexed_global_functions = true;
|
||||
});
|
||||
}
|
||||
|
||||
// Index all Rust functions
|
||||
module.functions.iter().for_each(|(&hash, f)| {
|
||||
for (&hash, f) in &module.functions {
|
||||
match f.metadata.namespace {
|
||||
FnNamespace::Global => {
|
||||
// Flatten all functions with global namespace
|
||||
@@ -1806,7 +1835,7 @@ impl Module {
|
||||
}
|
||||
match f.metadata.access {
|
||||
FnAccess::Public => (),
|
||||
FnAccess::Private => return, // Do not index private functions
|
||||
FnAccess::Private => continue, // Do not index private functions
|
||||
}
|
||||
|
||||
if !f.func.is_script() {
|
||||
@@ -1824,7 +1853,7 @@ impl Module {
|
||||
);
|
||||
functions.insert(hash_qualified_script, f.func.clone());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
contains_indexed_global_functions
|
||||
}
|
||||
|
@@ -124,7 +124,7 @@ impl ModuleResolver for ModuleResolversCollection {
|
||||
path: &str,
|
||||
pos: Position,
|
||||
) -> RhaiResultOf<Shared<Module>> {
|
||||
for resolver in self.0.iter() {
|
||||
for resolver in &self.0 {
|
||||
match resolver.resolve(engine, source_path, path, pos) {
|
||||
Ok(module) => return Ok(module),
|
||||
Err(err) => match *err {
|
||||
|
@@ -1,9 +1,10 @@
|
||||
#![cfg(not(feature = "no_std"))]
|
||||
#![cfg(not(target_family = "wasm"))]
|
||||
|
||||
use crate::func::native::shared_write_lock;
|
||||
use crate::func::native::locked_write;
|
||||
use crate::{
|
||||
Engine, Identifier, Module, ModuleResolver, Position, RhaiResultOf, Scope, Shared, ERR,
|
||||
Engine, GlobalRuntimeState, Identifier, Module, ModuleResolver, Position, RhaiResultOf, Scope,
|
||||
Shared, ERR,
|
||||
};
|
||||
|
||||
use std::{
|
||||
@@ -207,12 +208,12 @@ impl FileModuleResolver {
|
||||
|
||||
let file_path = self.get_file_path(path.as_ref(), source_path);
|
||||
|
||||
shared_write_lock(&self.cache).contains_key(&file_path)
|
||||
locked_write(&self.cache).contains_key(&file_path)
|
||||
}
|
||||
/// Empty the internal cache.
|
||||
#[inline]
|
||||
pub fn clear_cache(&mut self) -> &mut Self {
|
||||
shared_write_lock(&self.cache).clear();
|
||||
locked_write(&self.cache).clear();
|
||||
self
|
||||
}
|
||||
/// Remove the specified path from internal cache.
|
||||
@@ -227,7 +228,7 @@ impl FileModuleResolver {
|
||||
) -> Option<Shared<Module>> {
|
||||
let file_path = self.get_file_path(path.as_ref(), source_path.as_ref().map(<_>::as_ref));
|
||||
|
||||
shared_write_lock(&self.cache)
|
||||
locked_write(&self.cache)
|
||||
.remove_entry(&file_path)
|
||||
.map(|(_, v)| v)
|
||||
}
|
||||
@@ -252,24 +253,25 @@ impl FileModuleResolver {
|
||||
file_path.set_extension(self.extension.as_str()); // Force extension
|
||||
file_path
|
||||
}
|
||||
}
|
||||
|
||||
impl ModuleResolver for FileModuleResolver {
|
||||
fn resolve(
|
||||
/// Resolve a module based on a path.
|
||||
fn impl_resolve(
|
||||
&self,
|
||||
engine: &Engine,
|
||||
source_path: Option<&str>,
|
||||
global: Option<&mut GlobalRuntimeState>,
|
||||
source: Option<&str>,
|
||||
path: &str,
|
||||
pos: Position,
|
||||
) -> RhaiResultOf<Shared<Module>> {
|
||||
) -> Result<Shared<Module>, Box<crate::EvalAltResult>> {
|
||||
// Load relative paths from source if there is no base path specified
|
||||
let source_path =
|
||||
source_path.and_then(|p| Path::new(p).parent().map(|p| p.to_string_lossy()));
|
||||
let source_path = global
|
||||
.as_ref()
|
||||
.and_then(|g| g.source())
|
||||
.or(source)
|
||||
.and_then(|p| Path::new(p).parent().map(|p| p.to_string_lossy()));
|
||||
|
||||
// Construct the script file path
|
||||
let file_path = self.get_file_path(path, source_path.as_ref().map(|p| p.as_ref()));
|
||||
|
||||
// See if it is cached
|
||||
if self.is_cache_enabled() {
|
||||
#[cfg(not(feature = "sync"))]
|
||||
let c = self.cache.borrow();
|
||||
@@ -281,7 +283,6 @@ impl ModuleResolver for FileModuleResolver {
|
||||
}
|
||||
}
|
||||
|
||||
// Load the script file and compile it
|
||||
let scope = Scope::new();
|
||||
|
||||
let mut ast = engine
|
||||
@@ -295,18 +296,43 @@ impl ModuleResolver for FileModuleResolver {
|
||||
|
||||
ast.set_source(path);
|
||||
|
||||
// Make a module from the AST
|
||||
let m: Shared<Module> = 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> = if let Some(global) = global {
|
||||
Module::eval_ast_as_new_raw(engine, scope, global, &ast)
|
||||
} else {
|
||||
Module::eval_ast_as_new(scope, &ast, engine)
|
||||
}
|
||||
.map_err(|err| Box::new(ERR::ErrorInModule(path.to_string(), err, pos)))?
|
||||
.into();
|
||||
|
||||
// Put it into the cache
|
||||
if self.is_cache_enabled() {
|
||||
shared_write_lock(&self.cache).insert(file_path, m.clone());
|
||||
locked_write(&self.cache).insert(file_path, m.clone());
|
||||
}
|
||||
|
||||
Ok(m)
|
||||
}
|
||||
}
|
||||
|
||||
impl ModuleResolver for FileModuleResolver {
|
||||
fn resolve_raw(
|
||||
&self,
|
||||
engine: &Engine,
|
||||
global: &mut GlobalRuntimeState,
|
||||
path: &str,
|
||||
pos: Position,
|
||||
) -> RhaiResultOf<Shared<Module>> {
|
||||
self.impl_resolve(engine, Some(global), None, path, pos)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn resolve(
|
||||
&self,
|
||||
engine: &Engine,
|
||||
source: Option<&str>,
|
||||
path: &str,
|
||||
pos: Position,
|
||||
) -> RhaiResultOf<Shared<Module>> {
|
||||
self.impl_resolve(engine, None, source, path, pos)
|
||||
}
|
||||
|
||||
/// Resolve an `AST` based on a path string.
|
||||
///
|
||||
|
@@ -1,5 +1,5 @@
|
||||
use crate::func::native::SendSync;
|
||||
use crate::{Engine, Module, Position, RhaiResultOf, Shared, AST};
|
||||
use crate::{Engine, GlobalRuntimeState, Module, Position, RhaiResultOf, Shared, AST};
|
||||
#[cfg(feature = "no_std")]
|
||||
use std::prelude::v1::*;
|
||||
|
||||
@@ -21,11 +21,26 @@ pub trait ModuleResolver: SendSync {
|
||||
fn resolve(
|
||||
&self,
|
||||
engine: &Engine,
|
||||
source_path: Option<&str>,
|
||||
source: Option<&str>,
|
||||
path: &str,
|
||||
pos: Position,
|
||||
) -> RhaiResultOf<Shared<Module>>;
|
||||
|
||||
/// Resolve a module based on a path string, given a [`GlobalRuntimeState`].
|
||||
///
|
||||
/// # WARNING - Low Level API
|
||||
///
|
||||
/// This function is very low level.
|
||||
fn resolve_raw(
|
||||
&self,
|
||||
engine: &Engine,
|
||||
global: &mut GlobalRuntimeState,
|
||||
path: &str,
|
||||
pos: Position,
|
||||
) -> RhaiResultOf<Shared<Module>> {
|
||||
self.resolve(engine, global.source(), path, pos)
|
||||
}
|
||||
|
||||
/// Resolve an `AST` based on a path string.
|
||||
///
|
||||
/// Returns [`None`] (default) if such resolution is not supported
|
||||
@@ -40,7 +55,7 @@ pub trait ModuleResolver: SendSync {
|
||||
fn resolve_ast(
|
||||
&self,
|
||||
engine: &Engine,
|
||||
source_path: Option<&str>,
|
||||
source: Option<&str>,
|
||||
path: &str,
|
||||
pos: Position,
|
||||
) -> Option<RhaiResultOf<AST>> {
|
||||
|
Reference in New Issue
Block a user