Remove fields and parameters under no_function.
This commit is contained in:
parent
a3e79c0bd0
commit
95dc2ad502
@ -18,9 +18,8 @@ Enhancements
|
|||||||
Deprecated API's
|
Deprecated API's
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
* The internal `no_smartstring` feature is removed since `SmartString` now supports `no-std`.
|
|
||||||
* `NativeCallContext::new` is deprecated because it is simpler to call a function pointer via `FnPtr::call`.
|
* `NativeCallContext::new` is deprecated because it is simpler to call a function pointer via `FnPtr::call`.
|
||||||
* `AST::shared_lib` is changed to return `&Shared<Module>` while `AST::lib` is deprecated.
|
* `AST::merge_filtered` and `AST::combine_filtered` are no longer exported under `no_function`.
|
||||||
|
|
||||||
|
|
||||||
Version 1.2.1
|
Version 1.2.1
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
use crate::engine::{EvalState, Imports};
|
use crate::engine::{EvalState, Imports};
|
||||||
use crate::parser::ParseState;
|
use crate::parser::ParseState;
|
||||||
use crate::types::dynamic::Variant;
|
use crate::types::dynamic::Variant;
|
||||||
use crate::{Dynamic, Engine, EvalAltResult, Position, RhaiResult, Scope, AST};
|
use crate::{Dynamic, Engine, EvalAltResult, Module, Position, RhaiResult, Scope, AST};
|
||||||
use std::any::type_name;
|
use std::any::type_name;
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
@ -217,7 +217,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
{
|
{
|
||||||
mods.embedded_module_resolver = ast.resolver();
|
mods.embedded_module_resolver = ast.resolver().cloned();
|
||||||
}
|
}
|
||||||
|
|
||||||
let statements = ast.statements();
|
let statements = ast.statements();
|
||||||
@ -226,7 +226,15 @@ impl Engine {
|
|||||||
return Ok(Dynamic::UNIT);
|
return Ok(Dynamic::UNIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
let lib = &[ast.as_ref()];
|
let lib = [
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
ast.as_ref(),
|
||||||
|
];
|
||||||
|
let lib = if lib.first().map(|m: &&Module| m.is_empty()).unwrap_or(true) {
|
||||||
|
&lib[0..0]
|
||||||
|
} else {
|
||||||
|
&lib
|
||||||
|
};
|
||||||
self.eval_global_statements(scope, mods, &mut state, statements, lib, level)
|
self.eval_global_statements(scope, mods, &mut state, statements, lib, level)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,12 +86,16 @@ impl Engine {
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
#[cfg(feature = "no_function")]
|
|
||||||
let lib = crate::StaticVec::new_const();
|
|
||||||
|
|
||||||
let statements = std::mem::take(ast.statements_mut());
|
let statements = std::mem::take(ast.statements_mut());
|
||||||
|
|
||||||
crate::optimizer::optimize_into_ast(self, scope, statements, lib, optimization_level)
|
crate::optimizer::optimize_into_ast(
|
||||||
|
self,
|
||||||
|
scope,
|
||||||
|
statements,
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
lib,
|
||||||
|
optimization_level,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
use crate::engine::{EvalState, Imports};
|
use crate::engine::{EvalState, Imports};
|
||||||
use crate::parser::ParseState;
|
use crate::parser::ParseState;
|
||||||
use crate::{Engine, EvalAltResult, Scope, AST};
|
use crate::{Engine, EvalAltResult, Module, Scope, AST};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
|
|
||||||
@ -59,12 +59,20 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
{
|
{
|
||||||
mods.embedded_module_resolver = ast.resolver();
|
mods.embedded_module_resolver = ast.resolver().cloned();
|
||||||
}
|
}
|
||||||
|
|
||||||
let statements = ast.statements();
|
let statements = ast.statements();
|
||||||
if !statements.is_empty() {
|
if !statements.is_empty() {
|
||||||
let lib = &[ast.as_ref()];
|
let lib = [
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
ast.as_ref(),
|
||||||
|
];
|
||||||
|
let lib = if lib.first().map(|m: &&Module| m.is_empty()).unwrap_or(true) {
|
||||||
|
&lib[0..0]
|
||||||
|
} else {
|
||||||
|
&lib
|
||||||
|
};
|
||||||
self.eval_global_statements(scope, mods, &mut state, statements, lib, 0)?;
|
self.eval_global_statements(scope, mods, &mut state, statements, lib, 0)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
119
src/ast.rs
119
src/ast.rs
@ -1,7 +1,6 @@
|
|||||||
//! Module defining the AST (abstract syntax tree).
|
//! Module defining the AST (abstract syntax tree).
|
||||||
|
|
||||||
use crate::calc_fn_hash;
|
use crate::calc_fn_hash;
|
||||||
use crate::func::native::shared_make_mut;
|
|
||||||
use crate::module::NamespaceRef;
|
use crate::module::NamespaceRef;
|
||||||
use crate::tokenizer::Token;
|
use crate::tokenizer::Token;
|
||||||
use crate::types::dynamic::Union;
|
use crate::types::dynamic::Union;
|
||||||
@ -187,10 +186,9 @@ pub struct AST {
|
|||||||
/// Global statements.
|
/// Global statements.
|
||||||
body: StmtBlock,
|
body: StmtBlock,
|
||||||
/// Script-defined functions.
|
/// Script-defined functions.
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
functions: Shared<Module>,
|
functions: Shared<Module>,
|
||||||
/// Embedded module resolver, if any.
|
/// Embedded module resolver, if any.
|
||||||
///
|
|
||||||
/// Not available under `no_module`.
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
resolver: Option<Shared<crate::module::resolvers::StaticModuleResolver>>,
|
resolver: Option<Shared<crate::module::resolvers::StaticModuleResolver>>,
|
||||||
}
|
}
|
||||||
@ -208,11 +206,12 @@ impl AST {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
statements: impl IntoIterator<Item = Stmt>,
|
statements: impl IntoIterator<Item = Stmt>,
|
||||||
functions: impl Into<Shared<Module>>,
|
#[cfg(not(feature = "no_function"))] functions: impl Into<Shared<Module>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
source: None,
|
source: None,
|
||||||
body: StmtBlock::new(statements, Position::NONE),
|
body: StmtBlock::new(statements, Position::NONE),
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
functions: functions.into(),
|
functions: functions.into(),
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
resolver: None,
|
resolver: None,
|
||||||
@ -225,6 +224,7 @@ impl AST {
|
|||||||
Self {
|
Self {
|
||||||
source: None,
|
source: None,
|
||||||
body: StmtBlock::NONE,
|
body: StmtBlock::NONE,
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
functions: Module::new().into(),
|
functions: Module::new().into(),
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
resolver: None,
|
resolver: None,
|
||||||
@ -235,12 +235,13 @@ impl AST {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new_with_source(
|
pub fn new_with_source(
|
||||||
statements: impl IntoIterator<Item = Stmt>,
|
statements: impl IntoIterator<Item = Stmt>,
|
||||||
functions: impl Into<Shared<Module>>,
|
#[cfg(not(feature = "no_function"))] functions: impl Into<Shared<Module>>,
|
||||||
source: impl Into<Identifier>,
|
source: impl Into<Identifier>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
source: Some(source.into()),
|
source: Some(source.into()),
|
||||||
body: StmtBlock::new(statements, Position::NONE),
|
body: StmtBlock::new(statements, Position::NONE),
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
functions: functions.into(),
|
functions: functions.into(),
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
resolver: None,
|
resolver: None,
|
||||||
@ -262,6 +263,7 @@ impl AST {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_source(&mut self, source: impl Into<Identifier>) -> &mut Self {
|
pub fn set_source(&mut self, source: impl Into<Identifier>) -> &mut Self {
|
||||||
let source = source.into();
|
let source = source.into();
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
Shared::get_mut(&mut self.functions)
|
Shared::get_mut(&mut self.functions)
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.map(|m| m.set_id(source.clone()));
|
.map(|m| m.set_id(source.clone()));
|
||||||
@ -296,9 +298,17 @@ impl AST {
|
|||||||
pub(crate) fn statements_mut(&mut self) -> &mut StaticVec<Stmt> {
|
pub(crate) fn statements_mut(&mut self) -> &mut StaticVec<Stmt> {
|
||||||
&mut self.body.0
|
&mut self.body.0
|
||||||
}
|
}
|
||||||
|
/// Does this [`AST`] contain script-defined functions?
|
||||||
|
///
|
||||||
|
/// Not available under `no_function`.
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn has_functions(&self) -> bool {
|
||||||
|
!self.functions.is_empty()
|
||||||
|
}
|
||||||
/// Get the internal shared [`Module`] containing all script-defined functions.
|
/// Get the internal shared [`Module`] containing all script-defined functions.
|
||||||
#[cfg(not(feature = "internals"))]
|
#[cfg(not(feature = "internals"))]
|
||||||
#[cfg(not(feature = "no_module"))]
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
@ -308,9 +318,8 @@ impl AST {
|
|||||||
/// _(internals)_ Get the internal shared [`Module`] containing all script-defined functions.
|
/// _(internals)_ Get the internal shared [`Module`] containing all script-defined functions.
|
||||||
/// Exported under the `internals` feature only.
|
/// Exported under the `internals` feature only.
|
||||||
///
|
///
|
||||||
/// Not available under `no_function` or `no_module`.
|
/// Not available under `no_function`.
|
||||||
#[cfg(feature = "internals")]
|
#[cfg(feature = "internals")]
|
||||||
#[cfg(not(feature = "no_module"))]
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
@ -318,25 +327,25 @@ impl AST {
|
|||||||
&self.functions
|
&self.functions
|
||||||
}
|
}
|
||||||
/// Get the embedded [module resolver][`ModuleResolver`].
|
/// Get the embedded [module resolver][`ModuleResolver`].
|
||||||
#[cfg(not(feature = "no_module"))]
|
|
||||||
#[cfg(not(feature = "internals"))]
|
#[cfg(not(feature = "internals"))]
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn resolver(
|
pub(crate) fn resolver(
|
||||||
&self,
|
&self,
|
||||||
) -> Option<Shared<crate::module::resolvers::StaticModuleResolver>> {
|
) -> Option<&Shared<crate::module::resolvers::StaticModuleResolver>> {
|
||||||
self.resolver.clone()
|
self.resolver.as_ref()
|
||||||
}
|
}
|
||||||
/// _(internals)_ Get the embedded [module resolver][crate::ModuleResolver].
|
/// _(internals)_ Get the embedded [module resolver][crate::ModuleResolver].
|
||||||
/// Exported under the `internals` feature only.
|
/// Exported under the `internals` feature only.
|
||||||
///
|
///
|
||||||
/// Not available under `no_module`.
|
/// Not available under `no_module`.
|
||||||
#[cfg(not(feature = "no_module"))]
|
|
||||||
#[cfg(feature = "internals")]
|
#[cfg(feature = "internals")]
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn resolver(&self) -> Option<Shared<crate::module::resolvers::StaticModuleResolver>> {
|
pub fn resolver(&self) -> Option<&Shared<crate::module::resolvers::StaticModuleResolver>> {
|
||||||
self.resolver.clone()
|
self.resolver.as_ref()
|
||||||
}
|
}
|
||||||
/// Set the embedded [module resolver][`ModuleResolver`].
|
/// Set the embedded [module resolver][`ModuleResolver`].
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
@ -391,6 +400,7 @@ impl AST {
|
|||||||
Self {
|
Self {
|
||||||
source: self.source.clone(),
|
source: self.source.clone(),
|
||||||
body: self.body.clone(),
|
body: self.body.clone(),
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
functions: Module::new().into(),
|
functions: Module::new().into(),
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
resolver: self.resolver.clone(),
|
resolver: self.resolver.clone(),
|
||||||
@ -448,7 +458,7 @@ impl AST {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn merge(&self, other: &Self) -> Self {
|
pub fn merge(&self, other: &Self) -> Self {
|
||||||
self.merge_filtered(other, |_, _, _, _, _| true)
|
self.merge_filtered_impl(other, |_, _, _, _, _| true)
|
||||||
}
|
}
|
||||||
/// Combine one [`AST`] with another. The second [`AST`] is consumed.
|
/// Combine one [`AST`] with another. The second [`AST`] is consumed.
|
||||||
///
|
///
|
||||||
@ -500,11 +510,13 @@ impl AST {
|
|||||||
/// ```
|
/// ```
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn combine(&mut self, other: Self) -> &mut Self {
|
pub fn combine(&mut self, other: Self) -> &mut Self {
|
||||||
self.combine_filtered(other, |_, _, _, _, _| true)
|
self.combine_filtered_impl(other, |_, _, _, _, _| true)
|
||||||
}
|
}
|
||||||
/// Merge two [`AST`] into one. Both [`AST`]'s are untouched and a new, merged, version
|
/// Merge two [`AST`] into one. Both [`AST`]'s are untouched and a new, merged, version
|
||||||
/// is returned.
|
/// is returned.
|
||||||
///
|
///
|
||||||
|
/// Not available under `no_function`.
|
||||||
|
///
|
||||||
/// Statements in the second [`AST`] are simply appended to the end of the first _without any processing_.
|
/// Statements in the second [`AST`] are simply appended to the end of the first _without any processing_.
|
||||||
/// Thus, the return value of the first [`AST`] (if using expression-statement syntax) is buried.
|
/// Thus, the return value of the first [`AST`] (if using expression-statement syntax) is buried.
|
||||||
/// Of course, if the first [`AST`] uses a `return` statement at the end, then
|
/// Of course, if the first [`AST`] uses a `return` statement at the end, then
|
||||||
@ -518,8 +530,6 @@ impl AST {
|
|||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
||||||
/// # #[cfg(not(feature = "no_function"))]
|
|
||||||
/// # {
|
|
||||||
/// use rhai::Engine;
|
/// use rhai::Engine;
|
||||||
///
|
///
|
||||||
/// let engine = Engine::new();
|
/// let engine = Engine::new();
|
||||||
@ -550,45 +560,67 @@ impl AST {
|
|||||||
///
|
///
|
||||||
/// // Evaluate it
|
/// // Evaluate it
|
||||||
/// assert_eq!(engine.eval_ast::<String>(&ast)?, "42!");
|
/// assert_eq!(engine.eval_ast::<String>(&ast)?, "42!");
|
||||||
/// # }
|
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn merge_filtered(
|
pub fn merge_filtered(
|
||||||
&self,
|
&self,
|
||||||
other: &Self,
|
other: &Self,
|
||||||
filter: impl Fn(FnNamespace, FnAccess, bool, &str, usize) -> bool,
|
filter: impl Fn(FnNamespace, FnAccess, bool, &str, usize) -> bool,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let Self {
|
self.merge_filtered_impl(other, filter)
|
||||||
body, functions, ..
|
}
|
||||||
} = self;
|
/// Merge two [`AST`] into one. Both [`AST`]'s are untouched and a new, merged, version
|
||||||
|
/// is returned.
|
||||||
let merged = match (body.is_empty(), other.body.is_empty()) {
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
fn merge_filtered_impl(
|
||||||
|
&self,
|
||||||
|
other: &Self,
|
||||||
|
_filter: impl Fn(FnNamespace, FnAccess, bool, &str, usize) -> bool,
|
||||||
|
) -> Self {
|
||||||
|
let merged = match (self.body.is_empty(), other.body.is_empty()) {
|
||||||
(false, false) => {
|
(false, false) => {
|
||||||
let mut body = body.clone();
|
let mut body = self.body.clone();
|
||||||
body.0.extend(other.body.0.iter().cloned());
|
body.0.extend(other.body.0.iter().cloned());
|
||||||
body
|
body
|
||||||
}
|
}
|
||||||
(false, true) => body.clone(),
|
(false, true) => self.body.clone(),
|
||||||
(true, false) => other.body.clone(),
|
(true, false) => other.body.clone(),
|
||||||
(true, true) => StmtBlock::NONE,
|
(true, true) => StmtBlock::NONE,
|
||||||
};
|
};
|
||||||
|
|
||||||
let source = other.source.clone().or_else(|| self.source.clone());
|
let source = other.source.clone().or_else(|| self.source.clone());
|
||||||
|
|
||||||
let mut functions = functions.as_ref().clone();
|
#[cfg(not(feature = "no_function"))]
|
||||||
functions.merge_filtered(&other.functions, &filter);
|
let functions = {
|
||||||
|
let mut functions = self.functions.as_ref().clone();
|
||||||
|
functions.merge_filtered(&other.functions, &_filter);
|
||||||
|
functions
|
||||||
|
};
|
||||||
|
|
||||||
if let Some(source) = source {
|
if let Some(source) = source {
|
||||||
Self::new_with_source(merged.0, functions, source)
|
Self::new_with_source(
|
||||||
|
merged.0,
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
functions,
|
||||||
|
source,
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
Self::new(merged.0, functions)
|
Self::new(
|
||||||
|
merged.0,
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
functions,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Combine one [`AST`] with another. The second [`AST`] is consumed.
|
/// Combine one [`AST`] with another. The second [`AST`] is consumed.
|
||||||
///
|
///
|
||||||
|
/// Not available under `no_function`.
|
||||||
|
///
|
||||||
/// Statements in the second [`AST`] are simply appended to the end of the first _without any processing_.
|
/// Statements in the second [`AST`] are simply appended to the end of the first _without any processing_.
|
||||||
/// Thus, the return value of the first [`AST`] (if using expression-statement syntax) is buried.
|
/// Thus, the return value of the first [`AST`] (if using expression-statement syntax) is buried.
|
||||||
/// Of course, if the first [`AST`] uses a `return` statement at the end, then
|
/// Of course, if the first [`AST`] uses a `return` statement at the end, then
|
||||||
@ -602,8 +634,6 @@ impl AST {
|
|||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
||||||
/// # #[cfg(not(feature = "no_function"))]
|
|
||||||
/// # {
|
|
||||||
/// use rhai::Engine;
|
/// use rhai::Engine;
|
||||||
///
|
///
|
||||||
/// let engine = Engine::new();
|
/// let engine = Engine::new();
|
||||||
@ -634,20 +664,31 @@ impl AST {
|
|||||||
///
|
///
|
||||||
/// // Evaluate it
|
/// // Evaluate it
|
||||||
/// assert_eq!(engine.eval_ast::<String>(&ast1)?, "42!");
|
/// assert_eq!(engine.eval_ast::<String>(&ast1)?, "42!");
|
||||||
/// # }
|
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
#[inline(always)]
|
||||||
pub fn combine_filtered(
|
pub fn combine_filtered(
|
||||||
&mut self,
|
&mut self,
|
||||||
other: Self,
|
other: Self,
|
||||||
filter: impl Fn(FnNamespace, FnAccess, bool, &str, usize) -> bool,
|
filter: impl Fn(FnNamespace, FnAccess, bool, &str, usize) -> bool,
|
||||||
|
) -> &mut Self {
|
||||||
|
self.combine_filtered_impl(other, filter)
|
||||||
|
}
|
||||||
|
/// Combine one [`AST`] with another. The second [`AST`] is consumed.
|
||||||
|
#[inline]
|
||||||
|
fn combine_filtered_impl(
|
||||||
|
&mut self,
|
||||||
|
other: Self,
|
||||||
|
_filter: impl Fn(FnNamespace, FnAccess, bool, &str, usize) -> bool,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
self.body.0.extend(other.body.0.into_iter());
|
self.body.0.extend(other.body.0.into_iter());
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
if !other.functions.is_empty() {
|
if !other.functions.is_empty() {
|
||||||
shared_make_mut(&mut self.functions).merge_filtered(&other.functions, &filter);
|
crate::func::native::shared_make_mut(&mut self.functions)
|
||||||
|
.merge_filtered(&other.functions, &_filter);
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -683,7 +724,8 @@ impl AST {
|
|||||||
filter: impl Fn(FnNamespace, FnAccess, &str, usize) -> bool,
|
filter: impl Fn(FnNamespace, FnAccess, &str, usize) -> bool,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
if !self.functions.is_empty() {
|
if !self.functions.is_empty() {
|
||||||
shared_make_mut(&mut self.functions).retain_script_functions(filter);
|
crate::func::native::shared_make_mut(&mut self.functions)
|
||||||
|
.retain_script_functions(filter);
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -875,6 +917,7 @@ impl AsRef<[Stmt]> for AST {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
impl AsRef<Module> for AST {
|
impl AsRef<Module> for AST {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn as_ref(&self) -> &Module {
|
fn as_ref(&self) -> &Module {
|
||||||
@ -882,6 +925,7 @@ impl AsRef<Module> for AST {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
impl AsRef<Shared<Module>> for AST {
|
impl AsRef<Shared<Module>> for AST {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn as_ref(&self) -> &Shared<Module> {
|
fn as_ref(&self) -> &Shared<Module> {
|
||||||
@ -2456,6 +2500,7 @@ impl AST {
|
|||||||
/// This method will be removed in the next major version.
|
/// This method will be removed in the next major version.
|
||||||
#[deprecated(since = "1.3.0", note = "use `shared_lib` instead")]
|
#[deprecated(since = "1.3.0", note = "use `shared_lib` instead")]
|
||||||
#[cfg(feature = "internals")]
|
#[cfg(feature = "internals")]
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn lib(&self) -> &crate::Module {
|
pub fn lib(&self) -> &crate::Module {
|
||||||
|
@ -13,7 +13,7 @@ use crate::tokenizer::Token;
|
|||||||
use crate::{
|
use crate::{
|
||||||
ast::{Expr, Stmt},
|
ast::{Expr, Stmt},
|
||||||
calc_fn_hash, calc_fn_params_hash, combine_hashes, Dynamic, Engine, EvalAltResult, FnPtr,
|
calc_fn_hash, calc_fn_params_hash, combine_hashes, Dynamic, Engine, EvalAltResult, FnPtr,
|
||||||
Identifier, ImmutableString, Module, ParseErrorType, Position, RhaiResult, Scope, StaticVec,
|
Identifier, ImmutableString, Module, Position, RhaiResult, Scope, StaticVec,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
@ -554,14 +554,14 @@ impl Engine {
|
|||||||
let mut lib_merged = StaticVec::with_capacity(lib.len() + 1);
|
let mut lib_merged = StaticVec::with_capacity(lib.len() + 1);
|
||||||
let orig_fn_resolution_caches_len = state.fn_resolution_caches_len();
|
let orig_fn_resolution_caches_len = state.fn_resolution_caches_len();
|
||||||
|
|
||||||
let lib = if let Some(ref env_lib) = fn_def.lib {
|
let lib = if let Some(ref fn_lib) = fn_def.lib {
|
||||||
if env_lib.is_empty() {
|
if fn_lib.is_empty() {
|
||||||
lib
|
lib
|
||||||
} else {
|
} else {
|
||||||
state.push_fn_resolution_cache();
|
state.push_fn_resolution_cache();
|
||||||
lib_merged.push(env_lib.as_ref());
|
lib_merged.push(fn_lib.as_ref());
|
||||||
lib_merged.extend(lib.iter().cloned());
|
lib_merged.extend(lib.iter().cloned());
|
||||||
lib_merged.as_ref()
|
&lib_merged
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
lib
|
lib
|
||||||
@ -886,8 +886,9 @@ impl Engine {
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
// If new functions are defined within the eval string, it is an error
|
// If new functions are defined within the eval string, it is an error
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
if !ast.shared_lib().is_empty() {
|
if !ast.shared_lib().is_empty() {
|
||||||
return Err(ParseErrorType::WrongFnDefinition.into());
|
return Err(crate::ParseErrorType::WrongFnDefinition.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let statements = ast.statements();
|
let statements = ast.statements();
|
||||||
|
@ -1460,7 +1460,7 @@ impl Module {
|
|||||||
|
|
||||||
// Non-private functions defined become module functions
|
// Non-private functions defined become module functions
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
if !ast.shared_lib().functions.is_empty() {
|
if ast.has_functions() {
|
||||||
ast.shared_lib()
|
ast.shared_lib()
|
||||||
.functions
|
.functions
|
||||||
.values()
|
.values()
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
//! Module implementing the [`AST`] optimizer.
|
//! Module implementing the [`AST`] optimizer.
|
||||||
#![cfg(not(feature = "no_optimize"))]
|
#![cfg(not(feature = "no_optimize"))]
|
||||||
|
|
||||||
use crate::ast::{Expr, OpAssignment, ScriptFnDef, Stmt, AST_OPTION_FLAGS::*};
|
use crate::ast::{Expr, OpAssignment, Stmt, AST_OPTION_FLAGS::*};
|
||||||
use crate::engine::{
|
use crate::engine::{
|
||||||
EvalState, Imports, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_PRINT, KEYWORD_TYPE_OF,
|
EvalState, Imports, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_PRINT, KEYWORD_TYPE_OF,
|
||||||
};
|
};
|
||||||
@ -11,7 +11,7 @@ use crate::tokenizer::Token;
|
|||||||
use crate::types::dynamic::AccessMode;
|
use crate::types::dynamic::AccessMode;
|
||||||
use crate::{
|
use crate::{
|
||||||
calc_fn_hash, calc_fn_params_hash, combine_hashes, Dynamic, Engine, FnPtr, ImmutableString,
|
calc_fn_hash, calc_fn_params_hash, combine_hashes, Dynamic, Engine, FnPtr, ImmutableString,
|
||||||
Module, Position, Scope, Shared, StaticVec, AST,
|
Position, Scope, StaticVec, AST,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
@ -59,8 +59,9 @@ struct OptimizerState<'a> {
|
|||||||
propagate_constants: bool,
|
propagate_constants: bool,
|
||||||
/// An [`Engine`] instance for eager function evaluation.
|
/// An [`Engine`] instance for eager function evaluation.
|
||||||
engine: &'a Engine,
|
engine: &'a Engine,
|
||||||
/// [Module] containing script-defined functions.
|
/// [Module][crate::Module] containing script-defined functions.
|
||||||
lib: &'a [&'a Module],
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
lib: &'a [&'a crate::Module],
|
||||||
/// Optimization level.
|
/// Optimization level.
|
||||||
optimization_level: OptimizationLevel,
|
optimization_level: OptimizationLevel,
|
||||||
}
|
}
|
||||||
@ -70,7 +71,7 @@ impl<'a> OptimizerState<'a> {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub const fn new(
|
pub const fn new(
|
||||||
engine: &'a Engine,
|
engine: &'a Engine,
|
||||||
lib: &'a [&'a Module],
|
#[cfg(not(feature = "no_function"))] lib: &'a [&'a crate::Module],
|
||||||
optimization_level: OptimizationLevel,
|
optimization_level: OptimizationLevel,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -78,6 +79,7 @@ impl<'a> OptimizerState<'a> {
|
|||||||
variables: StaticVec::new_const(),
|
variables: StaticVec::new_const(),
|
||||||
propagate_constants: true,
|
propagate_constants: true,
|
||||||
engine,
|
engine,
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
lib,
|
lib,
|
||||||
optimization_level,
|
optimization_level,
|
||||||
}
|
}
|
||||||
@ -139,11 +141,16 @@ impl<'a> OptimizerState<'a> {
|
|||||||
fn_name: impl AsRef<str>,
|
fn_name: impl AsRef<str>,
|
||||||
arg_values: &mut [Dynamic],
|
arg_values: &mut [Dynamic],
|
||||||
) -> Option<Dynamic> {
|
) -> Option<Dynamic> {
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
let lib = self.lib;
|
||||||
|
#[cfg(feature = "no_function")]
|
||||||
|
let lib = &[];
|
||||||
|
|
||||||
self.engine
|
self.engine
|
||||||
.call_native_fn(
|
.call_native_fn(
|
||||||
&mut Imports::new(),
|
&mut Imports::new(),
|
||||||
&mut EvalState::new(),
|
&mut EvalState::new(),
|
||||||
self.lib,
|
lib,
|
||||||
&fn_name,
|
&fn_name,
|
||||||
calc_fn_hash(&fn_name, arg_values.len()),
|
calc_fn_hash(&fn_name, arg_values.len()),
|
||||||
&mut arg_values.iter_mut().collect::<StaticVec<_>>(),
|
&mut arg_values.iter_mut().collect::<StaticVec<_>>(),
|
||||||
@ -992,7 +999,12 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) {
|
|||||||
_ if x.args.len() == 2 && !state.has_native_fn_override(x.hashes.native, arg_types.as_ref()) => {
|
_ if x.args.len() == 2 && !state.has_native_fn_override(x.hashes.native, arg_types.as_ref()) => {
|
||||||
if let Some(result) = get_builtin_binary_op_fn(x.name.as_ref(), &arg_values[0], &arg_values[1])
|
if let Some(result) = get_builtin_binary_op_fn(x.name.as_ref(), &arg_values[0], &arg_values[1])
|
||||||
.and_then(|f| {
|
.and_then(|f| {
|
||||||
let context = (state.engine, x.name.as_str(), state.lib).into();
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
let lib = state.lib;
|
||||||
|
#[cfg(feature = "no_function")]
|
||||||
|
let lib = &[];
|
||||||
|
|
||||||
|
let context = (state.engine, x.name.as_str(), lib).into();
|
||||||
let (first, second) = arg_values.split_first_mut().expect("not empty");
|
let (first, second) = arg_values.split_first_mut().expect("not empty");
|
||||||
(f)(context, &mut [ first, &mut second[0] ]).ok()
|
(f)(context, &mut [ first, &mut second[0] ]).ok()
|
||||||
}) {
|
}) {
|
||||||
@ -1091,7 +1103,7 @@ fn optimize_top_level(
|
|||||||
statements: StaticVec<Stmt>,
|
statements: StaticVec<Stmt>,
|
||||||
engine: &Engine,
|
engine: &Engine,
|
||||||
scope: &Scope,
|
scope: &Scope,
|
||||||
lib: &[&Module],
|
#[cfg(not(feature = "no_function"))] lib: &[&crate::Module],
|
||||||
optimization_level: OptimizationLevel,
|
optimization_level: OptimizationLevel,
|
||||||
) -> StaticVec<Stmt> {
|
) -> StaticVec<Stmt> {
|
||||||
let mut statements = statements;
|
let mut statements = statements;
|
||||||
@ -1103,7 +1115,12 @@ fn optimize_top_level(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set up the state
|
// Set up the state
|
||||||
let mut state = OptimizerState::new(engine, lib, optimization_level);
|
let mut state = OptimizerState::new(
|
||||||
|
engine,
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
lib,
|
||||||
|
optimization_level,
|
||||||
|
);
|
||||||
|
|
||||||
// Add constants and variables from the scope
|
// Add constants and variables from the scope
|
||||||
scope.iter().for_each(|(name, constant, value)| {
|
scope.iter().for_each(|(name, constant, value)| {
|
||||||
@ -1123,7 +1140,9 @@ pub fn optimize_into_ast(
|
|||||||
engine: &Engine,
|
engine: &Engine,
|
||||||
scope: &Scope,
|
scope: &Scope,
|
||||||
statements: StaticVec<Stmt>,
|
statements: StaticVec<Stmt>,
|
||||||
functions: StaticVec<Shared<ScriptFnDef>>,
|
#[cfg(not(feature = "no_function"))] functions: StaticVec<
|
||||||
|
crate::Shared<crate::ast::ScriptFnDef>,
|
||||||
|
>,
|
||||||
optimization_level: OptimizationLevel,
|
optimization_level: OptimizationLevel,
|
||||||
) -> AST {
|
) -> AST {
|
||||||
let level = if cfg!(feature = "no_optimize") {
|
let level = if cfg!(feature = "no_optimize") {
|
||||||
@ -1133,19 +1152,18 @@ pub fn optimize_into_ast(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut statements = statements;
|
let mut statements = statements;
|
||||||
let _functions = functions;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
let lib = {
|
let lib = {
|
||||||
let mut module = Module::new();
|
let mut module = crate::Module::new();
|
||||||
|
|
||||||
if level != OptimizationLevel::None {
|
if level != OptimizationLevel::None {
|
||||||
// We only need the script library's signatures for optimization purposes
|
// We only need the script library's signatures for optimization purposes
|
||||||
let mut lib2 = Module::new();
|
let mut lib2 = crate::Module::new();
|
||||||
|
|
||||||
_functions
|
functions
|
||||||
.iter()
|
.iter()
|
||||||
.map(|fn_def| ScriptFnDef {
|
.map(|fn_def| crate::ast::ScriptFnDef {
|
||||||
name: fn_def.name.clone(),
|
name: fn_def.name.clone(),
|
||||||
access: fn_def.access,
|
access: fn_def.access,
|
||||||
body: crate::ast::StmtBlock::NONE,
|
body: crate::ast::StmtBlock::NONE,
|
||||||
@ -1163,7 +1181,7 @@ pub fn optimize_into_ast(
|
|||||||
|
|
||||||
let lib2 = &[&lib2];
|
let lib2 = &[&lib2];
|
||||||
|
|
||||||
_functions
|
functions
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|fn_def| {
|
.map(|fn_def| {
|
||||||
let mut fn_def = crate::func::native::shared_take_or_clone(fn_def);
|
let mut fn_def = crate::func::native::shared_take_or_clone(fn_def);
|
||||||
@ -1179,7 +1197,7 @@ pub fn optimize_into_ast(
|
|||||||
module.set_script_fn(fn_def);
|
module.set_script_fn(fn_def);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
_functions.into_iter().for_each(|fn_def| {
|
functions.into_iter().for_each(|fn_def| {
|
||||||
module.set_script_fn(fn_def);
|
module.set_script_fn(fn_def);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1187,18 +1205,21 @@ pub fn optimize_into_ast(
|
|||||||
module
|
module
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "no_function")]
|
|
||||||
let lib = Module::new();
|
|
||||||
|
|
||||||
statements.shrink_to_fit();
|
statements.shrink_to_fit();
|
||||||
|
|
||||||
AST::new(
|
AST::new(
|
||||||
match level {
|
match level {
|
||||||
OptimizationLevel::None => statements,
|
OptimizationLevel::None => statements,
|
||||||
OptimizationLevel::Simple | OptimizationLevel::Full => {
|
OptimizationLevel::Simple | OptimizationLevel::Full => optimize_top_level(
|
||||||
optimize_top_level(statements, engine, &scope, &[&lib], level)
|
statements,
|
||||||
}
|
engine,
|
||||||
|
&scope,
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
&[&lib],
|
||||||
|
level,
|
||||||
|
),
|
||||||
},
|
},
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
lib,
|
lib,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -90,7 +90,7 @@ fn collect_fn_metadata(ctx: NativeCallContext) -> crate::Array {
|
|||||||
.map(|&s| s.into())
|
.map(|&s| s.into())
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let mut list = ctx.iter_namespaces().flat_map(Module::iter_script_fn).fold(
|
let mut _list = ctx.iter_namespaces().flat_map(Module::iter_script_fn).fold(
|
||||||
Array::new(),
|
Array::new(),
|
||||||
|mut list, (_, _, _, _, f)| {
|
|mut list, (_, _, _, _, f)| {
|
||||||
list.push(make_metadata(&dict, None, f).into());
|
list.push(make_metadata(&dict, None, f).into());
|
||||||
@ -122,8 +122,8 @@ fn collect_fn_metadata(ctx: NativeCallContext) -> crate::Array {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ctx.iter_imports_raw()
|
ctx.iter_imports_raw()
|
||||||
.for_each(|(ns, m)| scan_module(&mut list, &dict, ns.clone(), m.as_ref()));
|
.for_each(|(ns, m)| scan_module(&mut _list, &dict, ns.clone(), m.as_ref()));
|
||||||
}
|
}
|
||||||
|
|
||||||
list
|
_list
|
||||||
}
|
}
|
||||||
|
@ -3264,6 +3264,7 @@ impl Engine {
|
|||||||
self,
|
self,
|
||||||
_scope,
|
_scope,
|
||||||
statements,
|
statements,
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
StaticVec::new_const(),
|
StaticVec::new_const(),
|
||||||
optimization_level,
|
optimization_level,
|
||||||
));
|
));
|
||||||
@ -3351,6 +3352,7 @@ impl Engine {
|
|||||||
self,
|
self,
|
||||||
_scope,
|
_scope,
|
||||||
statements,
|
statements,
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
_lib,
|
_lib,
|
||||||
optimization_level,
|
optimization_level,
|
||||||
));
|
));
|
||||||
|
@ -764,6 +764,9 @@ impl Token {
|
|||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
"private" => Private,
|
"private" => Private,
|
||||||
|
|
||||||
|
#[cfg(feature = "no_function")]
|
||||||
|
"fn" | "private" => Reserved(syntax.into()),
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
"import" => Import,
|
"import" => Import,
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
@ -771,9 +774,6 @@ impl Token {
|
|||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
"as" => As,
|
"as" => As,
|
||||||
|
|
||||||
#[cfg(feature = "no_function")]
|
|
||||||
"fn" | "private" => Reserved(syntax.into()),
|
|
||||||
|
|
||||||
#[cfg(feature = "no_module")]
|
#[cfg(feature = "no_module")]
|
||||||
"import" | "export" | "as" => Reserved(syntax.into()),
|
"import" | "export" | "as" => Reserved(syntax.into()),
|
||||||
|
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
use crate::tokenizer::is_valid_identifier;
|
use crate::tokenizer::is_valid_identifier;
|
||||||
use crate::types::dynamic::Variant;
|
use crate::types::dynamic::Variant;
|
||||||
use crate::{
|
use crate::{
|
||||||
Dynamic, Engine, EvalAltResult, FuncArgs, Identifier, NativeCallContext, Position, RhaiResult,
|
Dynamic, Engine, EvalAltResult, FuncArgs, Identifier, Module, NativeCallContext, Position,
|
||||||
StaticVec, AST,
|
RhaiResult, StaticVec, AST,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
@ -137,12 +137,21 @@ impl FnPtr {
|
|||||||
ast: &AST,
|
ast: &AST,
|
||||||
args: impl FuncArgs,
|
args: impl FuncArgs,
|
||||||
) -> Result<T, Box<EvalAltResult>> {
|
) -> Result<T, Box<EvalAltResult>> {
|
||||||
|
let _ast = ast;
|
||||||
let mut arg_values = crate::StaticVec::new_const();
|
let mut arg_values = crate::StaticVec::new_const();
|
||||||
args.parse(&mut arg_values);
|
args.parse(&mut arg_values);
|
||||||
|
|
||||||
let lib = [ast.as_ref()];
|
let lib = [
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
_ast.as_ref(),
|
||||||
|
];
|
||||||
|
let lib = if lib.first().map(|m: &&Module| m.is_empty()).unwrap_or(true) {
|
||||||
|
&lib[0..0]
|
||||||
|
} else {
|
||||||
|
&lib
|
||||||
|
};
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
let ctx = NativeCallContext::new(engine, self.fn_name(), &lib);
|
let ctx = NativeCallContext::new(engine, self.fn_name(), lib);
|
||||||
|
|
||||||
let result = self.call_dynamic(&ctx, None, arg_values)?;
|
let result = self.call_dynamic(&ctx, None, arg_values)?;
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#![cfg(not(feature = "no_function"))]
|
#![cfg(not(feature = "no_function"))]
|
||||||
use rhai::{Engine, EvalAltResult, FnPtr, NativeCallContext, ParseErrorType, Scope, INT};
|
use rhai::{Engine, EvalAltResult, FnPtr, ParseErrorType, Scope, INT};
|
||||||
use std::any::TypeId;
|
use std::any::TypeId;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::mem::take;
|
use std::mem::take;
|
||||||
@ -318,30 +318,18 @@ fn test_closures_shared_obj() -> Result<(), Box<EvalAltResult>> {
|
|||||||
fn test_closures_external() -> Result<(), Box<EvalAltResult>> {
|
fn test_closures_external() -> Result<(), Box<EvalAltResult>> {
|
||||||
let engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
let mut ast = engine.compile(
|
let ast = engine.compile(
|
||||||
r#"
|
r#"
|
||||||
let test = "hello";
|
let test = "hello";
|
||||||
|x| test + x
|
|x| test + x
|
||||||
"#,
|
"#,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Save the function pointer together with captured variables
|
|
||||||
let fn_ptr = engine.eval_ast::<FnPtr>(&ast)?;
|
let fn_ptr = engine.eval_ast::<FnPtr>(&ast)?;
|
||||||
|
|
||||||
// Get rid of the script, retaining only functions
|
let f = move |x: INT| -> String { fn_ptr.call(&engine, &ast, (x,)).unwrap() };
|
||||||
ast.retain_functions(|_, _, _, _| true);
|
|
||||||
|
|
||||||
// Create function namespace from the 'AST'
|
assert_eq!(f(42), "hello42");
|
||||||
let lib = [ast.as_ref()];
|
|
||||||
|
|
||||||
// Create native call context
|
|
||||||
let fn_name = fn_ptr.fn_name().to_string();
|
|
||||||
let context = NativeCallContext::new(&engine, &fn_name, &lib);
|
|
||||||
|
|
||||||
// Closure 'f' captures: the engine, the AST, and the curried function pointer
|
|
||||||
let f = move |x: INT| fn_ptr.call_dynamic(&context, None, [x.into()]);
|
|
||||||
|
|
||||||
assert_eq!(f(42)?.into_string(), Ok("hello42".to_string()));
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -69,6 +69,7 @@ fn test_optimizer_run() -> Result<(), Box<EvalAltResult>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
#[cfg(not(feature = "no_position"))]
|
#[cfg(not(feature = "no_position"))]
|
||||||
#[test]
|
#[test]
|
||||||
fn test_optimizer_parse() -> Result<(), Box<EvalAltResult>> {
|
fn test_optimizer_parse() -> Result<(), Box<EvalAltResult>> {
|
||||||
|
Loading…
Reference in New Issue
Block a user