Change fast_ops to options.
This commit is contained in:
parent
43c4d7e3ca
commit
06dea067b7
@ -30,9 +30,9 @@ New features
|
|||||||
* `if`-expressions are allowed in `Engine::eval_expression` and `Engine::compile_expression` provided that both statement blocks each contain at most a single expression.
|
* `if`-expressions are allowed in `Engine::eval_expression` and `Engine::compile_expression` provided that both statement blocks each contain at most a single expression.
|
||||||
* `switch`-expressions are allowed in `Engine::eval_expression` and `Engine::compile_expression` provided that match actions are expressions only.
|
* `switch`-expressions are allowed in `Engine::eval_expression` and `Engine::compile_expression` provided that match actions are expressions only.
|
||||||
|
|
||||||
### `fast_ops` feature
|
### Fast operators
|
||||||
|
|
||||||
* A new feature `fast_ops` is introduced that short-circuits all built-in operators of built-in types for higher speed. New user overloads are ignored.
|
* A new option `Engine::fast_operators` is introduced that short-circuits all built-in operators of built-in types for higher speed. User overloads are ignored. For operator-heavy scripts, this may yield substantial speed-up's.
|
||||||
|
|
||||||
Enhancements
|
Enhancements
|
||||||
------------
|
------------
|
||||||
|
@ -39,10 +39,9 @@ serde_bytes = "0.11"
|
|||||||
serde_json = { version = "1.0", default-features = false, features = ["alloc"] }
|
serde_json = { version = "1.0", default-features = false, features = ["alloc"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["std", "fast_ops"]
|
default = ["std"]
|
||||||
std = ["ahash/std", "ahash/runtime-rng", "num-traits/std", "smartstring/std"]
|
std = ["ahash/std", "ahash/runtime-rng", "num-traits/std", "smartstring/std"]
|
||||||
unchecked = [] # unchecked arithmetic
|
unchecked = [] # unchecked arithmetic
|
||||||
fast_ops = [] # ignore overloaded standard operators
|
|
||||||
sync = [] # restrict to only types that implement Send + Sync
|
sync = [] # restrict to only types that implement Send + Sync
|
||||||
no_position = [] # do not track position in the parser
|
no_position = [] # do not track position in the parser
|
||||||
no_optimize = [] # no script optimizer
|
no_optimize = [] # no script optimizer
|
||||||
|
@ -7,26 +7,28 @@ use std::prelude::v1::*;
|
|||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
/// Bit-flags containing all language options for the [`Engine`].
|
/// Bit-flags containing all language options for the [`Engine`].
|
||||||
pub struct LangOptions: u8 {
|
pub struct LangOptions: u16 {
|
||||||
/// Is `if`-expression allowed?
|
/// Is `if`-expression allowed?
|
||||||
const IF_EXPR = 0b_0000_0001;
|
const IF_EXPR = 0b_0000_0000_0001;
|
||||||
/// Is `switch` expression allowed?
|
/// Is `switch` expression allowed?
|
||||||
const SWITCH_EXPR = 0b_0000_0010;
|
const SWITCH_EXPR = 0b_0000_0000_0010;
|
||||||
/// Is statement-expression allowed?
|
/// Is statement-expression allowed?
|
||||||
const STMT_EXPR = 0b_0000_0100;
|
const STMT_EXPR = 0b_0000_0000_0100;
|
||||||
/// Is anonymous function allowed?
|
/// Is anonymous function allowed?
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
const ANON_FN = 0b_0000_1000;
|
const ANON_FN = 0b_0000_0000_1000;
|
||||||
/// Is looping allowed?
|
/// Is looping allowed?
|
||||||
const LOOPING = 0b_0001_0000;
|
const LOOPING = 0b_0000_0001_0000;
|
||||||
/// Is variables shadowing allowed?
|
/// Is variables shadowing allowed?
|
||||||
const SHADOW = 0b_0010_0000;
|
const SHADOW = 0b_0000_0010_0000;
|
||||||
/// Strict variables mode?
|
/// Strict variables mode?
|
||||||
const STRICT_VAR = 0b_0100_0000;
|
const STRICT_VAR = 0b_0000_0100_0000;
|
||||||
/// Raise error if an object map property does not exist?
|
/// Raise error if an object map property does not exist?
|
||||||
/// Returns `()` if `false`.
|
/// Returns `()` if `false`.
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
const FAIL_ON_INVALID_MAP_PROPERTY = 0b_1000_0000;
|
const FAIL_ON_INVALID_MAP_PROPERTY = 0b_0000_1000_0000;
|
||||||
|
/// Fast operators mode?
|
||||||
|
const FAST_OPS = 0b_0001_0000_0000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,4 +160,16 @@ impl Engine {
|
|||||||
self.options
|
self.options
|
||||||
.set(LangOptions::FAIL_ON_INVALID_MAP_PROPERTY, enable);
|
.set(LangOptions::FAIL_ON_INVALID_MAP_PROPERTY, enable);
|
||||||
}
|
}
|
||||||
|
/// Is fast operators mode enabled?
|
||||||
|
/// Default is `false`.
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn fast_operators(&self) -> bool {
|
||||||
|
self.options.contains(LangOptions::FAST_OPS)
|
||||||
|
}
|
||||||
|
/// Set whether fast operators mode is enabled.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn set_fast_operators(&mut self, enable: bool) {
|
||||||
|
self.options.set(LangOptions::FAST_OPS, enable);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -228,8 +228,7 @@ impl Engine {
|
|||||||
..
|
..
|
||||||
} = expr;
|
} = expr;
|
||||||
|
|
||||||
#[cfg(feature = "fast_ops")]
|
if *std_ops && self.fast_operators() {
|
||||||
if *std_ops {
|
|
||||||
let mut lhs = self
|
let mut lhs = self
|
||||||
.get_arg_value(scope, global, caches, lib, this_ptr, &args[0], level)?
|
.get_arg_value(scope, global, caches, lib, this_ptr, &args[0], level)?
|
||||||
.0
|
.0
|
||||||
|
@ -1181,7 +1181,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, _chaining: bool) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Overloaded operators can override built-in.
|
// Overloaded operators can override built-in.
|
||||||
_ if x.args.len() == 2 && (cfg!(feature = "fast_ops") || !has_native_fn_override(state.engine, x.hashes.native, &arg_types)) => {
|
_ if x.args.len() == 2 && (state.engine.fast_operators() || !has_native_fn_override(state.engine, x.hashes.native, &arg_types)) => {
|
||||||
if let Some(result) = get_builtin_binary_op_fn(&x.name, &arg_values[0], &arg_values[1])
|
if let Some(result) = get_builtin_binary_op_fn(&x.name, &arg_values[0], &arg_values[1])
|
||||||
.and_then(|f| {
|
.and_then(|f| {
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
@ -77,19 +77,22 @@ fn test_native_overload() -> Result<(), Box<EvalAltResult>> {
|
|||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
engine.eval::<String>(r#"let x = "hello"; let y = "world"; x + y"#)?,
|
engine.eval::<String>(r#"let x = "hello"; let y = "world"; x + y"#)?,
|
||||||
if cfg!(not(feature = "fast_ops")) {
|
"hello***world"
|
||||||
"hello***world"
|
|
||||||
} else {
|
|
||||||
"helloworld"
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
engine.eval::<String>(r#"let x = "hello"; let y = (); x + y"#)?,
|
engine.eval::<String>(r#"let x = "hello"; let y = (); x + y"#)?,
|
||||||
if cfg!(not(feature = "fast_ops")) {
|
"hello Foo!"
|
||||||
"hello Foo!"
|
);
|
||||||
} else {
|
|
||||||
"hello"
|
engine.set_fast_operators(true);
|
||||||
}
|
|
||||||
|
assert_eq!(
|
||||||
|
engine.eval::<String>(r#"let x = "hello"; let y = "world"; x + y"#)?,
|
||||||
|
"helloworld"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
engine.eval::<String>(r#"let x = "hello"; let y = (); x + y"#)?,
|
||||||
|
"hello"
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -49,24 +49,21 @@ fn test_optimizer_run() -> Result<(), Box<EvalAltResult>> {
|
|||||||
run_test(&mut engine)?;
|
run_test(&mut engine)?;
|
||||||
|
|
||||||
// Override == operator
|
// Override == operator
|
||||||
#[cfg(not(feature = "fast_ops"))]
|
engine.register_fn("==", |_x: INT, _y: INT| false);
|
||||||
{
|
|
||||||
engine.register_fn("==", |_x: INT, _y: INT| false);
|
|
||||||
|
|
||||||
engine.set_optimization_level(OptimizationLevel::Simple);
|
engine.set_optimization_level(OptimizationLevel::Simple);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
engine.eval::<INT>("if 1 == 1 || 2 > 3 { 42 } else { 123 }")?,
|
engine.eval::<INT>("if 1 == 1 || 2 > 3 { 42 } else { 123 }")?,
|
||||||
123
|
123
|
||||||
);
|
);
|
||||||
|
|
||||||
engine.set_optimization_level(OptimizationLevel::Full);
|
engine.set_optimization_level(OptimizationLevel::Full);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
engine.eval::<INT>("if 1 == 1 || 2 > 3 { 42 } else { 123 }")?,
|
engine.eval::<INT>("if 1 == 1 || 2 > 3 { 42 } else { 123 }")?,
|
||||||
123
|
123
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -128,14 +128,7 @@ fn test_plugins_package() -> Result<(), Box<EvalAltResult>> {
|
|||||||
assert_eq!(engine.eval::<INT>("let a = [1, 2, 3]; test(a, 2)")?, 6);
|
assert_eq!(engine.eval::<INT>("let a = [1, 2, 3]; test(a, 2)")?, 6);
|
||||||
assert_eq!(engine.eval::<INT>("let a = [1, 2, 3]; hi(a, 2)")?, 6);
|
assert_eq!(engine.eval::<INT>("let a = [1, 2, 3]; hi(a, 2)")?, 6);
|
||||||
assert_eq!(engine.eval::<INT>("let a = [1, 2, 3]; test(a, 2)")?, 6);
|
assert_eq!(engine.eval::<INT>("let a = [1, 2, 3]; test(a, 2)")?, 6);
|
||||||
assert_eq!(
|
assert_eq!(engine.eval::<INT>("2 + 2")?, 5);
|
||||||
engine.eval::<INT>("2 + 2")?,
|
|
||||||
if cfg!(not(feature = "fast_ops")) {
|
|
||||||
5
|
|
||||||
} else {
|
|
||||||
4
|
|
||||||
}
|
|
||||||
);
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
engine.eval::<String>("let a = [1, 2, 3]; greet(test(a, 2))")?,
|
engine.eval::<String>("let a = [1, 2, 3]; greet(test(a, 2))")?,
|
||||||
"6 kitties"
|
"6 kitties"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user