Propagate constants to functions for Engine::XXX_with_scope calls.
This commit is contained in:
parent
31ef7e6c69
commit
5083df3096
17
CHANGELOG.md
17
CHANGELOG.md
@ -4,6 +4,11 @@ Rhai Release Notes
|
||||
Version 1.2.0
|
||||
=============
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
|
||||
* `Engine::XXX_with_scope` API's now properly propagate constants within the provided scope also to _functions_ in the script.
|
||||
|
||||
New features
|
||||
------------
|
||||
|
||||
@ -28,16 +33,6 @@ Deprecated API's
|
||||
* `From<EvalAltResult>` for `Result<T, Box<EvalAltResult>>` is deprecated so it will no longer be possible to do `EvalAltResult::ErrorXXXXX.into()` to convert to a `Result`; instead, `Err(EvalAltResult:ErrorXXXXX.into())` must be used. Code is clearer if errors are explicitly wrapped in `Err`.
|
||||
|
||||
|
||||
Version 1.1.3
|
||||
=============
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
|
||||
* Reverses a regression on string `+` operations.
|
||||
* The global namespace is now searched before packages, which is the correct behavior.
|
||||
|
||||
|
||||
Version 1.1.2
|
||||
=============
|
||||
|
||||
@ -46,6 +41,8 @@ Bug fixes
|
||||
|
||||
* `0.0` now prints correctly (used to print `0e0`).
|
||||
* Unary operators are now properly recognized as an expression statement.
|
||||
* Reverses a regression on string `+` operations.
|
||||
* The global namespace is now searched before packages, which is the correct behavior.
|
||||
|
||||
|
||||
Version 1.1.1
|
||||
|
@ -1006,8 +1006,11 @@ impl Engine {
|
||||
}
|
||||
/// Compile a string into an [`AST`] using own scope, which can be used later for evaluation.
|
||||
///
|
||||
/// The scope is useful for passing constants into the script for optimization
|
||||
/// when using [`OptimizationLevel::Full`].
|
||||
/// ## Constants Propagation
|
||||
///
|
||||
/// If not [`OptimizationLevel::None`], constants defined within the scope are propagated
|
||||
/// throughout the script _including_ functions. This allows functions to be optimized based on
|
||||
/// dynamic global constants.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
@ -1019,10 +1022,6 @@ impl Engine {
|
||||
///
|
||||
/// let mut engine = Engine::new();
|
||||
///
|
||||
/// // Set optimization level to 'Full' so the Engine can fold constants
|
||||
/// // into function calls and operators.
|
||||
/// engine.set_optimization_level(OptimizationLevel::Full);
|
||||
///
|
||||
/// // Create initialized scope
|
||||
/// let mut scope = Scope::new();
|
||||
/// scope.push_constant("x", 42_i64); // 'x' is a constant
|
||||
@ -1130,6 +1129,12 @@ impl Engine {
|
||||
/// All strings are simply parsed one after another with nothing inserted in between, not even
|
||||
/// a newline or space.
|
||||
///
|
||||
/// ## Constants Propagation
|
||||
///
|
||||
/// If not [`OptimizationLevel::None`], constants defined within the scope are propagated
|
||||
/// throughout the script _including_ functions. This allows functions to be optimized based on
|
||||
/// dynamic global constants.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
@ -1140,10 +1145,6 @@ impl Engine {
|
||||
///
|
||||
/// let mut engine = Engine::new();
|
||||
///
|
||||
/// // Set optimization level to 'Full' so the Engine can fold constants
|
||||
/// // into function calls and operators.
|
||||
/// engine.set_optimization_level(OptimizationLevel::Full);
|
||||
///
|
||||
/// // Create initialized scope
|
||||
/// let mut scope = Scope::new();
|
||||
/// scope.push_constant("x", 42_i64); // 'x' is a constant
|
||||
@ -1179,6 +1180,12 @@ impl Engine {
|
||||
)
|
||||
}
|
||||
/// Join a list of strings and compile into an [`AST`] using own scope at a specific optimization level.
|
||||
///
|
||||
/// ## Constants Propagation
|
||||
///
|
||||
/// If not [`OptimizationLevel::None`], constants defined within the scope are propagated
|
||||
/// throughout the script _including_ functions. This allows functions to be optimized based on
|
||||
/// dynamic global constants.
|
||||
#[inline]
|
||||
pub(crate) fn compile_with_scope_and_optimization_level(
|
||||
&self,
|
||||
@ -1262,8 +1269,11 @@ impl Engine {
|
||||
///
|
||||
/// Not available under `no_std` or `WASM`.
|
||||
///
|
||||
/// The scope is useful for passing constants into the script for optimization
|
||||
/// when using [`OptimizationLevel::Full`].
|
||||
/// ## Constants Propagation
|
||||
///
|
||||
/// If not [`OptimizationLevel::None`], constants defined within the scope are propagated
|
||||
/// throughout the script _including_ functions. This allows functions to be optimized based on
|
||||
/// dynamic global constants.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
@ -1275,9 +1285,6 @@ impl Engine {
|
||||
///
|
||||
/// let mut engine = Engine::new();
|
||||
///
|
||||
/// // Set optimization level to 'Full' so the Engine can fold constants.
|
||||
/// engine.set_optimization_level(OptimizationLevel::Full);
|
||||
///
|
||||
/// // Create initialized scope
|
||||
/// let mut scope = Scope::new();
|
||||
/// scope.push_constant("x", 42_i64); // 'x' is a constant
|
||||
@ -1429,9 +1436,6 @@ impl Engine {
|
||||
/// Compile a string containing an expression into an [`AST`] using own scope,
|
||||
/// which can be used later for evaluation.
|
||||
///
|
||||
/// The scope is useful for passing constants into the script for optimization
|
||||
/// when using [`OptimizationLevel::Full`].
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
@ -1442,10 +1446,6 @@ impl Engine {
|
||||
///
|
||||
/// let mut engine = Engine::new();
|
||||
///
|
||||
/// // Set optimization level to 'Full' so the Engine can fold constants
|
||||
/// // into function calls and operators.
|
||||
/// engine.set_optimization_level(OptimizationLevel::Full);
|
||||
///
|
||||
/// // Create initialized scope
|
||||
/// let mut scope = Scope::new();
|
||||
/// scope.push_constant("x", 10_i64); // 'x' is a constant
|
||||
@ -1515,6 +1515,12 @@ impl Engine {
|
||||
///
|
||||
/// Not available under `no_std` or `WASM`.
|
||||
///
|
||||
/// ## Constants Propagation
|
||||
///
|
||||
/// If not [`OptimizationLevel::None`], constants defined within the scope are propagated
|
||||
/// throughout the script _including_ functions. This allows functions to be optimized based on
|
||||
/// dynamic global constants.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
@ -1562,6 +1568,12 @@ impl Engine {
|
||||
}
|
||||
/// Evaluate a string with own scope.
|
||||
///
|
||||
/// ## Constants Propagation
|
||||
///
|
||||
/// If not [`OptimizationLevel::None`], constants defined within the scope are propagated
|
||||
/// throughout the script _including_ functions. This allows functions to be optimized based on
|
||||
/// dynamic global constants.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
@ -1768,6 +1780,12 @@ impl Engine {
|
||||
/// Evaluate a file with own scope, returning any error (if any).
|
||||
///
|
||||
/// Not available under `no_std` or `WASM`.
|
||||
///
|
||||
/// ## Constants Propagation
|
||||
///
|
||||
/// If not [`OptimizationLevel::None`], constants defined within the scope are propagated
|
||||
/// throughout the script _including_ functions. This allows functions to be optimized based on
|
||||
/// dynamic global constants.
|
||||
#[cfg(not(feature = "no_std"))]
|
||||
#[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))]
|
||||
#[inline]
|
||||
@ -1784,6 +1802,12 @@ impl Engine {
|
||||
self.run_with_scope(&mut Scope::new(), script)
|
||||
}
|
||||
/// Evaluate a script with own scope, returning any error (if any).
|
||||
///
|
||||
/// ## Constants Propagation
|
||||
///
|
||||
/// If not [`OptimizationLevel::None`], constants defined within the scope are propagated
|
||||
/// throughout the script _including_ functions. This allows functions to be optimized based on
|
||||
/// dynamic global constants.
|
||||
#[inline]
|
||||
pub fn run_with_scope(
|
||||
&self,
|
||||
@ -2065,8 +2089,9 @@ impl Engine {
|
||||
#[cfg(feature = "no_function")]
|
||||
let lib = crate::StaticVec::new();
|
||||
|
||||
let stmt = std::mem::take(ast.statements_mut());
|
||||
crate::optimize::optimize_into_ast(self, scope, stmt, lib, optimization_level)
|
||||
let statements = std::mem::take(ast.statements_mut());
|
||||
|
||||
crate::optimize::optimize_into_ast(self, scope, statements, lib, optimization_level)
|
||||
}
|
||||
/// _(metadata)_ Generate a list of all registered functions.
|
||||
/// Exported under the `metadata` feature only.
|
||||
|
@ -113,16 +113,16 @@ impl<'a> OptimizerState<'a> {
|
||||
return None;
|
||||
}
|
||||
|
||||
self.variables.iter().rev().find_map(|(n, access, value)| {
|
||||
for (n, access, value) in self.variables.iter().rev() {
|
||||
if n == name {
|
||||
match access {
|
||||
return match access {
|
||||
AccessMode::ReadWrite => None,
|
||||
AccessMode::ReadOnly => value.as_ref(),
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
/// Call a registered function
|
||||
#[inline]
|
||||
@ -1095,6 +1095,8 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) {
|
||||
}
|
||||
|
||||
/// Optimize a block of [statements][Stmt] at top level.
|
||||
///
|
||||
/// Constants and variables from the scope are added.
|
||||
fn optimize_top_level(
|
||||
statements: StaticVec<Stmt>,
|
||||
engine: &Engine,
|
||||
@ -1179,11 +1181,9 @@ pub fn optimize_into_ast(
|
||||
let mut fn_def = crate::fn_native::shared_take_or_clone(fn_def);
|
||||
|
||||
// Optimize the function body
|
||||
let state = &mut OptimizerState::new(engine, lib2, level);
|
||||
|
||||
let body = mem::take(fn_def.body.deref_mut());
|
||||
|
||||
*fn_def.body = optimize_stmt_block(body, state, true, true, true);
|
||||
*fn_def.body = optimize_top_level(body, engine, scope, lib2, level);
|
||||
|
||||
fn_def
|
||||
})
|
||||
|
@ -1,6 +1,6 @@
|
||||
#![cfg(not(feature = "no_optimize"))]
|
||||
|
||||
use rhai::{Engine, EvalAltResult, OptimizationLevel, INT};
|
||||
use rhai::{Engine, EvalAltResult, OptimizationLevel, Scope, INT};
|
||||
|
||||
#[test]
|
||||
fn test_optimizer() -> Result<(), Box<EvalAltResult>> {
|
||||
@ -107,3 +107,24 @@ fn test_optimizer_parse() -> Result<(), Box<EvalAltResult>> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_optimizer_scope() -> Result<(), Box<EvalAltResult>> {
|
||||
let engine = Engine::new();
|
||||
let mut scope = Scope::new();
|
||||
|
||||
scope.push_constant("FOO", 42 as INT);
|
||||
|
||||
let ast = engine.compile_with_scope(&scope, "fn foo() { FOO } foo()")?;
|
||||
|
||||
scope.push("FOO", 123 as INT);
|
||||
|
||||
assert_eq!(engine.eval_ast::<INT>(&ast)?, 42);
|
||||
assert_eq!(engine.eval_ast_with_scope::<INT>(&mut scope, &ast)?, 42);
|
||||
|
||||
let ast = engine.compile_with_scope(&scope, "fn foo() { FOO } foo()")?;
|
||||
|
||||
assert!(engine.eval_ast_with_scope::<INT>(&mut scope, &ast).is_err());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user