Rhai - An embedded scripting language for Rust.

Overview

Rhai - Embedded Scripting for Rust

GitHub last commit Build Status license crates.io crates.io API Docs chat Reddit

Rhai logo

Rhai is an embedded scripting language and evaluation engine for Rust that gives a safe and easy way to add scripting to any application.

Supported targets and builds

  • All common CPU targets for Windows, Linux and MacOS.
  • WebAssembly (WASM)
  • no-std
  • Minimum Rust version 1.49

Standard features

  • Simple language similar to JavaScript+Rust with dynamic typing.
  • Fairly efficient evaluation (1 million iterations in 0.3 sec on a single-core, 2.3 GHz Linux VM).
  • Tight integration with native Rust functions and types, including getters/setters, methods and indexers.
  • Freely pass Rust variables/constants into a script via an external Scope - all clonable Rust types are supported; no need to implement any special trait.
  • Built-in support for most common data types including booleans, integers, floating-point numbers (including Decimal), strings, Unicode characters, arrays and maps.
  • Easily call a script-defined function from Rust.
  • Relatively little unsafe code (yes there are some for performance reasons).
  • Few dependencies (currently only smallvec and ahash).
  • Re-entrant scripting engine can be made Send + Sync (via the sync feature).
  • Compile once to AST form for repeated evaluations.
  • Scripts are optimized (useful for template-based machine-generated scripts).
  • Easy custom API development via plugins system powered by procedural macros.
  • Function overloading and operator overloading.
  • Dynamic dispatch via function pointers with additional support for currying.
  • Closures (anonymous functions) that can capture shared values.
  • Some syntactic support for object-oriented programming (OOP).
  • Organize code base with dynamically-loadable modules, optionally overriding the resolution process
  • Serialization/deserialization support via serde (requires the serde feature).
  • Support for minimal builds by excluding unneeded language features.

Protected against attacks

  • Sand-boxed - the scripting engine, if declared immutable, cannot mutate the containing environment unless explicitly permitted.
  • Rugged - protected against malicious attacks (such as stack-overflow, over-sized data, and runaway scripts etc.) that may come from untrusted third-party user-land scripts.
  • Track script evaluation progress and manually terminate a script run.

For those who actually want their own language

Documentation

See The Rhai Book for details on the Rhai scripting engine and language.

Playground

An Online Playground is available with syntax-highlighting editor, powered by WebAssembly.

Scripts can be evaluated directly from the editor.

License

Licensed under either of the following, at your choice:

Unless explicitly stated otherwise, any contribution intentionally submitted for inclusion in this crate, as defined in the Apache-2.0 license, shall be dual-licensed as above, without any additional terms or conditions.

