Releases: rhaiscript/rhai
v1.15.0
Bug fixes
- Fixes a concurrency error in static hashing keys (thanks
garypen
!).
Enhancements
- Expressions involving
this
should now run slightly faster due to a dedicatedAST
nodeThisPtr
. - A
take
function is added to the standard library to take ownership of any data (replacing with()
) in order to avoid cloning. Dynamic::take
is added to take ownership of the data (replacing with()
) in order to avoid cloning.EvalAltResult::ErrorMismatchOutputType
now gives a better name for the requested generic type (e.g.&str
is now&str
and notstring
).
v1.14.0
This new version contains a substantial number of bug fixes for edge cases.
A new syntax is supported to facilitate writing object methods in script.
The code hacks that attempt to optimize branch prediction performance are removed because benchmarks do not show any material speed improvements.
Bug fixes
is_shared
is a reserved keyword and is now handled properly (e.g. it cannot be the target of a function pointer).- Re-optimizing an AST via
optimize_ast
with constants now works correctly for closures. Previously the hiddenShare
nodes are not removed and causes variable-not-found errors during runtime if the constants are not available in the scope. - Expressions such as
(v[0].func()).prop
now parse correctly. - Shadowed variable exports are now handled correctly.
- Shadowed constant definitions are now optimized correctly when propagated (e.g.
const X = 1; const X = 1 + 1 + 1; X
now evaluates to 3 instead of 0). - Identifiers and comma's in the middle of custom syntax now register correctly.
- Exporting an object map from a module with closures defined on properties now works correctly when those properties are called to mimic method calls in OOP-style.
- Compiling for
thumbv6m-none-eabi
target (e.g. Raspberry Pi Pico) now completes successfully. Dependency tono-std-compat
is now pointed to the latest repo instead ofcrates.io
.
New features
- It is now possible to require a specific type to the
this
pointer for a particular script-defined function so that it is called only when thethis
pointer contains the specified type. is_def_fn
is extended to support checking for typed methods, with syntaxis_def_fn(this_type, fn_name, arity)
Dynamic::take
is added as a short-cut forstd::mem::take(&mut value)
.
Enhancements
Engine::is_symbol_disabled
is added to test whether a particular keyword/symbol is disabled.- Support is added to deserialize a
Dynamic
value containing custom types or shared values back into anotherDynamic
(essentially a straight cloned copy).
v1.13.0
This version attempts a number of optimizations that may yield small speed improvements:
- Simple operators (e.g. integer arithmetic) are inlined to avoid the overhead of a function call.
- The tokenizer uses pre-calculated tables (generated by GNU
gperf
) for keyword recognition. - A black-arts trick (see
Engine::black_box
) is used to prevent LLVM from optimizing hand-tuned AST node matches back into a lookup table, which messes up branch prediction on modern CPU's.
Bug fixes
- Complex indexing/dotting chains now parse correctly, for example:
a[b][c[d]].e
map
andfilter
for arrays are markedpure
. Warnings are added to the documentation of pure array methods that takethis
closures.- Syntax such as
foo.bar::baz
no longer panics, but returns a proper parse error. - Expressions such as
!inside
now parses correctly instead of as!in
followed byside
. - Custom syntax starting with symbols now works correctly and no longer raises a parse error.
- Comparing different custom types now works correctly when the appropriate comparison operators are registered.
- Some op-assignments, such as
x += y
wherex
andy
arechar
, now work correctly instead of failing silently. - Op-assignments to bit flags or bit ranges now work correctly.
Potentially breaking changes
- The trait method
ModuleResolver::resolve_raw
(which is a low-level API) now takes a&mut Scope
parameter. This is a breaking change because the signature is modified, but this trait method has a default and is rarely called/implemented in practice. Module::eval_ast_as_new_raw
(a low-level API) now takes a&mut Scope
instead of theScope
parameter. This is a breaking change because the&mut
is now required.Engine::allow_loop_expressions
now correctly defaults totrue
(was erroneouslyfalse
by default).
Enhancements
Engine::new_raw
is nowconst
and runs very fast, delaying all other initialization until first use.- The functions
min
andmax
are added for numbers. - Range cases in
switch
statements now also match floating-point and decimal values. In order to support this, however, small numeric ranges cases are no longer unrolled. - Loading a module via
import
now gives the module access to the current scope, including variables and constants defined inside. - Some very simple operator calls (e.g. integer add) are inlined to avoid the overhead of a function call, resulting in a small speed improvement.
- The tokenizer now uses table-driven keyword recognizers generated by GNU
gperf
. At least theoretically it should be faster... - The field
isAnonymous
is added to JSON functions metadata.
v1.12.0
Bug fixes
- Integer numbers that are too large to deserialize into
INT
now fall back toDecimal
orFLOAT
instead of silently truncating. - Parsing deeply-nested closures (e.g.
||{||{||{||{||{||{||{...}}}}}}}
) no longer panics but will be confined to the nesting limit. - Closures containing a single expression are now allowed in
Engine::eval_expression
etc. - Strings interpolation now works under
Engine::new_raw
without any standard package. Fn
now throws an error if the name is a reserved keyword as it cannot possibly map to such a function. This also disallows creating function pointers to custom operators which are defined as disabled keywords (a mouthful), but such custom operators are designed primarily to be used as operators.
Breaking API changes
- The callback for initializing a debugger instance has changed to
Fn(&Engine, Debugger) -> Debugger
. This allows more control over the initial setup of the debugger. - The internal macro
reify!
is no longer available publicly.
Deprecated API's
Module::with_capacity
is deprecated.- The internal method
Engine::eval_statements_raw
is deprecated. - Array overloaded methods that take function names (as string) are deprecated in favor of using the
Fn("...")
call.
Speed improvements
- The function registration mechanism is revamped to take advantage of constant generics, among others, to omit checking code where possible. This yields a 10-20% speed improvements on certain real-life, function-call-heavy workloads.
- Functions taking function pointers as parameters, usually called with closures, now run faster because a link to the anonymous function (generated by the closure) is stored together with the function pointer itself. This allows short-circuiting the function lookup step.
Net features
First class functions (sort of)
- A function pointer created via a closure definition now links to the particular anonymous function itself.
- This avoids a potentially expensive function lookup when the function pointer is called, speeding up closures.
- Closures now also encapsulate their defining environment, so function pointers can now be freely
export
ed from modules!
!in
- A new operator
!in
is added which maps to!(... in ...)
.
Engine::call_fn_with_options
Engine::call_fn_raw
is deprecated in favor ofEngine::call_fn_with_options
which allows setting options for the function call.- The options are for future-proofing the API.
- In this version, it gains the ability to set the value of the custom state (accessible via
NativeCallContext::tag
) for a function evaluation, overridingEngine::set_default_tag
.
Compact a script for compression
Engine::compact_script
is added which takes a valid script (it still returns parsing errors) and returns a compacted version of the script with all insignificant whitespaces and all comments removed.- A compact script compresses better than one with liberal whitespaces and comments.
- Unlike some uglifiers or minifiers,
Engine::compact_script
does not optimize the script in any way, nor does it rename variables.
Enhanced array API
- Array methods that take a function pointer, usually a closure (e.g.
map
,filter
,index_of
,reduce
etc.), can now bind the array element tothis
when calling a closure. - This vastly improves performance when working with arrays of large types (e.g. object maps) by avoiding unnecessary cloning.
find
andfind_map
are added for arrays.for_each
is also added for arrays, allowing a closure to mutate array elements (bound tothis
) in turn.
Enhancements
- Optimizations have been done to key data structures to minimize size and creation time, which involves turning rarely-used fields into
Option<Box<T>>
. This resulted in some speed improvements. CallableFunction
is exported underinternals
.- The
TypeBuilder
type andCustomType
trait are no longer marked as volatile. FuncArgs
is also implemented for arrays.Engine::set_XXX
API can now be chained.EvalContext::scope_mut
now returns&mut Scope
instead of&mut &mut Scope
.- Line-style doc-comments are now merged into a single string to avoid creating many strings. Block-style doc-comments continue to be independent strings.
- Block-style doc-comments are now "un-indented" for better formatting.
- Doc-comments on plugin modules are now captured in the module's
doc
field. - Expression nesting levels is refined such that it grows less excessively for common patterns.
- The traits
Index
andIndexMut
are added toFnPtr
. FnPtr::iter_curry
andFnPtr::iter_curry_mut
are added.Dynamic::deep_scan
is added to recursively scan forDynamic
values.>>
and<<
operators on integers no longer throw errors when the number of bits to shift is out of bounds. Shifting by a negative number of bits simply reverses the shift direction.
v1.11.0
This is a large release containing numerous new features, bug fixes and speed improvements.
Speed Improvements
- Due to a code refactor, built-in operators for standard types now run even faster, in certain cases by 20-30%.
Bug fixes
Engine::parse_json
now returns an error on unquoted keys to be consistent with JSON specifications.import
statements insideeval
no longer cause errors in subsequent code.- Functions marked
global
inimport
ed modules with no alias names now work properly. - Incorrect loop optimizations that are too aggressive (e.g. unrolling a
do { ... } until true
with abreak
statement inside) and cause crashes are removed. Dynamic::is
now works properly for shared values.
Breaking changes
NativeCallContext::new
is completely deprecated and unimplemented (always panics) in favor of new API's.
New features
Dynamic
detection API
- New methods are added to
Dynamic
in the form ofis_XXX()
whereXXX
is a type (e.g.is_int
,is_unit
,is_bool
,is_array
). - This new API is to make it easier to detect the data type, instead of having to call
is::<XXX>()
.
Loop expressions
- Loops (such as
loop
,do
,while
andfor
) can now act as expressions, with thebreak
statement returning an optional value. - Normal loops return
()
as the value. - Loop expressions can be enabled/disabled via
Engine::set_allow_loop_expressions
Static hashing
- It is now possible to specify a fixed seed for use with the
ahash
hasher, via a static functionrhai::config::hashing::set_ahash_seed
or an environment variable (RHAI_AHASH_SEED
), in order to force static (i.e. deterministic) hashes for function signatures. - This is necessary when using Rhai across shared-library boundaries.
- A build script is used to extract the environment variable (
RHAI_AHASH_SEED
, if any) and splice it into the source code before compilation.
no_time
for no timestamps
- A new feature,
no_time
, is added to disable support for timestamps. - This may be necessary when building for architectures without time support, such as raw WASM.
Serializable Scope
Scope
is now serializable and deserializable viaserde
.
Store and recreate NativeCallContext
- A convenient API is added to store a
NativeCallContext
into a newNativeCallContextStore
type. - This allows a
NativeCallContext
to be stored and recreated later on.
Call native Rust functions in NativeCallContext
NativeCallContext::call_native_fn
is added to call registered native Rust functions only.NativeCallContext::call_native_fn_raw
is added as the advanced version.- This is often desirable as Rust functions typically do not want a similar-named scripted function to hijack the process -- which will cause brittleness.
Custom syntax improvements
- The look-ahead symbol for custom syntax now renders a string literal in quotes (instead of the generic term
string
). - This facilitates more accurate parsing by separating strings and identifiers.
Limits API
- Methods returning maximum limits (e.g.
Engine::max_string_len
) are now available even underunchecked
. - This helps avoid the proliferation of unnecessary feature flags in third-party library code.
Enhancements
parse_json
function is added to parse a JSON string into an object map.Error::ErrorNonPureMethodCallOnConstant
is added which is raised when a non-pure method is called on a constant value.
v1.10.1
This is a bug-fix release that fixes an error when compiling for 32-bit architectures.
Bug fixes
- Compiling on 32-bit architectures no longer cause a compilation error.
- Fix type-size test for 32-bit architectures without the
decimal
feature.
Custom syntax with state
- [
Engine::register_custom_syntax_with_state_raw
] is added. The custom syntax parser and implementation functions take on an additional parameter that holds a user-defined custom state which should substantially simplify writing some custom parsers. - [
Engine::register_custom_syntax_raw
] is deprecated.
v1.10.0
This version introduces Fast Operators mode, which is turned on by default but can be disabled via
a new options API: Engine::set_fast_operators
.
Fast Operators mode assumes that none of Rhai's built-in operators for standard data types are
overloaded by user-registered functions. In the vast majority of cases this should be so (really,
who overloads the +
operator for integers anyway?).
This assumption allows the Engine
to avoid checking for overloads for every single operator call.
This usually results in substantial speed improvements, especially for expressions.
Minimum Rust Version
The minimum Rust version is now 1.61.0
in order to use some const
generics.
Bug fixes
- API for registering property getters/setters and indexers to an
Engine
now works with functions that take a first parameter ofNativeCallContext
. - Missing API function
Module::set_getter_setter_fn
is added. - To avoid subtle errors, simple optimization is used for
rhai-run
; previous it was full optimization.
Deprecated API
- All versions of the
Engine::register_XXX_result
API that register a function returningResult<T, Box<EvalAltResult>>
are now deprecated. The regular, non-result
versions handle all functions correctly.
New features
Fast operators
- A new option
Engine::fast_operators
is introduced (default totrue
) to enable/disable Fast Operators mode.
Fallible type iterators
- For very special needs, the ability to register fallible type iterators is added.
Expressions
if
-expressions are allowed inEngine::eval_expression
andEngine::compile_expression
provided that both statement blocks each contain at most a single expression.switch
-expressions are allowed inEngine::eval_expression
andEngine::compile_expression
provided that match actions are expressions only.
Enhancements
is_empty
method is added to arrays, BLOB's, object maps, strings and ranges.StaticModuleResolver
now stores the path in the module'sid
field.Engine::module_resolver
is added to grant access to theEngine
's module resolver.- Constants and variables now have types in generated definition files.
v1.9.1
v1.9.0
The minimum Rust version is now 1.60.0
in order to use the dep:
syntax for dependencies.
Bug fixes
switch
cases with conditions that evaluate to constant()
no longer optimize tofalse
(should raise a type error during runtime).- Fixes concatenation of BLOB's and strings, where the BLOB's should be interpreted as UTF-8 encoded strings.
- Capturing an unknown variable in a closure no longer panics.
- Fixes panic in interpolated strings with constant expressions.
- Using
call_fn_raw
on a function without evaluating the AST no longer panics on namespace-qualified function calls due toimport
statements not run. - Some reserved tokens (such as "?", "++") cannot be used in custom syntax; this is now fixed.
Breaking changes
- The first closure passed to
Engine::register_debugger
now takes a single parameter which is a reference to the currentEngine
.
New features
New feature flags
- A new feature flag,
std
, which is enabled by default, is added due to requirements from dependency crates. - A new feature flag,
no_custom_syntax
, is added to remove custom syntax support from Rhai for applications that do not require it (which should be most).
Module documentation
- Comment lines beginning with
//!
(requires themetadata
feature) are now collected as the script file's module documentation. AST
andModule
have methods to access and manipulate documentation.
Output definition files
- An API is added to automatically generate definition files from a fully-configured
Engine
, for use with the Rhai Language Server.
Short-hand to function pointers
- Using a script-defined function's name (in place of a variable) implicitly creates a function pointer to the function.
Top-level functions
- Crate-level functions
rhai::eval
,rhai::run
,rhai::eval_file
,rhai::run_file
are added as convenient wrappers.
CustomType trait and TypeBuilder
- A new volatile API,
Engine::build_type
, enables registration of the entire API of a custom type in one go, provided that the custom type implements theCustomType
trait (which usesTypeBuilder
to register the API functions).
Simpler Package API
- It is now easier to register packages via the
Package::register_into_engine
andPackage::register_into_engine_as
API. - Defining a custom package with base packages is also much easier with a new syntax - put the new base packages after a colon.
Enhancements
switch
statement
switch
cases can now include multiple values separated by|
.- Duplicated
switch
cases are now allowed. - The error
ParseErrorType::DuplicatedSwitchCase
is deprecated. - Ranges in
switch
statements that are small (currently no more than 16 items) are unrolled if possible.
Others
EvalContext::eval_expression_tree_raw
andExpression::eval_with_context_raw
are added to allow for not rewinding theScope
at the end of a statements block.- A new
range
function variant that takes an exclusive range with a step. as_string
is added to BLOB's to convert it into a string by interpreting it as a UTF-8 byte stream.FnAccess::is_private
,FnAccess::is_public
,FnNamespace::is_module_namespace
andFnNameSpace::is_global_namespace
are added for convenience.Iterator<Item=T>
type for functions metadata is simplified toIterator<T>
.Scope::remove
is added to remove a variable from aScope
, returning its value.- The code base is cleaner by running it through Clippy.
ParseError::err_type
andParseError::position
are added for convenience.- The source of an
AST
compiled from a script file is set to the file's path. |>
and<|
are now reserved symbols.
v1.8.0
This version includes a number of usability improvements, especially the Elvis operator ?.
and null-coalescing operator ??
.
Bug fixes
- Self-contained
AST
now works properly withEngine::call_fn
. - Missing
to_int
fromDecimal
is added. - Parsing of index expressions is relaxed and many cases no longer result in an index-type error to allow for custom indexers. Closes #562
- Merging or combining a self-contained
AST
into anotherAST
now works properly. - 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. Closes #573
- Strict Variables Mode now checks for module namespaces within functions as well. Closes #574
- Module defined via
Engine::register_static_module
are now checked in Strict Variables Mode.
Reserved Symbols
?
,??
,?.
,?[
and!.
are now reserved symbols.
Deprecated API's
FnPtr::num_curried
is deprecated in favor ofFnPtr::curry().len()
.
New features
- The Elvis operators (
?.
and?[
) are now supported for property access, method calls and indexing. - The null-coalescing operator (
??
) is now supported to short-circuit()
values.
Enhancements
- Indexing and property access are now faster.
EvalAltResult::IndexNotFound
is added to aid in raising errors for indexers.Engine::default_tag
,Engine::default_tag_mut
andEngine::set_default_tag
are added to manage a default value for the custom evaluation state, accessible viaEvalState::tag()
(which is the same asNativeCallContext::tag()
). Closes #563- Originally, the debugger's custom state uses the same state as
EvalState::tag()
(which is the same asNativeCallContext::tag()
). It is now split into its own variable accessible underDebugger::state()
. - Non-borrowed string keys can now be deserialized for object maps via
serde
. Scope::get
is added to get a reference to a variable's value.- Variable resolvers can now return a shared value which can be mutated.