14 KiB
Rhai Release Notes
Version 0.18.0
This version adds:
- Binding the
thispointer in a function pointercall. - Anonymous functions (in Rust closure syntax). Simplifies creation of single-use ad-hoc functions.
- Currying of function pointers.
- Auto-currying of anonymous functions.
- Capturing call scope via
func!(...)syntax.
New features
callcan now be called function-call style for function pointers - this is to handle builds withno_object.- Reserve language keywords, such as
print,eval,call,thisetc. x.call(f, ...)allows bindingxtothisfor the function referenced by the function pointerf.- Anonymous functions are supported in the syntax of a Rust closure, e.g.
|x, y, z| x + y - z. - Custom syntax now works even without the
internalsfeature. - Currying of function pointers is supported via the new
currykeyword. - Automatic currying of anonymous functions to capture environment variables.
- Capturing of the calling scope for function call via the
func!(...)syntax. Module::set_indexer_get_set_fnis added as a shorthand of bothModule::set_indexer_get_fnandModule::set_indexer_set_fn.- New
unicode-xid-identfeature to allow Unicode Standard Annex #31 for identifiers. Scope::iter_rawreturns an iterator with a reference to the underlyingDynamicvalue (which may be shared).
Breaking changes
- Language keywords are now reserved (even when disabled) and they can no longer be used as variable names.
- Function signature for defining custom syntax is simplified.
Engine::register_raw_fn_XXXAPI shortcuts are removed.PackagesCollection::get_fn,PackagesCollection::contains_fn,Module::get_fnandModule::contains_fnnow take an additionalpublic_onlyparameter indicating whether only public functions are accepted.- The iterator returned by
Scope::iternow contains a clone of theDynamicvalue (unshared). Engine::load_packagetakes any type that isInto<PackageLibrary>.
Housekeeping
- Most compilation warnings are eliminated via feature gates.
Version 0.17.0
This version adds:
serdesupport for working withDynamicvalues (particularly object maps).- Low-level API to register functions.
- Surgically disable keywords and/or operators in the language.
- Define custom operators.
- Extend the language via custom syntax.
Bug fixes
- Fixed method calls in the middle of a dot chain.
Breaking changes
EvalAltResult::ErrorMismatchOutputTypehas an extra argument containing the name of the requested type.Engine::call_fn_dynamictake an extra argument, allowing aDynamicvalue to be bound to thethispointer.- Precedence of the
%(modulo) operator is lowered to below<<ad>>. This is to handle the case ofx << 3 % 10.
New features
- New
serdefeature to allow serializing/deserializing to/fromDynamicvalues usingserde. This is particularly useful when converting a Ruststructto aDynamicobject map and back. Engine::disable_symbolto surgically disable keywords and/or operators.Engine::register_custom_operatorto define a custom operator.Engine::register_custom_syntaxto define a custom syntax.- New low-level API
Engine::register_raw_fn. - New low-level API
Module::set_raw_fnmirroringEngine::register_raw_fn. AST::clone_functions_only,AST::clone_functions_only_filteredandAST::clone_statements_onlyto clone only part of anAST.- The boolean
^(XOR) operator is added. FnPtris exposed as the function pointer type.rhai::module_resolvers::ModuleResolversCollectionadded to try a list of module resolvers.- It is now possible to mutate the first argument of a module-qualified function call when the argument is a simple variable (but not a module constant).
- Many configuration/setting API's now returns
&mut Selfso that the calls can be chained. Stringparameters in functions are supported (but inefficiently).
Version 0.16.1
Bug fix release to fix errors when compiling with features.
Version 0.16.0
The major new feature in this version is OOP - well, poor man's OOP, that is.
The README is officially transferred to The Rhai Book.
An online Playground is available.
Breaking changes
- The trait function
ModuleResolver::resolveno longer takes aScopeas argument. - Functions defined in script now differentiates between using method-call style and normal function-call style.
The method-call style will bind the object to the
thisparameter instead of consuming the first parameter. - Imported modules are no longer stored in the
Scope.Scope::push_moduleis removed. Therefore, cannot rely on module imports to persist across invocations using aScope. AST::retain_functionsis used for another purpose. The oldAST::retain_functionsis renamed toAST::clear_statements.
New features
- Support for function pointers via
Fn(name)andFn.call(...)syntax - a poor man's first-class function. - Support for calling script-defined functions in method-call style with
thisbinding to the object. - Special support in object maps for OOP.
- Expanded the
ASTAPI for fine-tuned manipulation of functions.
Enhancements
- The Rhai Book is online. Most content in the original
READMEwas transferred to the Book. - New feature
internalsto expose internal data structures (e.g. the AST nodes).
Version 0.15.1
This is a minor release which enables updating indexers (via registered indexer setters) and supports functions
with &str parameters (maps transparently to ImmutableString). WASM is also a tested target.
Bug fix
let s="abc"; s[1].change_to('X');now correctly sets the character 'X' into 's' yielding"aXc".
Breaking changes
- Callback closure passed to
Engine::on_progressnow takes&u64instead ofu64to be consistent with other callback signatures. Engine::register_indexeris renamed toEngine::register_indexer_get.Module::set_indexer_fnis renamed toModule::set_indexer_get_fn.- The tuple
ParseErrornow exposes the internal fields and theParseError::error_typeandParseError::positionmethods are removed. The first tuple field is theParseErrorTypeand the second tuple field is thePosition. Engine::call_fn_dynamicnow takes any type that implementsIntoIterator<Item = Dynamic>.
New features
- Indexers are now split into getters and setters (which now support updates). The API is split into
Engine::register_indexer_getandEngine::register_indexer_setwithEngine::register_indexer_get_setbeing a shorthand. Similarly,Module::set_indexer_get_fnandModule::set_indexer_set_fnare added. Engine:register_fnandEngine:register_result_fnaccepts functions that take parameters of type&str(immutable string slice), which maps directly toImmutableString. This is to avoid needing wrappers for functions taking string parameters.- Set maximum limit on data sizes:
Engine::set_max_string_size,Engine::set_max_array_sizeandEngine::set_max_map_size. - Supports trailing commas on array literals, object map literals, function definitions and function calls.
- Enhances support for compiling to WASM.
Version 0.15.0
This version uses immutable strings (ImmutableString type) and built-in operator functions (e.g. +, >, +=) to improve speed, plus some bug fixes.
Regression fix
- Do not optimize script with
eval_expression- it is assumed to be one-off and short.
Bug fixes
- Indexing with an index or dot expression now works property (it compiled wrongly before).
For example,
let s = "hello"; s[s.len-1] = 'x';now works property instead of causing a runtime error. ifexpressions are not supposed to be allowed when compiling for expressions only. This is fixed.
Breaking changes
Engine::compile_XXXfunctions now returnParseErrorinstead ofBox<ParseError>.- The
RegisterDynamicFntrait is merged into theRegisterResultFntrait which now always returnsResult<Dynamic, Box<EvalAltResult>>. - Default maximum limit on levels of nested function calls is fine-tuned and set to a different value.
- Some operator functions are now built in (see Speed enhancements below), so they are available even under
Engine::new_raw. - Strings are now immutable. The type
rhai::ImmutableStringis used instead ofstd::string::String. This is to avoid excessive cloning of strings. All native-Rust functions taking string parameters should switch torhai::ImmutableString(which is eitherRc<String>orArc<String>depending on whether thesyncfeature is used). - Native Rust functions registered with the
Enginealso mutates the first argument when called in normal function-call style (previously the first argument will be passed by value if not called in method-call style). Of course, if the first argument is a calculated value (e.g. result of an expression), then mutating it has no effect, but at least it is not cloned. - Some built-in methods (e.g.
lenfor string,floorforFLOAT) now have property versions in addition to methods to simplify coding.
New features
- Set limit on maximum level of nesting expressions and statements to avoid panics during parsing.
- New
EvalPackageto disableeval. Module::set_getter_fn,Module::set_setter_fnandModule:set_indexer_fnto register getter/setter/indexer functions.Engine::call_fn_dynamicfor more control in calling script functions.
Speed enhancements
- Common operators (e.g.
+,>,==) now call into highly efficient built-in implementations for standard types (i.e.INT,FLOAT,bool,char,()andImmutableString) if not overridden by a registered function. This yields a 5-10% speed benefit depending on script operator usage. Scripts running tight loops will see significant speed-up. - Common assignment operators (e.g.
+=,%=) now call into highly efficient built-in implementations for standard types (i.e.INT,FLOAT,bool,char,()andImmutableString) if not overridden by a registered function. - Implementations of common operators for standard types are removed from the
ArithmeticPackageandLogicPackage(and therefore theCorePackage) because they are now always available, even underEngine::new_raw. - Operator-assignment statements (e.g.
+=) are now handled directly and much faster. - Strings are now immutable and use the
rhai::ImmutableStringtype, eliminating large amounts of cloning. - For Native Rust functions taking a first
&mutparameter, the first argument is passed by reference instead of by value, even if not called in method-call style. This allows many functions declared with&mutparameter to avoid excessive cloning. For example, ifais a large array, getting its length in this manner:len(a)used to result in a full clone ofabefore taking the length and throwing the copy away. Now,ais simply passed by reference, avoiding the cloning altogether. - A custom hasher simply passes through
u64keys without hashing to avoid function call hash keys (which are by themselvesu64) being hashed twice.
Version 0.14.1
The major features for this release is modules, script resource limits, and speed improvements (mainly due to avoiding allocations).
New features
- Modules and module resolvers allow loading external scripts under a module namespace. A module can contain constant variables, Rust functions and Rhai functions.
exportvariables andprivatefunctions.- Indexers for Rust types.
- Track script evaluation progress and terminate script run.
- Set limit on maximum number of operations allowed per script run.
- Set limit on maximum number of modules loaded per script run.
- A new API,
Engine::compile_scripts_with_scope, can compile a list of script segments without needing to first concatenate them together into one large string. - Stepped
rangefunction with a custom step.
Speed improvements
StaticVec
A script contains many lists - statements in a block, arguments to a function call etc.
In a typical script, most of these lists tend to be short - e.g. the vast majority of function calls contain
fewer than 4 arguments, while most statement blocks have fewer than 4-5 statements, with one or two being
the most common. Before, dynamic Vec's are used to hold these short lists for very brief periods of time,
causing allocations churn.
In this version, large amounts of allocations are avoided by converting to a StaticVec -
a list type based on a static array for a small number of items (currently four) -
wherever possible plus other tricks. Most real-life scripts should see material speed increases.
Pre-computed variable lookups
Almost all variable lookups, as well as lookups in loaded modules, are now pre-computed. A variable's name is almost never used to search for the variable in the current scope.
Getters and setter function names are also pre-computed and cached, so no string allocations are performed during a property get/set call.
Pre-computed function call hashes
Lookup of all function calls, including Rust and Rhai ones, are now through pre-computed hashes. The function name is no longer used to search for a function, making function call dispatches much faster.
Large Boxes for expressions and statements
The expression (Expr) and statement (Stmt) types are modified so that all of the variants contain only
one single Box to a large allocated structure containing all the fields. This makes the Expr and
Stmt types very small (only one single pointer) and improves evaluation speed due to cache efficiency.
Error handling
Previously, when an error occurs inside a function call, the error position reported is the function call site. This makes it difficult to diagnose the actual location of the error within the function.
A new error variant EvalAltResult::ErrorInFunctionCall is added in this version.
It wraps the internal error returned by the called function, including the error position within the function.