Remove fields and parameters under no_function.
This commit is contained in:
parent
a3e79c0bd0
commit
95dc2ad502
@ -18,9 +18,8 @@ Enhancements
|
||||
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`.
|
||||
* `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
|
||||
|
@ -3,7 +3,7 @@
|
||||
use crate::engine::{EvalState, Imports};
|
||||
use crate::parser::ParseState;
|
||||
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;
|
||||
#[cfg(feature = "no_std")]
|
||||
use std::prelude::v1::*;
|
||||
@ -217,7 +217,7 @@ impl Engine {
|
||||
}
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
{
|
||||
mods.embedded_module_resolver = ast.resolver();
|
||||
mods.embedded_module_resolver = ast.resolver().cloned();
|
||||
}
|
||||
|
||||
let statements = ast.statements();
|
||||
@ -226,7 +226,15 @@ impl Engine {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -86,12 +86,16 @@ impl Engine {
|
||||
})
|
||||
.collect();
|
||||
|
||||
#[cfg(feature = "no_function")]
|
||||
let lib = crate::StaticVec::new_const();
|
||||
|
||||
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::parser::ParseState;
|
||||
use crate::{Engine, EvalAltResult, Scope, AST};
|
||||
use crate::{Engine, EvalAltResult, Module, Scope, AST};
|
||||
#[cfg(feature = "no_std")]
|
||||
use std::prelude::v1::*;
|
||||
|
||||
@ -59,12 +59,20 @@ impl Engine {
|
||||
}
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
{
|
||||
mods.embedded_module_resolver = ast.resolver();
|
||||
mods.embedded_module_resolver = ast.resolver().cloned();
|
||||
}
|
||||
|
||||
let statements = ast.statements();
|
||||
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)?;
|
||||
}
|
||||
Ok(())
|
||||
|
119
src/ast.rs
119
src/ast.rs
@ -1,7 +1,6 @@
|
||||
//! Module defining the AST (abstract syntax tree).
|
||||
|
||||
use crate::calc_fn_hash;
|
||||
use crate::func::native::shared_make_mut;
|
||||
use crate::module::NamespaceRef;
|
||||
use crate::tokenizer::Token;
|
||||
use crate::types::dynamic::Union;
|
||||
@ -187,10 +186,9 @@ pub struct AST {
|
||||
/// Global statements.
|
||||
body: StmtBlock,
|
||||
/// Script-defined functions.
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
functions: Shared<Module>,
|
||||
/// Embedded module resolver, if any.
|
||||
///
|
||||
/// Not available under `no_module`.
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
resolver: Option<Shared<crate::module::resolvers::StaticModuleResolver>>,
|
||||
}
|
||||
@ -208,11 +206,12 @@ impl AST {
|
||||
#[must_use]
|
||||
pub fn new(
|
||||
statements: impl IntoIterator<Item = Stmt>,
|
||||
functions: impl Into<Shared<Module>>,
|
||||
#[cfg(not(feature = "no_function"))] functions: impl Into<Shared<Module>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
source: None,
|
||||
body: StmtBlock::new(statements, Position::NONE),
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
functions: functions.into(),
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
resolver: None,
|
||||
@ -225,6 +224,7 @@ impl AST {
|
||||
Self {
|
||||
source: None,
|
||||
body: StmtBlock::NONE,
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
functions: Module::new().into(),
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
resolver: None,
|
||||
@ -235,12 +235,13 @@ impl AST {
|
||||
#[must_use]
|
||||
pub fn new_with_source(
|
||||
statements: impl IntoIterator<Item = Stmt>,
|
||||
functions: impl Into<Shared<Module>>,
|
||||
#[cfg(not(feature = "no_function"))] functions: impl Into<Shared<Module>>,
|
||||
source: impl Into<Identifier>,
|
||||
) -> Self {
|
||||
Self {
|
||||
source: Some(source.into()),
|
||||
body: StmtBlock::new(statements, Position::NONE),
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
functions: functions.into(),
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
resolver: None,
|
||||
@ -262,6 +263,7 @@ impl AST {
|
||||
#[inline]
|
||||
pub fn set_source(&mut self, source: impl Into<Identifier>) -> &mut Self {
|
||||
let source = source.into();
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
Shared::get_mut(&mut self.functions)
|
||||
.as_mut()
|
||||
.map(|m| m.set_id(source.clone()));
|
||||
@ -296,9 +298,17 @@ impl AST {
|
||||
pub(crate) fn statements_mut(&mut self) -> &mut StaticVec<Stmt> {
|
||||
&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.
|
||||
#[cfg(not(feature = "internals"))]
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
@ -308,9 +318,8 @@ impl AST {
|
||||
/// _(internals)_ Get the internal shared [`Module`] containing all script-defined functions.
|
||||
/// Exported under the `internals` feature only.
|
||||
///
|
||||
/// Not available under `no_function` or `no_module`.
|
||||
/// Not available under `no_function`.
|
||||
#[cfg(feature = "internals")]
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
@ -318,25 +327,25 @@ impl AST {
|
||||
&self.functions
|
||||
}
|
||||
/// Get the embedded [module resolver][`ModuleResolver`].
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
#[cfg(not(feature = "internals"))]
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub(crate) fn resolver(
|
||||
&self,
|
||||
) -> Option<Shared<crate::module::resolvers::StaticModuleResolver>> {
|
||||
self.resolver.clone()
|
||||
) -> Option<&Shared<crate::module::resolvers::StaticModuleResolver>> {
|
||||
self.resolver.as_ref()
|
||||
}
|
||||
/// _(internals)_ Get the embedded [module resolver][crate::ModuleResolver].
|
||||
/// Exported under the `internals` feature only.
|
||||
///
|
||||
/// Not available under `no_module`.
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
#[cfg(feature = "internals")]
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub fn resolver(&self) -> Option<Shared<crate::module::resolvers::StaticModuleResolver>> {
|
||||
self.resolver.clone()
|
||||
pub fn resolver(&self) -> Option<&Shared<crate::module::resolvers::StaticModuleResolver>> {
|
||||
self.resolver.as_ref()
|
||||
}
|
||||
/// Set the embedded [module resolver][`ModuleResolver`].
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
@ -391,6 +400,7 @@ impl AST {
|
||||
Self {
|
||||
source: self.source.clone(),
|
||||
body: self.body.clone(),
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
functions: Module::new().into(),
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
resolver: self.resolver.clone(),
|
||||
@ -448,7 +458,7 @@ impl AST {
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
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.
|
||||
///
|
||||
@ -500,11 +510,13 @@ impl AST {
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
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
|
||||
/// is returned.
|
||||
///
|
||||
/// Not available under `no_function`.
|
||||
///
|
||||
/// 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.
|
||||
/// 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>> {
|
||||
/// # #[cfg(not(feature = "no_function"))]
|
||||
/// # {
|
||||
/// use rhai::Engine;
|
||||
///
|
||||
/// let engine = Engine::new();
|
||||
@ -550,45 +560,67 @@ impl AST {
|
||||
///
|
||||
/// // Evaluate it
|
||||
/// assert_eq!(engine.eval_ast::<String>(&ast)?, "42!");
|
||||
/// # }
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[inline]
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub fn merge_filtered(
|
||||
&self,
|
||||
other: &Self,
|
||||
filter: impl Fn(FnNamespace, FnAccess, bool, &str, usize) -> bool,
|
||||
) -> Self {
|
||||
let Self {
|
||||
body, functions, ..
|
||||
} = self;
|
||||
|
||||
let merged = match (body.is_empty(), other.body.is_empty()) {
|
||||
self.merge_filtered_impl(other, filter)
|
||||
}
|
||||
/// Merge two [`AST`] into one. Both [`AST`]'s are untouched and a new, merged, version
|
||||
/// is returned.
|
||||
#[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) => {
|
||||
let mut body = body.clone();
|
||||
let mut body = self.body.clone();
|
||||
body.0.extend(other.body.0.iter().cloned());
|
||||
body
|
||||
}
|
||||
(false, true) => body.clone(),
|
||||
(false, true) => self.body.clone(),
|
||||
(true, false) => other.body.clone(),
|
||||
(true, true) => StmtBlock::NONE,
|
||||
};
|
||||
|
||||
let source = other.source.clone().or_else(|| self.source.clone());
|
||||
|
||||
let mut functions = functions.as_ref().clone();
|
||||
functions.merge_filtered(&other.functions, &filter);
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
let functions = {
|
||||
let mut functions = self.functions.as_ref().clone();
|
||||
functions.merge_filtered(&other.functions, &_filter);
|
||||
functions
|
||||
};
|
||||
|
||||
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 {
|
||||
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.
|
||||
///
|
||||
/// Not available under `no_function`.
|
||||
///
|
||||
/// 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.
|
||||
/// 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>> {
|
||||
/// # #[cfg(not(feature = "no_function"))]
|
||||
/// # {
|
||||
/// use rhai::Engine;
|
||||
///
|
||||
/// let engine = Engine::new();
|
||||
@ -634,20 +664,31 @@ impl AST {
|
||||
///
|
||||
/// // Evaluate it
|
||||
/// assert_eq!(engine.eval_ast::<String>(&ast1)?, "42!");
|
||||
/// # }
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[inline]
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
#[inline(always)]
|
||||
pub fn combine_filtered(
|
||||
&mut self,
|
||||
other: Self,
|
||||
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 {
|
||||
self.body.0.extend(other.body.0.into_iter());
|
||||
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
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
|
||||
}
|
||||
@ -683,7 +724,8 @@ impl AST {
|
||||
filter: impl Fn(FnNamespace, FnAccess, &str, usize) -> bool,
|
||||
) -> &mut Self {
|
||||
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
|
||||
}
|
||||
@ -875,6 +917,7 @@ impl AsRef<[Stmt]> for AST {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
impl AsRef<Module> for AST {
|
||||
#[inline(always)]
|
||||
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 {
|
||||
#[inline(always)]
|
||||
fn as_ref(&self) -> &Shared<Module> {
|
||||
@ -2456,6 +2500,7 @@ impl AST {
|
||||
/// This method will be removed in the next major version.
|
||||
#[deprecated(since = "1.3.0", note = "use `shared_lib` instead")]
|
||||
#[cfg(feature = "internals")]
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub fn lib(&self) -> &crate::Module {
|
||||
|
@ -13,7 +13,7 @@ use crate::tokenizer::Token;
|
||||
use crate::{
|
||||
ast::{Expr, Stmt},
|
||||
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")]
|
||||
use std::prelude::v1::*;
|
||||
@ -554,14 +554,14 @@ impl Engine {
|
||||
let mut lib_merged = StaticVec::with_capacity(lib.len() + 1);
|
||||
let orig_fn_resolution_caches_len = state.fn_resolution_caches_len();
|
||||
|
||||
let lib = if let Some(ref env_lib) = fn_def.lib {
|
||||
if env_lib.is_empty() {
|
||||
let lib = if let Some(ref fn_lib) = fn_def.lib {
|
||||
if fn_lib.is_empty() {
|
||||
lib
|
||||
} else {
|
||||
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.as_ref()
|
||||
&lib_merged
|
||||
}
|
||||
} else {
|
||||
lib
|
||||
@ -886,8 +886,9 @@ impl Engine {
|
||||
)?;
|
||||
|
||||
// If new functions are defined within the eval string, it is an error
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
if !ast.shared_lib().is_empty() {
|
||||
return Err(ParseErrorType::WrongFnDefinition.into());
|
||||
return Err(crate::ParseErrorType::WrongFnDefinition.into());
|
||||
}
|
||||
|
||||
let statements = ast.statements();
|
||||
|
@ -1460,7 +1460,7 @@ impl Module {
|
||||
|
||||
// Non-private functions defined become module functions
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
if !ast.shared_lib().functions.is_empty() {
|
||||
if ast.has_functions() {
|
||||
ast.shared_lib()
|
||||
.functions
|
||||
.values()
|
||||
|
@ -1,7 +1,7 @@
|
||||
//! Module implementing the [`AST`] optimizer.
|
||||
#![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::{
|
||||
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::{
|
||||
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")]
|
||||
use std::prelude::v1::*;
|
||||
@ -59,8 +59,9 @@ struct OptimizerState<'a> {
|
||||
propagate_constants: bool,
|
||||
/// An [`Engine`] instance for eager function evaluation.
|
||||
engine: &'a Engine,
|
||||
/// [Module] containing script-defined functions.
|
||||
lib: &'a [&'a Module],
|
||||
/// [Module][crate::Module] containing script-defined functions.
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
lib: &'a [&'a crate::Module],
|
||||
/// Optimization level.
|
||||
optimization_level: OptimizationLevel,
|
||||
}
|
||||
@ -70,7 +71,7 @@ impl<'a> OptimizerState<'a> {
|
||||
#[inline(always)]
|
||||
pub const fn new(
|
||||
engine: &'a Engine,
|
||||
lib: &'a [&'a Module],
|
||||
#[cfg(not(feature = "no_function"))] lib: &'a [&'a crate::Module],
|
||||
optimization_level: OptimizationLevel,
|
||||
) -> Self {
|
||||
Self {
|
||||
@ -78,6 +79,7 @@ impl<'a> OptimizerState<'a> {
|
||||
variables: StaticVec::new_const(),
|
||||
propagate_constants: true,
|
||||
engine,
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
lib,
|
||||
optimization_level,
|
||||
}
|
||||
@ -139,11 +141,16 @@ impl<'a> OptimizerState<'a> {
|
||||
fn_name: impl AsRef<str>,
|
||||
arg_values: &mut [Dynamic],
|
||||
) -> Option<Dynamic> {
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
let lib = self.lib;
|
||||
#[cfg(feature = "no_function")]
|
||||
let lib = &[];
|
||||
|
||||
self.engine
|
||||
.call_native_fn(
|
||||
&mut Imports::new(),
|
||||
&mut EvalState::new(),
|
||||
self.lib,
|
||||
lib,
|
||||
&fn_name,
|
||||
calc_fn_hash(&fn_name, arg_values.len()),
|
||||
&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 let Some(result) = get_builtin_binary_op_fn(x.name.as_ref(), &arg_values[0], &arg_values[1])
|
||||
.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");
|
||||
(f)(context, &mut [ first, &mut second[0] ]).ok()
|
||||
}) {
|
||||
@ -1091,7 +1103,7 @@ fn optimize_top_level(
|
||||
statements: StaticVec<Stmt>,
|
||||
engine: &Engine,
|
||||
scope: &Scope,
|
||||
lib: &[&Module],
|
||||
#[cfg(not(feature = "no_function"))] lib: &[&crate::Module],
|
||||
optimization_level: OptimizationLevel,
|
||||
) -> StaticVec<Stmt> {
|
||||
let mut statements = statements;
|
||||
@ -1103,7 +1115,12 @@ fn optimize_top_level(
|
||||
}
|
||||
|
||||
// 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
|
||||
scope.iter().for_each(|(name, constant, value)| {
|
||||
@ -1123,7 +1140,9 @@ pub fn optimize_into_ast(
|
||||
engine: &Engine,
|
||||
scope: &Scope,
|
||||
statements: StaticVec<Stmt>,
|
||||
functions: StaticVec<Shared<ScriptFnDef>>,
|
||||
#[cfg(not(feature = "no_function"))] functions: StaticVec<
|
||||
crate::Shared<crate::ast::ScriptFnDef>,
|
||||
>,
|
||||
optimization_level: OptimizationLevel,
|
||||
) -> AST {
|
||||
let level = if cfg!(feature = "no_optimize") {
|
||||
@ -1133,19 +1152,18 @@ pub fn optimize_into_ast(
|
||||
};
|
||||
|
||||
let mut statements = statements;
|
||||
let _functions = functions;
|
||||
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
let lib = {
|
||||
let mut module = Module::new();
|
||||
let mut module = crate::Module::new();
|
||||
|
||||
if level != OptimizationLevel::None {
|
||||
// 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()
|
||||
.map(|fn_def| ScriptFnDef {
|
||||
.map(|fn_def| crate::ast::ScriptFnDef {
|
||||
name: fn_def.name.clone(),
|
||||
access: fn_def.access,
|
||||
body: crate::ast::StmtBlock::NONE,
|
||||
@ -1163,7 +1181,7 @@ pub fn optimize_into_ast(
|
||||
|
||||
let lib2 = &[&lib2];
|
||||
|
||||
_functions
|
||||
functions
|
||||
.into_iter()
|
||||
.map(|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);
|
||||
});
|
||||
} else {
|
||||
_functions.into_iter().for_each(|fn_def| {
|
||||
functions.into_iter().for_each(|fn_def| {
|
||||
module.set_script_fn(fn_def);
|
||||
});
|
||||
}
|
||||
@ -1187,18 +1205,21 @@ pub fn optimize_into_ast(
|
||||
module
|
||||
};
|
||||
|
||||
#[cfg(feature = "no_function")]
|
||||
let lib = Module::new();
|
||||
|
||||
statements.shrink_to_fit();
|
||||
|
||||
AST::new(
|
||||
match level {
|
||||
OptimizationLevel::None => statements,
|
||||
OptimizationLevel::Simple | OptimizationLevel::Full => {
|
||||
optimize_top_level(statements, engine, &scope, &[&lib], level)
|
||||
}
|
||||
OptimizationLevel::Simple | OptimizationLevel::Full => optimize_top_level(
|
||||
statements,
|
||||
engine,
|
||||
&scope,
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
&[&lib],
|
||||
level,
|
||||
),
|
||||
},
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
lib,
|
||||
)
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ fn collect_fn_metadata(ctx: NativeCallContext) -> crate::Array {
|
||||
.map(|&s| s.into())
|
||||
.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(),
|
||||
|mut list, (_, _, _, _, f)| {
|
||||
list.push(make_metadata(&dict, None, f).into());
|
||||
@ -122,8 +122,8 @@ fn collect_fn_metadata(ctx: NativeCallContext) -> crate::Array {
|
||||
}
|
||||
|
||||
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,
|
||||
_scope,
|
||||
statements,
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
StaticVec::new_const(),
|
||||
optimization_level,
|
||||
));
|
||||
@ -3351,6 +3352,7 @@ impl Engine {
|
||||
self,
|
||||
_scope,
|
||||
statements,
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
_lib,
|
||||
optimization_level,
|
||||
));
|
||||
|
@ -764,6 +764,9 @@ impl Token {
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
"private" => Private,
|
||||
|
||||
#[cfg(feature = "no_function")]
|
||||
"fn" | "private" => Reserved(syntax.into()),
|
||||
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
"import" => Import,
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
@ -771,9 +774,6 @@ impl Token {
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
"as" => As,
|
||||
|
||||
#[cfg(feature = "no_function")]
|
||||
"fn" | "private" => Reserved(syntax.into()),
|
||||
|
||||
#[cfg(feature = "no_module")]
|
||||
"import" | "export" | "as" => Reserved(syntax.into()),
|
||||
|
||||
|
@ -3,8 +3,8 @@
|
||||
use crate::tokenizer::is_valid_identifier;
|
||||
use crate::types::dynamic::Variant;
|
||||
use crate::{
|
||||
Dynamic, Engine, EvalAltResult, FuncArgs, Identifier, NativeCallContext, Position, RhaiResult,
|
||||
StaticVec, AST,
|
||||
Dynamic, Engine, EvalAltResult, FuncArgs, Identifier, Module, NativeCallContext, Position,
|
||||
RhaiResult, StaticVec, AST,
|
||||
};
|
||||
#[cfg(feature = "no_std")]
|
||||
use std::prelude::v1::*;
|
||||
@ -137,12 +137,21 @@ impl FnPtr {
|
||||
ast: &AST,
|
||||
args: impl FuncArgs,
|
||||
) -> Result<T, Box<EvalAltResult>> {
|
||||
let _ast = ast;
|
||||
let mut arg_values = crate::StaticVec::new_const();
|
||||
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)]
|
||||
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)?;
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
#![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::cell::RefCell;
|
||||
use std::mem::take;
|
||||
@ -318,30 +318,18 @@ fn test_closures_shared_obj() -> Result<(), Box<EvalAltResult>> {
|
||||
fn test_closures_external() -> Result<(), Box<EvalAltResult>> {
|
||||
let engine = Engine::new();
|
||||
|
||||
let mut ast = engine.compile(
|
||||
let ast = engine.compile(
|
||||
r#"
|
||||
let test = "hello";
|
||||
|x| test + x
|
||||
"#,
|
||||
)?;
|
||||
|
||||
// Save the function pointer together with captured variables
|
||||
let fn_ptr = engine.eval_ast::<FnPtr>(&ast)?;
|
||||
|
||||
// Get rid of the script, retaining only functions
|
||||
ast.retain_functions(|_, _, _, _| true);
|
||||
let f = move |x: INT| -> String { fn_ptr.call(&engine, &ast, (x,)).unwrap() };
|
||||
|
||||
// Create function namespace from the 'AST'
|
||||
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()));
|
||||
assert_eq!(f(42), "hello42");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -69,6 +69,7 @@ fn test_optimizer_run() -> Result<(), Box<EvalAltResult>> {
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
#[cfg(not(feature = "no_position"))]
|
||||
#[test]
|
||||
fn test_optimizer_parse() -> Result<(), Box<EvalAltResult>> {
|
||||
|
Loading…
Reference in New Issue
Block a user