Comments
  • Rhai playground (using WebAssembly)

    Rhai playground (using WebAssembly)

    The idea is to make a playground for Rhai scripts that runs in a web browser which can showcase the features of the Rhai scripting language. It might also be possible for others to repurpose it as a Rhai script editor.

    I've started an attempt on https://github.com/alvinhochun/rhai-playground, but I am not making any promises. The master branch gets automatically built and deployed to: https://alvinhochun.github.io/rhai-playground-unstable/ I might irregularly upload specific builds to: https://alvinhochun.github.io/rhai-demo/

    Wish list (not a roadmap or to-do list):

    • [X] Ability to run Rhai scripts
    • [x] Proper syntax handling for Rhai scripts
    • [ ] Real-time AST compilation with error reporting (already works though pretty limited)
    • [ ] Integration with the book (embedding is now possible)
    • [ ] REPL
    • [ ] Autocomplete list for built-in packages
    • [ ] Provide more fancy IDE-like features
    • [ ] Engine settings
    • [ ] Custom modules
    • [ ] Heuristically guess variable types?
    • [ ] Debugging
    opened by alvinhochun 75
  • no_std error

    no_std error

    I keep getting can't find crate for std even with "no_std" feature

    [dependencies.rhai]
    git = "https://github.com/jonathandturner/rhai"
    features = ["no_std"]
    default-features = false
    

    Here is some of the output

    Blocking waiting for file lock on build directory
       Compiling core-error v0.0.0
       Compiling stm32f4 v0.11.0
    error[E0463]: can't find crate for `std`
      |                                                                                                                                  ing waiting for file lock on package cache
      = note: the `thumbv7em-none-eabihf` target may not be installed
    
    error: aborting due to previous error
    
    For more information about this error, try `rustc --explain E0463`.
    error: could not compile `core-error`.
    
    To learn more, run the command again with --verbose.
    warning: build failed, waiting for other jobs to finish...
    error: build failed
    
    bug 
    opened by ahmtcn123 47
  • [Question] How do I save rhai callbacks?

    [Question] How do I save rhai callbacks?

    Hey, I am trying to register a function that takes a rhai function as parameter and saves it in a struct, so that I can later call it. I am currently very confused and I don't know what I should do to achieve my goal.

    Should I save the AST of the function and later evaluate it?

    Setup

    engine.register_fn(
        "popup_new",
        |options: Map| {
            let mut p = Popup::new();
    
            for (key, val) in options {
                match key.as_str() {
                    // ... other stuff
                    "actions" => {
                        let actions = val.cast::<Array>();
                        
                        for action in actions {
                            let settings = action.cast::<Map>();
                            let mut action = PopupAction::default();
    
                            for (key, val) in settings {
                                match key.as_str() {
                                    "text" => { action.text = val.to_string(); },
                                    "cb" => { 
                                         // what do I do here?
                                    },
                                    _ => {}
                                };
                            }
                        }
                    }
                };
            }
        },
    )
    

    Usage

    popup_new(#{
        text: ["Checking for updates..."],
        padding: 5,
        actions: [#{
            text: "Update",
            cb: || { 
                print("Updating") 
            }
        }]
    });
    

    Thank you!

    bug question 
    opened by TimUntersberger 46
  • `DynamicWriteLock` used but not exposed in public API

    `DynamicWriteLock` used but not exposed in public API

    When creating a dynamic shared between the script and external environment, it's often convenient to create wrapper APIs for functions that do some of the heavy-lifted cast magic:

    struct Context {
        value: rhai::Dynamic,
    }
    
    impl Context {
        fn value(&self) -> rhai::INT {
            self.value.as_int().unwrap()
        }
    
        fn cooldown_mut(&self) -> rhai::dynamic::DynamicWriteLock<rhai::INT> {
            self.value.write_lock::<rhai::INT>().unwrap()
        }
    }
    

    However, DynamicWriteLock is not accessible, despite its use in the public API:

    error[E0603]: module `dynamic` is private
    
    enhancement 
    opened by CJKay 39
  • Structural data construction and anonymous functions without closures

    Structural data construction and anonymous functions without closures

    Hello!

    I'm very impressed with Rhai project, and especially because of it's minimalistic design, transparent interoperability with Rust and active development. In my opinion Rhai is the best choice for Rust embedding scripting among other options we currently have in Rust ecosystem. And I'm going to use Rhai in my personal project of 3D procedural modelling toolkit based on ray marching of signed-distance fields. The scripting will be used for high-level scene live coding in my project.

    The scene itself consists of a hierarchy of domain specific objects describing various 3D primitives, their combinations and a lot of effects applied on top of them. And is currently constructing using Rust functions that I would like to export(at least partially) into Rhai context.

    There are practically two issues that I faced between my design and Rhai interoperability limitations. Let me show an example of a scene code in Rust:

    
    // starting scene description
    // "space" is a context of the current subspace of the scene
    Primitive::scene(|space| {
    
        space
            .view() // receiving &mut reference to the model view related to the current "space"
            .translate(1.5); // Mutating model view matrix
    
        space
            .add_spape(&Ellipsoid::sphere(1.0)) // creating a Sphere in the current context
            .union(|space| { // entering into a new inner context related to the just added shape of the outer context
                ... // similar operation with the inner context
            });
    
    });
    
    

    So, the first issue is that in Rhai we can't return &mut reference to the object. This is actually not a big deal as I can provide a setter instead of "&mut" getter to redefine(or update) owned property of the space object.

    But the second issue is actual hierarchical structures encoding. Entering into a new "space" scope as shown in my example above as far as I understand is not achievable in Rhai, because it doesn't have anonymous functions. In #159 @schungx mentioned that it would be easy to add such functions without closures, but he said without closures they are not really useful. I want to say that in my particular case they would be VERY useful even without closures. I don't practically use closures to the upper context that much. So, if you can include simplified syntax version in prior-1.0 release that would be very helpful.

    Also, as I understood from The Book, it is possible to deal with the context through the this variable inside a "method" function, but I didn't realize how to access(and especially how to "shadow") this in the registered functions if it's even possible.

    Since my project is in relatively early stage, I'm fine to slightly change my API design to better fit Rhai design requirements. I will be appreciated for your help and advices. My goal is to have a long-term cooperation with the project teams my project is related to. So if you need my contribution to Rhai, I will be glad to participate too.

    Thanks in advance!

    Ilya.

    opened by Eliah-Lakhin 39
  • Compiling Rhai to WASM

    Compiling Rhai to WASM

    I'm asking specifically for the wasm32-unknown-unknown target on web browser using wasm-pack. It looks like there should be nothing preventing Rhai from working, but since it is not explicitly stated anywhere I think I should ask.

    enhancement 
    opened by alvinhochun 38
  • Allow functions to access global imports

    Allow functions to access global imports

    Splitting functionality up into multiple files is a bit annoying right now.

    Example

    main.rhai

    fn test1() {
      import "mod" as M;
    
      M::echo();
    }
    
    fn test2() {
      import "mod" as M;
    
      M::echo();
    }
    

    mod.rhai

    fn echo() {
      print("Hello World");
    }
    

    Having to write the import statement twice is really ugly and a bit annoying to write. Is there a way to write the main.rhai file like this?

    main.rhai

    import "mod" as M;
    
    fn test1() {
      M::echo();
    }
    
    fn test2() {
      M::echo();
    }
    

    Using the namespace merging feature makes this a bit more bearable, but requires you to scope your functions with prefixes.

    Any ideas?

    enhancement 
    opened by TimUntersberger 32
  • Use cargo features additively.

    Use cargo features additively.

    Adding more Cargo features should bring in more code and features, not less. Also adding a Cargo feature should almost never break existing scripts.

    With a major semver bump, I suggest to make the following changes:

    no_std

    Reverse it to std.

    plugins

    I don't know what it is, probably leave it as is.

    unchecked

    Reverse to checked.

    sync

    Leave as is.

    no_optimize

    Reverse to optimize. Maybe rhai::OptimizationLevel::None should be available even without it.

    no_float

    Reverse to float

    only_i32 only_i64

    This one is tricky. There should probably be integer feature that enables all integer types and also i32 and i64 features that selectively enable those types.

    integer should imply (but not be limited to) i32 + i64.

    A compile error should be emitted if none of three features (i32, i64, integers) are activated, unless Rhai can work without integers at all.

    It should be OK to activate both i32 and i64 features without integer feature.

    no_index

    Reverse to index.

    no_object

    Reverse to object

    no_function

    Reverse to function

    no_module

    Reverse to module.

    internals

    Leave as is.

    default = []

    default=["std","module","function","object","index","integer","float","optimize","checked","plugins?"]
    

    Additionally, I think keywords from missing features should still be reserved in scripts (unless explicitly configured otherwise from the Rust side), to avoid typical Rhai scripts breaking when a feature suddenly gets turned on from afar.

    wontfix 
    opened by vi 32
  • Advice for adding rust_decimal support

    Advice for adding rust_decimal support

    I'm looking to use Rhai for scripting in a financial application and I'm starting to research how I can add rust_decimal support to the runtime.

    Best case scenario for me is that all decimal literals are stored as a Decimal type. In my case I want to disable floating point support (which is already possible with features gates) and enable Decimal support.

    Does anyone have advice on the various approaches I can take?

    opened by bheylin 30
  • How to use with no-std

    How to use with no-std

    I'm trying out rust on a cheap microcontroller following this tutorial https://polyfractal.com/post/rustl8710/

    The tutorial works great and the sample echo program runs over serial.

    I'd love to add in a rust scripting language and I really like the design of Rhai. But when I add the library, the compile fails because of std is missing.

    info: using existing install for 'nightly-x86_64-unknown-linux-gnu'
    info: override toolchain for '/home/tim/rustl8710/src/rust' set to 'nightly-x86_64-unknown-linux-gnu'
    
      nightly-x86_64-unknown-linux-gnu unchanged - rustc 1.16.0-nightly (4ce7accaa 2017-01-17)
    
    cd src/rust && xargo build --target thumbv7m-none-eabi
       Compiling rhai v0.4.0
    error[E0463]: can't find crate for `std`
      |
      = note: the `thumbv7m-none-eabi` target may not be installed
    

    I'm fairly new to rust still and am not quite clear on what this all means. Is Rhai meant to be used in such embedded use cases? It sure would be neat if it or something like it did work.

    enhancement 
    opened by creationix 30
  • objects in rhai

    objects in rhai

    I see documentation on how to define structs in Rust and then make them available for use in Rhai. These structs can have fields that are accessible with dot notation, e.g:

    let foo = new_ts(); // new_ts() is a Rust-defined fn that returns a Rust-defined struct
    foo.bar = 5;
    

    Is there any way to create an object in Rhai without first having to define it in Rust? I'm looking for something like Javascript's objects which allow you do something like this:

    var foo = { bar: 0 };
    foo.bar = 5;
    

    Is this on the roadmap for Rhai?

    enhancement 
    opened by brianwp3000 29
  • Using `clippy`

    Using `clippy`

    :wave:

    I added these line to lib.rs :

    #![warn(clippy::all)]
    #![warn(clippy::pedantic)]
    #![warn(clippy::nursery)]
    #![warn(clippy::cargo)]
    

    And there is quite a lot of warnings (1K+)

    Do you think these should be addressed ?

    opened by Mathieu-Lala 1
  • Arena/Allocator for Dynamic types

    Arena/Allocator for Dynamic types

    I've been browsing the code, but cannot seem to find the use for the double allocation, What's the purpose of it?

    This effectively means there are three indirection layers between the consumer and the underlying type:

    • &dyn
    • Box
    • Box
    enhancement 
    opened by makspll 11
  • Consider adding to github/linguist

    Consider adding to github/linguist

    I noticed that .rhai files don't have any highlighting on github, and that no issues exist about this yet. Github's highlighting is powered by github/linguist, and they allow people to submit new languages if they're popular enough (used in >200 repos). Unfortunately github's search is pretty broken atm so I'm not sure how many repositories rhai is in.

    Until github supports it, throwing this in a repo's .gitattributes will highlight it by pretending it's rust:

    *.rhai linguist-language=Rust
    
    enhancement 
    opened by Purpzie 6
  • Type hints

    Type hints

    I'm in the middle of writing the LSP server I mentioned in #268, and in order to provide more useful information (such as field completions), some kind of type system is essential. Right now I'm planning HM-style type inference and external type definitions for modules just like it is in TypeScript's .d.ts files, but allowing users to define types for function signatures and let/const bindings inline would be very useful.

    Would it be possible (acceptable) to add optional type hint syntax in Rhai? I am thinking along the lines of Python's type hints, or a much simpler version of TypeScript's type system.

    Type hints would only serve the users and static analyzers, and they could be completely stripped when a script is compiled.

    I don't have exact fleshed-out proposal for this yet as I will have to experiment more in the LSP project first, but I would like to see something like this supported in Rhai in the future.

    new feature 
    opened by tamasfe 4
  • Rhai standard library.

    Rhai standard library.

    There currently seems to be no plugin/library that allows giving rhai scripts full system access by allowing them to do things like spawning subprocesses or doing filesystem operations. Is something like this planned as an optional feature or has someone already made this as a seperate crate?

    help wanted new feature 
    opened by LordMZTE 8
