Strict mode in functions check for static modules.
This commit is contained in:
parent
285bf23dfa
commit
dcaac20eb9
@ -13,6 +13,8 @@ Bug fixes
|
||||
* Merging or combining a self-contained `AST` into another `AST` now works properly.
|
||||
* Plugin modules/functions no longer generate errors under `#![deny(missing_docs)]`.
|
||||
* Calling a property on a function call that returns a shared value no longer causes an error.
|
||||
* _Strict Variables Mode_ now checks for module namespaces within functions as well.
|
||||
* Module defined via `Engine::register_static_module` are now checked in _Strict Variables Mode_.
|
||||
|
||||
Deprecated API's
|
||||
----------------
|
||||
|
@ -32,15 +32,19 @@ impl Engine {
|
||||
|
||||
if let Some(index) = index {
|
||||
let offset = global.num_imports() - index.get();
|
||||
Some(global.get_shared_import(offset).unwrap())
|
||||
} else {
|
||||
global
|
||||
.find_import(root)
|
||||
.map(|n| global.get_shared_import(n).unwrap())
|
||||
.or_else(|| self.global_sub_modules.get(root).cloned())
|
||||
|
||||
if let m @ Some(_) = global.get_shared_import(offset) {
|
||||
return m;
|
||||
}
|
||||
}
|
||||
|
||||
// Do a text-match search if the index doesn't work
|
||||
global.find_import(root).map_or_else(
|
||||
|| self.global_sub_modules.get(root).cloned(),
|
||||
|offset| global.get_shared_import(offset),
|
||||
)
|
||||
}
|
||||
|
||||
/// Search for a variable within the scope or within imports,
|
||||
/// depending on whether the variable name is namespace-qualified.
|
||||
pub(crate) fn search_namespace<'s>(
|
||||
|
@ -57,7 +57,7 @@ pub struct ParseState<'e> {
|
||||
pub block_stack_len: usize,
|
||||
/// Tracks a list of external variables (variables that are not explicitly declared in the scope).
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
pub external_vars: crate::FnArgsVec<crate::ast::Ident>,
|
||||
pub external_vars: Vec<crate::ast::Ident>,
|
||||
/// An indicator that disables variable capturing into externals one single time
|
||||
/// up until the nearest consumed Identifier token.
|
||||
/// If set to false the next call to [`access_var`][ParseState::access_var] will not capture the variable.
|
||||
@ -80,7 +80,7 @@ impl<'e> ParseState<'e> {
|
||||
Self {
|
||||
tokenizer_control,
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
external_vars: crate::FnArgsVec::new_const(),
|
||||
external_vars: Vec::new(),
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
allow_capture: true,
|
||||
interned_strings: StringsInterner::new(),
|
||||
@ -494,20 +494,17 @@ impl Engine {
|
||||
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
let hash = if !namespace.is_empty() {
|
||||
let index = state.find_module(namespace.root());
|
||||
let root = namespace.root();
|
||||
let index = state.find_module(root);
|
||||
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
let relax = settings.is_function_scope;
|
||||
#[cfg(feature = "no_function")]
|
||||
let relax = false;
|
||||
|
||||
if !relax
|
||||
&& settings.options.contains(LangOptions::STRICT_VAR)
|
||||
&& index.is_none()
|
||||
if settings.options.contains(LangOptions::STRICT_VAR) && index.is_none() {
|
||||
if root != crate::engine::KEYWORD_GLOBAL
|
||||
&& !self.global_sub_modules.contains_key(root)
|
||||
{
|
||||
return Err(PERR::ModuleUndefined(namespace.root().to_string())
|
||||
return Err(PERR::ModuleUndefined(root.to_string())
|
||||
.into_err(namespace.position()));
|
||||
}
|
||||
}
|
||||
|
||||
namespace.set_index(index);
|
||||
|
||||
@ -557,20 +554,17 @@ impl Engine {
|
||||
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
let hash = if !namespace.is_empty() {
|
||||
let index = state.find_module(namespace.root());
|
||||
let root = namespace.root();
|
||||
let index = state.find_module(root);
|
||||
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
let relax = settings.is_function_scope;
|
||||
#[cfg(feature = "no_function")]
|
||||
let relax = false;
|
||||
|
||||
if !relax
|
||||
&& settings.options.contains(LangOptions::STRICT_VAR)
|
||||
&& index.is_none()
|
||||
if settings.options.contains(LangOptions::STRICT_VAR) && index.is_none() {
|
||||
if root != crate::engine::KEYWORD_GLOBAL
|
||||
&& !self.global_sub_modules.contains_key(root)
|
||||
{
|
||||
return Err(PERR::ModuleUndefined(namespace.root().to_string())
|
||||
return Err(PERR::ModuleUndefined(root.to_string())
|
||||
.into_err(namespace.position()));
|
||||
}
|
||||
}
|
||||
|
||||
namespace.set_index(index);
|
||||
|
||||
@ -1268,6 +1262,7 @@ impl Engine {
|
||||
Token::Pipe | Token::Or if settings.options.contains(LangOptions::ANON_FN) => {
|
||||
let mut new_state =
|
||||
ParseState::new(self, state.scope, state.tokenizer_control.clone());
|
||||
new_state.imports = state.imports.clone();
|
||||
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
{
|
||||
@ -1678,20 +1673,17 @@ impl Engine {
|
||||
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
{
|
||||
let index = state.find_module(namespace.root());
|
||||
let root = namespace.root();
|
||||
let index = state.find_module(root);
|
||||
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
let relax = settings.is_function_scope;
|
||||
#[cfg(feature = "no_function")]
|
||||
let relax = false;
|
||||
|
||||
if !relax
|
||||
&& settings.options.contains(LangOptions::STRICT_VAR)
|
||||
&& index.is_none()
|
||||
if settings.options.contains(LangOptions::STRICT_VAR) && index.is_none() {
|
||||
if root != crate::engine::KEYWORD_GLOBAL
|
||||
&& !self.global_sub_modules.contains_key(root)
|
||||
{
|
||||
return Err(PERR::ModuleUndefined(namespace.root().to_string())
|
||||
return Err(PERR::ModuleUndefined(root.to_string())
|
||||
.into_err(namespace.position()));
|
||||
}
|
||||
}
|
||||
|
||||
namespace.set_index(index);
|
||||
}
|
||||
@ -3080,6 +3072,7 @@ impl Engine {
|
||||
(Token::Fn, pos) => {
|
||||
let mut new_state =
|
||||
ParseState::new(self, state.scope, state.tokenizer_control.clone());
|
||||
new_state.imports = state.imports.clone();
|
||||
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
{
|
||||
|
@ -52,7 +52,7 @@ pub trait Variant: Any + private::Sealed {
|
||||
#[must_use]
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any;
|
||||
|
||||
/// Convert this [`Variant`] trait object to [`Box<dyn Any>`].
|
||||
/// Convert this [`Variant`] trait object to [`Box<dyn Any>`][Any].
|
||||
#[must_use]
|
||||
fn as_boxed_any(self: Box<Self>) -> Box<dyn Any>;
|
||||
|
||||
@ -79,7 +79,7 @@ pub trait Variant: Any + Send + Sync + private::Sealed {
|
||||
#[must_use]
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any;
|
||||
|
||||
/// Convert this [`Variant`] trait object to [`Box<dyn Any>`].
|
||||
/// Convert this [`Variant`] trait object to [`Box<dyn Any>`][Any].
|
||||
#[must_use]
|
||||
fn as_boxed_any(self: Box<Self>) -> Box<dyn Any>;
|
||||
|
||||
|
@ -91,18 +91,17 @@ fn test_options_strict_var() -> Result<(), Box<EvalAltResult>> {
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
assert!(engine.compile("fn foo(x) { x + y }").is_err());
|
||||
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
{
|
||||
assert!(engine.compile("print(h::y::z);").is_err());
|
||||
engine.compile(r#"import "hello" as h; print(h::y::z);"#)?;
|
||||
assert!(engine.compile("fn foo() { h::y::z }").is_err());
|
||||
assert!(engine.compile("fn foo() { h::y::foo() }").is_err());
|
||||
engine.compile(r#"import "hello" as h; fn foo() { h::a::b::c } print(h::y::z);"#)?;
|
||||
assert!(engine.compile("let x = h::y::foo();").is_err());
|
||||
engine.compile(r#"import "hello" as h; let x = h::y::foo();"#)?;
|
||||
engine.compile(r#"import "hello" as h; fn foo() { h::a::b::c() } let x = h::y::foo();"#)?;
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
engine.compile("fn foo() { h::y::foo() }")?;
|
||||
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
{
|
||||
assert!(engine.compile("let f = |y| x * y;").is_err());
|
||||
|
Loading…
Reference in New Issue
Block a user