27 KiB
Rhai Release Notes
Version 0.19.7
Bug fixes
- Fixes compilation errors with certain feature flag combinations.
Enhancements
- Property getters/setters and indexers defined in a plugin module are by default
#[rhai_fn(global)]. to_debugis a new standard function for converting a value into debug format.- Arrays and object maps now print values using
to_debug(if available).
Version 0.19.6
This version adds the switch statement.
It also allows exposing selected module functions (usually methods) to the global namespace. This is very convenient when encapsulating the API of a custom Rust type into a module while having methods and iterators registered on the custom type work normally.
A new gen_fn_signatures API enables enumerating the registered functions of an Engine for documentation purposes.
It also prepares the way for a future reflection API.
Bug fixes
- Custom syntax that introduces a shadowing variable now works properly.
Breaking changes
Module::set_fn,Module::set_raw_fnandModule::set_fn_XXX_mutall take an additional parameter ofFnNamespace.Module::set_fntakes a further parameter with a list of parameter names/types plus the function return type, if any.Module::get_sub_module_mutis removed.begin,end,unlessare now reserved keywords.EvalPackageis removed in favor ofEngine::disable_symbol.
New features
- New
switchstatement. - New
do ... whileanddo ... untilstatements. - New
Engine::gen_fn_signatures,Module::gen_fn_signaturesandPackagesCollection::gen_fn_signaturesto generate a list of signatures for functions registered. - New
Engine::register_moduleto register a module as a sub-module in the global namespace. - New
set_exported_global_fn!macro to register a plugin function and expose it to the global namespace. Module::set_fn_XXX_mutcan expose a module function to the global namespace. This is convenient when registering an API for a custom type.Module::set_getter_fn,Module::set_setter_fn,Module::set_indexer_get_fn,Module::set_indexer_set_fnall expose the function to the global namespace by default. This is convenient when registering an API for a custom type.- New
Module::update_fn_metadatato update a module function's parameter names and types. - New
#[rhai_fn(global)]and#[rhai_fn(internal)]attributes to determine whether a function defined in a plugin module should be exposed to the global namespace. This is convenient when defining an API for a custom type. - New
get_fn_metadata_listto get the metadata of all script-defined functions in scope.
Enhancements
- New constants under
DynamicincludingUNIT,TRUE,FALSE,ZERO,ONEetc. - Floating-point numbers ending with a decimal point without a trailing
0are supported.
Version 0.19.5
This version fixes a bug that prevents compilation with the internals feature.
It also speeds up importing modules.
Bug fixes
- Fixes compilation error when using the
internalsfeature. Bug introduced in0.19.4. - Importing script files recursively no longer panics.
Breaking changes
- Modules imported at global level can now be accessed in functions.
ModuleResolver::resolvenow returnsShared<Module>for better resources sharing when loading modules.ParseErrorType::DuplicatedExportis removed as multipleexport's are now allowed.
Enhancements
- Modules imported via
importstatements at global level can now be used in functions. There is no longer any need to re-importthe modules at the beginning of each function block. - Modules imported via
importstatements are encapsulated into theASTwhen loading a module from a script file. exportkeyword can now be tagged ontoletandconststatements as a short-hand, e.g.:export let x = 42;- Variables can now be
export-ed multiple times under different names. index_of,==and!=are defined for arrays.==and!=are defined for object maps.
Version 0.19.4
This version basically cleans up the code structure in preparation for a potential 1.0 release in the future.
Most scripts should see a material speed increase.
This version also adds a low-level API for more flexibility when defining custom syntax.
Bug fixes
- Fixes
Send + SyncforEvalAltResultunder thesyncfeature. Bug introduced with0.19.3.
Breaking changes
- Custom syntax can no longer start with a keyword (even a reserved one), even if it has been disabled. That is to avoid breaking scripts later when the keyword is no longer disabled.
Changes to Error Handling
EvalAltResult::ErrorAssignmentToUnknownLHSis moved toParseError::AssignmentToInvalidLHS.ParseError::AssignmentToCopyis removed.EvalAltResult::ErrorDataTooLargeis simplified.Engine::on_progressclosure signature now returnsOption<Dynamic>with the termination value passed on toEvalAltResult::ErrorTerminated.ParseErrorType::BadInputnow wraps aLexErrorinstead of a text string.
New features
f32_floatfeature to setFLOATtof32.- Low-level API for custom syntax allowing more flexibility in designing the syntax.
Module::fill_withto poly-fill a module with another.- Scripts terminated via
Engine::on_progresscan now pass on a value as a termination token.
Enhancements
- Essential AST structures like
ExprandStmtare packed into smaller sizes (16 bytes and 32 bytes on 64-bit), stored inline for more cache friendliness, and de-Boxed as much as possible. Scopeis optimized for cache friendliness.
Version 0.19.3
This version streamlines some of the advanced API's, and adds the try ... catch statement
to catch exceptions.
Breaking changes
EvalAltResult::ErrorReadingScriptFileis removed in favor of the newEvalAltResult::ErrorSystem.EvalAltResult::ErrorLoopBreakis renamed toEvalAltResult::LoopBreak.Engine::register_raw_fnandFnPtr::call_dynamicfunction signatures have changed.- Callback signatures to
Engine::on_varandEngine::register_custom_syntaxhave changed. EvalAltResult::ErrorRuntimenow wraps aDynamicinstead of a string.- Default call stack depth for
debugbuilds is reduced to 8 (from 12) because it keeps overflowing the stack in GitHub CI! - Keyword
threadis reserved.
New features
- The plugins system is enhanced to support functions taking a
NativeCallContextas the first parameter. throwstatement can now throw any value instead of just text strings.- New
try...catchstatement to catch exceptions.
Enhancements
- Calling
evalorFnin method-call style, which is an error, is now caught during parsing. func!()call style is valid even underno_closurefeature.
Version 0.19.2
Bug fix on call module functions.
Version 0.19.1
This version adds a variable resolver with the ability to short-circuit variable access, plus a whole bunch of array methods.
Breaking changes
AST::iter_functionsnow returns an iterator instead of taking a closure.Module::get_script_function_by_signaturerenamed toModule::get_script_fnand returns&<Shared<ScriptFnDef>>.Module::num_fn,Module::num_varandModule::num_iterare removed and merged intoModule::count.- The
merge_namespacesparameter toModule::eval_ast_as_newis removed and now defaults totrue. GlobalFileModuleResolveris removed because its performance gain over theFileModuleResolveris no longer very significant.- The following
EvalAltResultvariants are removed and merged intoEvalAltResult::ErrorMismatchDataType:ErrorCharMismatch,ErrorNumericIndexExpr,ErrorStringIndexExpr,ErrorImportExpr,ErrorLogicGuard,ErrorBooleanArgMismatch Scope::iter_rawreturns an iterator with an additional field indicating whether the variable is constant or not.rhai::serandrhai::denamespaces are merged intorhai::serde.- New reserved symbols:
++,--,..,.... - Callback signature for custom syntax implementation function is changed to allow for more flexibility.
- Default call stack depth for
debugbuilds is reduced to 12 (from 16). - Precedence for
~is raised, whileinis moved below logic comparison operators.
New features
- New
Engine::on_varto register a variable resolver. conststatements can now take any expression (or none at all) instead of only constant values.OptimizationLevel::Simplenow eagerly evaluates built-in binary operators of primary types (if not overloaded).is_def_var()to detect if variable is defined, andis_def_fn()to detect if script function is defined.Dynamic::from(&str)now constructs aDynamicwith a copy of the string as value.AST::combineandAST::combine_filteredallows combining twoAST's without creating a new one.map,filter,reduce,reduce_rev,some,all,extract,splice,chopandsortfunctions for arrays.- New
Module::set_iterableandModule::set_iteratorto define type iterators more easily.Engine::register_iteratoris changed to use the simpler version.
Enhancements
- Many one-liners and few-liners are now marked
#[inline]or[inline(always)], just in case it helps when LTO is not turned on.
Version 0.19.0
The major new feature for this version is Plugins support, powered by procedural macros.
Plugins make it extremely easy to develop and register Rust functions with an Engine.
Bug fixes
ifstatement with an emptytrueblock would not evaluate thefalseblock. This is now fixed.- Fixes a bug in
Module::set_fn_4_mut. - Module API's now properly handle
&strandStringparameters. - Indexers are available under
no_object. - Registered operator-assignment functions (e.g.
+=) now work correctly.
Breaking changes
Engine::register_set_resultandEngine::register_indexer_set_resultnow take a function that returnsResult<(), Box<EvalAltResult>>.Engine::register_indexer_XXXandModule::set_indexer_XXXpanic when the type isArray,MaporString.EvalAltResulthas a new variantErrorInModulewhich holds errors when loading an external module.Module::eval_ast_as_newnow takes an extra boolean parameter, indicating whether to encapsulate the entire module into a separate namespace.- Functions in
FileModuleResolverloaded modules now can cross-call each other in addition to functions in the global namespace. For the old behavior, useMergingFileModuleResolverinstead. - New
EvalAltResult::ErrorInModulevariant capturing errors when loading a module from a script file.
New features
- Plugins support via procedural macros.
- Scripted functions are allowed in packages.
parse_intandparse_floatfunctions for parsing numbers;splitfunction for splitting strings.AST::iter_functionsandModule::iter_script_fn_infoto iterate functions.- Functions iteration functions for
ASTandModulenow takeFnMutinstead ofFn. - New
FileModuleResolverthat encapsulates the entireASTof the module script, allowing function cross-calling. The old version is renamedMergingFileModuleResolver. +and-operators for timestamps to increment/decrement by seconds.
Version 0.18.3
Bug fixes
Engine::compile_expression,Engine::eval_expressionetc. no longer parse anonymous functions and closures.- Imported modules now work inside closures.
- Closures that capture now work under
no_object.
New features
- Adds
Module::combine_flattento combine two modules while flattening to the root level.
Version 0.18.2
Bug fixes
- Fixes bug that prevents calling functions in closures.
- Fixes bug that erroneously consumes the first argument to a namespace-qualified function call.
New features
- Adds
Engine::register_get_result,Engine::register_set_result,Engine::register_indexer_get_result,Engine::register_indexer_set_resultAPI. - Adds
Module::combineto combine two modules. Engine::parse_jsonnow also accepts a JSON object starting with#{.
Version 0.18.1
This version adds:
- Anonymous functions (in Rust closure syntax). Simplifies creation of single-use ad-hoc functions.
- Currying of function pointers.
- Closures - auto-currying of anonymous functions to capture shared variables from the external scope. Use the
no_closurefeature to disable sharing values and capturing. - Binding the
thispointer in a function pointercall. - 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 shared variables from the external scope.
- Capturing of the calling scope for function call via the
func!(...)syntax. Module::set_indexer_get_set_fnis added as a short-hand 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>.- Error in
Engine::register_custom_syntaxis no longerBox-ed.
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 namespace-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 short-hand. 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.