No modules in scope.
This commit is contained in:
parent
aac04a5e53
commit
527d41d0e3
@ -13,6 +13,7 @@ Breaking changes
|
|||||||
* Functions defined in script now differentiates between using method-call style and normal function-call style.
|
* Functions defined in script now differentiates between using method-call style and normal function-call style.
|
||||||
The method-call style will bind the object to the `this` parameter instead of consuming the first parameter.
|
The method-call style will bind the object to the `this` parameter instead of consuming the first parameter.
|
||||||
* Imported modules are no longer stored in the `Scope`. `Scope::push_module` is removed.
|
* Imported modules are no longer stored in the `Scope`. `Scope::push_module` is removed.
|
||||||
|
Therefore, cannot rely on module imports to persist across invocations using a `Scope`.
|
||||||
|
|
||||||
New features
|
New features
|
||||||
------------
|
------------
|
||||||
|
112
src/engine.rs
112
src/engine.rs
@ -4,7 +4,7 @@ use crate::any::{Dynamic, Union, Variant};
|
|||||||
use crate::calc_fn_hash;
|
use crate::calc_fn_hash;
|
||||||
use crate::error::ParseErrorType;
|
use crate::error::ParseErrorType;
|
||||||
use crate::fn_native::{CallableFunction, Callback, FnCallArgs, FnPtr};
|
use crate::fn_native::{CallableFunction, Callback, FnCallArgs, FnPtr};
|
||||||
use crate::module::{resolvers, Module, ModuleResolver};
|
use crate::module::{resolvers, Module, ModuleRef, ModuleResolver};
|
||||||
use crate::optimize::OptimizationLevel;
|
use crate::optimize::OptimizationLevel;
|
||||||
use crate::packages::{Package, PackageLibrary, PackagesCollection, StandardPackage};
|
use crate::packages::{Package, PackageLibrary, PackagesCollection, StandardPackage};
|
||||||
use crate::parser::{Expr, FnAccess, ImmutableString, ReturnType, ScriptFnDef, Stmt, AST, INT};
|
use crate::parser::{Expr, FnAccess, ImmutableString, ReturnType, ScriptFnDef, Stmt, AST, INT};
|
||||||
@ -393,6 +393,39 @@ fn default_print(s: &str) {
|
|||||||
println!("{}", s);
|
println!("{}", s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Search for a module within an imports stack.
|
||||||
|
/// Position in `EvalAltResult` is None and must be set afterwards.
|
||||||
|
fn search_imports<'s>(
|
||||||
|
mods: &'s mut Imports,
|
||||||
|
state: &mut State,
|
||||||
|
modules: &Box<ModuleRef>,
|
||||||
|
) -> Result<&'s mut Module, Box<EvalAltResult>> {
|
||||||
|
let (root, root_pos) = modules.get(0);
|
||||||
|
|
||||||
|
// Qualified - check if the root module is directly indexed
|
||||||
|
let index = if state.always_search {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
modules.index()
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(if let Some(index) = index {
|
||||||
|
let offset = mods.len() - index.get();
|
||||||
|
&mut mods.get_mut(offset).unwrap().1
|
||||||
|
} else {
|
||||||
|
mods.iter_mut()
|
||||||
|
.rev()
|
||||||
|
.find(|(n, _)| n == root)
|
||||||
|
.map(|(_, m)| m)
|
||||||
|
.ok_or_else(|| {
|
||||||
|
Box::new(EvalAltResult::ErrorModuleNotFound(
|
||||||
|
root.to_string(),
|
||||||
|
*root_pos,
|
||||||
|
))
|
||||||
|
})?
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Search for a variable within the scope
|
/// Search for a variable within the scope
|
||||||
fn search_scope<'s, 'a>(
|
fn search_scope<'s, 'a>(
|
||||||
scope: &'s mut Scope,
|
scope: &'s mut Scope,
|
||||||
@ -416,29 +449,16 @@ fn search_scope<'s, 'a>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if it is qualified
|
// Check if it is qualified
|
||||||
if let Some(modules) = modules.as_ref() {
|
if let Some(modules) = modules {
|
||||||
// Qualified - check if the root module is directly indexed
|
let module = search_imports(mods, state, modules)?;
|
||||||
let index = if state.always_search {
|
let target = module
|
||||||
None
|
.get_qualified_var_mut(*hash_var)
|
||||||
} else {
|
.map_err(|err| match *err {
|
||||||
modules.index()
|
EvalAltResult::ErrorVariableNotFound(_, _) => Box::new(
|
||||||
};
|
EvalAltResult::ErrorVariableNotFound(format!("{}{}", modules, name), *pos),
|
||||||
|
),
|
||||||
let module = if let Some(index) = index {
|
_ => err.new_position(*pos),
|
||||||
let offset = mods.len() - index.get();
|
})?;
|
||||||
&mut mods.get_mut(offset).unwrap().1
|
|
||||||
} else {
|
|
||||||
// Find the root module in the scope
|
|
||||||
let (id, root_pos) = modules.get(0);
|
|
||||||
|
|
||||||
mods.iter_mut()
|
|
||||||
.rev()
|
|
||||||
.find(|(n, _)| n == id)
|
|
||||||
.map(|(_, m)| m)
|
|
||||||
.ok_or_else(|| Box::new(EvalAltResult::ErrorModuleNotFound(id.into(), *root_pos)))?
|
|
||||||
};
|
|
||||||
|
|
||||||
let target = module.get_qualified_var_mut(name, *hash_var, *pos)?;
|
|
||||||
|
|
||||||
// Module variables are constant
|
// Module variables are constant
|
||||||
Ok((target, name, ScopeEntryType::Constant, *pos))
|
Ok((target, name, ScopeEntryType::Constant, *pos))
|
||||||
@ -1952,29 +1972,10 @@ impl Engine {
|
|||||||
|
|
||||||
let mut args: StaticVec<_> = arg_values.iter_mut().collect();
|
let mut args: StaticVec<_> = arg_values.iter_mut().collect();
|
||||||
|
|
||||||
let (id, root_pos) = modules.get(0); // First module
|
let module = search_imports(mods, state, modules)?;
|
||||||
|
|
||||||
let index = if state.always_search {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
modules.index()
|
|
||||||
};
|
|
||||||
|
|
||||||
let module = if let Some(index) = index {
|
|
||||||
let offset = mods.len() - index.get();
|
|
||||||
&mut mods.get_mut(offset).unwrap().1
|
|
||||||
} else {
|
|
||||||
mods.iter_mut()
|
|
||||||
.rev()
|
|
||||||
.find(|(n, _)| n == id)
|
|
||||||
.map(|(_, m)| m)
|
|
||||||
.ok_or_else(|| {
|
|
||||||
Box::new(EvalAltResult::ErrorModuleNotFound(id.into(), *root_pos))
|
|
||||||
})?
|
|
||||||
};
|
|
||||||
|
|
||||||
// First search in script-defined functions (can override built-in)
|
// First search in script-defined functions (can override built-in)
|
||||||
let func = match module.get_qualified_fn(name, *hash_script) {
|
let func = match module.get_qualified_fn(*hash_script) {
|
||||||
Err(err) if matches!(*err, EvalAltResult::ErrorFunctionNotFound(_, _)) => {
|
Err(err) if matches!(*err, EvalAltResult::ErrorFunctionNotFound(_, _)) => {
|
||||||
// Then search in Rust functions
|
// Then search in Rust functions
|
||||||
self.inc_operations(state)
|
self.inc_operations(state)
|
||||||
@ -1990,7 +1991,7 @@ impl Engine {
|
|||||||
// 3) The final hash is the XOR of the two hashes.
|
// 3) The final hash is the XOR of the two hashes.
|
||||||
let hash_qualified_fn = *hash_script ^ hash_fn_args;
|
let hash_qualified_fn = *hash_script ^ hash_fn_args;
|
||||||
|
|
||||||
module.get_qualified_fn(name, hash_qualified_fn)
|
module.get_qualified_fn(hash_qualified_fn)
|
||||||
}
|
}
|
||||||
r => r,
|
r => r,
|
||||||
};
|
};
|
||||||
@ -2009,13 +2010,18 @@ impl Engine {
|
|||||||
Ok(f) => {
|
Ok(f) => {
|
||||||
f.get_native_fn()(self, args.as_mut()).map_err(|err| err.new_position(*pos))
|
f.get_native_fn()(self, args.as_mut()).map_err(|err| err.new_position(*pos))
|
||||||
}
|
}
|
||||||
Err(err)
|
Err(err) => match *err {
|
||||||
if def_val.is_some()
|
EvalAltResult::ErrorFunctionNotFound(_, _) if def_val.is_some() => {
|
||||||
&& matches!(*err, EvalAltResult::ErrorFunctionNotFound(_, _)) =>
|
Ok(def_val.clone().unwrap())
|
||||||
{
|
}
|
||||||
Ok(def_val.clone().unwrap())
|
EvalAltResult::ErrorFunctionNotFound(_, _) => {
|
||||||
}
|
Err(Box::new(EvalAltResult::ErrorFunctionNotFound(
|
||||||
Err(err) => Err(err),
|
format!("{}{}", modules, name),
|
||||||
|
*pos,
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
_ => Err(err.new_position(*pos)),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,17 +218,19 @@ impl Module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get a mutable reference to a modules-qualified variable.
|
/// Get a mutable reference to a modules-qualified variable.
|
||||||
|
/// Name and Position in `EvalAltResult` are None and must be set afterwards.
|
||||||
///
|
///
|
||||||
/// The `u64` hash is calculated by the function `crate::calc_fn_hash`.
|
/// The `u64` hash is calculated by the function `crate::calc_fn_hash`.
|
||||||
pub(crate) fn get_qualified_var_mut(
|
pub(crate) fn get_qualified_var_mut(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: &str,
|
|
||||||
hash_var: u64,
|
hash_var: u64,
|
||||||
pos: Position,
|
|
||||||
) -> Result<&mut Dynamic, Box<EvalAltResult>> {
|
) -> Result<&mut Dynamic, Box<EvalAltResult>> {
|
||||||
self.all_variables
|
self.all_variables.get_mut(&hash_var).ok_or_else(|| {
|
||||||
.get_mut(&hash_var)
|
Box::new(EvalAltResult::ErrorVariableNotFound(
|
||||||
.ok_or_else(|| Box::new(EvalAltResult::ErrorVariableNotFound(name.to_string(), pos)))
|
String::new(),
|
||||||
|
Position::none(),
|
||||||
|
))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a script-defined function into the module.
|
/// Set a script-defined function into the module.
|
||||||
@ -839,17 +841,17 @@ impl Module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get a modules-qualified function.
|
/// Get a modules-qualified function.
|
||||||
|
/// Name and Position in `EvalAltResult` are None and must be set afterwards.
|
||||||
///
|
///
|
||||||
/// The `u64` hash is calculated by the function `crate::calc_fn_hash` and must match
|
/// The `u64` hash is calculated by the function `crate::calc_fn_hash` and must match
|
||||||
/// the hash calculated by `index_all_sub_modules`.
|
/// the hash calculated by `index_all_sub_modules`.
|
||||||
pub(crate) fn get_qualified_fn(
|
pub(crate) fn get_qualified_fn(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: &str,
|
|
||||||
hash_qualified_fn: u64,
|
hash_qualified_fn: u64,
|
||||||
) -> Result<&CallableFunction, Box<EvalAltResult>> {
|
) -> Result<&CallableFunction, Box<EvalAltResult>> {
|
||||||
self.all_functions.get(&hash_qualified_fn).ok_or_else(|| {
|
self.all_functions.get(&hash_qualified_fn).ok_or_else(|| {
|
||||||
Box::new(EvalAltResult::ErrorFunctionNotFound(
|
Box::new(EvalAltResult::ErrorFunctionNotFound(
|
||||||
name.to_string(),
|
String::new(),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
|
@ -2016,13 +2016,13 @@ fn parse_for(
|
|||||||
ensure_not_statement_expr(input, "a boolean")?;
|
ensure_not_statement_expr(input, "a boolean")?;
|
||||||
let expr = parse_expr(input, state, settings.level_up())?;
|
let expr = parse_expr(input, state, settings.level_up())?;
|
||||||
|
|
||||||
let prev_len = state.stack.len();
|
let prev_stack_len = state.stack.len();
|
||||||
state.stack.push((name.clone(), ScopeEntryType::Normal));
|
state.stack.push((name.clone(), ScopeEntryType::Normal));
|
||||||
|
|
||||||
settings.is_breakable = true;
|
settings.is_breakable = true;
|
||||||
let body = parse_block(input, state, settings.level_up())?;
|
let body = parse_block(input, state, settings.level_up())?;
|
||||||
|
|
||||||
state.stack.truncate(prev_len);
|
state.stack.truncate(prev_stack_len);
|
||||||
|
|
||||||
Ok(Stmt::For(Box::new((name, expr, body))))
|
Ok(Stmt::For(Box::new((name, expr, body))))
|
||||||
}
|
}
|
||||||
@ -2209,7 +2209,8 @@ fn parse_block(
|
|||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
let mut statements = StaticVec::new();
|
let mut statements = StaticVec::new();
|
||||||
let prev_len = state.stack.len();
|
let prev_stack_len = state.stack.len();
|
||||||
|
let prev_mods_len = state.modules.len();
|
||||||
|
|
||||||
while !match_token(input, Token::RightBrace)? {
|
while !match_token(input, Token::RightBrace)? {
|
||||||
// Parse statements inside the block
|
// Parse statements inside the block
|
||||||
@ -2249,7 +2250,8 @@ fn parse_block(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
state.stack.truncate(prev_len);
|
state.stack.truncate(prev_stack_len);
|
||||||
|
state.modules.truncate(prev_mods_len);
|
||||||
|
|
||||||
Ok(Stmt::Block(Box::new((statements, settings.pos))))
|
Ok(Stmt::Block(Box::new((statements, settings.pos))))
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user