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.
|
* Merging or combining a self-contained `AST` into another `AST` now works properly.
|
||||||
* Plugin modules/functions no longer generate errors under `#![deny(missing_docs)]`.
|
* 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.
|
* 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
|
Deprecated API's
|
||||||
----------------
|
----------------
|
||||||
|
@ -32,15 +32,19 @@ impl Engine {
|
|||||||
|
|
||||||
if let Some(index) = index {
|
if let Some(index) = index {
|
||||||
let offset = global.num_imports() - index.get();
|
let offset = global.num_imports() - index.get();
|
||||||
Some(global.get_shared_import(offset).unwrap())
|
|
||||||
} else {
|
if let m @ Some(_) = global.get_shared_import(offset) {
|
||||||
global
|
return m;
|
||||||
.find_import(root)
|
|
||||||
.map(|n| global.get_shared_import(n).unwrap())
|
|
||||||
.or_else(|| self.global_sub_modules.get(root).cloned())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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,
|
/// Search for a variable within the scope or within imports,
|
||||||
/// depending on whether the variable name is namespace-qualified.
|
/// depending on whether the variable name is namespace-qualified.
|
||||||
pub(crate) fn search_namespace<'s>(
|
pub(crate) fn search_namespace<'s>(
|
||||||
|
@ -57,7 +57,7 @@ pub struct ParseState<'e> {
|
|||||||
pub block_stack_len: usize,
|
pub block_stack_len: usize,
|
||||||
/// Tracks a list of external variables (variables that are not explicitly declared in the scope).
|
/// Tracks a list of external variables (variables that are not explicitly declared in the scope).
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[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
|
/// An indicator that disables variable capturing into externals one single time
|
||||||
/// up until the nearest consumed Identifier token.
|
/// 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.
|
/// 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 {
|
Self {
|
||||||
tokenizer_control,
|
tokenizer_control,
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
external_vars: crate::FnArgsVec::new_const(),
|
external_vars: Vec::new(),
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
allow_capture: true,
|
allow_capture: true,
|
||||||
interned_strings: StringsInterner::new(),
|
interned_strings: StringsInterner::new(),
|
||||||
@ -494,20 +494,17 @@ impl Engine {
|
|||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
let hash = if !namespace.is_empty() {
|
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"))]
|
if settings.options.contains(LangOptions::STRICT_VAR) && index.is_none() {
|
||||||
let relax = settings.is_function_scope;
|
if root != crate::engine::KEYWORD_GLOBAL
|
||||||
#[cfg(feature = "no_function")]
|
&& !self.global_sub_modules.contains_key(root)
|
||||||
let relax = false;
|
|
||||||
|
|
||||||
if !relax
|
|
||||||
&& settings.options.contains(LangOptions::STRICT_VAR)
|
|
||||||
&& index.is_none()
|
|
||||||
{
|
{
|
||||||
return Err(PERR::ModuleUndefined(namespace.root().to_string())
|
return Err(PERR::ModuleUndefined(root.to_string())
|
||||||
.into_err(namespace.position()));
|
.into_err(namespace.position()));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace.set_index(index);
|
namespace.set_index(index);
|
||||||
|
|
||||||
@ -557,20 +554,17 @@ impl Engine {
|
|||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
let hash = if !namespace.is_empty() {
|
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"))]
|
if settings.options.contains(LangOptions::STRICT_VAR) && index.is_none() {
|
||||||
let relax = settings.is_function_scope;
|
if root != crate::engine::KEYWORD_GLOBAL
|
||||||
#[cfg(feature = "no_function")]
|
&& !self.global_sub_modules.contains_key(root)
|
||||||
let relax = false;
|
|
||||||
|
|
||||||
if !relax
|
|
||||||
&& settings.options.contains(LangOptions::STRICT_VAR)
|
|
||||||
&& index.is_none()
|
|
||||||
{
|
{
|
||||||
return Err(PERR::ModuleUndefined(namespace.root().to_string())
|
return Err(PERR::ModuleUndefined(root.to_string())
|
||||||
.into_err(namespace.position()));
|
.into_err(namespace.position()));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace.set_index(index);
|
namespace.set_index(index);
|
||||||
|
|
||||||
@ -1268,6 +1262,7 @@ impl Engine {
|
|||||||
Token::Pipe | Token::Or if settings.options.contains(LangOptions::ANON_FN) => {
|
Token::Pipe | Token::Or if settings.options.contains(LangOptions::ANON_FN) => {
|
||||||
let mut new_state =
|
let mut new_state =
|
||||||
ParseState::new(self, state.scope, state.tokenizer_control.clone());
|
ParseState::new(self, state.scope, state.tokenizer_control.clone());
|
||||||
|
new_state.imports = state.imports.clone();
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
{
|
{
|
||||||
@ -1678,20 +1673,17 @@ impl Engine {
|
|||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[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"))]
|
if settings.options.contains(LangOptions::STRICT_VAR) && index.is_none() {
|
||||||
let relax = settings.is_function_scope;
|
if root != crate::engine::KEYWORD_GLOBAL
|
||||||
#[cfg(feature = "no_function")]
|
&& !self.global_sub_modules.contains_key(root)
|
||||||
let relax = false;
|
|
||||||
|
|
||||||
if !relax
|
|
||||||
&& settings.options.contains(LangOptions::STRICT_VAR)
|
|
||||||
&& index.is_none()
|
|
||||||
{
|
{
|
||||||
return Err(PERR::ModuleUndefined(namespace.root().to_string())
|
return Err(PERR::ModuleUndefined(root.to_string())
|
||||||
.into_err(namespace.position()));
|
.into_err(namespace.position()));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace.set_index(index);
|
namespace.set_index(index);
|
||||||
}
|
}
|
||||||
@ -3080,6 +3072,7 @@ impl Engine {
|
|||||||
(Token::Fn, pos) => {
|
(Token::Fn, pos) => {
|
||||||
let mut new_state =
|
let mut new_state =
|
||||||
ParseState::new(self, state.scope, state.tokenizer_control.clone());
|
ParseState::new(self, state.scope, state.tokenizer_control.clone());
|
||||||
|
new_state.imports = state.imports.clone();
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
{
|
{
|
||||||
|
@ -52,7 +52,7 @@ pub trait Variant: Any + private::Sealed {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
fn as_any_mut(&mut self) -> &mut dyn Any;
|
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]
|
#[must_use]
|
||||||
fn as_boxed_any(self: Box<Self>) -> Box<dyn Any>;
|
fn as_boxed_any(self: Box<Self>) -> Box<dyn Any>;
|
||||||
|
|
||||||
@ -79,7 +79,7 @@ pub trait Variant: Any + Send + Sync + private::Sealed {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
fn as_any_mut(&mut self) -> &mut dyn Any;
|
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]
|
#[must_use]
|
||||||
fn as_boxed_any(self: Box<Self>) -> Box<dyn Any>;
|
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"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
assert!(engine.compile("fn foo(x) { x + y }").is_err());
|
assert!(engine.compile("fn foo(x) { x + y }").is_err());
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
{
|
{
|
||||||
assert!(engine.compile("print(h::y::z);").is_err());
|
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());
|
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"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
{
|
{
|
||||||
assert!(engine.compile("let f = |y| x * y;").is_err());
|
assert!(engine.compile("let f = |y| x * y;").is_err());
|
||||||
|
Loading…
Reference in New Issue
Block a user