Skip to content

Releases: rhaiscript/rhai

v1.15.0

18 Jun 05:20
fd162ab
Compare
Choose a tag to compare

Bug fixes

  • Fixes a concurrency error in static hashing keys (thanks garypen!).

Enhancements

  • Expressions involving this should now run slightly faster due to a dedicated AST node ThisPtr.
  • 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 not string).

v1.14.0

02 May 17:01
517f219
Compare
Choose a tag to compare

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 hidden Share 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 to no-std-compat is now pointed to the latest repo instead of crates.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 the this pointer contains the specified type.
  • is_def_fn is extended to support checking for typed methods, with syntax is_def_fn(this_type, fn_name, arity)
  • Dynamic::take is added as a short-cut for std::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 another Dynamic (essentially a straight cloned copy).

v1.13.0

16 Mar 23:04
4d84401
Compare
Choose a tag to compare

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 and filter for arrays are marked pure. Warnings are added to the documentation of pure array methods that take this 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 by side.
  • 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 where x and y are char, 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 the Scope parameter. This is a breaking change because the &mut is now required.
  • Engine::allow_loop_expressions now correctly defaults to true (was erroneously false by default).

Enhancements

  • Engine::new_raw is now const and runs very fast, delaying all other initialization until first use.
  • The functions min and max 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

31 Dec 04:03
4c2630b
Compare
Choose a tag to compare

Bug fixes

  • Integer numbers that are too large to deserialize into INT now fall back to Decimal or FLOAT 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 exported 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 of Engine::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, overriding Engine::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 to this when calling a closure.
  • This vastly improves performance when working with arrays of large types (e.g. object maps) by avoiding unnecessary cloning.
  • find and find_map are added for arrays.
  • for_each is also added for arrays, allowing a closure to mutate array elements (bound to this) 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 under internals.
  • The TypeBuilder type and CustomType 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 and IndexMut are added to FnPtr.
  • FnPtr::iter_curry and FnPtr::iter_curry_mut are added.
  • Dynamic::deep_scan is added to recursively scan for Dynamic 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

11 Nov 07:37
af10825
Compare
Choose a tag to compare

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 inside eval no longer cause errors in subsequent code.
  • Functions marked global in imported modules with no alias names now work properly.
  • Incorrect loop optimizations that are too aggressive (e.g. unrolling a do { ... } until true with a break 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 of is_XXX() where XXX 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 and for) can now act as expressions, with the break 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 function rhai::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 via serde.

Store and recreate NativeCallContext

  • A convenient API is added to store a NativeCallContext into a new NativeCallContextStore 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 under unchecked.
  • 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

22 Sep 13:17
a5c3c11
Compare
Choose a tag to compare

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

10 Sep 06:30
a2f679b
Compare
Choose a tag to compare

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 of NativeCallContext.
  • 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 returning Result<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 to true) 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 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.

Enhancements

  • is_empty method is added to arrays, BLOB's, object maps, strings and ranges.
  • StaticModuleResolver now stores the path in the module's id field.
  • Engine::module_resolver is added to grant access to the Engine's module resolver.
  • Constants and variables now have types in generated definition files.

v1.9.1

29 Aug 15:39
186b6d0
Compare
Choose a tag to compare

This is a bug-fix version that fixes a bug.

Accessing properties in Strict Variables Mode no longer generates a variable not found error.

v1.9.0

21 Aug 08:53
00f84ef
Compare
Choose a tag to compare

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 to false (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 to import 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 current Engine.

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 the metadata feature) are now collected as the script file's module documentation.
  • AST and Module 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 the CustomType trait (which uses TypeBuilder to register the API functions).

Simpler Package API

  • It is now easier to register packages via the Package::register_into_engine and Package::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 and Expression::eval_with_context_raw are added to allow for not rewinding the Scope 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 and FnNameSpace::is_global_namespace are added for convenience.
  • Iterator<Item=T> type for functions metadata is simplified to Iterator<T>.
  • Scope::remove is added to remove a variable from a Scope, returning its value.
  • The code base is cleaner by running it through Clippy.
  • ParseError::err_type and ParseError::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

01 Jul 04:52
60e3661
Compare
Choose a tag to compare

This version includes a number of usability improvements, especially the Elvis operator ?. and null-coalescing operator ??.

Bug fixes

  • Self-contained AST now works properly with Engine::call_fn.
  • Missing to_int from Decimal 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 another AST 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 of FnPtr::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 and Engine::set_default_tag are added to manage a default value for the custom evaluation state, accessible via EvalState::tag() (which is the same as NativeCallContext::tag()). Closes #563
  • Originally, the debugger's custom state uses the same state as EvalState::tag() (which is the same as NativeCallContext::tag()). It is now split into its own variable accessible under Debugger::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.