Releases(v1.11.0)
  • v1.11.0(Nov 11, 2022)

    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.
    Source code(tar.gz)
    Source code(zip)
  • v1.10.1(Sep 22, 2022)

    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.
    Source code(tar.gz)
    Source code(zip)
  • v1.10.0(Sep 10, 2022)

    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.
    Source code(tar.gz)
    Source code(zip)
  • v1.9.1(Aug 29, 2022)

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

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

    Source code(tar.gz)
    Source code(zip)
  • v1.9.0(Aug 21, 2022)

    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.
    Source code(tar.gz)
    Source code(zip)
  • v1.8.0(Jul 1, 2022)

    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.
    Source code(tar.gz)
    Source code(zip)
  • v1.7.0(May 4, 2022)

    This release is primarily minor functionality and API enhancements.

    Bug fixes

    • Compound assignments now work properly with indexers.
    • Cloning a Scope no longer turns all constants to mutable.

    Script-breaking changes

    • Strict Variables Mode no longer returns an error when an undeclared variable matches a variable/constant in the provided external Scope.

    Potentially breaking API changes

    • The Engine::on_var and Engine::on_parse_token API's are now marked unstable/volatile.
    • The closures passed to Engine::on_var, Engine::on_def_var and Engine::register_debugger take EvalContext instead of &EvalContext or &mut EvalContext.
    • The following enum's are marked non_exhaustive: AccessMode, FnAccess, FnNamespace, FnMetadata, OptimizationLevel

    New API

    • Module::eval_ast_as_new_raw is made public as a low-level API.
    • format_map_as_json is provided globally, which is the same as to_json for object maps.
    • Engine::call_fn_raw_raw is added to add speed to repeated function calls.
    • Engine::eval_statements_raw is added to evaluate a sequence of statements.

    New features

    • A custom state is provided that is persistent during the entire evaluation run. This custom state is a Dynamic, which can hold any data, and can be accessed by the host via EvalContext::tag, EvalContext::tag_mut, NativeCallContext::tag and GlobalRuntimeState.tag.

    Enhancements

    • Improper switch case condition syntax is now caught at parse time.
    • Engine::parse_json now natively handles nested JSON inputs (using a token remap filter) without needing to replace { with #{.
    • to_json is added to object maps to cheaply convert it to JSON format (() is mapped to null, all other data types must be supported by JSON)
    • FileModuleResolver now accepts a custom Scope to provide constants for optimization.
    • New variants, Start and End, are added to DebuggerEvent triggered at the start/end of script evaluation.
    Source code(tar.gz)
    Source code(zip)
  • v1.6.1(Apr 11, 2022)

    This is a minor bug-fix release Bug fixes

    • Functions with Dynamic parameters now work in qualified calls from imported modules.
    • rhai-repl now compiles with the new patch version of rustyline.
    • rhai_codegen dependency is now explicitly 1.4 or higher.

    Script-breaking changes

    • split now splits a string by whitespaces instead of splitting it into individual characters. This is more in line with common practices.
    • A new function to_chars for strings is added to split the string into individual characters.

    Enhancements

    • Strings are now directly iterable (via for .. in) yielding individual characters.
    Source code(tar.gz)
    Source code(zip)
  • v1.6.0(Mar 30, 2022)

    This version, in particular, fixes a plugin macro hygiene error for the nightly compiler:

    error[E0425]: cannot find value `args` in this scope
    

    rhai_codegen needs to be version 1.4.0. Run cargo update if it is a lower version.

    Compiler version

    • Minimum compiler version is now 1.57 due to smartstring dependency.

    Bug fixes

    • Fixed macro hygiene error with nightly compiler.
    • Invalid property or method access such as a.b::c.d or a.b::func() no longer panics but properly returns a syntax error.
    • Scope::is_constant now returns the correct value.
    • Exporting a variable that contains a local function pointer (including anonymous function or closure) now raises a runtime error.
    • Full optimization is now skipped for method calls.

    New features

    • Type aliases in plugin modules are now used as friendly names for custom types. This makes plugin modules more self-contained when they are used to define a custom type's API.

    Enhancements

    • Variable definitions are optimized so that shadowed variables are reused as much as possible to reduce memory consumption.
    • FnAccess and FnNamespace now implement Ord and PartialOrd.
    • The event_handler_map example is enhanced to prevent shadowing of the state object map.
    • Separation of constants in function calls is removed as its performance benefit is dubious.
    • A function sleep is added to block the current thread by a specified number of seconds.
    • Scope::set_alias is added to export a variable under a particular alias name.
    • starts_with and ends_with are added for strings.
    • Variables in modules registered via register_global_module can now be accessed in the global namespace.
    • Dynamic::into_read_only is added to convert a Dynamic value into constant.
    • Module now holds a collection of custom types with an API.
    Source code(tar.gz)
    Source code(zip)
  • v1.5.0(Feb 15, 2022)

    This version adds a debugging interface, which can be used to integrate a debugger.

    Based on popular demand, an option is added to throw exceptions when invalid properties are accessed on object maps (default is to return ()).

    Also based on popular demand, the REPL tool now uses a slightly enhanced version of rustyline for line editing and history.

    Bug fixes

    • In Scope::clone_visible, constants are now properly cloned as constants.
    • Variables introduced inside try blocks are now properly cleaned up upon an exception.
    • Off-by-one error in character positions after a comment line is now fixed.
    • Globally-defined constants are now encapsulated correctly inside a loaded module and no longer spill across call boundaries.
    • Type names display is fixed.
    • Exceptions thrown inside function calls now unwrap correctly when catch-ed.
    • Error messages for certain invalid property accesses are fixed.

    Script-breaking changes

    • For consistency with the import statement, the export statement no longer exports multiple variables.
    • Appending a BLOB to a string (via +, +=, append or string interpolation) now treats the BLOB as a UTF-8 encoded string.
    • Appending a string/character to a BLOB (via += or append) now adds the string/character as a UTF-8 encoded byte stream.

    New features

    • A debugging interface is added.
    • A new bin tool, rhai-dbg (aka The Rhai Debugger), is added to showcase the debugging interface.
    • A new package, DebuggingPackage, is added which contains the back_trace function to get the current call stack anywhere in a script.
    • Engine::set_fail_on_invalid_map_property is added to control whether to raise an error (new EvalAltResult::ErrorPropertyNotFound) when invalid properties are accessed on object maps.
    • Engine::set_allow_shadowing is added to allow/disallow variables shadowing, with new errors EvalAltResult::ErrorVariableExists and ParseErrorType::VariableExists.
    • Engine::on_def_var allows registering a closure which can decide whether a variable definition is allow to continue, during compilation or runtime, or should fail with an error (ParseErrorType::ForbiddenVariable or EvalAltResult::ErrorForbiddenVariable).
    • A new syntax for defining custom packages is introduced that removes the need to specify the Rhai crate name (internally uses the $crate meta variable).

    Enhancements

    • Default features for dependencies (such as ahash/std and num-traits/std) are no longer required.
    • The no_module feature now eliminates large sections of code via feature gates.
    • Debug display of AST is improved.
    • NativeCallContext::call_level() is added to give the current nesting level of function calls.
    • A new feature, bin-features, pulls in all the required features for bin tools.
    • AST position display is improved:
      • Expr::start_position is added to give the beginning of the expression (not the operator's position).
      • StmtBlock and Stmt::Block now keep the position of the closing } as well.
    • EvalAltResult::unwrap_inner is added to access the base error inside multiple layers of wrappings (e.g. EvalAltResult::ErrorInFunction).
    • Yet another new syntax is introduced for def_package! that further simplifies the old syntax.
    • A new method to_blob is added to convert a string into a BLOB as UTF-8 encoded bytes.
    • A new method to_array is added to convert a BLOB into array of integers.

    REPL tool changes

    The REPL bin tool, rhai-rpl, has been enhanced.

    Build changes

    • The rustyline feature is now required in order to build rhai-repl.
    • Therefore, rhai-repl is no longer automatically built when using a simple cargo build with default features.

    Line editor

    • rhai-repl now uses a modified version of rustyline as a line editor with history.
    • Ctrl-Enter can now be used to enter multiple lines without having to attach the \ continuation character the end of each line.
    • Bracketed paste is supported, even on Windows (version 10 or above), so pasting code directly into rhai-repl is made much more convenient.

    New commands

    • strict to turn on/off Strict Variables Mode.
    • optimize to turn on/off script optimization.
    • history to print lines history.
    • !!, !num, !text and !?text to recall a history line.
    • keys to print all key bindings.
    Source code(tar.gz)
    Source code(zip)
  • v1.4.1(Jan 23, 2022)

    This is primarily a bug-fix version which fixes a large number of bugs.

    Bug fixes

    • Expressions such as x = x + 1 no longer panics.
    • Padding arrays with another array via pad no longer loops indefinitely.
    • chop for arrays and BLOB's now works properly.
    • set_bit for bit-flags with negative index now works correctly.
    • Misnamed params field name in the JSON output of Engine::gen_fn_metadata_to_json is fixed (was incorrectly named type).
    • Fixes a potential unsafe violation in for loop.
    • Missing to_hex, to_octal and to_binary for i128 and u128 are added.
    • remove for arrays and BLOB's now treat negative index correctly.
    • parse_int now works properly for negative numbers.
    • Engine::gen_fn_signatures now generates signatures for external packages registered via Engine::register_global_module.
    • \r\n pairs are now recognized correctly for doc-comments.

    Enhancements

    • Formatting of return types in functions metadata info is improved.
    • Use SmartString for Scope variable names and remove unsafe lifetime casting.
    • Functions in the standard library now have doc-comments (which can be obtained via Engine::gen_fn_metadata_to_json).
    • get and set methods are added to arrays, BLOB's, object maps and strings.
    Source code(tar.gz)
    Source code(zip)
  • v1.4.0(Jan 11, 2022)

    This version adds support for integer ranges via the .. and ..= operators. Many standard API's are extended with range parameters where appropriate.

    A number of usability improvements simplify integration with Rust.

    Script-breaking changes

    • is is (pun intended) now a reserved keyword to prepare for possible future type checking expressions (e.g. x is "string").

    Breaking changes

    • LogicPackage is removed from CorePackage.
    • Bit-field functions are moved into a new BitFieldPackage (used to be in LogicPackage) which makes more sense.

    Bug fixes

    • Custom syntax now works properly inside binary expressions and with method calls.
    • Hex numbers with the high-bit set now parse correctly into negative integer numbers.
    • Constructing a literal array or object map now checks for size limits for each item instead of at the very end when it is already too late.
    • Non-INT integer types are now treated exactly as custom types under only_i64 and only_i32.
    • Calling pad on an array now checks for total size over limit after each item added.

    New features

    • Added support for integer ranges via the .. and ..= operators.
    • Added EvalAltResult::ErrorCustomSyntax to catch errors in custom syntax, which should not happen unless an AST is compiled on one Engine but evaluated on another unrelated Engine.

    Enhancements

    • BLOB's are refined to display in a more compact hex format.
    • A new syntax is introduced for def_package! that will replace the old syntax in future versions.
    • Added NativeCallContext::call_fn to easily call a function.
    • Doc-comments on plugin module functions are extracted into the functions' metadata.

    Deprecated API's

    • Expression::get_variable_name is deprecated in favor of the new Expression::get_string_value.
    • The old syntax of def_package! is deprecated in favor of the new syntax.
    Source code(tar.gz)
    Source code(zip)
  • v1.3.0(Dec 12, 2021)

    Version 1.3.0 released to crates.io.

    This version adds native support for BLOB's (byte arrays), as well as a number of configuration settings to fine-tun language features.

    Compiler requirement

    • Minimum compiler version is now 1.51.

    Bug fixes

    • from_dynamic now supports deserializing Option.

    New features

    • BLOB (essentially a byte array) is added as a supported primitive value type parallel to arrays.
    • New options for Engine which allows disabling if-expressions, switch-expressions, statement expressions, anonymous functions and/or looping (i.e. while, loop, do and for statements):
      • Engine::set_allow_if_expression
      • Engine::set_allow_switch_expression
      • Engine::set_allow_statement_expression
      • Engine::set_allow_anonymous_fn
      • Engine::set_allow_looping
    • New strict variables mode for Engine (enabled via Engine::set_strict_variables) to throw parse errors on undefined variable usage. Two new parse error variants, ParseErrorType::VariableNotFound and ParseErrorType::ModuleNotFound, are added.

    Enhancements

    • Two double quotes ("") in a string literal now maps to "; two back-ticks (``) in a literal string now maps to `.
    • Added Engine::register_type_with_name_raw to register a custom type based on a fully-qualified type path.
    • Added into_array and into_typed_array for Dynamic.
    • Added FnPtr::call and FnPtr::call_within_context to simplify calling a function pointer.
    • A function's hashes are included in its JSON metadata to assist in debugging. Each function's baseHash field in the JSON object should map directly to the pre-calculated hash in the function call.
    • Expression now derefs to Expr.

    Deprecated and Gated API's

    • NativeCallContext::new is deprecated because it is simpler to call a function pointer via FnPtr::call.
    • AST::merge_filtered and AST::combine_filtered are no longer exported under no_function.
    • AST::new and AST::new_with_source are moved under internals.
    • FnPtr::call_dynamic is deprecated in favor of FnPtr::call_raw.
    Source code(tar.gz)
    Source code(zip)
  • v1.2.1(Nov 24, 2021)

  • v1.2.0(Nov 19, 2021)

    Version 1.2.0 released to crates.io.

    Bug fixes with breaking script changes

    • As originally intended, function calls with a bang (!) now operates directly on the caller's scope, allowing variables inside the scope to be mutated.
    • As originally intended, Engine::XXX_with_scope API's now properly propagate constants within the provided scope also to functions in the script.
    • Printing of integral floating-point numbers is fixed (used to only prints 0.0).
    • func!() calls now work properly under no_closure.
    • Fixed parsing of unary negation such that expressions like if foo { ... } -x parses correctly.

    New features

    • #[cfg(...)] attributes can now be put directly on plugin functions or function defined in a plugin module.
    • A custom syntax parser can now return a symbol starting with $$ to inform the implementation function which syntax variant was actually parsed.
    • AST::iter_literal_variables is added to extract all top-level literal constant/variable definitions from a script without running it.
    • Engine::call_fn_dynamic is deprecated and Engine::call_fn_raw is added which allows keeping new variables in the custom scope.

    Enhancements

    • Array methods now avoid cloning as much as possible (although most predicates will involve cloning anyway if passed a closure).
    • Array methods that take function pointers (e.g. closures) now optionally take the function name as a string.
    • Array adds the dedup method.
    • Array adds a sort method with no parameters which sorts homogeneous arrays of built-in comparable types (e.g. INT).
    • Inlining is disabled for error-path functions because errors are exceptional and scripts usually fail completely when an error is encountered.
    • The optimize module is completely eliminated under no_optimize, which should yield smaller code size.
    • NativeCallContext::position is added to return the position of the function call.
    • Scope::clone_visible is added that copies only the last instance of each variable, omitting all shadowed variables.

    Deprecated API's

    • NativeCallContext::call_fn_dynamic_raw is deprecated and NativeCallContext::call_fn_raw is added.
    • From<EvalAltResult> for Result<T, Box<EvalAltResult>> is deprecated so it will no longer be possible to do EvalAltResult::ErrorXXXXX.into() to convert to a Result; instead, Err(EvalAltResult:ErrorXXXXX.into()) must be used. Code is clearer if errors are explicitly wrapped in Err.
    Source code(tar.gz)
    Source code(zip)
  • v1.1.2(Nov 5, 2021)

    This release fixes a number of bugs:

    • 0.0 now prints correctly (used to print 0e0).
    • Unary operators are now properly recognized as an expression statement.
    • The global namespace is now searched before packages, which is the correct behavior.

    A regression in string operations via the + operator is also reversed.

    Source code(tar.gz)
    Source code(zip)
  • v1.1.1(Nov 1, 2021)

    Bug fixes

    • Assignment to indexing expression with dot expressions inside no longer cause a compilation error.
    • The no_module and internals features now work together without a compilation error.
    • String literal operations (such as "hello" + ", world") now optimizes correctly.
    Source code(tar.gz)
    Source code(zip)
  • v1.1.0(Oct 11, 2021)

    Version 1.1.0 released to crates.io.

    Bug fixes

    • Custom syntax starting with a disabled standard keyword now works properly.
    • When calling Engine::call_fn, new variables defined during evaluation of the body script are removed and no longer spill into the function call.
    • NamespaceRef::new is fixed.

    Enhancements

    Engine API

    • Engine::consume_XXX methods are renamed to Engine::run_XXX to make meanings clearer. The consume_XXX API is deprecated.
    • Engine::register_type_XXX are now available even under no_object.
    • Added Engine::on_parse_token to allow remapping certain tokens during parsing.
    • Added Engine::const_empty_string to merge empty strings into a single instance.

    Custom Syntax

    • $symbol$ is supported in custom syntax to match any symbol.
    • Custom syntax with $block$, } or ; as the last symbol are now self-terminating (i.e. no need to attach a terminating ;).

    Dynamic Values

    • Dynamic::as_string and Dynamic::as_immutable_string are deprecated and replaced by into_string and into_immutable_string respectively.
    • Added a number of constants to Dynamic.
    • Added a number of constants and fromXXX constant methods to Dynamic.
    • Added sin, cos and tan for Decimal values.

    Decimal Values

    • parse_float(), PI() and E() now defer to Decimal under no_float if decimal is turned on.
    • Added log10() for Decimal.
    • ln for Decimal is now checked and won't panic.

    String Values

    • SmartString now uses LazyCompact instead of Compact to minimize allocations.
    • Added pop for strings.
    • Added ImmutableString::ptr_eq to test if two strings point to the same allocation.
    • The serde feature of SmartString is turned on under metadata to make Map serializable.

    Scope API

    • Scope::set_value now takes anything that implements Into<Cow<str>>.
    • Added Scope::is_constant to check if a variable is constant.
    • Added Scope::set_or_push to add a new variable only if one doesn't already exist.

    AST API

    • Added ASTNode::position.
    • ReturnType is removed in favor of option flags for Stmt::Return.
    • Stmt::Break and Stmt::Continue are merged into Stmt::BreakLoop via an option flag.
    • StaticVec is changed to keep three items inline instead of four.
    Source code(tar.gz)
    Source code(zip)
  • v1.0.6(Sep 28, 2021)

    Bug fixes

    • Eliminate unnecessary property write-back when accessed via a getter since property getters are assumed to be pure.
    • Writing to a property of an indexed valued obtained via an indexer now works properly by writing back the changed value via an index setter.

    Enhancements

    • MultiInputsStream, ParseState, TokenIterator, IdentifierBuilder and AccessMode are exported under the internals feature.
    Source code(tar.gz)
    Source code(zip)
  • v1.0.5(Sep 19, 2021)

    This is a bug fix version with the following fixes:

    • FloatWrapper is no longer erroneously exported under no_float+internals.
    • The sign function now works properly for float values that are NaN.
    Source code(tar.gz)
    Source code(zip)
  • v1.0.4(Sep 3, 2021)

  • v1.0.2(Aug 17, 2021)

  • v1.0.1(Aug 6, 2021)

    Bug fixes

    • Fixed bug in using indexing/dotting inside index bracket.
    • while and loop statements are no longer considered pure (since a loop can go on forever and this is a side effect).
    Source code(tar.gz)
    Source code(zip)
  • v1.0.0(Jul 7, 2021)

    The official version 1.0.

    Almost the same version as 0.20.3 but with deprecated API's removed.

    Version 1.0.0 released to crates.io.

    Bug fixes

    • Fixed infinite loop in certain script optimizations.
    • Building for no-std no longer requires patching smartstring.
    • Parsing a lone return or throw without a semicolon at the end of a block no longer raises an error.

    Breaking changes

    • All deprecated API's (e.g. the RegisterFn and RegisterResultFn traits) are removed.
    • Module::set_id is split into Module::set_id and Module::clear_id pair.
    • begin, end, each, then, unless are no longer reserved keywords.

    Enhancements

    • New methods is_odd, is_even for integers, and is_zero for all numbers.
    • From<BTreeSet> and From<HashSet> are added for Dynamic, which create object maps with () values.
    Source code(tar.gz)
    Source code(zip)
  • v0.20.3(Jun 22, 2021)

    This version adds support to index into an integer number, treating it as a bit-field.

    Version 0.20.3 released to crates.io.

    Bug fixes

    • Fixed incorrect optimization regarding chain-indexing with non-numeric index.
    • Variable values are checked for over-sized violations after assignments and setters.

    Breaking changes

    • To keep the API consistent, strings are no longer iterable by default. Use the chars method to iterate through the characters in a string.
    • Dynamic::take_string and Dynamic::take_immutable_string are renamed to Dynamic::as_string and Dynamic::as_immutable_string respectively.

    New features

    • New syntax for for statement to include counter variable.
    • An integer value can now be indexed to get/set a single bit.
    • The bits method of an integer can be used to iterate through its bits.
    • New $bool$, $int$, $float$ and $string$ expression types for custom syntax.
    • New methods to_hex, to_octal and to_binary for integer numbers.
    • New methods to_upper, to_lower, make_upper, make_lower for strings/characters.
    Source code(tar.gz)
    Source code(zip)
  • v0.20.2(May 26, 2021)

    This version adds a number of convenience features:

    • Ability for a Dynamic to hold an i32 tag of arbitrary data

    • Simplifies dynamic properties access by falling back to an indexer (passing the name of the property as a string) when a property is not found.

    Version 0.20.2 released to crates.io.

    Bug fixes

    • Propagation of constants held in a custom scope now works properly instead of always replacing by ().

    Breaking changes

    • Engine::disable_doc_comments is removed because doc-comments are now placed under the metadata feature flag.
    • Registering a custom syntax now only requires specifying whether the Scope is adjusted (i.e. whether variables are added or removed). There is no need to specify the number of variables added/removed.
    • Assigning to a property of a constant is now allowed and no longer raise an EvalAltResult::ErrorAssignmentToConstant error. This is to facilitate the Singleton pattern. Registered setter functions are automatically guarded against setters calling on constants and will continue to raise errors unless the pure attribute is present (for plugins).
    • If a property getter/setter is not found, an indexer with string index, if any, is tried.
    • The indexers API (Engine::register_indexer_XXX and Module::set_indexer_XXX) are now also exposed under no_index.

    New features

    • Each Dynamic value can now contain arbitrary data (type i32) in the form of a tag. This is to use up otherwise wasted space in the Dynamic type.
    • A new internal feature no_smartstring to turn off SmartString for those rare cases that it is needed.
    • DynamicReadLock and DynamicWriteLoc are exposed under internals.
    • From<Shared<Locked<Dynamic>>> is added for Dynamic mapping directly to a shared value, together with support for Dynamic::from.
    • An indexer with string index acts as a fallback to a property getter/setter.

    Enhancements

    • Registering a custom syntax now only requires specifying whether the Scope is adjusted (i.e. whether variables are added or removed). This allows more flexibility for cases where the number of new variables declared depends on internal logic.
    • Putting a pure attribute on a plugin property/index setter now enables it to be used on constants.
    Source code(tar.gz)
    Source code(zip)
  • v0.20.1(May 2, 2021)

    This version enables functions to access constants declared at global level via the special global module.

    Version 0.20.1 released to crates.io.

    Bug fixes

    • Fixed bug when position is zero in insert and split_at methods for arrays.
    • Indexing operations with pure index values are no longer considered pure due to the possibility of indexers.

    Breaking changes

    • Dynamic::is_shared and Dynamic::is_locked are removed under the no_closure feature. They used to always return false.
    • Engine::call_fn now evaluates the AST before calling the function.
    • Engine::on_progress is disabled with unchecked.

    New features

    • A module called global is automatically created to hold global-level constants, which can then be accessed from functions.
    • A new feature no_position is added to turn off position tracking during parsing to squeeze out the last drop of performance.

    Enhancements

    • The crate no-std-compat is used to compile for no-std. This removes the need to use a special crate::stdlib namespace for std imports.
    Source code(tar.gz)
    Source code(zip)
  • v0.20.0(Apr 16, 2021)

    This version adds string interpolation with `... ${ ... } ...` syntax.

    switch statement cases can now have conditions.

    Negative indices for arrays and strings are allowed and now count from the end (-1 = last item/character).

    Version 0.20.0 released to crates.io.

    Bug fixes

    • Property setter op-assignments now work properly.
    • Off-by-one bug in Array::drain method with range is fixed.

    Breaking changes

    • Negative index to an array or string yields the appropriate element/character counting from the end.
    • The default _ case of a switch statement now must be the last case, together with two new error variants: EvalAltResult::WrongSwitchDefaultCase and EvalAltResult::WrongSwitchCaseCondition.
    • ModuleResolver trait methods take an additional parameter source_path that contains the path of the current environment. This is to facilitate loading other script files always from the current directory.
    • FileModuleResolver now resolves relative paths under the source path if there is no base path set.
    • FileModuleResolver::base_path now returns Option<&str> which is None if there is no base path set.
    • Doc-comments now require the metadata feature.

    Enhancements

    • Array::drain and Array::retain methods with predicate now scan the array in forward order instead of in reverse.

    New features

    • String interpolation support is added via the `... ${ ... } ...` syntax.
    • FileModuleResolver resolves relative paths under the parent path (i.e. the path holding the script that does the loading). This allows seamless cross-loading of scripts from a directory hierarchy instead of having all relative paths load from the current working directory.
    • Negative index to an array or string yields the appropriate element/character counting from the end.
    • switch statement cases can now have an optional if clause.
    Source code(tar.gz)
    Source code(zip)
  • v0.19.15(Mar 31, 2021)

    This version replaces all internal usage of HashMap with BTreeMap, which should result in some speed improvement because a BTreeMap is leaner when the number of items held is small. Most, if not all, collections in Rhai hold very few data items, so this is a typical scenario of many tiny-sized collections.

    The Rhai object map type, Map, used to be an alias to HashMap and is now aliased to BTreeMap instead. This is also because, in the vast majority of usage cases, the number of properties held by an object map is small.

    HashMap and BTreeMap have almost identical public API's so this change is unlikely to break existing code.

    SmartString is used to store identifiers (which tend to be short, fewer than 23 characters, and ASCII-based) because they can usually be stored inline. Map keys now also use SmartString.

    In addition, there is now support for line continuation in strings (put \ at the end of line) as well as multi-line literal strings (wrapped by back-ticks: `...`).

    Finally, all function signature/metadata methods are now grouped under the umbrella metadata feature. This avoids spending precious resources maintaining metadata for functions for the vast majority of use cases where such information is not required.

    Version 0.19.15 released to crates.io.

    Bug fixes

    • The feature flags no_index + no_object now compile without errors.

    Breaking changes

    • The traits RegisterFn and RegisterResultFn are removed. Engine::register_fn and Engine::register_result_fn are now implemented directly on Engine.
    • FnPtr::call_dynamic now takes &NativeCallContext instead of consuming it.
    • All Module::set_fn_XXX methods are removed, in favor of Module::set_native_fn.
    • Array::reduce and Array::reduce_rev now take a Dynamic as initial value instead of a function pointer.
    • protected, super are now reserved keywords.
    • The Module::set_fn_XXX API now take &str as the function name instead of Into<String>.
    • The reflections API such as Engine::gen_fn_signatures, Module::update_fn_metadata etc. are put under the metadata feature gate.
    • The shebang #! is now a reserved symbol.
    • Shebangs at the very beginning of script files are skipped when loading them.
    • SmartString is used for identifiers by default. Currently, a PR branch is pulled for no-std builds. The official crate will be used once SmartString is fixed to support no-std.
    • Map is now an alias to BTreeMap<SmartString, Dynamic> instead of HashMap because most object maps hold few properties.
    • EvalAltResult::FnWrongDefinition is renamed WrongFnDefinition for consistency.

    New features

    • Line continuation (via \) and multi-line literal strings (wrapped with `) support are added.
    • Rhai scripts can now start with a shebang #! which is ignored.

    Enhancements

    • Replaced all HashMap usage with BTreeMap for better performance because collections in Rhai are tiny.
    • Engine::register_result_fn no longer requires the successful return type to be Dynamic. It can now be any clonable type.
    • #[rhai_fn(return_raw)] can now return Result<T, Box<EvalAltResult>> where T is any clonable type instead of Result<Dynamic, Box<EvalAltResult>>.
    • Dynamic::clone_cast is added to simplify casting from a &Dynamic.
    Source code(tar.gz)
    Source code(zip)
  • v0.19.14(Mar 14, 2021)

    This version runs faster due to optimizations done on AST node structures. It also fixes a number of panic bugs related to passing shared values as function call arguments.

    Version 0.19.14 released to crates.io.

    Bug fixes

    • Panic when passing a shared string into a registered function as &str argument is fixed.
    • Panic when calling switch statements on custom types is fixed.
    • Potential overflow panics in range(from, to, step) is fixed.
    • &mut String parameters in registered functions no longer panic when passed a string.
    • Some expressions involving shared variables now work properly, for example x in shared_value, return shared_value, obj.field = shared_value etc. Previously, the resultant value is still shared which is counter-intuitive.
    • Errors in native Rust functions now contain the correct function call positions.
    • Fixed error types in EvalAltResult::ErrorMismatchDataType which were swapped.

    Breaking changes

    • Dynamic::as_str is removed because it does not properly handle shared values.
    • Zero step in the range function now raises an error instead of creating an infinite stream.
    • Error variable captured by catch is now an object map containing error fields.
    • EvalAltResult::clear_position is renamed EvalAltResult::take_position and returns the position taken.
    • private functions in an AST can now be called with call_fn etc.
    • NativeCallContext::call_fn_dynamic_raw no longer has the pub_only parameter.
    • Module::update_fn_metadata input parameter is changed.
    • Function keywords (e.g. type_of, eval, Fn) can no longer be overloaded. It is more trouble than worth. To disable these keywords, use Engine::disable_symbol.
    • is_def_var and is_def_fn are now reserved keywords.
    • Engine::id field is removed because it is never used.
    • num-traits is now a required dependency.
    • The in operator is now implemented on top of the contains function and is no longer restricted to a few specific types.
    • EvalAltResult::ErrorInExpr is removed because the in operator now calls contains.
    • The methods AST::walk, Expr::walk, Stmt::walk and ASTNode::walk and the callbacks they take now return bool to optionally terminate the recursive walk.

    Enhancements

    • Layout of AST nodes is optimized to reduce redirections, so speed is improved.
    • Function calls are more optimized and should now run faster.
    • range function now supports negative step and decreasing streams (i.e. to < from).
    • More information is provided to the error variable captured by the catch statement in an object map.
    • Previously, private functions in an AST cannot be called with call_fn etc. This is inconvenient when trying to call a function inside a script which also serves as a loadable module exporting part (but not all) of the functions. Now, all functions (private or not) can be called in an AST. The private keyword is relegated to preventing a function from being exported.
    • Dynamic::as_unit just for completeness sake.
    • bytes method added for strings to get length quickly (if the string is ASCII-only).
    • FileModuleResolver can now enable/disable caching.
    • Recursively walking an AST can now be terminated in the middle.
    Source code(tar.gz)
    Source code(zip)
Owner
Rhai - Embedded scripting language and engine for Rust
A small, fast, easy-to-use scripting language and evaluation engine that integrates tightly with Rust. Builds for most common targets including no-std and WASM.
Rhai - Embedded scripting language and engine for Rust
A rusty dynamically typed scripting language

dyon A rusty dynamically typed scripting language Tutorial Dyon-Interactive Dyon Snippets /r/dyon Dyon script files end with .dyon. To run Dyon script

PistonDevelopers 1.5k Nov 28, 2022
Scripting language focused on processing tabular data.

ogma Welcome to the ogma project! ogma is a scripting language focused on ergonomically and efficiently processing tabular data, with batteries includ

kdr-aus 144 Nov 26, 2022
A static, type inferred and embeddable language written in Rust.

gluon Gluon is a small, statically-typed, functional programming language designed for application embedding. Features Statically-typed - Static typin

null 2.7k Nov 26, 2022
Implementation of Immix Mark-Region Garbage collector written in Rust Programming Language.

libimmixcons Implementation of Immix Mark-Region Garbage collector written in Rust Programming Language. Status This is mostly usable library. You can

playX 33 Nov 10, 2022
A computer programming language interpreter written in Rust

Ella lang Welcome to Ella lang! Ella lang is a computer programming language implemented in Rust.

Luke Chu 64 May 27, 2022
Interpreted language developed in Rust

Xelis VM Xelis is an interpreted language developed in Rust. It supports constants, functions, while/for loops, arrays and structures. The syntax is s

null 8 Jun 21, 2022
REPL for the Rust programming language

Rusti A REPL for the Rust programming language. The rusti project is deprecated. It is not recommended for regular use. Dependencies On Unix systems,

Murarth 1.3k Nov 10, 2022
Source code for the Mun language and runtime.

Mun Mun is a programming language empowering creation through iteration. Features Ahead of time compilation - Mun is compiled ahead of time (AOT), as

The Mun Programming Language 1.4k Dec 2, 2022
Oxide Programming Language

Oxide Programming Language Interpreted C-like language with a Rust influenced syntax. Latest release Example programs /// recursive function calls to

Arthur Kurbidaev 112 Nov 8, 2022
The hash programming language compiler

The Hash Programming language Run Using the command cargo run hash. This will compile, build and run the program in the current terminal/shell. Submit

Hash 13 Nov 3, 2022
Interactive interpreter for a statement-based proof-of-concept language.

nhotyp-lang Nhotyp is a conceptual language designed for ease of implementation during my tutoring in an introductive algorithmic course at Harbin Ins

Geoffrey Tang 5 Jun 26, 2022
🍖 ham, general purpose programming language

?? ham, a programming language made in rust status: alpha Goals Speed Security Comfort Example fn calc(value){ if value == 5 { return 0

Marc Espín 19 Nov 10, 2022
A small programming language created in an hour

Building a programming language in an hour This is the project I made while doing the Building a programming language in an hour video. You can run it

JT 39 Jul 29, 2022
The Loop programming language

Loop Language Documentation | Website A dynamic type-safe general purpose programming language Note: currently Loop is being re-written into Rust. Mea

LoopLanguage 20 Oct 21, 2022
Stackbased programming language

Rack is a stackbased programming language inspired by Forth, every operation push or pop on the stack. Because the language is stackbased and for a ve

Xavier Hamel 1 Oct 28, 2021
A Python compiler targeting JS, implemented in Rust.

A Python compiler targeting JavaScript, implemented in Rust.

Gideon Grinberg 5 Jun 17, 2021
Diplo is a script runner and dependency manager made in rust mainly for Deno.

Diplo is a script runner and dependency manager made in rust mainly for Deno. Documentation Tricked.pro/diplo Installing - windows installer Features

Tricked 23 May 9, 2022
A safe-against-invalid-input version of wren.io, written in Rust.

safe_wren A nearly-complete implementation of the Wren language (wren.io) in Rust. The original https://github.com/wren-lang/wren from wren.io is refe

Rubber Duck Engineering 20 Jul 16, 2022
Rhai - An embedded scripting language for Rust.

Rhai is an embedded scripting language and evaluation engine for Rust that gives a safe and easy way to add scripting to any application.

Rhai - Embedded scripting language and engine for Rust 2.4k Dec 3, 2022
A plugin system for the Rhai embedded scripting language.

Rhai Dylib This crate exposes a simple API to load dylib Rust crates in a Rhai engine using Rhai modules. ?? This is a work in progress, the API is su

Rhai - Embedded scripting language and engine for Rust 4 Oct 7, 2022