Merge pull request #327 from schungx/master

Code fixups.
This commit is contained in:
Stephen Chung 2021-01-08 19:24:22 +08:00 committed by GitHub
commit 899e466818
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
210 changed files with 428 additions and 11679 deletions

1
.gitignore vendored
View File

@ -2,6 +2,5 @@ target/
Cargo.lock
.vscode/
.cargo/
doc/book/
before*
after*

View File

@ -10,8 +10,8 @@ version = "0.19.10"
edition = "2018"
authors = ["Jonathan Turner", "Lukáš Hozda", "Stephen Chung", "jhwgh1968"]
description = "Embedded scripting for Rust"
homepage = "https://schungx.github.io/rhai"
repository = "https://github.com/jonathandturner/rhai"
homepage = "https://rhaiscript.github.io/book"
repository = "https://github.com/rhaiscript/rhai"
readme = "README.md"
license = "MIT OR Apache-2.0"
include = [

View File

@ -1,16 +1,16 @@
Rhai - Embedded Scripting for Rust
=================================
![GitHub last commit](https://img.shields.io/github/last-commit/jonathandturner/rhai?logo=github)
[![Build Status](https://github.com/jonathandturner/rhai/workflows/Build/badge.svg)](https://github.com/jonathandturner/rhai/actions)
[![license](https://img.shields.io/crates/l/rhai)](https://github.com/license/jonathandturner/rhai)
![GitHub last commit](https://img.shields.io/github/last-commit/rhaiscript/rhai?logo=github)
[![Build Status](https://github.com/rhaiscript/rhai/workflows/Build/badge.svg)](https://github.com/rhaiscript/rhai/actions)
[![license](https://img.shields.io/crates/l/rhai)](https://github.com/license/rhaiscript/rhai)
[![crates.io](https://img.shields.io/crates/v/rhai?logo=rust)](https://crates.io/crates/rhai/)
[![crates.io](https://img.shields.io/crates/d/rhai?logo=rust)](https://crates.io/crates/rhai/)
[![API Docs](https://docs.rs/rhai/badge.svg?logo=docs.rs)](https://docs.rs/rhai/)
[![chat](https://img.shields.io/discord/767611025456889857.svg?logo=discord)](https://discord.gg/HquqbYFcZ9)
[![Reddit](https://img.shields.io/reddit/subreddit-subscribers/Rhai?logo=reddit)](https://www.reddit.com/r/Rhai)
![Rhai logo](https://schungx.github.io/rhai/images/logo/rhai-banner-transparent-colour.svg)
![Rhai logo](https://rhaiscript.github.io/book/images/logo/rhai-banner-transparent-colour.svg)
Rhai is an embedded scripting language and evaluation engine for Rust that gives a safe and easy way
to add scripting to any application.
@ -31,44 +31,44 @@ Standard features
* Easy-to-use language similar to JavaScript+Rust with dynamic typing.
* Fairly low compile-time overhead.
* 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](https://schungx.github.io/rhai/rust/functions.html) and [types]([#custom-types-and-methods](https://schungx.github.io/rhai/rust/custom.html)), including [getters/setters](https://schungx.github.io/rhai/rust/getters-setters.html), [methods](https://schungx.github.io/rhai/rust/custom.html) and [indexers](https://schungx.github.io/rhai/rust/indexers.html).
* Freely pass Rust variables/constants into a script via an external [`Scope`](https://schungx.github.io/rhai/rust/scope.html) - all clonable Rust types are supported; no need to implement any special trait.
* Easily [call a script-defined function](https://schungx.github.io/rhai/engine/call-fn.html) from Rust.
* Tight integration with native Rust [functions](https://rhaiscript.github.io/book/rust/functions.html) and [types]([#custom-types-and-methods](https://rhaiscript.github.io/book/rust/custom.html)), including [getters/setters](https://rhaiscript.github.io/book/rust/getters-setters.html), [methods](https://rhaiscript.github.io/book/rust/custom.html) and [indexers](https://rhaiscript.github.io/book/rust/indexers.html).
* Freely pass Rust variables/constants into a script via an external [`Scope`](https://rhaiscript.github.io/book/rust/scope.html) - all clonable Rust types are supported; no need to implement any special trait.
* Easily [call a script-defined function](https://rhaiscript.github.io/book/engine/call-fn.html) from Rust.
* Relatively little `unsafe` code (yes there are some for performance reasons).
* Few dependencies (currently only [`smallvec`](https://crates.io/crates/smallvec)).
* Re-entrant scripting engine can be made `Send + Sync` (via the `sync` feature).
* Scripts are [optimized](https://schungx.github.io/rhai/engine/optimize.html) (useful for template-based machine-generated scripts) for repeated evaluations.
* Easy custom API development via [plugins](https://schungx.github.io/rhai/plugins/index.html) system powered by procedural macros.
* [Function overloading](https://schungx.github.io/rhai/language/overload.html) and [operator overloading](https://schungx.github.io/rhai/rust/operators.html).
* Dynamic dispatch via [function pointers](https://schungx.github.io/rhai/language/fn-ptr.html) with additional support for [currying](https://schungx.github.io/rhai/language/fn-curry.html).
* [Closures](https://schungx.github.io/rhai/language/fn-closure.html) (anonymous functions) that can capture shared values.
* Some syntactic support for [object-oriented programming (OOP)](https://schungx.github.io/rhai/language/oop.html).
* Organize code base with dynamically-loadable [modules](https://schungx.github.io/rhai/language/modules.html).
* Scripts are [optimized](https://rhaiscript.github.io/book/engine/optimize.html) (useful for template-based machine-generated scripts) for repeated evaluations.
* Easy custom API development via [plugins](https://rhaiscript.github.io/book/plugins/index.html) system powered by procedural macros.
* [Function overloading](https://rhaiscript.github.io/book/language/overload.html) and [operator overloading](https://rhaiscript.github.io/book/rust/operators.html).
* Dynamic dispatch via [function pointers](https://rhaiscript.github.io/book/language/fn-ptr.html) with additional support for [currying](https://rhaiscript.github.io/book/language/fn-curry.html).
* [Closures](https://rhaiscript.github.io/book/language/fn-closure.html) (anonymous functions) that can capture shared values.
* Some syntactic support for [object-oriented programming (OOP)](https://rhaiscript.github.io/book/language/oop.html).
* Organize code base with dynamically-loadable [modules](https://rhaiscript.github.io/book/language/modules.html).
* Serialization/deserialization support via [serde](https://crates.io/crates/serde) (requires the `serde` feature).
* Support for [minimal builds](https://schungx.github.io/rhai/start/builds/minimal.html) by excluding unneeded language [features](https://schungx.github.io/rhai/start/features.html).
* Support for [minimal builds](https://rhaiscript.github.io/book/start/builds/minimal.html) by excluding unneeded language [features](https://rhaiscript.github.io/book/start/features.html).
Protected against attacks
-------------------------
* Sand-boxed - the scripting engine, if declared immutable, cannot mutate the containing environment unless [explicitly permitted](https://schungx.github.io/rhai/patterns/control.html).
* Rugged - protected against malicious attacks (such as [stack-overflow](https://schungx.github.io/rhai/safety/max-call-stack.html), [over-sized data](https://schungx.github.io/rhai/safety/max-string-size.html), and [runaway scripts](https://schungx.github.io/rhai/safety/max-operations.html) etc.) that may come from untrusted third-party user-land scripts.
* Track script evaluation [progress](https://schungx.github.io/rhai/safety/progress.html) and manually terminate a script run.
* Sand-boxed - the scripting engine, if declared immutable, cannot mutate the containing environment unless [explicitly permitted](https://rhaiscript.github.io/book/patterns/control.html).
* Rugged - protected against malicious attacks (such as [stack-overflow](https://rhaiscript.github.io/book/safety/max-call-stack.html), [over-sized data](https://rhaiscript.github.io/book/safety/max-string-size.html), and [runaway scripts](https://rhaiscript.github.io/book/safety/max-operations.html) etc.) that may come from untrusted third-party user-land scripts.
* Track script evaluation [progress](https://rhaiscript.github.io/book/safety/progress.html) and manually terminate a script run.
For those who actually want their own language
---------------------------------------------
* Use as a [DSL](https://schungx.github.io/rhai/engine/dsl.html).
* Restrict the language by surgically [disabling keywords and operators](https://schungx.github.io/rhai/engine/disable.html).
* Define [custom operators](https://schungx.github.io/rhai/engine/custom-op.html).
* Extend the language with [custom syntax](https://schungx.github.io/rhai/engine/custom-syntax.html).
* Use as a [DSL](https://rhaiscript.github.io/book/engine/dsl.html).
* Restrict the language by surgically [disabling keywords and operators](https://rhaiscript.github.io/book/engine/disable.html).
* Define [custom operators](https://rhaiscript.github.io/book/engine/custom-op.html).
* Extend the language with [custom syntax](https://rhaiscript.github.io/book/engine/custom-syntax.html).
Documentation
-------------
See [The Rhai Book](https://schungx.github.io/rhai) for details on the Rhai scripting engine and language.
See [The Rhai Book](https://rhaiscript.github.io/book) for details on the Rhai scripting engine and language.
To build _The Book_, first install [`mdbook`](https://github.com/rust-lang/mdBook)
and [`mdbook-tera`](https://github.com/avitex/mdbook-tera) (for templating).
@ -87,8 +87,8 @@ License
Licensed under either of the following, at your choice:
* [Apache License, Version 2.0](https://github.com/jonathandturner/rhai/blob/master/LICENSE-APACHE.txt), or
* [MIT license](https://github.com/jonathandturner/rhai/blob/master/LICENSE-MIT.txt)
* [Apache License, Version 2.0](https://github.com/rhaiscript/rhai/blob/master/LICENSE-APACHE.txt), or
* [MIT license](https://github.com/rhaiscript/rhai/blob/master/LICENSE-MIT.txt)
Unless explicitly stated otherwise, any contribution intentionally submitted
for inclusion in this crate, as defined in the Apache-2.0 license, shall

View File

@ -8,12 +8,15 @@ Breaking changes
----------------
* The error variant `EvalAltResult::ErrorInFunctionCall` has a new parameter holding the _source_ of the function.
* `ParseErrorType::WrongFnDefinition` is renamed `FnWrongDefinition`.
* Redefining an existing function within the same script now throws a new `ParseErrorType::FnDuplicatedDefinition`. This is to prevent accidental overwriting an earlier function definition.
Enhancements
------------
* Source information is provided when there is an error within a call to a function defined in another module.
* Source information is provided to the `NativeCallContext` for native Rust functions.
* `EvalAltResult::clear_position` to clear the position information of an error - useful when only the message is needed and the position doesn't need to be printed out.
Version 0.19.9
@ -478,7 +481,7 @@ 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](https://schungx.github.io/rhai).
The `README` is officially transferred to [The Rhai Book](https://rhaiscript.github.io/book).
An online [Playground](https://alvinhochun.github.io/rhai-demo/) is available.
@ -503,7 +506,7 @@ New features
Enhancements
------------
* [The Rhai Book](https://schungx.github.io/rhai) is online. Most content in the original `README` was transferred to the Book.
* [The Rhai Book](https://rhaiscript.github.io/book) is online. Most content in the original `README` was transferred to the Book.
* New feature `internals` to expose internal data structures (e.g. the AST nodes).

View File

@ -4,8 +4,8 @@ version = "0.3.1"
edition = "2018"
authors = ["jhwgh1968"]
description = "Procedural macro support package for Rhai, a scripting language for Rust"
homepage = "https://schungx.github.io/rhai/plugins/index.html"
repository = "https://github.com/jonathandturner/rhai"
homepage = "https://rhaiscript.github.io/book/plugins/index.html"
repository = "https://github.com/rhaiscript/rhai"
license = "MIT OR Apache-2.0"
[lib]

View File

@ -2,4 +2,4 @@ Procedural Macros for Plugins
=============================
This crate holds procedural macros for code generation, supporting the plugins system
for [Rhai](https://github.com/jonathandturner/rhai).
for [Rhai](https://github.com/rhaiscript/rhai).

View File

@ -17,7 +17,7 @@ pub mod test_module {
fn main() {
let n = Point {
x: 0.0,
y: 10.0,
y: 10.0
};
if test_module::test_fn(n) {
println!("yes");

View File

@ -19,5 +19,5 @@ help: consider importing one of these items
|
11 | use std::fmt::Pointer;
|
11 | use syn::export::fmt::Pointer;
11 | use syn::__private::fmt::Pointer;
|

View File

@ -1,41 +0,0 @@
The Rhai Book
=============
[_The Rhai Book_](https://schungx.github.io/rhai) serves as Rhai's primary
documentation and tutorial resource.
How to Build from Source
------------------------
* Install [`mdbook`](https://github.com/rust-lang/mdBook):
```bash
cargo install mdbook
```
* Install [`mdbook-tera`](https://github.com/avitex/mdbook-tera) (for templating):
```bash
cargo install mdbook-tera
```
* Run build in source directory:
```bash
cd doc
mdbook build
```
Configuration Settings
----------------------
Settings stored in `context.json`:
| Setting | Description |
| ---------- | ------------------------------------------------------------------------------------------------- |
| `version` | version of Rhai |
| `repoHome` | points to the [root of the GitHub repo](https://github.com/jonathandturner/rhai/blob/master) |
| `repoTree` | points to the [root of the GitHub repo tree](https://github.com/jonathandturner/rhai/tree/master) |
| `rootUrl` | sub-directory for the root domain, e.g. `/rhai` |

View File

@ -1,22 +0,0 @@
[book]
title = "Rhai - Embedded Scripting for Rust"
authors = ["Jonathan Turner", "Stephen Chung"]
description = "Tutorial and reference on the Rhai scripting engine and language."
language = "en"
[output.html]
no-section-label = true
git-repository-url = "https://github.com/jonathandturner/rhai"
curly-quotes = true
[output.html.fold]
enable = true
level = 4
[outputX.linkcheck]
follow-web-links = false
traverse-parent-directories = false
warning-policy = "ignore"
[preprocessor.tera]
command = "mdbook-tera --json ./src/context.json"

View File

@ -1,149 +0,0 @@
The Rhai Scripting Language
==========================
1. [What is Rhai](about/index.md)
1. [Features](about/features.md)
2. [Supported Targets and Builds](about/targets.md)
3. [What Rhai Isn't](about/non-design.md)
4. [Licensing](about/license.md)
5. [Related Resources](about/related.md)
2. [Getting Started](start/index.md)
1. [Online Playground](start/playground.md)
2. [Install the Rhai Crate](start/install.md)
3. [Optional Features](start/features.md)
4. [Special Builds](start/builds/index.md)
1. [Performance](start/builds/performance.md)
2. [Minimal](start/builds/minimal.md)
3. [no-std](start/builds/no-std.md)
4. [WebAssembly (WASM)](start/builds/wasm.md)
5. [Packaged Utilities](start/bin.md)
6. [Examples](start/examples/index.md)
1. [Rust](start/examples/rust.md)
2. [Scripts](start/examples/scripts.md)
3. [Using the `Engine`](engine/index.md)
1. [Hello World in Rhai – Evaluate a Script](engine/hello-world.md)
2. [Compile to AST for Repeated Evaluations](engine/compile.md)
3. [Call a Rhai Function from Rust](engine/call-fn.md)
4. [Create a Rust Closure from a Rhai Function](engine/func.md)
5. [Evaluate Expressions Only](engine/expressions.md)
6. [Raw Engine](engine/raw.md)
7. [Scope – Initializing and Maintaining State](engine/scope.md)
8. [Engine Configuration Options](engine/options.md)
4. [Extend Rhai with Rust](rust/index.md)
1. [Traits](rust/traits.md)
2. [Register a Rust Function](rust/functions.md)
1. [String Parameters in Rust Functions](rust/strings.md)
3. [Register a Generic Rust Function](rust/generic.md)
4. [Register a Fallible Rust Function](rust/fallible.md)
5. [Override a Built-in Function](rust/override.md)
6. [Operator Overloading](rust/operators.md)
7. [Register any Rust Type and its Methods](rust/custom.md)
1. [Property Getters and Setters](rust/getters-setters.md)
2. [Indexers](rust/indexers.md)
3. [Disable Custom Types](rust/disable-custom.md)
4. [Printing Custom Types](rust/print-custom.md)
8. [Modules](rust/modules/index.md)
1. [Create from Rust](rust/modules/create.md)
2. [Create from AST](rust/modules/ast.md)
3. [Module Resolvers](rust/modules/resolvers.md)
1. [Custom Module Resolvers](rust/modules/imp-resolver.md)
9. [Plugins](plugins/index.md)
1. [Export a Rust Module](plugins/module.md)
2. [Export a Rust Function](plugins/function.md)
10. [Packages](rust/packages/index.md)
1. [Built-in Packages](rust/packages/builtin.md)
2. [Custom Packages](rust/packages/create.md)
5. [Rhai Language Reference](language/index.md)
1. [Comments](language/comments.md)
1. [Doc-Comments](language/doc-comments.md)
2. [Values and Types](language/values-and-types.md)
1. [Dynamic Values](language/dynamic.md)
2. [Serialization/Deserialization with `serde`](rust/serde.md)
3. [type_of()](language/type-of.md)
4. [Numbers](language/numbers.md)
1. [Operators](language/num-op.md)
2. [Functions](language/num-fn.md)
3. [Value Conversions](language/convert.md)
5. [Strings and Characters](language/strings-chars.md)
1. [Built-in Functions](language/string-fn.md)
6. [Arrays](language/arrays.md)
7. [Object Maps](language/object-maps.md)
1. [Parse from JSON](language/json.md)
2. [Special Support for OOP](language/object-maps-oop.md)
8. [Time-Stamps](language/timestamps.md)
3. [Keywords](language/keywords.md)
4. [Statements](language/statements.md)
5. [Variables](language/variables.md)
6. [Constants](language/constants.md)
7. [Logic Operators](language/logic.md)
8. [Assignment Operators](language/assignment-op.md)
9. [If Statement](language/if.md)
10. [Switch Expression](language/switch.md)
11. [While Loop](language/while.md)
12. [Do Loop](language/do.md)
13. [Loop Statement](language/loop.md)
14. [For Loop](language/for.md)
1. [Iterators for Custom Types](language/iterator.md)
15. [Return Values](language/return.md)
16. [Throw Exception on Error](language/throw.md)
17. [Catch Exceptions](language/try-catch.md)
18. [Functions](language/functions.md)
1. [Call Method as Function](language/method.md)
2. [Overloading](language/overload.md)
3. [Namespaces](language/fn-namespaces.md)
4. [Function Pointers](language/fn-ptr.md)
5. [Currying](language/fn-curry.md)
6. [Anonymous Functions](language/fn-anon.md)
7. [Closures](language/fn-closure.md)
19. [Print and Debug](language/print-debug.md)
20. [Modules](language/modules/index.md)
1. [Export Variables, Functions and Sub-Modules](language/modules/export.md)
2. [Import Modules](language/modules/import.md)
21. [Eval Function](language/eval.md)
6. [Safety and Protection](safety/index.md)
1. [Checked Arithmetic](safety/checked.md)
2. [Sand-Boxing](safety/sandbox.md)
3. [Maximum Length of Strings](safety/max-string-size.md)
4. [Maximum Size of Arrays](safety/max-array-size.md)
5. [Maximum Size of Object Maps](safety/max-map-size.md)
6. [Maximum Number of Operations](safety/max-operations.md)
1. [Tracking Progress and Force-Termination](safety/progress.md)
7. [Maximum Number of Modules](safety/max-modules.md)
8. [Maximum Call Stack Depth](safety/max-call-stack.md)
9. [Maximum Statement Depth](safety/max-stmt-depth.md)
7. [Script Optimization](engine/optimize/index.md)
1. [Optimization Levels](engine/optimize/optimize-levels.md)
2. [Re-Optimize an AST](engine/optimize/reoptimize.md)
3. [Eager Function Evaluation](engine/optimize/eager.md)
4. [Side-Effect Considerations](engine/optimize/side-effects.md)
5. [Volatility Considerations](engine/optimize/volatility.md)
6. [Subtle Semantic Changes](engine/optimize/semantics.md)
8. [Usage Patterns](patterns/index.md)
1. [Object-Oriented Programming (OOP)](patterns/oop.md)
2. [Working With Rust Enums](patterns/enums.md)
3. [Loadable Configuration](patterns/config.md)
4. [Control Layer](patterns/control.md)
5. [Singleton Command](patterns/singleton.md)
6. [Multi-Layer Functions](patterns/multi-layer.md)
7. [One Engine Instance Per Call](patterns/parallel.md)
8. [Scriptable Event Handler with State](patterns/events.md)
9. [Dynamic Constants Provider](patterns/dynamic-const.md)
9. [Advanced Topics](advanced.md)
1. [Capture Scope for Function Call](language/fn-capture.md)
2. [Low-Level API](rust/register-raw.md)
3. [Variable Resolver](engine/var.md)
4. [Use as DSL](engine/dsl.md)
1. [Disable Keywords and/or Operators](engine/disable.md)
2. [Custom Operators](engine/custom-op.md)
3. [Extending with Custom Syntax](engine/custom-syntax.md)
5. [Multiple Instantiation](patterns/multiple.md)
6. [Functions Metadata](engine/metadata/index.md)
1. [Generate Function Signatures](engine/metadata/gen_fn_sig.md)
2. [Export Metadata to JSON](engine/metadata/export_to_json.md)
10. [External Tools](tools/index.md)
1. [Online Playground](tools/playground.md)
2. [`rhai-doc`](tools/rhai-doc.md)
11. [Appendix](appendix/index.md)
1. [Keywords](appendix/keywords.md)
2. [Operators and Symbols](appendix/operators.md)
3. [Literals](appendix/literals.md)

View File

@ -1,79 +0,0 @@
Features
========
{{#include ../links.md}}
Easy
----
* Easy-to-use language similar to JavaScript+Rust with dynamic typing.
* Tight integration with native Rust [functions] and [types][custom types] including [getters/setters],
[methods][custom type] and [indexers].
* Freely pass Rust variables/constants into a script via an external [`Scope`] – all clonable Rust types are supported seamlessly
without the need to implement any special trait.
* Easily [call a script-defined function]({{rootUrl}}/engine/call-fn.md) from Rust.
* Very few additional dependencies – right now only [`smallvec`](https://crates.io/crates/smallvec/) plus crates for procedural macros;
for [`no-std`] and `WASM` builds, a number of additional dependencies are pulled in to provide for missing functionalities.
* [Plugins] system powered by procedural macros simplifies custom API development.
Fast
----
* Fairly low compile-time overhead.
* Fairly efficient evaluation (1 million iterations in 0.3 sec on a single core, 2.3 GHz Linux VM).
* Scripts are [optimized][script optimization] (useful for template-based machine-generated scripts) for repeated evaluations.
Dynamic
-------
* [Function overloading]({{rootUrl}}/language/overload.md).
* [Operator overloading]({{rootUrl}}/rust/operators.md).
* Organize code base with dynamically-loadable [modules].
* Dynamic dispatch via [function pointers] with additional support for [currying].
* [Closures] that can capture shared variables.
* Some support for [object-oriented programming (OOP)][OOP].
* Hook into variables access via [variable resolver].
Safe
----
* Relatively little `unsafe` code (yes there are some for performance reasons).
* Sand-boxed – the scripting [`Engine`], if declared immutable, cannot mutate the containing environment unless
[explicitly permitted]({{rootUrl}}/patterns/control.md).
Rugged
------
* Protected against malicious attacks (such as [stack-overflow][maximum call stack depth], [over-sized data][maximum length of strings],
and [runaway scripts][maximum number of operations] etc.) that may come from untrusted third-party user-land scripts.
* Track script evaluation [progress] and manually terminate a script run.
Flexible
--------
* Re-entrant scripting [`Engine`] can be made `Send + Sync` (via the [`sync`] feature).
* Serialization/deserialization support via [`serde`](https://crates.io/crates/serde).
* Support for [minimal builds] by excluding unneeded language [features].
* Supports [most build targets](targets.md) including `no-std` and [WASM].
* Surgically [disable keywords and operators] to restrict the language.
* Use as a [DSL] by defining [custom operators] and/or extending the language with [custom syntax].

View File

@ -1,46 +0,0 @@
What is Rhai
============
{{#include ../links.md}}
![Rhai Logo]({{rootUrl}}/images/logo/rhai-banner-transparent-colour.svg)
Rhai is an embedded scripting language and evaluation engine for Rust that gives a safe and easy way
to add scripting to any application.
Versions
--------
This Book is for version **{{version}}** of Rhai.
{% if rootUrl != "" and not rootUrl is ending_with("vnext") %}
For the latest development version, see [here]({{rootUrl}}/vnext/).
{% endif %}
Etymology of the name "Rhai"
---------------------------
### As per Rhai's author Johnathan Turner
In the beginning there was [ChaiScript](http://chaiscript.com),
which is an embedded scripting language for C++.
Originally it was intended to be a scripting language similar to **JavaScript**.
With java being a kind of hot beverage, the new language was named after
another hot beverage – **Chai**, which is the word for "tea" in many world languages
and, in particular, a popular kind of milk tea consumed in India.
Later, when the novel implementation technique behind ChaiScript was ported from C++ to Rust,
logically the `C` was changed to an `R` to make it "RhaiScript", or just "Rhai".
### On the origin of the semi-official Rhai logo
One of Rhai's maintainers, [Stephen Chung](https://github.com/schungx), was thinking about a logo when he accidentally
came across a copy of _Catcher in the Rye_ in a restaurant, and drew the first version
of the logo.
Then [`@semirix`](https://github.com/semirix) refined it to the current version.
The plan is to make the logo official together with a `1.0` release.

View File

@ -1,14 +0,0 @@
Licensing
=========
{{#include ../links.md}}
Rhai is licensed under either of the following, at your choice:
* [Apache License, Version 2.0]({{repoHome}}/LICENSE-APACHE.txt), or
* [MIT license]({{repoHome}}/LICENSE-MIT.txt).
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.

View File

@ -1,77 +0,0 @@
What Rhai Isn't
===============
{{#include ../links.md}}
Rhai's purpose is to provide a dynamic layer over Rust code, in the same spirit of _zero cost abstractions_.
It doesn't attempt to be a new language. For example:
* **No classes**. Well, Rust doesn't either. On the other hand...
* **No traits**... so it is also not Rust. Do your Rusty stuff in Rust.
* **No structures/records/tuples** – define your types in Rust instead; Rhai can seamlessly work with _any Rust type_.
There is, however, a built-in [object map] type which is adequate for most uses.
It is possible to simulate [object-oriented programming (OOP)][OOP] by storing [function pointers]
or [closures] in [object map] properties, turning them into _methods_.
* **No first-class functions** – Code your functions in Rust instead, and register them with Rhai.
There is, however, support for simple [function pointers] to allow runtime dispatch by function name.
* **No garbage collection** – this should be expected, so...
* **No first-class closures** – do your closure magic in Rust instead: [turn a Rhai scripted function into a Rust closure]({{rootUrl}}/engine/call-fn.md).
There is, however, support for simulated [closures] via [currying] a [function pointer] with
captured shared variables.
* **No byte-codes/JIT** – Rhai has an optimized AST-walking interpreter which is fast enough for most casual
usage scenarios. Essential AST data structures are packed and kept together to maximize cache friendliness.
Functions are dispatched based on pre-calculated hashes and accessing variables are mostly through pre-calculated
offsets to the variables file (a [`Scope`]), so it is seldom necessary to look something up by text name.
In addition, Rhai's design deliberately avoids maintaining a _scope chain_ so function scopes do not
pay any speed penalty. This particular design also allows variables data to be kept together in a contiguous
block, avoiding allocations and fragmentation while being cache-friendly. In a typical script evaluation run,
no data is shared and nothing is locked.
Still, the purpose of Rhai is not to be super _fast_, but to make it as easy and versatile as possible to
integrate with native Rust applications.
* **No formal language grammar** – Rhai uses a hand-coded lexer, a hand-coded top-down recursive-descent parser
for statements, and a hand-coded Pratt parser for expressions.
This lack of formalism allows the _tokenizer_ and _parser_ themselves to be exposed as services in order
to support [disabling keywords/operators][disable keywords and operators], adding [custom operators],
and defining [custom syntax].
Do Not Write The Next 4D VR Game in Rhai
---------------------------------------
Due to this intended usage, Rhai deliberately keeps the language simple and small by omitting
advanced language features such as classes, inheritance, interfaces, generics,
first-class functions/closures, pattern matching, concurrency, byte-codes VM, JIT etc.
Focus is on _flexibility_ and _ease of use_ instead of raw speed.
Avoid the temptation to write full-fledge application logic entirely in Rhai -
that use case is best fulfilled by more complete languages such as JavaScript or Lua.
Thin Dynamic Wrapper Layer Over Rust Code
----------------------------------------
In actual practice, it is usually best to expose a Rust API into Rhai for scripts to call.
All the core functionalities should be written in Rust, with Rhai being the dynamic _control_ layer.
This is similar to some dynamic languages where most of the core functionalities reside in a C/C++
standard library.
Another similar scenario is a web front-end driving back-end services written in a systems language.
In this case, JavaScript takes the role of Rhai while the back-end language, well... it can actually also be Rust.
Except that Rhai integrates with Rust _much_ more tightly, removing the need for interfaces such
as XHR calls and payload encoding such as JSON.

View File

@ -1,36 +0,0 @@
Related Resources
=================
{{#include ../links.md}}
Online Resources for Rhai
-------------------------
* [GitHub](https://github.com/jonathandturner/rhai) – Home repository
* [`crates.io`](https://crates.io/crates/rhai) – Rhai crate
* [`DOCS.RS`](https://docs.rs/rhai) – Rhai API documentation
* [`LIB.RS`](https://lib.rs/crates/rhai) – Rhai library info
* [Discord Chat](https://discord.gg/HquqbYFcZ9) – Rhai channel
* [Reddit](https://www.reddit.com/r/Rhai) – Rhai community
External Tools
--------------
* [Online Playground][playground] – Run Rhai scripts directly from an editor in the browser
* [`rhai-doc`] – Rhai script documentation tool
Other Cool Projects
-------------------
* [ChaiScript](http://chaiscript.com) – A strong inspiration for Rhai. An embedded scripting language for C++.
* Check out the list of [scripting languages for Rust](https://github.com/rust-unofficial/awesome-rust#scripting) on [awesome-rust](https://github.com/rust-unofficial/awesome-rust)

View File

@ -1,18 +0,0 @@
Supported Targets and Builds
===========================
{{#include ../links.md}}
The following targets and builds are support by Rhai:
* All common CPU targets for Windows, Linux and MacOS.
* WebAssembly ([WASM])
* [`no-std`]
Minimum Rust Version
--------------------
The minimum version of Rust required to compile Rhai is `1.45.0`.

View File

@ -1,6 +0,0 @@
Advanced Topics
===============
{{#include links.md}}
This section covers advanced features of the Rhai [`Engine`].

View File

@ -1,6 +0,0 @@
Appendix
========
{{#include ../links.md}}
This section contains miscellaneous reference materials.

View File

@ -1,75 +0,0 @@
Keywords List
=============
{{#include ../links.md}}
| Keyword | Description | Inactive under | Is function? | Overloadable |
| :-------------------: | ------------------------------------------- | :-------------: | :----------: | :----------: |
| `true` | boolean true literal | | no | |
| `false` | boolean false literal | | no | |
| `let` | variable declaration | | no | |
| `const` | constant declaration | | no | |
| `if` | if statement | | no | |
| `else` | else block of if statement | | no | |
| `switch` | matching | | no | |
| `do` | looping | | no | |
| `while` | 1) while loop<br/>2) condition for do loop | | no | |
| `until` | do loop | | no | |
| `loop` | infinite loop | | no | |
| `for` | for loop | | no | |
| `in` | 1) containment test<br/>2) part of for loop | | no | |
| `continue` | continue a loop at the next iteration | | no | |
| `break` | break out of loop iteration | | no | |
| `return` | return value | | no | |
| `throw` | throw exception | | no | |
| `try` | trap exception | | no | |
| `catch` | catch exception | | no | |
| `import` | import module | [`no_module`] | no | |
| `export` | export variable | [`no_module`] | no | |
| `as` | alias for variable export | [`no_module`] | no | |
| `private` | mark function private | [`no_function`] | no | |
| `fn` (lower-case `f`) | function definition | [`no_function`] | no | |
| `Fn` (capital `F`) | create a [function pointer] | | yes | yes |
| `call` | call a [function pointer] | | yes | no |
| `curry` | curry a [function pointer] | | yes | no |
| `this` | reference to base object for method call | [`no_function`] | no | |
| `type_of` | get type name of value | | yes | yes |
| `print` | print value | | yes | yes |
| `debug` | print value in debug format | | yes | yes |
| `eval` | evaluate script | | yes | yes |
Reserved Keywords
-----------------
| Keyword | Potential usage |
| --------- | --------------------- |
| `var` | variable declaration |
| `static` | variable declaration |
| `begin` | block scope |
| `end` | block scope |
| `shared` | share value |
| `each` | looping |
| `then` | control flow |
| `goto` | control flow |
| `exit` | control flow |
| `unless` | control flow |
| `match` | matching |
| `case` | matching |
| `public` | function/field access |
| `new` | constructor |
| `use` | import namespace |
| `with` | scope |
| `module` | module |
| `package` | package |
| `thread` | threading |
| `spawn` | threading |
| `go` | threading |
| `await` | async |
| `async` | async |
| `sync` | async |
| `yield` | async |
| `default` | special value |
| `void` | special value |
| `null` | special value |
| `nil` | special value |

View File

@ -1,16 +0,0 @@
Literals Syntax
===============
{{#include ../links.md}}
| Type | Literal syntax |
| :--------------------------------: | :-----------------------------------------------------------------------------------------: |
| `INT` | decimal: `42`, `-123`, `0`<br/>hex: `0x????..`<br/>binary: `0b????..`<br/>octal: `0o????..` |
| `FLOAT` | `42.0`, `-123.456`, `0.0` |
| [String] | `"... \x?? \u???? \U???????? ..."` |
| [Character][string] | single: `'?'`<br/>ASCII hex: `'\x??'`<br/>Unicode: `'\u????'`, `'\U????????'` |
| [`Array`] | `[ ???, ???, ??? ]` |
| [Object map] | `#{ a: ???, b: ???, c: ???, "def": ??? }` |
| Boolean true | `true` |
| Boolean false | `false` |
| `Nothing`/`null`/`nil`/`void`/Unit | `()` |

View File

@ -1,74 +0,0 @@
Operators and Symbols
====================
{{#include ../links.md}}
Operators
---------
| Operator | Description | Binary? | Binding direction |
| :-----------------------------------------------------------------------------------------: | -------------------------------------- | :--------: | :---------------: |
| `+` | add | yes | left |
| `-` | 1) subtract<br/>2) negative (prefix) | yes<br/>no | left<br/>right |
| `*` | multiply | yes | left |
| `/` | divide | yes | left |
| `%` | modulo | yes | left |
| `~` | power | yes | left |
| `>>` | right bit-shift | yes | left |
| `<<` | left bit-shift | yes | left |
| `&` | 1) bit-wise _AND_<br/>2) boolean _AND_ | yes | left |
| <code>\|</code> | 1) bit-wise _OR_<br/>2) boolean _OR_ | yes | left |
| `^` | 1) bit-wise _XOR_<br/>2) boolean _XOR_ | yes | left |
| `=`, `+=`, `-=`, `*=`, `/=`,<br/>`~=`, `%=`, `<<=`, `>>=`, `&=`,<br/><code>\|=</code>, `^=` | assignments | yes | right |
| `==` | equals to | yes | left |
| `~=` | not equals to | yes | left |
| `>` | greater than | yes | left |
| `>=` | greater than or equals to | yes | left |
| `<` | less than | yes | left |
| `<=` | less than or equals to | yes | left |
| `&&` | boolean _AND_ (short-circuits) | yes | left |
| <code>\|\|</code> | boolean _OR_ (short-circuits) | yes | left |
| `!` | boolean _NOT_ | no | left |
| `[` .. `]` | indexing | yes | right |
| `.` | 1) property access<br/>2) method call | yes | right |
Symbols and Patterns
--------------------
| Symbol | Name | Description |
| ---------------------------------- | :------------------: | ------------------------------------- |
| `_` | underscore | default `switch` case |
| `;` | semicolon | statement separator |
| `,` | comma | list separator |
| `:` | colon | [object map] property value separator |
| `::` | path | module path separator |
| `#{` .. `}` | hash map | [object map] literal |
| `"` .. `"` | double quote | [string] |
| `'` .. `'` | single quote | [character][string] |
| `\` | escape | escape character literal |
| `(` .. `)` | parentheses | expression grouping |
| `{` .. `}` | braces | block statement |
| <code>\|</code> .. <code>\|</code> | pipes | closure |
| `[` .. `]` | brackets | [array] literal |
| `!` | bang | function call in calling scope |
| `=>` | double arrow | `switch` expression case separator |
| `//` | comment | line comment |
| `/*` .. `*/` | comment | block comment |
| `(*` .. `*)` | comment | _reserved_ |
| `<` .. `>` | angular brackets | _reserved_ |
| `++` | increment | _reserved_ |
| `--` | decrement | _reserved_ |
| `..` | range | _reserved_ |
| `...` | range | _reserved_ |
| `**` | exponentiation | _reserved_ |
| `#` | hash | _reserved_ |
| `@` | at | _reserved_ |
| `$` | dollar | _reserved_ |
| `->` | arrow | _reserved_ |
| `<-` | left arrow | _reserved_ |
| `===` | strict equals to | _reserved_ |
| `!==` | strict not equals to | _reserved_ |
| `:=` | assignment | _reserved_ |
| `::<` .. `>` | turbofish | _reserved_ |

View File

@ -1,8 +0,0 @@
{
"version": "0.19.10",
"repoHome": "https://github.com/jonathandturner/rhai/blob/master",
"repoTree": "https://github.com/jonathandturner/rhai/tree/master",
"rootUrl": "",
"rootUrlX": "/rhai",
"rootUrlXX": "/rhai/vnext"
}

View File

@ -1,95 +0,0 @@
Calling Rhai Functions from Rust
===============================
{{#include ../links.md}}
Rhai also allows working _backwards_ from the other direction &ndash; i.e. calling a Rhai-scripted function
from Rust via `Engine::call_fn`.
Functions declared with `private` are hidden and cannot be called from Rust (see also [modules]).
```rust
// Define functions in a script.
let ast = engine.compile(true,
r#"
// a function with two parameters: string and i64
fn hello(x, y) {
x.len + y
}
// functions can be overloaded: this one takes only one parameter
fn hello(x) {
x * 2
}
// this one takes no parameters
fn hello() {
42
}
// this one is private and cannot be called by 'call_fn'
private hidden() {
throw "you shouldn't see me!";
}
"#)?;
// A custom scope can also contain any variables/constants available to the functions
let mut scope = Scope::new();
// Evaluate a function defined in the script, passing arguments into the script as a tuple.
// Beware, arguments must be of the correct types because Rhai does not have built-in type conversions.
// If arguments of the wrong types are passed, the Engine will not find the function.
let result: i64 = engine.call_fn(&mut scope, &ast, "hello", ( String::from("abc"), 123_i64 ) )?;
// ^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// return type must be specified put arguments in a tuple
let result: i64 = engine.call_fn(&mut scope, &ast, "hello", (123_i64,) )?;
// ^^^^^^^^^^ tuple of one
let result: i64 = engine.call_fn(&mut scope, &ast, "hello", () )?;
// ^^ unit = tuple of zero
// The following call will return a function-not-found error because
// 'hidden' is declared with 'private'.
let result: () = engine.call_fn(&mut scope, &ast, "hidden", ())?;
```
Low-Level API &ndash; `Engine::call_fn_dynamic`
----------------------------------------------
For more control, construct all arguments as `Dynamic` values and use `Engine::call_fn_dynamic`, passing it
anything that implements `AsMut<Dynamic>` (such as a simple array or a `Vec<Dynamic>`):
```rust
let result = engine.call_fn_dynamic(
&mut scope, // scope to use
&ast, // AST containing the functions
"hello", // function entry-point
None, // 'this' pointer, if any
[ String::from("abc").into(), 123_i64.into() ] // arguments
)?;
```
Binding the `this` Pointer
-------------------------
`Engine::call_fn_dynamic` can also bind a value to the `this` pointer of a script-defined function.
```rust
let ast = engine.compile("fn action(x) { this += x; }")?;
let mut value: Dynamic = 1_i64.into();
let result = engine.call_fn_dynamic(
&mut scope,
&ast,
"action",
Some(&mut value), // binding the 'this' pointer
[ 41_i64.into() ]
)?;
assert_eq!(value.as_int()?, 42);
```

View File

@ -1,27 +0,0 @@
Compile a Script (to AST)
========================
{{#include ../links.md}}
To repeatedly evaluate a script, _compile_ it first with `Engine::compile` into an `AST`
(abstract syntax tree) form.
`Engine::eval_ast` evaluates a pre-compiled `AST`.
```rust
// Compile to an AST and store it for later evaluations
let ast = engine.compile("40 + 2")?;
for _ in 0..42 {
let result: i64 = engine.eval_ast(&ast)?;
println!("Answer #{}: {}", i, result); // prints 42
}
```
Compiling a script file is also supported with `Engine::compile_file`
(not available under [`no_std`] or in [WASM] builds):
```rust
let ast = engine.compile_file("hello_world.rhai".into())?;
```

View File

@ -1,115 +0,0 @@
Custom Operators
================
{{#include ../links.md}}
For use as a DSL (Domain-Specific Languages), it is sometimes more convenient to augment Rhai with
customized operators performing specific logic.
`Engine::register_custom_operator` registers a keyword as a custom operator, giving it a particular
_precedence_ (which cannot be zero).
Example
-------
```rust
use rhai::{Engine, RegisterFn};
let mut engine = Engine::new();
// Register a custom operator named 'foo' and give it a precedence of 160
// (i.e. between +|- and *|/)
// Also register the implementation of the customer operator as a function
engine
.register_custom_operator("foo", 160)?
.register_fn("foo", |x: i64, y: i64| (x * y) - (x + y));
// The custom operator can be used in expressions
let result = engine.eval_expression::<i64>("1 + 2 * 3 foo 4 - 5 / 6")?;
// ^ custom operator
// The above is equivalent to: 1 + ((2 * 3) foo 4) - (5 / 6)
result == 15;
```
Alternatives to a Custom Operator
--------------------------------
Custom operators are merely _syntactic sugar_. They map directly to registered functions.
Therefore, the following are equivalent (assuming `foo` has been registered as a custom operator):
```rust
1 + 2 * 3 foo 4 - 5 / 6 // use custom operator
1 + foo(2 * 3, 4) - 5 / 6 // use function call
```
A script using custom operators can always be pre-processed, via a pre-processor application,
into a syntax that uses the corresponding function calls.
Using `Engine::register_custom_operator` merely enables a convenient shortcut.
Must be a Valid Identifier or Reserved Symbol
--------------------------------------------
All custom operators must be _identifiers_ that follow the same naming rules as [variables].
Alternatively, they can also be [reserved symbols]({{rootUrl}}/appendix/operators.md#symbols),
[disabled operators or keywords][disable keywords and operators].
```rust
engine.register_custom_operator("foo", 20); // 'foo' is a valid custom operator
engine.register_custom_operator("#", 20); // the reserved symbol '#' is also
// a valid custom operator
engine.register_custom_operator("+", 30); // <- error: '+' is an active operator
engine.register_custom_operator("=>", 30); // <- error: '=>' is an active symbol
```
Binary Operators Only
---------------------
All custom operators must be _binary_ (i.e. they take two operands).
_Unary_ custom operators are not supported.
```rust
engine
.register_custom_operator("foo", 160)?
.register_fn("foo", |x: i64| x * x);
engine.eval::<i64>("1 + 2 * 3 foo 4 - 5 / 6")?; // error: function 'foo (i64, i64)' not found
```
Operator Precedence
-------------------
All operators in Rhai has a _precedence_ indicating how tightly they bind.
A higher precedence binds more tightly than a lower precedence, so `*` and `/` binds before `+` and `-` etc.
When registering a custom operator, the operator's precedence must also be provided.
The following _precedence table_ shows the built-in precedence of standard Rhai operators:
| Category | Operators | Precedence (0-255) |
| ------------------- | :-------------------------------------------------------------------------------------: | :----------------: |
| Assignments | `=`, `+=`, `-=`, `*=`, `/=`, `~=`, `%=`,<br/>`<<=`, `>>=`, `&=`, <code>\|=</code>, `^=` | 0 |
| Logic and bit masks | <code>\|\|</code>, <code>\|</code>, `^` | 30 |
| Logic and bit masks | `&&`, `&` | 60 |
| Comparisons | `==`, `!=` | 90 |
| | `in` | 110 |
| Comparisons | `>`, `>=`, `<`, `<=` | 130 |
| Arithmetic | `+`, `-` | 150 |
| Arithmetic | `*`, `/`, `%` | 180 |
| Arithmetic | `~` | 190 |
| Bit-shifts | `<<`, `>>` | 210 |
| Object | `.` _(binds to right)_ | 240 |
| Unary operators | unary `+`, `-`, `!` _(binds to right)_ | 255 |

View File

@ -1,404 +0,0 @@
Extend Rhai with Custom Syntax
=============================
{{#include ../links.md}}
For the ultimate adventurous, there is a built-in facility to _extend_ the Rhai language
with custom-defined _syntax_.
But before going off to define the next weird statement type, heed this warning:
Don't Do It™
------------
Stick with standard language syntax as much as possible.
Having to learn Rhai is bad enough, no sane user would ever want to learn _yet_ another
obscure language syntax just to do something.
Try to use [custom operators] first. Defining a custom syntax should be considered a _last resort_.
Where This Might Be Useful
-------------------------
* Where an operation is used a _LOT_ and a custom syntax saves a lot of typing.
* Where a custom syntax _significantly_ simplifies the code and _significantly_ enhances understanding of the code's intent.
* Where certain logic cannot be easily encapsulated inside a function.
* Where you just want to confuse your user and make their lives miserable, because you can.
Step One &ndash; Design The Syntax
---------------------------------
A custom syntax is simply a list of symbols.
These symbol types can be used:
* Standard [keywords]({{rootUrl}}/appendix/keywords.md)
* Standard [operators]({{rootUrl}}/appendix/operators.md#operators).
* Reserved [symbols]({{rootUrl}}/appendix/operators.md#symbols).
* Identifiers following the [variable] naming rules.
* `$expr$` &ndash; any valid expression, statement or statement block.
* `$block$` &ndash; any valid statement block (i.e. must be enclosed by `'{'` .. `'}'`).
* `$ident$` &ndash; any [variable] name.
### The First Symbol Must be an Identifier
There is no specific limit on the combination and sequencing of each symbol type,
except the _first_ symbol which must be a custom keyword that follows the naming rules
of [variables].
The first symbol also cannot be a normal or reserved [keyword].
In other words, any valid identifier that is not a [keyword] will work fine.
### The First Symbol Must be Unique
Rhai uses the _first_ symbol as a clue to parse custom syntax.
Therefore, at any one time, there can only be _one_ custom syntax starting with each unique symbol.
Any new custom syntax definition using the same first symbol simply _overwrites_ the previous one.
### Example
```rust
exec $ident$ <- $expr$ : $block$
```
The above syntax is made up of a stream of symbols:
| Position | Input | Symbol | Description |
| :------: | :---: | :-------: | -------------------------------------------------------------------------------------------------------- |
| 1 | | `exec` | custom keyword |
| 2 | 1 | `$ident$` | a variable name |
| 3 | | `<-` | the left-arrow symbol (which is a [reserved symbol]({{rootUrl}}/appendix/operators.md#symbols) in Rhai). |
| 4 | 2 | `$expr$` | an expression, which may be enclosed with `{` .. `}`, or not. |
| 5 | | `:` | the colon symbol |
| 6 | 3 | `$block$` | a statement block, which must be enclosed with `{` .. `}`. |
This syntax matches the following sample code and generates three inputs (one for each non-keyword):
```rust
// Assuming the 'exec' custom syntax implementation declares the variable 'hello':
let x = exec hello <- foo(1, 2) : {
hello += bar(hello);
baz(hello);
};
print(x); // variable 'x' has a value returned by the custom syntax
print(hello); // variable declared by a custom syntax persists!
```
Step Two &ndash; Implementation
------------------------------
Any custom syntax must include an _implementation_ of it.
### Function Signature
The function signature of an implementation is:
> `Fn(context: &mut EvalContext, inputs: &[Expression]) -> Result<Dynamic, Box<EvalAltResult>>`
where:
| Parameter | Type | Description |
| -------------------------- | :-------------------------------------: | ---------------------------------------------------------------------------------------------------------------------- |
| `context` | `&mut EvalContext` | mutable reference to the current evaluation _context_ |
| &bull; `scope()` | `&Scope` | reference to the current [`Scope`] |
| &bull; `scope_mut()` | `&mut &mut Scope` | mutable reference to the current [`Scope`]; variables can be added to/removed from it |
| &bull; `engine()` | `&Engine` | reference to the current [`Engine`] |
| &bull; `source()` | `Option<&str>` | reference to the current source, if any |
| &bull; `iter_imports()` | `impl Iterator<Item = (&str, &Module)>` | iterator of the current stack of [modules] imported via `import` statements |
| &bull; `imports()` | `&Imports` | reference to the current stack of [modules] imported via `import` statements; requires the [`internals`] feature |
| &bull; `iter_namespaces()` | `impl Iterator<Item = &Module>` | iterator of the namespaces (as [modules]) containing all script-defined functions |
| &bull; `namespaces()` | `&[&Module]` | reference to the namespaces (as [modules]) containing all script-defined functions; requires the [`internals`] feature |
| &bull; `this_ptr()` | `Option<&Dynamic>` | reference to the current bound [`this`] pointer, if any |
| &bull; `call_level()` | `usize` | the current nesting level of function calls |
| `inputs` | `&[Expression]` | a list of input expression trees |
### Return Value
Return value is the result of evaluating the custom syntax expression.
### Access Arguments
The most important argument is `inputs` where the matched identifiers (`$ident$`), expressions/statements (`$expr$`)
and statement blocks (`$block$`) are provided.
To access a particular argument, use the following patterns:
| Argument type | Pattern (`n` = slot in `inputs`) | Result type | Description |
| :-----------: | ---------------------------------------- | :----------: | ------------------ |
| `$ident$` | `inputs[n].get_variable_name().unwrap()` | `&str` | name of a variable |
| `$expr$` | `inputs.get(n).unwrap()` | `Expression` | an expression tree |
| `$block$` | `inputs.get(n).unwrap()` | `Expression` | an expression tree |
### Evaluate an Expression Tree
Use the `EvalContext::eval_expression_tree` method to evaluate an arbitrary expression tree
within the current evaluation context.
```rust
let expression = inputs.get(0).unwrap();
let result = context.eval_expression_tree(expression)?;
```
### Declare Variables
New variables maybe declared (usually with a variable name that is passed in via `$ident$).
It can simply be pushed into the [`Scope`].
However, beware that all new variables must be declared _prior_ to evaluating any expression tree.
In other words, any [`Scope`] calls that change the list of must come _before_ any
`EvalContext::eval_expression_tree` calls.
```rust
let var_name = inputs[0].get_variable_name().unwrap();
let expression = inputs.get(1).unwrap();
context.scope_mut().push(var_name, 0 as INT); // do this BEFORE 'context.eval_expression_tree'!
let result = context.eval_expression_tree(expression)?;
```
Step Three &ndash; Register the Custom Syntax
--------------------------------------------
Use `Engine::register_custom_syntax` to register a custom syntax.
Again, beware that the _first_ symbol must be unique. If there already exists a custom syntax starting
with that symbol, the previous syntax will be overwritten.
The syntax is passed simply as a slice of `&str`.
```rust
// Custom syntax implementation
fn implementation_func(
context: &mut EvalContext,
inputs: &[Expression]
) -> Result<Dynamic, Box<EvalAltResult>> {
let var_name = inputs[0].get_variable_name().unwrap().to_string();
let stmt = inputs.get(1).unwrap();
let condition = inputs.get(2).unwrap();
// Push one new variable into the scope BEFORE 'context.eval_expression_tree'
context.scope_mut().push(var_name, 0 as INT);
loop {
// Evaluate the statement block
context.eval_expression_tree(stmt)?;
// Evaluate the condition expression
let stop = !context.eval_expression_tree(condition)?
.as_bool().map_err(|err| Box::new(
EvalAltResult::ErrorMismatchDataType(
"bool".to_string(),
err.to_string(),
condition.position(),
)
))?;
if stop {
break;
}
}
Ok(Dynamic::UNIT)
}
// Register the custom syntax (sample): exec |x| -> { x += 1 } while x < 0
engine.register_custom_syntax(
&[ "exec", "|", "$ident$", "|", "->", "$block$", "while", "$expr$" ], // the custom syntax
1, // the number of new variables declared within this custom syntax
implementation_func
)?;
```
Remember that a custom syntax acts as an _expression_, so it can show up practically anywhere:
```rust
// Use as an expression:
let foo = (exec |x| -> { x += 1 } while x < 0) * 100;
// Use as a function call argument:
do_something(exec |x| -> { x += 1 } while x < 0, 24, true);
// Use as a statement:
exec |x| -> { x += 1 } while x < 0;
// ^ terminate statement with ';'
```
Step Four &ndash; Disable Unneeded Statement Types
-------------------------------------------------
When a DSL needs a custom syntax, most likely than not it is extremely specialized.
Therefore, many statement types actually may not make sense under the same usage scenario.
So, while at it, better [disable][disable keywords and operators] those built-in keywords
and operators that should not be used by the user. The would leave only the bare minimum
language surface exposed, together with the custom syntax that is tailor-designed for
the scenario.
A keyword or operator that is disabled can still be used in a custom syntax.
In an extreme case, it is possible to disable _every_ keyword in the language, leaving only
custom syntax (plus possibly expressions). But again, Don't Do It™ &ndash; unless you are certain
of what you're doing.
Step Five &ndash; Document
-------------------------
For custom syntax, documentation is crucial.
Make sure there are _lots_ of examples for users to follow.
Step Six &ndash; Profit!
------------------------
Really Advanced &ndash; Custom Parsers
-------------------------------------
Sometimes it is desirable to have multiple custom syntax starting with the
same symbol. This is especially common for _command-style_ syntax where the
second symbol calls a particular command:
```rust
// The following simulates a command-style syntax, all starting with 'perform'.
perform hello world; // A fixed sequence of symbols
perform action 42; // Perform a system action with a parameter
perform update system; // Update the system
perform check all; // Check all system settings
perform cleanup; // Clean up the system
perform add something; // Add something to the system
perform remove something; // Delete something from the system
```
Alternatively, a custom syntax may have variable length, with a termination symbol:
```rust
// The following is a variable-length list terminated by '>'
tags < "foo", "bar", 123, ... , x+y, true >
```
For even more flexibility in order to handle these advanced use cases, there is a
_low level_ API for custom syntax that allows the registration of an entire mini-parser.
Use `Engine::register_custom_syntax_raw` to register a custom syntax _parser_
together with the implementation function.
### How Custom Parsers Work
A custom parser takes as input parameters two pieces of information:
* The symbols parsed so far; `$ident$` is replaced with the actual identifier parsed,
while `$expr$` and `$block$` stay as they were.
The custom parser can inspect this symbols stream to determine the next symbol to parse.
* The _look-ahead_ symbol, which is the symbol that will be parsed _next_.
If the look-ahead is an expected symbol, the customer parser just returns it to continue parsing,
or it can return `$ident$` to parse it as an identifier, or even `$expr$` to start parsing
an expression.
If the look-ahead is '`{`', then the custom parser may also return `$block$` to start parsing a
statements block.
If the look-ahead is unexpected, the custom parser should then return the symbol expected
and Rhai will fail with a parse error containing information about the expected symbol.
A custom parser always returns the _next_ symbol expected, which can also be `$ident$`,
`$expr$` or `$block$`, or `None` if parsing should terminate (_without_ reading the
look-ahead symbol).
### Example
```rust
engine.register_custom_syntax_raw(
"perform",
// The custom parser implementation - always returns the next symbol expected
// 'look_ahead' is the next symbol about to be read
|symbols, look_ahead| match symbols.len() {
// perform ...
1 => Ok(Some("$ident$".to_string())),
// perform command ...
2 => match symbols[1].as_str() {
"action" => Ok(Some("$expr$".into())),
"hello" => Ok(Some("world".into())),
"update" | "check" | "add" | "remove" => Ok(Some("$ident$".into())),
"cleanup" => Ok(None),
cmd => Err(ParseError(Box::new(ParseErrorType::BadInput(
LexError::ImproperSymbol(format!("Improper command: {}", cmd))
)), Position::NONE)),
},
// perform command arg ...
3 => match (symbols[1].as_str(), symbols[2].as_str()) {
("action", _) => Ok(None),
("hello", "world") => Ok(None),
("update", arg) if arg == "system" => Ok(None),
("update", arg) if arg == "client" => Ok(None),
("check", arg) => Ok(None),
("add", arg) => Ok(None),
("remove", arg) => Ok(None),
(cmd, arg) => Err(ParseError(Box::new(ParseErrorType::BadInput(
LexError::ImproperSymbol(
format!("Invalid argument for command {}: {}", cmd, arg)
)
)), Position::NONE)),
},
_ => unreachable!(),
},
// Number of new variables declared by this custom syntax
0,
// Implementation function
implementation_func
);
```
### Function Signature
The custom syntax parser has the following signature:
> `Fn(symbols: &[ImmutableString], look_ahead: &str) -> Result<Option<ImmutableString>, ParseError>`
where:
| Parameter | Type | Description |
| ------------ | :------------------: | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `symbols` | `&[ImmutableString]` | a slice of symbols that have been parsed so far, possibly containing `$expr$` and/or `$block$`; `$ident$` is replaced by the actual identifier |
| `look_ahead` | `&str` | a string slice containing the next symbol that is about to be read |
Most strings are [`ImmutableString`][string]'s so it is usually more efficient to just `clone` the appropriate one
(if any matches, or keep an internal cache for commonly-used symbols) as the return value.
### Return Value
The return value is `Result<Option<ImmutableString>, ParseError>` where:
| Value | Description |
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Ok(None)` | parsing complete and there are no more symbols to match |
| `Ok(Some(symbol))` | the next symbol to match, which can also be `$expr$`, `$ident$` or `$block$` |
| `Err(ParseError)` | error that is reflected back to the [`Engine`] &ndash; normally `ParseError(ParseErrorType::BadInput(LexError::ImproperSymbol(message)), Position::NONE)` to indicate that there is a syntax error, but it can be any `ParseError`. |

View File

@ -1,28 +0,0 @@
Disable Certain Keywords and/or Operators
========================================
{{#include ../links.md}}
For certain embedded usage, it is sometimes necessary to restrict the language to a strict subset of Rhai
to prevent usage of certain language features.
Rhai supports surgically disabling a keyword or operator via the `Engine::disable_symbol` method.
```rust
use rhai::Engine;
let mut engine = Engine::new();
engine
.disable_symbol("if") // disable the 'if' keyword
.disable_symbol("+="); // disable the '+=' operator
// The following all return parse errors.
engine.compile("let x = if true { 42 } else { 0 };")?;
// ^ 'if' is rejected as a reserved keyword
engine.compile("let x = 40 + 2; x += 1;")?;
// ^ '+=' is not recognized as an operator
// ^ other operators are not affected
```

View File

@ -1,92 +0,0 @@
Use Rhai as a Domain-Specific Language (DSL)
===========================================
{{#include ../links.md}}
Rhai can be successfully used as a domain-specific language (DSL).
Expressions Only
----------------
In many DSL scenarios, only evaluation of expressions is needed.
The [`Engine::eval_expression_XXX`][`eval_expression`] API can be used to restrict
a script to expressions only.
Unicode Standard Annex #31 Identifiers
-------------------------------------
Variable names and other identifiers do not necessarily need to be ASCII-only.
The [`unicode-xid-ident`] feature, when turned on, causes Rhai to allow variable names and identifiers
that follow [Unicode Standard Annex #31](http://www.unicode.org/reports/tr31/).
This is sometimes useful in a non-English DSL.
Disable Keywords and/or Operators
--------------------------------
In some DSL scenarios, it is necessary to further restrict the language to exclude certain
language features that are not necessary or dangerous to the application.
For example, a DSL may disable the `while` loop while keeping all other statement types intact.
It is possible, in Rhai, to surgically [disable keywords and operators].
Custom Operators
----------------
On the other hand, some DSL scenarios require special operators that make sense only for
that specific environment. In such cases, it is possible to define [custom operators] in Rhai.
For example:
```rust
let animal = "rabbit";
let food = "carrot";
animal eats food // custom operator 'eats'
eats(animal, food) // <- the above really de-sugars to this
```
Although a [custom operator] always de-sugars to a simple function call,
nevertheless it makes the DSL syntax much simpler and expressive.
Custom Syntax
-------------
For advanced DSL scenarios, it is possible to define entire expression [_syntax_][custom syntax] &ndash
essentially custom statement types.
For example, the following is a SQL-like syntax for some obscure DSL operation:
```rust
let table = [..., ..., ..., ...];
// Syntax = calculate $ident$ ( $expr$ -> $ident$ ) => $ident$ : $expr$
let total = calculate sum(table->price) => row : row.weight > 50;
// Note: There is nothing special about those symbols; to make it look exactly like SQL:
// Syntax = SELECT $ident$ ( $ident$ ) AS $ident$ FROM $expr$ WHERE $expr$
let total = SELECT sum(price) AS row FROM table WHERE row.weight > 50;
```
After registering this custom syntax with Rhai, it can be used anywhere inside a script as
a normal expression.
For its evaluation, the callback function will receive the following list of inputs:
* `inputs[0] = "sum"` - math operator
* `inputs[1] = "price"` - field name
* `inputs[2] = "row"` - loop variable name
* `inputs[3] = Expression(table)` - data source
* `inputs[4] = Expression(row.wright > 50)` - filter predicate
Other identifiers, such as `"calculate"`, `"FROM"`, as well as symbols such as `->` and `:` etc.,
are parsed in the order defined within the custom syntax.

View File

@ -1,27 +0,0 @@
Evaluate Expressions Only
========================
{{#include ../links.md}}
Sometimes a use case does not require a full-blown scripting _language_, but only needs to evaluate _expressions_.
In these cases, use the `Engine::compile_expression` and `Engine::eval_expression` methods or their `_with_scope` variants.
```rust
let result = engine.eval_expression::<i64>("2 + (10 + 10) * 2")?;
```
When evaluating _expressions_, no full-blown statement (e.g. `if`, `while`, `for`, `fn`) &ndash; not even variable assignment &ndash;
is supported and will be considered parse errors when encountered.
[Closures] and [anonymous functions] are also not supported because in the background they compile to functions.
```rust
// The following are all syntax errors because the script is not an expression.
engine.eval_expression::<()>("x = 42")?;
let ast = engine.compile_expression("let x = 42")?;
let result = engine.eval_expression_with_scope::<i64>(&mut scope, "if x { 42 } else { 123 }")?;
```

View File

@ -1,43 +0,0 @@
Create a Rust Closure from a Rhai Function
=========================================
{{#include ../links.md}}
It is possible to further encapsulate a script in Rust such that it becomes a normal Rust function.
Such a _closure_ is very useful as call-back functions.
Creating them is accomplished via the `Func` trait which contains `create_from_script`
(as well as its companion method `create_from_ast`):
```rust
use rhai::{Engine, Func}; // use 'Func' for 'create_from_script'
let engine = Engine::new(); // create a new 'Engine' just for this
let script = "fn calc(x, y) { x + y.len < 42 }";
// Func takes two type parameters:
// 1) a tuple made up of the types of the script function's parameters
// 2) the return type of the script function
//
// 'func' will have type Box<dyn Fn(i64, String) -> Result<bool, Box<EvalAltResult>>> and is callable!
let func = Func::<(i64, String), bool>::create_from_script(
// ^^^^^^^^^^^^^ function parameter types in tuple
engine, // the 'Engine' is consumed into the closure
script, // the script, notice number of parameters must match
"calc" // the entry-point function name
)?;
func(123, "hello".to_string())? == false; // call the closure
schedule_callback(func); // pass it as a callback to another function
// Although there is nothing you can't do by manually writing out the closure yourself...
let engine = Engine::new();
let ast = engine.compile(script)?;
schedule_callback(Box::new(move |x: i64, y: String| -> Result<bool, Box<EvalAltResult>> {
engine.call_fn(&mut Scope::new(), &ast, "calc", (x, y))
}));
```

View File

@ -1,60 +0,0 @@
Hello World in Rhai
===================
{{#include ../links.md}}
To get going with Rhai is as simple as creating an instance of the scripting engine `rhai::Engine` via
`Engine::new`, then calling the `eval` method:
```rust
use rhai::{Engine, EvalAltResult};
fn main() -> Result<(), Box<EvalAltResult>>
{
let engine = Engine::new();
let result = engine.eval::<i64>("40 + 2")?;
// ^^^^^^^ cast the result to an 'i64', this is required
println!("Answer: {}", result); // prints 42
Ok(())
}
```
Evaluate a script file directly:
```rust
// 'eval_file' takes a 'PathBuf'
let result = engine.eval_file::<i64>("hello_world.rhai".into())?;
```
Error Type
----------
`rhai::EvalAltResult` is the standard Rhai error type, which is a Rust `enum` containing all errors encountered
during the parsing or evaluation process.
Return Type
-----------
The type parameter for `Engine::eval` is used to specify the type of the return value,
which _must_ match the actual type or an error is returned. Rhai is very strict here.
There are two ways to specify the return type &ndash; _turbofish_ notation, or type inference.
Use [`Dynamic`] for uncertain return types.
```rust
let result = engine.eval::<i64>("40 + 2")?; // return type is i64, specified using 'turbofish' notation
let result: i64 = engine.eval("40 + 2")?; // return type is inferred to be i64
result.is::<i64>() == true;
let result: Dynamic = engine.eval("boo()")?; // use 'Dynamic' if you're not sure what type it'll be!
let result = engine.eval::<String>("40 + 2")?; // returns an error because the actual return type is i64, not String
```

View File

@ -1,8 +0,0 @@
Using the Engine
================
{{#include ../links.md}}
Rhai's interpreter resides in the [`Engine`] type under the master `rhai` namespace.
This section shows how to set up, configure and use this scripting engine.

View File

@ -1,107 +0,0 @@
Export Functions Metadata to JSON
================================
{{#include ../../links.md}}
`Engine::gen_fn_metadata_to_json`<br/>`Engine::gen_fn_metadata_with_ast_to_json`
------------------------------------------------------------------------------
As part of a _reflections_ API, `Engine::gen_fn_metadata_to_json` and the corresponding
`Engine::gen_fn_metadata_with_ast_to_json` export the full list of [functions metadata]
in JSON format.
The [`metadata`] feature must be used to turn on this API, which requires
the [`serde_json`](https://crates.io/crates/serde_json) crate.
### Sources
Functions from the following sources are included:
1) Script-defined functions in an [`AST`] (for `Engine::gen_fn_metadata_with_ast_to_json`)
2) Native Rust functions registered into the global namespace via the `Engine::register_XXX` API
3) _Public_ (i.e. non-[`private`]) functions (native Rust or Rhai scripted) in static modules
registered via `Engine::register_static_module`
4) Native Rust functions in global modules registered via `Engine::register_global_module` (optional)
Notice that if a function has been [overloaded][function overloading], only the overriding function's
metadata is included.
JSON Schema
-----------
The JSON schema used to hold functions metadata is very simple, containing a nested structure of
`modules` and a list of `functions`.
### Modules Schema
```json
{
"modules":
{
"sub_module_1":
{
"modules":
{
"sub_sub_module_A":
{
"functions":
[
{ ... function metadata ... },
{ ... function metadata ... },
{ ... function metadata ... },
{ ... function metadata ... },
...
]
},
"sub_sub_module_B":
{
...
}
}
},
"sub_module_2":
{
...
},
...
},
"functions":
[
{ ... function metadata ... },
{ ... function metadata ... },
{ ... function metadata ... },
{ ... function metadata ... },
...
]
}
```
### Function Metadata Schema
```json
{
"namespace": "internal" | "global",
"access": "public" | "private",
"name": "fn_name",
"type": "native" | "script",
"numParams": 42, /* number of parameters */
"params": /* omitted if no parameters */
[
{ "name": "param_1", "type": "type_1" },
{ "name": "param_2" }, /* no type info */
{ "name": "_", "type": "type_3" },
...
],
"returnType": "ret_type", /* omitted if unknown */
"signature": "[private] fn_name(param_1: type_1, param_2, _: type_3) -> ret_type",
"docComments": /* omitted if none */
[
"/// doc-comment line 1",
"/// doc-comment line 2",
"/** doc-comment block */",
...
]
}
```

View File

@ -1,91 +0,0 @@
Generate Function Signatures
===========================
{{#include ../../links.md}}
`Engine::gen_fn_signatures`
--------------------------
As part of a _reflections_ API, `Engine::gen_fn_signatures` returns a list of function _signatures_
(as `Vec<String>`), each corresponding to a particular function available to that [`Engine`] instance.
> `fn_name ( param_1: type_1, param_2: type_2, ... , param_n : type_n ) -> return_type`
### Sources
Functions from the following sources are included, in order:
1) Native Rust functions registered into the global namespace via the `Engine::register_XXX` API
2) _Public_ (i.e. non-[`private`]) functions (native Rust or Rhai scripted) in global sub-modules
registered via `Engine::register_static_module`.
3) Native Rust functions in global modules registered via `Engine::register_global_module` (optional)
Functions Metadata
------------------
Beware, however, that not all function signatures contain parameters and return value information.
### `Engine::register_XXX`
For instance, functions registered via `Engine::register_XXX` contain no information on
the names of parameter and their actual types because Rust simply does not make such metadata
available natively. The return type is also undetermined.
A function registered under the name `foo` with three parameters and unknown return type:
> `foo(_, _, _)`
An operator function &ndash; again, unknown parameters and return type.
Notice that function names do not need to be valid identifiers.
> `+(_, _)`
A [property setter][getters/setters] &ndash; again, unknown parameters and return type.
Notice that function names do not need to be valid identifiers.
In this case, the first parameter should be `&mut T` of the custom type and the return value is `()`:
> `set$prop(_, _, _)`
### Script-Defined Functions
Script-defined [function] signatures contain parameter names. Since all parameters, as well as
the return value, are [`Dynamic`] the types are simply not shown.
A script-defined function always takes dynamic arguments, and the return type is also dynamic,
so no type information is needed:
> `foo(x, y, z)`
probably defined as:
```rust
fn foo(x, y, z) {
...
}
```
is the same as:
> `foo(x: Dynamic, y: Dynamic, z: Dynamic) -> Result<Dynamic, Box<EvalAltResult>>`
### Plugin Functions
Functions defined in [plugin modules] are the best. They contain all the metadata
describing the functions.
For example, a plugin function `merge`:
> `merge(list: &mut MyStruct<i64>, num: usize, name: &str) -> Option<bool>`
Notice that function names do not need to be valid identifiers.
For example, an operator defined as a [fallible function] in a [plugin module] via
`#[rhai_fn(name="+=", return_raw)]` returns `Result<bool, Box<EvalAltResult>>`:
> `+=(list: &mut MyStruct<i64>, num: usize, name: &str) -> Result<bool, Box<EvalAltResult>>`
For example, a [property getter][getters/setters] defined in a [plugin module]:
> `get$prop(obj: &mut MyStruct<i64>) -> String`

View File

@ -1,28 +0,0 @@
Functions Metadata
==================
{{#include ../../links.md}}
The _metadata_ of a [function] means all relevant information related to a function's
definition including:
1. Its callable name
2. Its access mode (public or [private][`private`])
3. Its parameters and types (if any)
4. Its return value and type (if any)
5. Its nature (i.e. native Rust-based or Rhai script-based)
6. Its [namespace][function namespace] (module or global)
7. Its purpose, in the form of [doc-comments]
8. Usage notes, warnings, etc., in the form of [doc-comments]
A function's _signature_ encapsulates the first four pieces of information in a single
concise line of definition:
> `[private] fn_name ( param_1: type_1, param_2: type_2, ... , param_n : type_n ) -> return_type`

View File

@ -1,24 +0,0 @@
Turn Off Script Optimizations
============================
{{#include ../../links.md}}
When scripts:
* are known to be run only _once_,
* are known to contain no dead code,
* do not use constants in calculations
the optimization pass may be a waste of time and resources. In that case, turn optimization off
by setting the optimization level to [`OptimizationLevel::None`].
Alternatively, turn off optimizations via the [`no_optimize`] feature.
```rust
let engine = rhai::Engine::new();
// Turn off the optimizer
engine.set_optimization_level(rhai::OptimizationLevel::None);
```

View File

@ -1,26 +0,0 @@
Eager Function Evaluation When Using Full Optimization Level
==========================================================
{{#include ../../links.md}}
When the optimization level is [`OptimizationLevel::Full`], the [`Engine`] assumes all functions to be _pure_
and will _eagerly_ evaluated all function calls with constant arguments, using the result to replace the call.
This also applies to all operators (which are implemented as functions).
For instance, the same example above:
```rust
// When compiling the following with OptimizationLevel::Full...
const DECISION = 1;
// this condition is now eliminated because 'sign(DECISION) > 0'
if DECISION.sign() > 0 { // is a call to the 'sign' and '>' functions, and they return 'true'
print("hello!"); // this block is promoted to the parent level
} else {
print("boo!"); // this block is eliminated because it is never reached
}
print("hello!"); // <- the above is equivalent to this
// ('print' and 'debug' are handled specially)
```

View File

@ -1,146 +0,0 @@
Script Optimization
===================
{{#include ../../links.md}}
Rhai includes an _optimizer_ that tries to optimize a script after parsing.
This can reduce resource utilization and increase execution speed.
Script optimization can be turned off via the [`no_optimize`] feature.
Dead Code Removal
----------------
For example, in the following:
```rust
{
let x = 999; // NOT eliminated: variable may be used later on (perhaps even an 'eval')
123; // eliminated: no effect
"hello"; // eliminated: no effect
[1, 2, x, x*2, 5]; // eliminated: no effect
foo(42); // NOT eliminated: the function 'foo' may have side-effects
666 // NOT eliminated: this is the return value of the block,
// and the block is the last one so this is the return value of the whole script
}
```
Rhai attempts to eliminate _dead code_ (i.e. code that does nothing, for example an expression by itself as a statement,
which is allowed in Rhai).
The above script optimizes to:
```rust
{
let x = 999;
foo(42);
666
}
```
Constants Propagation
--------------------
Constants propagation is used to remove dead code:
```rust
const ABC = true;
if ABC || some_work() { print("done!"); } // 'ABC' is constant so it is replaced by 'true'...
if true || some_work() { print("done!"); } // since '||' short-circuits, 'some_work' is never called
if true { print("done!"); } // <- the line above is equivalent to this
print("done!"); // <- the line above is further simplified to this
// because the condition is always true
```
These are quite effective for template-based machine-generated scripts where certain constant values
are spliced into the script text in order to turn on/off certain sections.
For fixed script texts, the constant values can be provided in a user-defined [`Scope`] object
to the [`Engine`] for use in compilation and evaluation.
### Caveat
If the [constants] are modified later on (yes, it is possible, via Rust functions),
the modified values will not show up in the optimized script.
Only the initialization values of [constants] are ever retained.
This is almost never a problem because real-world scripts seldom modify a constant,
but the possibility is always there.
Eager Operator Evaluations
-------------------------
Beware, however, that most operators are actually function calls, and those functions can be overridden,
so whether they are optimized away depends on the situation:
* If the operands are not _constant_ values, it is not optimized.
* If the operator is [overloaded][operator overloading], it is not optimized because the overloading function may not be _pure_
(i.e. may cause side-effects when called).
* If the operator is not _binary_, it is not optimized. Only binary operators are built-in to Rhai.
* If the operands are not of the same type, it is not optimized.
* If the operator is not _built-in_ (see list of [built-in operators]), it is not optimized.
* If the operator is a binary built-in operator for a [standard type][standard types], it is called and replaced by a constant result.
Rhai guarantees that no external function will be run (in order not to trigger side-effects) during the
optimization process (unless the optimization level is set to [`OptimizationLevel::Full`]).
```rust
// The following is most likely generated by machine.
const DECISION = 1; // this is an integer, one of the standard types
if DECISION == 1 { // this is optimized into 'true'
:
} else if DECISION == 2 { // this is optimized into 'false'
:
} else if DECISION == 3 { // this is optimized into 'false'
:
} else {
:
}
```
Because of the eager evaluation of operators for [standard types], many constant expressions will be evaluated
and replaced by the result.
```rust
let x = (1+2) * 3-4 / 5%6; // will be replaced by 'let x = 9'
let y = (1 > 2) || (3 < =4); // will be replaced by 'let y = true'
```
For operators that are not optimized away due to one of the above reasons, the function calls
are simply left behind:
```rust
// Assume 'new_state' returns some custom type that is NOT one of the standard types.
// Also assume that the '==; operator is defined for that custom type.
const DECISION_1 = new_state(1);
const DECISION_2 = new_state(2);
const DECISION_3 = new_state(3);
if DECISION == 1 { // NOT optimized away because the operator is not built-in
: // and may cause side-effects if called!
:
} else if DECISION == 2 { // same here, NOT optimized away
:
} else if DECISION == 3 { // same here, NOT optimized away
:
} else {
:
}
```
Alternatively, turn the optimizer to [`OptimizationLevel::Full`].

View File

@ -1,34 +0,0 @@
Optimization Levels
==================
{{#include ../../links.md}}
There are three levels of optimization: `None`, `Simple` and `Full`.
* `None` is obvious &ndash; no optimization on the AST is performed.
* `Simple` (default) performs only relatively _safe_ optimizations without causing side-effects
(i.e. it only relies on static analysis and [built-in operators] for constant [standard types],
and will not perform any external function calls).
However, it is important to bear in mind that _constants propagation_ is performed with the
caveat that, if [constants] are modified later on (yes, it is possible, via Rust functions),
the modified values will not show up in the optimized script. Only the initialization values
of [constants] are ever retained.
Furthermore, overriding a [built-in operator][built-in operators] in the [`Engine`] afterwards
has no effect after the optimizer replaces an expression with its calculated value.
* `Full` is _much_ more aggressive, _including_ calling external functions on constant arguments to determine their result.
One benefit to this is that many more optimization opportunities arise, especially with regards to comparison operators.
Set Optimization Level
---------------------
An [`Engine`]'s optimization level is set via a call to `Engine::set_optimization_level`:
```rust
// Turn on aggressive optimizations
engine.set_optimization_level(rhai::OptimizationLevel::Full);
```

View File

@ -1,38 +0,0 @@
Re-Optimize an AST
==================
{{#include ../../links.md}}
Sometimes it is more efficient to store one single, large script with delimited code blocks guarded by
constant variables. This script is compiled once to an [`AST`].
Then, depending on the execution environment, constants are passed into the [`Engine`] and the [`AST`]
is _re_-optimized based on those constants via the `Engine::optimize_ast` method,
effectively pruning out unused code sections.
The final, optimized [`AST`] is then used for evaluations.
```rust
// Compile master script to AST
let master_ast = engine.compile(
r"
if SCENARIO == 1 {
do_work();
} else if SCENARIO == 2 {
do_something();
} else if SCENARIO == 3 {
do_something_else();
} else {
do_nothing();
}
")?;
// Create a new 'Scope' - put constants in it to aid optimization
let mut scope = Scope::new();
scope.push_constant("SCENARIO", 1_i64);
// Re-optimize the AST
let new_ast = engine.optimize_ast(&scope, master_ast.clone(), OptimizationLevel::Simple);
// 'new_ast' is essentially: 'do_work()'
```

View File

@ -1,43 +0,0 @@
Subtle Semantic Changes After Optimization
=========================================
{{#include ../../links.md}}
Some optimizations can alter subtle semantics of the script.
For example:
```rust
if true { // condition always true
123.456; // eliminated
hello; // eliminated, EVEN THOUGH the variable doesn't exist!
foo(42) // promoted up-level
}
foo(42) // <- the above optimizes to this
```
If the original script were evaluated instead, it would have been an error &ndash; the variable `hello` does not exist,
so the script would have been terminated at that point with an error return.
In fact, any errors inside a statement that has been eliminated will silently _disappear_:
```rust
print("start!");
if my_decision { /* do nothing... */ } // eliminated due to no effect
print("end!");
// The above optimizes to:
print("start!");
print("end!");
```
In the script above, if `my_decision` holds anything other than a boolean value,
the script should have been terminated due to a type error.
However, after optimization, the entire `if` statement is removed (because an access to `my_decision` produces
no side-effects), thus the script silently runs to completion without errors.
It is usually a _Very Bad Idea™_ to depend on a script failing or such kind of subtleties, but if it turns out to be necessary
(why? I would never guess), turn script optimization off by setting the optimization level to [`OptimizationLevel::None`].

View File

@ -1,22 +0,0 @@
Side-Effect Considerations for Full Optimization Level
====================================================
{{#include ../../links.md}}
All of Rhai's built-in functions (and operators which are implemented as functions) are _pure_
(i.e. they do not mutate state nor cause any side-effects, with the exception of `print` and `debug`
which are handled specially) so using [`OptimizationLevel::Full`] is usually quite safe _unless_
custom types and functions are registered.
If custom functions are registered, they _may_ be called (or maybe not, if the calls happen to lie
within a pruned code block).
If custom functions are registered to overload built-in operators, they will also be called when
the operators are used (in an `if` statement, for example) causing side-effects.
Therefore, the rule-of-thumb is:
* _Always_ register custom types and functions _after_ compiling scripts if [`OptimizationLevel::Full`] is used.
* _DO NOT_ depend on knowledge that the functions have no side-effects, because those functions can change later on and,
when that happens, existing scripts may break in subtle ways.

View File

@ -1,16 +0,0 @@
Volatility Considerations for Full Optimization Level
===================================================
{{#include ../../links.md}}
Even if a custom function does not mutate state nor cause side-effects, it may still be _volatile_,
i.e. it _depends_ on the external environment and is not _pure_.
A perfect example is a function that gets the current time &ndash; obviously each run will return a different value!
The optimizer, when using [`OptimizationLevel::Full`], will _merrily assume_ that all functions are _pure_,
so when it finds constant arguments (or none) it eagerly executes the function call and replaces it with the result.
This causes the script to behave differently from the intended semantics.
Therefore, **avoid using [`OptimizationLevel::Full`]** if non-_pure_ custom types and/or functions are involved.

View File

@ -1,19 +0,0 @@
Engine Configuration Options
===========================
{{#include ../links.md}}
A number of other configuration options are available from the `Engine` to fine-tune behavior and safeguards.
| Method | Not available under | Description |
| ------------------------ | ---------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| `set_doc_comments` | | enables/disables [doc-comments] |
| `set_optimization_level` | [`no_optimize`] | sets the amount of script _optimizations_ performedSee [script optimization] |
| `set_max_expr_depths` | [`unchecked`] | sets the maximum nesting levels of an expression/statementSee [maximum statement depth] |
| `set_max_call_levels` | [`unchecked`] | sets the maximum number of function call levels (default 50) to avoid infinite recursionSee [maximum call stack depth] |
| `set_max_operations` | [`unchecked`] | sets the maximum number of _operations_ that a script is allowed to consumeSee [maximum number of operations] |
| `set_max_modules` | [`unchecked`] | sets the maximum number of [modules] that a script is allowed to loadSee [maximum number of modules] |
| `set_max_string_size` | [`unchecked`] | sets the maximum length (in UTF-8 bytes) for [strings]See [maximum length of strings] |
| `set_max_array_size` | [`unchecked`], [`no_index`] | sets the maximum size for [arrays]See [maximum size of arrays] |
| `set_max_map_size` | [`unchecked`], [`no_object`] | sets the maximum number of properties for [object maps]See [maximum size of object maps] |
| `disable_symbol` | | disables a certain keyword or operatorSee [disable keywords and operators] |

View File

@ -1,28 +0,0 @@
Raw `Engine`
===========
{{#include ../links.md}}
`Engine::new` creates a scripting [`Engine`] with common functionalities (e.g. printing to the console via `print`).
In many controlled embedded environments, however, these may not be needed and unnecessarily occupy
application code storage space.
Use `Engine::new_raw` to create a _raw_ `Engine`, in which only a minimal set of
basic arithmetic and logical operators are supported (see below).
To add more functionalities to a _raw_ `Engine`, load [packages] into it.
Built-in Operators
------------------
| Operators | Assignment operators | Supported for types<br/>(see [standard types]) |
| ------------------------- | ---------------------------- | ----------------------------------------------------------------------------- |
| `+`, | `+=` | `INT`, `FLOAT` (if not [`no_float`]), `char`, `ImmutableString` |
| `-`, `*`, `/`, `%`, `~`, | `-=`, `*=`, `/=`, `%=`, `~=` | `INT`, `FLOAT` (if not [`no_float`]) |
| `<<`, `>>` | `<<=`, `>>=` | `INT` |
| `&`, <code>\|</code>, `^` | `&=`, <code>\|=</code>, `^=` | `INT`, `bool` |
| `&&`, <code>\|\|</code> | | `bool` |
| `==`, `!=` | | `INT`, `FLOAT` (if not [`no_float`]), `bool`, `char`, `()`, `ImmutableString` |
| `>`, `>=`, `<`, `<=` | | `INT`, `FLOAT` (if not [`no_float`]), `char`, `()`, `ImmutableString` |

View File

@ -1,55 +0,0 @@
`Scope` &ndash; Initializing and Maintaining State
=================================================
{{#include ../links.md}}
By default, Rhai treats each [`Engine`] invocation as a fresh one, persisting only the functions that have been defined
but no global state. This gives each evaluation a clean starting slate.
In order to continue using the same global state from one invocation to the next,
such a state must be manually created and passed in.
All `Scope` variables are [`Dynamic`], meaning they can store values of any type.
Under [`sync`], however, only types that are `Send + Sync` are supported, and the entire `Scope` itself
will also be `Send + Sync`. This is extremely useful in multi-threaded applications.
In this example, a global state object (a `Scope`) is created with a few initialized variables,
then the same state is threaded through multiple invocations:
```rust
use rhai::{Engine, Scope, EvalAltResult};
let engine = Engine::new();
// First create the state
let mut scope = Scope::new();
// Then push (i.e. add) some initialized variables into the state.
// Remember the system number types in Rhai are i64 (i32 if 'only_i32') ond f64.
// Better stick to them or it gets hard working with the script.
scope
.push("y", 42_i64)
.push("z", 999_i64)
.push_constant("MY_NUMBER", 123_i64) // constants can also be added
.set_value("s", "hello, world!".to_string()); //'set_value' adds a variable when one doesn't exist
// remember to use 'String', not '&str'
// First invocation
engine.eval_with_scope::<()>(&mut scope, r"
let x = 4 + 5 &ndash; y + z + MY_NUMBER + s.len;
y = 1;
")?;
// Second invocation using the same state
let result = engine.eval_with_scope::<i64>(&mut scope, "x")?;
println!("result: {}", result); // prints 1102
// Variable y is changed in the script &ndash; read it with 'get_value'
assert_eq!(scope.get_value::<i64>("y").expect("variable y should exist"), 1);
// We can modify scope variables directly with 'set_value'
scope.set_value("y", 42_i64);
assert_eq!(scope.get_value::<i64>("y").expect("variable y should exist"), 42);
```

View File

@ -1,93 +0,0 @@
Variable Resolver
=================
{{#include ../links.md}}
By default, Rhai looks up access to variables from the enclosing block scope,
working its way outwards until it reaches the top (global) level, then it
searches the [`Scope`] that is passed into the `Engine::eval` call.
There is a built-in facility for advanced users to _hook_ into the variable
resolution service and to override its default behavior.
To do so, provide a closure to the [`Engine`] via the `Engine::on_var` method:
```rust
let mut engine = Engine::new();
// Register a variable resolver.
engine.on_var(|name, index, context| {
match name {
"MYSTIC_NUMBER" => Ok(Some((42 as INT).into())),
// Override a variable - make it not found even if it exists!
"DO_NOT_USE" => Err(Box::new(
EvalAltResult::ErrorVariableNotFound(name.to_string(), Position::NONE)
)),
// Silently maps 'chameleon' into 'innocent'.
"chameleon" => context.scope().get_value("innocent").map(Some).ok_or_else(|| Box::new(
EvalAltResult::ErrorVariableNotFound(name.to_string(), Position::NONE)
)),
// Return Ok(None) to continue with the normal variable resolution process.
_ => Ok(None)
}
});
```
Returned Values are Constants
----------------------------
Variable values, if any returned, are treated as _constants_ by the script and cannot be assigned to.
This is to avoid needing a mutable reference to the underlying data provider which may not be possible to obtain.
In order to change these variables, it is best to push them into a custom [`Scope`] instead of using
a variable resolver. Then these variables can be assigned to and their updated values read back after
the script is evaluated.
Benefits of Using a Variable Resolver
------------------------------------
1. Avoid having to maintain a custom [`Scope`] with all variables regardless of need (because a script may not use them all).
2. _Short-circuit_ variable access, essentially overriding standard behavior.
3. _Lazy-load_ variables when they are accessed, not up-front. This benefits when the number of variables is very large, when they are timing-dependent, or when they are expensive to load.
4. Rename system variables on a script-by-script basis without having to construct different [`Scope`]'s.
Function Signature
------------------
The function signature passed to `Engine::on_var` takes the following form:
> `Fn(name: &str, index: usize, context: &EvalContext)`
> `-> Result<Option<Dynamic>, Box<EvalAltResult>> + 'static`
where:
| Parameter | Type | Description |
| -------------------------- | :-------------------------------------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name` | `&str` | variable name |
| `index` | `usize` | an offset from the bottom of the current [`Scope`] that the variable is supposed to reside.<br/>Offsets start from 1, with 1 meaning the last variable in the current [`Scope`]. Essentially the correct variable is at position `scope.len() - index`.<br/>If `index` is zero, then there is no pre-calculated offset position and a search through the current [`Scope`] must be performed. |
| `context` | `&EvalContext` | reference to the current evaluation _context_ |
| &bull; `scope()` | `&Scope` | reference to the current [`Scope`] |
| &bull; `engine()` | `&Engine` | reference to the current [`Engine`] |
| &bull; `source()` | `Option<&str>` | reference to the current source, if any |
| &bull; `iter_imports()` | `impl Iterator<Item = (&str, &Module)>` | iterator of the current stack of [modules] imported via `import` statements |
| &bull; `imports()` | `&Imports` | reference to the current stack of [modules] imported via `import` statements; requires the [`internals`] feature |
| &bull; `iter_namespaces()` | `impl Iterator<Item = &Module>` | iterator of the namespaces (as [modules]) containing all script-defined functions |
| &bull; `namespaces()` | `&[&Module]` | reference to the namespaces (as [modules]) containing all script-defined functions; requires the [`internals`] feature |
| &bull; `this_ptr()` | `Option<&Dynamic>` | reference to the current bound [`this`] pointer, if any |
| &bull; `call_level()` | `usize` | the current nesting level of function calls |
### Return Value
The return value is `Result<Option<Dynamic>, Box<EvalAltResult>>` where:
| Value | Description |
| ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Ok(None)` | normal variable resolution process should continue, i.e. continue searching through the [`Scope`] |
| `Ok(Some(Dynamic))` | value of the variable, treated as a constant |
| `Err(Box<EvalAltResult>)` | error that is reflected back to the [`Engine`].<br/>Normally this is `EvalAltResult::ErrorVariableNotFound(var_name, Position::NONE)` to indicate that the variable does not exist, but it can be any `EvalAltResult`. |

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -1,15 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,-2132,0)">
<g id="favicon" transform="matrix(0.591824,0,0,0.558091,1146.76,0)">
<rect x="1664.76" y="0" width="54.07" height="57.338" style="fill:none;"/>
<g transform="matrix(0.180947,0,0,0.191884,1645.83,-30.569)">
<path d="M244.724,402.002L226.114,402.002C205.572,402.002 188.894,385.324 188.894,364.782L188.894,253.122L188.895,253.242C188.959,263.418 197.208,271.667 207.384,271.732L207.504,271.732L218.288,271.732C211.035,256.892 213.572,238.455 225.902,226.126L254.029,197.998C254.029,197.998 282.157,226.126 282.157,226.126C294.486,238.455 297.023,256.892 289.77,271.732L300.554,271.732L300.674,271.732C310.85,271.667 319.099,263.418 319.164,253.242L319.164,253.122L319.164,364.782C319.164,385.324 302.486,402.002 281.944,402.002L263.334,402.002L263.334,420.612L244.724,420.612L244.724,402.002ZM244.724,383.392L244.724,364.782C244.724,354.511 236.385,346.172 226.114,346.172L207.504,346.172L207.504,364.782C207.504,375.053 215.843,383.392 226.114,383.392L244.724,383.392ZM263.334,364.782C263.334,354.511 271.673,346.172 281.944,346.172L300.554,346.172L300.554,364.782C300.554,375.053 292.215,383.392 281.944,383.392L263.334,383.392L263.334,364.782ZM263.334,308.952C263.334,298.681 271.673,290.342 281.944,290.342L300.554,290.342L300.554,308.952C300.554,319.223 292.215,327.562 281.944,327.562L263.334,327.562L263.334,308.952ZM244.724,308.952C244.724,298.681 236.385,290.342 226.114,290.342L207.504,290.342L207.504,308.952C207.504,319.223 215.843,327.562 226.114,327.562L244.724,327.562L244.724,308.952ZM267.188,267.412C274.451,260.15 274.451,248.357 267.188,241.094C267.188,241.094 254.029,227.935 254.029,227.935L240.87,241.094C233.607,248.357 233.607,260.15 240.87,267.412L254.029,280.572L267.188,267.412Z" style="fill:url(#_Linear1);"/>
</g>
</g>
</g>
<defs>
<linearGradient id="_Linear1" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.36312e-14,222.614,-222.614,1.36312e-14,254.029,197.998)"><stop offset="0" style="stop-color:rgb(255,215,118);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(246,117,0);stop-opacity:1"/></linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

View File

@ -1,31 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 960 272" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,0,-962)">
<g id="rhai-banner-transparent-colour" transform="matrix(0.588957,0,0,0.998422,0,1.39642)">
<rect x="0" y="962.121" width="1630" height="272.43" style="fill:none;"/>
<g transform="matrix(1.69792,0,0,0.751185,-277.179,872.981)">
<g transform="matrix(1,0,0,1.33333,0,-112.407)">
<path d="M244.724,402.002L226.114,402.002C205.572,402.002 188.894,385.324 188.894,364.782L188.894,253.122L188.895,253.242C188.959,263.418 197.208,271.667 207.384,271.732L207.504,271.732L218.288,271.732C211.035,256.892 213.572,238.455 225.902,226.126L254.029,197.998C254.029,197.998 282.157,226.126 282.157,226.126C294.486,238.455 297.023,256.892 289.77,271.732L300.554,271.732L300.674,271.732C310.85,271.667 319.099,263.418 319.164,253.242L319.164,253.122L319.164,364.782C319.164,385.324 302.486,402.002 281.944,402.002L263.334,402.002L263.334,420.612L244.724,420.612L244.724,402.002ZM244.724,383.392L244.724,364.782C244.724,354.511 236.385,346.172 226.114,346.172L207.504,346.172L207.504,364.782C207.504,375.053 215.843,383.392 226.114,383.392L244.724,383.392ZM263.334,364.782C263.334,354.511 271.673,346.172 281.944,346.172L300.554,346.172L300.554,364.782C300.554,375.053 292.215,383.392 281.944,383.392L263.334,383.392L263.334,364.782ZM263.334,308.952C263.334,298.681 271.673,290.342 281.944,290.342L300.554,290.342L300.554,308.952C300.554,319.223 292.215,327.562 281.944,327.562L263.334,327.562L263.334,308.952ZM244.724,308.952C244.724,298.681 236.385,290.342 226.114,290.342L207.504,290.342L207.504,308.952C207.504,319.223 215.843,327.562 226.114,327.562L244.724,327.562L244.724,308.952ZM267.188,267.412C274.451,260.15 274.451,248.357 267.188,241.094C267.188,241.094 254.029,227.935 254.029,227.935L240.87,241.094C233.607,248.357 233.607,260.15 240.87,267.412L254.029,280.572L267.188,267.412Z" style="fill:url(#_Linear1);"/>
</g>
<g transform="matrix(1,0,0,1.33333,95.1496,-261.61)">
<g transform="matrix(144,0,0,144,256.612,491.233)">
<path d="M0.231,-0.512C0.246,-0.522 0.263,-0.53 0.281,-0.535C0.301,-0.54 0.32,-0.543 0.339,-0.543C0.352,-0.543 0.363,-0.542 0.374,-0.54L0.374,-0.428C0.362,-0.431 0.349,-0.433 0.336,-0.433C0.309,-0.433 0.284,-0.427 0.262,-0.415C0.238,-0.402 0.22,-0.383 0.209,-0.359C0.197,-0.335 0.191,-0.307 0.191,-0.274L0.191,-0L0.07,-0L0.07,-0.54L0.177,-0.54L0.177,-0.454C0.192,-0.479 0.21,-0.499 0.231,-0.512Z" style="fill-rule:nonzero;"/>
</g>
<g transform="matrix(144,0,0,144,314.068,491.233)">
<path d="M0.353,-0.555C0.438,-0.555 0.495,-0.528 0.524,-0.472C0.552,-0.418 0.566,-0.361 0.566,-0.302L0.566,-0L0.444,-0L0.444,-0.26C0.444,-0.381 0.402,-0.442 0.317,-0.442C0.281,-0.442 0.251,-0.43 0.227,-0.405C0.203,-0.38 0.191,-0.338 0.191,-0.278L0.191,-0L0.069,-0L0.069,-0.72L0.177,-0.72L0.177,-0.48C0.218,-0.53 0.277,-0.555 0.353,-0.555Z" style="fill-rule:nonzero;"/>
</g>
<g transform="matrix(144,0,0,144,404.212,491.233)">
<path d="M0.496,-0.455C0.505,-0.438 0.51,-0.42 0.513,-0.402C0.515,-0.383 0.516,-0.36 0.516,-0.331L0.516,-0L0.411,-0L0.411,-0.073C0.388,-0.043 0.361,-0.021 0.331,-0.007C0.3,0.008 0.264,0.015 0.221,0.015C0.183,0.015 0.15,0.008 0.123,-0.007C0.096,-0.022 0.075,-0.041 0.061,-0.066C0.047,-0.091 0.04,-0.118 0.04,-0.148C0.04,-0.187 0.05,-0.221 0.07,-0.248C0.09,-0.275 0.121,-0.295 0.163,-0.31C0.189,-0.318 0.22,-0.325 0.256,-0.332C0.292,-0.338 0.339,-0.345 0.398,-0.353C0.396,-0.385 0.386,-0.408 0.369,-0.423C0.351,-0.438 0.324,-0.445 0.287,-0.445C0.26,-0.445 0.236,-0.439 0.215,-0.427C0.193,-0.414 0.178,-0.395 0.17,-0.369L0.059,-0.404C0.073,-0.451 0.099,-0.488 0.138,-0.515C0.176,-0.542 0.226,-0.555 0.288,-0.555C0.393,-0.555 0.462,-0.522 0.496,-0.455ZM0.384,-0.171C0.391,-0.188 0.396,-0.216 0.397,-0.255C0.358,-0.249 0.324,-0.243 0.295,-0.237C0.265,-0.232 0.241,-0.226 0.224,-0.221C0.202,-0.212 0.186,-0.203 0.174,-0.192C0.164,-0.181 0.158,-0.167 0.158,-0.15C0.158,-0.129 0.166,-0.113 0.181,-0.1C0.196,-0.087 0.217,-0.081 0.245,-0.081C0.282,-0.081 0.313,-0.09 0.338,-0.109C0.362,-0.128 0.377,-0.148 0.384,-0.171Z" style="fill-rule:nonzero;"/>
</g>
<g transform="matrix(144,0,0,144,487.156,491.233)">
<path d="M0.08,-0.734L0.2,-0.734L0.2,-0.624L0.08,-0.624L0.08,-0.734ZM0.08,-0.54L0.2,-0.54L0.2,-0L0.08,-0L0.08,-0.54Z" style="fill-rule:nonzero;"/>
</g>
</g>
</g>
</g>
</g>
<defs>
<linearGradient id="_Linear1" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.36312e-14,222.614,-222.614,1.36312e-14,254.029,197.998)"><stop offset="0" style="stop-color:rgb(255,215,118);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(246,117,0);stop-opacity:1"/></linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

View File

@ -1,39 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 800 450" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,-830,-480)">
<g id="rhai-colour-white" transform="matrix(1,0,0,0.75,830,480)">
<rect x="0" y="0" width="800" height="600" style="fill:none;"/>
<clipPath id="_clip1">
<rect x="0" y="0" width="800" height="600"/>
</clipPath>
<g clip-path="url(#_clip1)">
<g transform="matrix(1,0,0,1.33333,0,-641.217)">
<rect x="0" y="480.913" width="800" height="450"/>
</g>
<g>
<g transform="matrix(1,0,0,1.33333,0,-112.407)">
<path d="M244.724,402.002L226.114,402.002C205.572,402.002 188.894,385.324 188.894,364.782L188.894,253.122L188.895,253.242C188.959,263.418 197.208,271.667 207.384,271.732L207.504,271.732L218.288,271.732C211.035,256.892 213.572,238.455 225.902,226.126L254.029,197.998C254.029,197.998 282.157,226.126 282.157,226.126C294.486,238.455 297.023,256.892 289.77,271.732L300.554,271.732L300.674,271.732C310.85,271.667 319.099,263.418 319.164,253.242L319.164,253.122L319.164,364.782C319.164,385.324 302.486,402.002 281.944,402.002L263.334,402.002L263.334,420.612L244.724,420.612L244.724,402.002ZM244.724,383.392L244.724,364.782C244.724,354.511 236.385,346.172 226.114,346.172L207.504,346.172L207.504,364.782C207.504,375.053 215.843,383.392 226.114,383.392L244.724,383.392ZM263.334,364.782C263.334,354.511 271.673,346.172 281.944,346.172L300.554,346.172L300.554,364.782C300.554,375.053 292.215,383.392 281.944,383.392L263.334,383.392L263.334,364.782ZM263.334,308.952C263.334,298.681 271.673,290.342 281.944,290.342L300.554,290.342L300.554,308.952C300.554,319.223 292.215,327.562 281.944,327.562L263.334,327.562L263.334,308.952ZM244.724,308.952C244.724,298.681 236.385,290.342 226.114,290.342L207.504,290.342L207.504,308.952C207.504,319.223 215.843,327.562 226.114,327.562L244.724,327.562L244.724,308.952ZM267.188,267.412C274.451,260.15 274.451,248.357 267.188,241.094C267.188,241.094 254.029,227.935 254.029,227.935L240.87,241.094C233.607,248.357 233.607,260.15 240.87,267.412L254.029,280.572L267.188,267.412Z" style="fill:url(#_Linear2);"/>
</g>
<g transform="matrix(1,0,0,1.33333,95.1496,-261.61)">
<g transform="matrix(144,0,0,144,256.612,491.233)">
<path d="M0.231,-0.512C0.246,-0.522 0.263,-0.53 0.281,-0.535C0.301,-0.54 0.32,-0.543 0.339,-0.543C0.352,-0.543 0.363,-0.542 0.374,-0.54L0.374,-0.428C0.362,-0.431 0.349,-0.433 0.336,-0.433C0.309,-0.433 0.284,-0.427 0.262,-0.415C0.238,-0.402 0.22,-0.383 0.209,-0.359C0.197,-0.335 0.191,-0.307 0.191,-0.274L0.191,-0L0.07,-0L0.07,-0.54L0.177,-0.54L0.177,-0.454C0.192,-0.479 0.21,-0.499 0.231,-0.512Z" style="fill:white;fill-rule:nonzero;"/>
</g>
<g transform="matrix(144,0,0,144,314.068,491.233)">
<path d="M0.353,-0.555C0.438,-0.555 0.495,-0.528 0.524,-0.472C0.552,-0.418 0.566,-0.361 0.566,-0.302L0.566,-0L0.444,-0L0.444,-0.26C0.444,-0.381 0.402,-0.442 0.317,-0.442C0.281,-0.442 0.251,-0.43 0.227,-0.405C0.203,-0.38 0.191,-0.338 0.191,-0.278L0.191,-0L0.069,-0L0.069,-0.72L0.177,-0.72L0.177,-0.48C0.218,-0.53 0.277,-0.555 0.353,-0.555Z" style="fill:white;fill-rule:nonzero;"/>
</g>
<g transform="matrix(144,0,0,144,404.212,491.233)">
<path d="M0.496,-0.455C0.505,-0.438 0.51,-0.42 0.513,-0.402C0.515,-0.383 0.516,-0.36 0.516,-0.331L0.516,-0L0.411,-0L0.411,-0.073C0.388,-0.043 0.361,-0.021 0.331,-0.007C0.3,0.008 0.264,0.015 0.221,0.015C0.183,0.015 0.15,0.008 0.123,-0.007C0.096,-0.022 0.075,-0.041 0.061,-0.066C0.047,-0.091 0.04,-0.118 0.04,-0.148C0.04,-0.187 0.05,-0.221 0.07,-0.248C0.09,-0.275 0.121,-0.295 0.163,-0.31C0.189,-0.318 0.22,-0.325 0.256,-0.332C0.292,-0.338 0.339,-0.345 0.398,-0.353C0.396,-0.385 0.386,-0.408 0.369,-0.423C0.351,-0.438 0.324,-0.445 0.287,-0.445C0.26,-0.445 0.236,-0.439 0.215,-0.427C0.193,-0.414 0.178,-0.395 0.17,-0.369L0.059,-0.404C0.073,-0.451 0.099,-0.488 0.138,-0.515C0.176,-0.542 0.226,-0.555 0.288,-0.555C0.393,-0.555 0.462,-0.522 0.496,-0.455ZM0.384,-0.171C0.391,-0.188 0.396,-0.216 0.397,-0.255C0.358,-0.249 0.324,-0.243 0.295,-0.237C0.265,-0.232 0.241,-0.226 0.224,-0.221C0.202,-0.212 0.186,-0.203 0.174,-0.192C0.164,-0.181 0.158,-0.167 0.158,-0.15C0.158,-0.129 0.166,-0.113 0.181,-0.1C0.196,-0.087 0.217,-0.081 0.245,-0.081C0.282,-0.081 0.313,-0.09 0.338,-0.109C0.362,-0.128 0.377,-0.148 0.384,-0.171Z" style="fill:white;fill-rule:nonzero;"/>
</g>
<g transform="matrix(144,0,0,144,487.156,491.233)">
<path d="M0.08,-0.734L0.2,-0.734L0.2,-0.624L0.08,-0.624L0.08,-0.734ZM0.08,-0.54L0.2,-0.54L0.2,-0L0.08,-0L0.08,-0.54Z" style="fill:white;fill-rule:nonzero;"/>
</g>
</g>
</g>
</g>
</g>
</g>
<defs>
<linearGradient id="_Linear2" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.36312e-14,222.614,-222.614,1.36312e-14,254.029,197.998)"><stop offset="0" style="stop-color:rgb(255,215,118);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(246,117,0);stop-opacity:1"/></linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

View File

@ -1,34 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 800 450" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,-830,0)">
<g id="rhai-colour-white" transform="matrix(1,0,0,0.75,830,0)">
<rect x="0" y="0" width="800" height="600" style="fill:none;"/>
<g transform="matrix(1,0,0,1.33333,0,0)">
<rect x="0" y="0" width="800" height="450" style="fill:white;"/>
</g>
<g>
<g transform="matrix(1,0,0,1.33333,0,-112.407)">
<path d="M244.724,402.002L226.114,402.002C205.572,402.002 188.894,385.324 188.894,364.782L188.894,253.122L188.895,253.242C188.959,263.418 197.208,271.667 207.384,271.732L207.504,271.732L218.288,271.732C211.035,256.892 213.572,238.455 225.902,226.126L254.029,197.998C254.029,197.998 282.157,226.126 282.157,226.126C294.486,238.455 297.023,256.892 289.77,271.732L300.554,271.732L300.674,271.732C310.85,271.667 319.099,263.418 319.164,253.242L319.164,253.122L319.164,364.782C319.164,385.324 302.486,402.002 281.944,402.002L263.334,402.002L263.334,420.612L244.724,420.612L244.724,402.002ZM244.724,383.392L244.724,364.782C244.724,354.511 236.385,346.172 226.114,346.172L207.504,346.172L207.504,364.782C207.504,375.053 215.843,383.392 226.114,383.392L244.724,383.392ZM263.334,364.782C263.334,354.511 271.673,346.172 281.944,346.172L300.554,346.172L300.554,364.782C300.554,375.053 292.215,383.392 281.944,383.392L263.334,383.392L263.334,364.782ZM263.334,308.952C263.334,298.681 271.673,290.342 281.944,290.342L300.554,290.342L300.554,308.952C300.554,319.223 292.215,327.562 281.944,327.562L263.334,327.562L263.334,308.952ZM244.724,308.952C244.724,298.681 236.385,290.342 226.114,290.342L207.504,290.342L207.504,308.952C207.504,319.223 215.843,327.562 226.114,327.562L244.724,327.562L244.724,308.952ZM267.188,267.412C274.451,260.15 274.451,248.357 267.188,241.094C267.188,241.094 254.029,227.935 254.029,227.935L240.87,241.094C233.607,248.357 233.607,260.15 240.87,267.412L254.029,280.572L267.188,267.412Z" style="fill:url(#_Linear1);"/>
</g>
<g transform="matrix(1,0,0,1.33333,95.1496,-261.61)">
<g transform="matrix(144,0,0,144,256.612,491.233)">
<path d="M0.231,-0.512C0.246,-0.522 0.263,-0.53 0.281,-0.535C0.301,-0.54 0.32,-0.543 0.339,-0.543C0.352,-0.543 0.363,-0.542 0.374,-0.54L0.374,-0.428C0.362,-0.431 0.349,-0.433 0.336,-0.433C0.309,-0.433 0.284,-0.427 0.262,-0.415C0.238,-0.402 0.22,-0.383 0.209,-0.359C0.197,-0.335 0.191,-0.307 0.191,-0.274L0.191,-0L0.07,-0L0.07,-0.54L0.177,-0.54L0.177,-0.454C0.192,-0.479 0.21,-0.499 0.231,-0.512Z" style="fill-rule:nonzero;"/>
</g>
<g transform="matrix(144,0,0,144,314.068,491.233)">
<path d="M0.353,-0.555C0.438,-0.555 0.495,-0.528 0.524,-0.472C0.552,-0.418 0.566,-0.361 0.566,-0.302L0.566,-0L0.444,-0L0.444,-0.26C0.444,-0.381 0.402,-0.442 0.317,-0.442C0.281,-0.442 0.251,-0.43 0.227,-0.405C0.203,-0.38 0.191,-0.338 0.191,-0.278L0.191,-0L0.069,-0L0.069,-0.72L0.177,-0.72L0.177,-0.48C0.218,-0.53 0.277,-0.555 0.353,-0.555Z" style="fill-rule:nonzero;"/>
</g>
<g transform="matrix(144,0,0,144,404.212,491.233)">
<path d="M0.496,-0.455C0.505,-0.438 0.51,-0.42 0.513,-0.402C0.515,-0.383 0.516,-0.36 0.516,-0.331L0.516,-0L0.411,-0L0.411,-0.073C0.388,-0.043 0.361,-0.021 0.331,-0.007C0.3,0.008 0.264,0.015 0.221,0.015C0.183,0.015 0.15,0.008 0.123,-0.007C0.096,-0.022 0.075,-0.041 0.061,-0.066C0.047,-0.091 0.04,-0.118 0.04,-0.148C0.04,-0.187 0.05,-0.221 0.07,-0.248C0.09,-0.275 0.121,-0.295 0.163,-0.31C0.189,-0.318 0.22,-0.325 0.256,-0.332C0.292,-0.338 0.339,-0.345 0.398,-0.353C0.396,-0.385 0.386,-0.408 0.369,-0.423C0.351,-0.438 0.324,-0.445 0.287,-0.445C0.26,-0.445 0.236,-0.439 0.215,-0.427C0.193,-0.414 0.178,-0.395 0.17,-0.369L0.059,-0.404C0.073,-0.451 0.099,-0.488 0.138,-0.515C0.176,-0.542 0.226,-0.555 0.288,-0.555C0.393,-0.555 0.462,-0.522 0.496,-0.455ZM0.384,-0.171C0.391,-0.188 0.396,-0.216 0.397,-0.255C0.358,-0.249 0.324,-0.243 0.295,-0.237C0.265,-0.232 0.241,-0.226 0.224,-0.221C0.202,-0.212 0.186,-0.203 0.174,-0.192C0.164,-0.181 0.158,-0.167 0.158,-0.15C0.158,-0.129 0.166,-0.113 0.181,-0.1C0.196,-0.087 0.217,-0.081 0.245,-0.081C0.282,-0.081 0.313,-0.09 0.338,-0.109C0.362,-0.128 0.377,-0.148 0.384,-0.171Z" style="fill-rule:nonzero;"/>
</g>
<g transform="matrix(144,0,0,144,487.156,491.233)">
<path d="M0.08,-0.734L0.2,-0.734L0.2,-0.624L0.08,-0.624L0.08,-0.734ZM0.08,-0.54L0.2,-0.54L0.2,-0L0.08,-0L0.08,-0.54Z" style="fill-rule:nonzero;"/>
</g>
</g>
</g>
</g>
</g>
<defs>
<linearGradient id="_Linear1" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.36312e-14,222.614,-222.614,1.36312e-14,254.029,197.998)"><stop offset="0" style="stop-color:rgb(255,215,118);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(246,117,0);stop-opacity:1"/></linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

View File

@ -1,23 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 450 450" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,-1656,-480)">
<g id="rhai-icon-colour-black" transform="matrix(1.55094,0,0,1.55094,-913.734,480)">
<rect x="1656.88" y="0" width="290.146" height="290.146" style="fill:none;"/>
<clipPath id="_clip1">
<rect x="1656.88" y="0" width="290.146" height="290.146"/>
</clipPath>
<g clip-path="url(#_clip1)">
<g transform="matrix(0.362683,0,0,0.644769,1656.89,-310.078)">
<rect x="0" y="480.913" width="800" height="450"/>
</g>
<g transform="matrix(0.644769,0,0,0.644769,1638.17,-54.3573)">
<path d="M244.724,402.002L226.114,402.002C205.572,402.002 188.894,385.324 188.894,364.782L188.894,253.122L188.895,253.242C188.959,263.418 197.208,271.667 207.384,271.732L207.504,271.732L218.288,271.732C211.035,256.892 213.572,238.455 225.902,226.126L254.029,197.998C254.029,197.998 282.157,226.126 282.157,226.126C294.486,238.455 297.023,256.892 289.77,271.732L300.554,271.732L300.674,271.732C310.85,271.667 319.099,263.418 319.164,253.242L319.164,253.122L319.164,364.782C319.164,385.324 302.486,402.002 281.944,402.002L263.334,402.002L263.334,420.612L244.724,420.612L244.724,402.002ZM244.724,383.392L244.724,364.782C244.724,354.511 236.385,346.172 226.114,346.172L207.504,346.172L207.504,364.782C207.504,375.053 215.843,383.392 226.114,383.392L244.724,383.392ZM263.334,364.782C263.334,354.511 271.673,346.172 281.944,346.172L300.554,346.172L300.554,364.782C300.554,375.053 292.215,383.392 281.944,383.392L263.334,383.392L263.334,364.782ZM263.334,308.952C263.334,298.681 271.673,290.342 281.944,290.342L300.554,290.342L300.554,308.952C300.554,319.223 292.215,327.562 281.944,327.562L263.334,327.562L263.334,308.952ZM244.724,308.952C244.724,298.681 236.385,290.342 226.114,290.342L207.504,290.342L207.504,308.952C207.504,319.223 215.843,327.562 226.114,327.562L244.724,327.562L244.724,308.952ZM267.188,267.412C274.451,260.15 274.451,248.357 267.188,241.094C267.188,241.094 254.029,227.935 254.029,227.935L240.87,241.094C233.607,248.357 233.607,260.15 240.87,267.412L254.029,280.572L267.188,267.412Z" style="fill:url(#_Linear2);"/>
</g>
</g>
</g>
</g>
<defs>
<linearGradient id="_Linear2" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.36312e-14,222.614,-222.614,1.36312e-14,254.029,197.998)"><stop offset="0" style="stop-color:rgb(255,215,118);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(246,117,0);stop-opacity:1"/></linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

View File

@ -1,23 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 450 450" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,-1656,0)">
<g id="rhai-icon-colour-white" transform="matrix(1.55094,0,0,1.55094,-913.734,0)">
<rect x="1656.88" y="0" width="290.146" height="290.146" style="fill:none;"/>
<clipPath id="_clip1">
<rect x="1656.88" y="0" width="290.146" height="290.146"/>
</clipPath>
<g clip-path="url(#_clip1)">
<g transform="matrix(0.644769,0,0,0.644769,589.147,0)">
<rect x="1656" y="0" width="450" height="450" style="fill:white;"/>
</g>
<g transform="matrix(0.644769,0,0,0.644769,1638.17,-54.3573)">
<path d="M244.724,402.002L226.114,402.002C205.572,402.002 188.894,385.324 188.894,364.782L188.894,253.122L188.895,253.242C188.959,263.418 197.208,271.667 207.384,271.732L207.504,271.732L218.288,271.732C211.035,256.892 213.572,238.455 225.902,226.126L254.029,197.998C254.029,197.998 282.157,226.126 282.157,226.126C294.486,238.455 297.023,256.892 289.77,271.732L300.554,271.732L300.674,271.732C310.85,271.667 319.099,263.418 319.164,253.242L319.164,253.122L319.164,364.782C319.164,385.324 302.486,402.002 281.944,402.002L263.334,402.002L263.334,420.612L244.724,420.612L244.724,402.002ZM244.724,383.392L244.724,364.782C244.724,354.511 236.385,346.172 226.114,346.172L207.504,346.172L207.504,364.782C207.504,375.053 215.843,383.392 226.114,383.392L244.724,383.392ZM263.334,364.782C263.334,354.511 271.673,346.172 281.944,346.172L300.554,346.172L300.554,364.782C300.554,375.053 292.215,383.392 281.944,383.392L263.334,383.392L263.334,364.782ZM263.334,308.952C263.334,298.681 271.673,290.342 281.944,290.342L300.554,290.342L300.554,308.952C300.554,319.223 292.215,327.562 281.944,327.562L263.334,327.562L263.334,308.952ZM244.724,308.952C244.724,298.681 236.385,290.342 226.114,290.342L207.504,290.342L207.504,308.952C207.504,319.223 215.843,327.562 226.114,327.562L244.724,327.562L244.724,308.952ZM267.188,267.412C274.451,260.15 274.451,248.357 267.188,241.094C267.188,241.094 254.029,227.935 254.029,227.935L240.87,241.094C233.607,248.357 233.607,260.15 240.87,267.412L254.029,280.572L267.188,267.412Z" style="fill:url(#_Linear2);"/>
</g>
</g>
</g>
</g>
<defs>
<linearGradient id="_Linear2" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.36312e-14,222.614,-222.614,1.36312e-14,254.029,197.998)"><stop offset="0" style="stop-color:rgb(255,215,118);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(246,117,0);stop-opacity:1"/></linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

View File

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 132 224" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,-188,-113)">
<g transform="matrix(1,0,0,0.75,0,0)">
<g transform="matrix(1,0,0,1.33333,0,-112.407)">
<path d="M244.724,402.002L226.114,402.002C205.572,402.002 188.894,385.324 188.894,364.782L188.894,253.122L188.895,253.242C188.959,263.418 197.208,271.667 207.384,271.732L207.504,271.732L218.288,271.732C211.035,256.892 213.572,238.455 225.902,226.126L254.029,197.998C254.029,197.998 282.157,226.126 282.157,226.126C294.486,238.455 297.023,256.892 289.77,271.732L300.554,271.732L300.674,271.732C310.85,271.667 319.099,263.418 319.164,253.242L319.164,253.122L319.164,364.782C319.164,385.324 302.486,402.002 281.944,402.002L263.334,402.002L263.334,420.612L244.724,420.612L244.724,402.002ZM244.724,383.392L244.724,364.782C244.724,354.511 236.385,346.172 226.114,346.172L207.504,346.172L207.504,364.782C207.504,375.053 215.843,383.392 226.114,383.392L244.724,383.392ZM263.334,364.782C263.334,354.511 271.673,346.172 281.944,346.172L300.554,346.172L300.554,364.782C300.554,375.053 292.215,383.392 281.944,383.392L263.334,383.392L263.334,364.782ZM263.334,308.952C263.334,298.681 271.673,290.342 281.944,290.342L300.554,290.342L300.554,308.952C300.554,319.223 292.215,327.562 281.944,327.562L263.334,327.562L263.334,308.952ZM244.724,308.952C244.724,298.681 236.385,290.342 226.114,290.342L207.504,290.342L207.504,308.952C207.504,319.223 215.843,327.562 226.114,327.562L244.724,327.562L244.724,308.952ZM267.188,267.412C274.451,260.15 274.451,248.357 267.188,241.094C267.188,241.094 254.029,227.935 254.029,227.935L240.87,241.094C233.607,248.357 233.607,260.15 240.87,267.412L254.029,280.572L267.188,267.412Z"/>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

View File

@ -1,14 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 132 224" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,-1815,-113)">
<g transform="matrix(1.55094,0,0,1.55094,-913.734,0)">
<g transform="matrix(0.644769,0,0,0.644769,1638.17,-54.3573)">
<path d="M244.724,402.002L226.114,402.002C205.572,402.002 188.894,385.324 188.894,364.782L188.894,253.122L188.895,253.242C188.959,263.418 197.208,271.667 207.384,271.732L207.504,271.732L218.288,271.732C211.035,256.892 213.572,238.455 225.902,226.126L254.029,197.998C254.029,197.998 282.157,226.126 282.157,226.126C294.486,238.455 297.023,256.892 289.77,271.732L300.554,271.732L300.674,271.732C310.85,271.667 319.099,263.418 319.164,253.242L319.164,253.122L319.164,364.782C319.164,385.324 302.486,402.002 281.944,402.002L263.334,402.002L263.334,420.612L244.724,420.612L244.724,402.002ZM244.724,383.392L244.724,364.782C244.724,354.511 236.385,346.172 226.114,346.172L207.504,346.172L207.504,364.782C207.504,375.053 215.843,383.392 226.114,383.392L244.724,383.392ZM263.334,364.782C263.334,354.511 271.673,346.172 281.944,346.172L300.554,346.172L300.554,364.782C300.554,375.053 292.215,383.392 281.944,383.392L263.334,383.392L263.334,364.782ZM263.334,308.952C263.334,298.681 271.673,290.342 281.944,290.342L300.554,290.342L300.554,308.952C300.554,319.223 292.215,327.562 281.944,327.562L263.334,327.562L263.334,308.952ZM244.724,308.952C244.724,298.681 236.385,290.342 226.114,290.342L207.504,290.342L207.504,308.952C207.504,319.223 215.843,327.562 226.114,327.562L244.724,327.562L244.724,308.952ZM267.188,267.412C274.451,260.15 274.451,248.357 267.188,241.094C267.188,241.094 254.029,227.935 254.029,227.935L240.87,241.094C233.607,248.357 233.607,260.15 240.87,267.412L254.029,280.572L267.188,267.412Z" style="fill:url(#_Linear1);"/>
</g>
</g>
</g>
<defs>
<linearGradient id="_Linear1" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.36312e-14,222.614,-222.614,1.36312e-14,254.029,197.998)"><stop offset="0" style="stop-color:rgb(255,215,118);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(246,117,0);stop-opacity:1"/></linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

View File

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 132 224" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,-188,-593)">
<g transform="matrix(1,0,0,0.75,0,480)">
<g transform="matrix(1,0,0,1.33333,0,-112.407)">
<path d="M244.724,402.002L226.114,402.002C205.572,402.002 188.894,385.324 188.894,364.782L188.894,253.122L188.895,253.242C188.959,263.418 197.208,271.667 207.384,271.732L207.504,271.732L218.288,271.732C211.035,256.892 213.572,238.455 225.902,226.126L254.029,197.998C254.029,197.998 282.157,226.126 282.157,226.126C294.486,238.455 297.023,256.892 289.77,271.732L300.554,271.732L300.674,271.732C310.85,271.667 319.099,263.418 319.164,253.242L319.164,253.122L319.164,364.782C319.164,385.324 302.486,402.002 281.944,402.002L263.334,402.002L263.334,420.612L244.724,420.612L244.724,402.002ZM244.724,383.392L244.724,364.782C244.724,354.511 236.385,346.172 226.114,346.172L207.504,346.172L207.504,364.782C207.504,375.053 215.843,383.392 226.114,383.392L244.724,383.392ZM263.334,364.782C263.334,354.511 271.673,346.172 281.944,346.172L300.554,346.172L300.554,364.782C300.554,375.053 292.215,383.392 281.944,383.392L263.334,383.392L263.334,364.782ZM263.334,308.952C263.334,298.681 271.673,290.342 281.944,290.342L300.554,290.342L300.554,308.952C300.554,319.223 292.215,327.562 281.944,327.562L263.334,327.562L263.334,308.952ZM244.724,308.952C244.724,298.681 236.385,290.342 226.114,290.342L207.504,290.342L207.504,308.952C207.504,319.223 215.843,327.562 226.114,327.562L244.724,327.562L244.724,308.952ZM267.188,267.412C274.451,260.15 274.451,248.357 267.188,241.094C267.188,241.094 254.029,227.935 254.029,227.935L240.87,241.094C233.607,248.357 233.607,260.15 240.87,267.412L254.029,280.572L267.188,267.412Z" style="fill:white;"/>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

View File

@ -1,28 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 424 224" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,-1018,-113)">
<g transform="matrix(1,0,0,0.75,830,0)">
<g transform="matrix(1,0,0,1.33333,0,-112.407)">
<path d="M244.724,402.002L226.114,402.002C205.572,402.002 188.894,385.324 188.894,364.782L188.894,253.122L188.895,253.242C188.959,263.418 197.208,271.667 207.384,271.732L207.504,271.732L218.288,271.732C211.035,256.892 213.572,238.455 225.902,226.126L254.029,197.998C254.029,197.998 282.157,226.126 282.157,226.126C294.486,238.455 297.023,256.892 289.77,271.732L300.554,271.732L300.674,271.732C310.85,271.667 319.099,263.418 319.164,253.242L319.164,253.122L319.164,364.782C319.164,385.324 302.486,402.002 281.944,402.002L263.334,402.002L263.334,420.612L244.724,420.612L244.724,402.002ZM244.724,383.392L244.724,364.782C244.724,354.511 236.385,346.172 226.114,346.172L207.504,346.172L207.504,364.782C207.504,375.053 215.843,383.392 226.114,383.392L244.724,383.392ZM263.334,364.782C263.334,354.511 271.673,346.172 281.944,346.172L300.554,346.172L300.554,364.782C300.554,375.053 292.215,383.392 281.944,383.392L263.334,383.392L263.334,364.782ZM263.334,308.952C263.334,298.681 271.673,290.342 281.944,290.342L300.554,290.342L300.554,308.952C300.554,319.223 292.215,327.562 281.944,327.562L263.334,327.562L263.334,308.952ZM244.724,308.952C244.724,298.681 236.385,290.342 226.114,290.342L207.504,290.342L207.504,308.952C207.504,319.223 215.843,327.562 226.114,327.562L244.724,327.562L244.724,308.952ZM267.188,267.412C274.451,260.15 274.451,248.357 267.188,241.094C267.188,241.094 254.029,227.935 254.029,227.935L240.87,241.094C233.607,248.357 233.607,260.15 240.87,267.412L254.029,280.572L267.188,267.412Z" style="fill:url(#_Linear1);"/>
</g>
<g transform="matrix(1,0,0,1.33333,95.1496,-261.61)">
<g transform="matrix(144,0,0,144,256.612,491.233)">
<path d="M0.231,-0.512C0.246,-0.522 0.263,-0.53 0.281,-0.535C0.301,-0.54 0.32,-0.543 0.339,-0.543C0.352,-0.543 0.363,-0.542 0.374,-0.54L0.374,-0.428C0.362,-0.431 0.349,-0.433 0.336,-0.433C0.309,-0.433 0.284,-0.427 0.262,-0.415C0.238,-0.402 0.22,-0.383 0.209,-0.359C0.197,-0.335 0.191,-0.307 0.191,-0.274L0.191,-0L0.07,-0L0.07,-0.54L0.177,-0.54L0.177,-0.454C0.192,-0.479 0.21,-0.499 0.231,-0.512Z" style="fill-rule:nonzero;"/>
</g>
<g transform="matrix(144,0,0,144,314.068,491.233)">
<path d="M0.353,-0.555C0.438,-0.555 0.495,-0.528 0.524,-0.472C0.552,-0.418 0.566,-0.361 0.566,-0.302L0.566,-0L0.444,-0L0.444,-0.26C0.444,-0.381 0.402,-0.442 0.317,-0.442C0.281,-0.442 0.251,-0.43 0.227,-0.405C0.203,-0.38 0.191,-0.338 0.191,-0.278L0.191,-0L0.069,-0L0.069,-0.72L0.177,-0.72L0.177,-0.48C0.218,-0.53 0.277,-0.555 0.353,-0.555Z" style="fill-rule:nonzero;"/>
</g>
<g transform="matrix(144,0,0,144,404.212,491.233)">
<path d="M0.496,-0.455C0.505,-0.438 0.51,-0.42 0.513,-0.402C0.515,-0.383 0.516,-0.36 0.516,-0.331L0.516,-0L0.411,-0L0.411,-0.073C0.388,-0.043 0.361,-0.021 0.331,-0.007C0.3,0.008 0.264,0.015 0.221,0.015C0.183,0.015 0.15,0.008 0.123,-0.007C0.096,-0.022 0.075,-0.041 0.061,-0.066C0.047,-0.091 0.04,-0.118 0.04,-0.148C0.04,-0.187 0.05,-0.221 0.07,-0.248C0.09,-0.275 0.121,-0.295 0.163,-0.31C0.189,-0.318 0.22,-0.325 0.256,-0.332C0.292,-0.338 0.339,-0.345 0.398,-0.353C0.396,-0.385 0.386,-0.408 0.369,-0.423C0.351,-0.438 0.324,-0.445 0.287,-0.445C0.26,-0.445 0.236,-0.439 0.215,-0.427C0.193,-0.414 0.178,-0.395 0.17,-0.369L0.059,-0.404C0.073,-0.451 0.099,-0.488 0.138,-0.515C0.176,-0.542 0.226,-0.555 0.288,-0.555C0.393,-0.555 0.462,-0.522 0.496,-0.455ZM0.384,-0.171C0.391,-0.188 0.396,-0.216 0.397,-0.255C0.358,-0.249 0.324,-0.243 0.295,-0.237C0.265,-0.232 0.241,-0.226 0.224,-0.221C0.202,-0.212 0.186,-0.203 0.174,-0.192C0.164,-0.181 0.158,-0.167 0.158,-0.15C0.158,-0.129 0.166,-0.113 0.181,-0.1C0.196,-0.087 0.217,-0.081 0.245,-0.081C0.282,-0.081 0.313,-0.09 0.338,-0.109C0.362,-0.128 0.377,-0.148 0.384,-0.171Z" style="fill-rule:nonzero;"/>
</g>
<g transform="matrix(144,0,0,144,487.156,491.233)">
<path d="M0.08,-0.734L0.2,-0.734L0.2,-0.624L0.08,-0.624L0.08,-0.734ZM0.08,-0.54L0.2,-0.54L0.2,-0L0.08,-0L0.08,-0.54Z" style="fill-rule:nonzero;"/>
</g>
</g>
</g>
</g>
<defs>
<linearGradient id="_Linear1" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.36312e-14,222.614,-222.614,1.36312e-14,254.029,197.998)"><stop offset="0" style="stop-color:rgb(255,215,118);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(246,117,0);stop-opacity:1"/></linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

View File

@ -1,28 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 424 224" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,-1018,-593)">
<g transform="matrix(1,0,0,0.75,830,480)">
<g transform="matrix(1,0,0,1.33333,0,-112.407)">
<path d="M244.724,402.002L226.114,402.002C205.572,402.002 188.894,385.324 188.894,364.782L188.894,253.122L188.895,253.242C188.959,263.418 197.208,271.667 207.384,271.732L207.504,271.732L218.288,271.732C211.035,256.892 213.572,238.455 225.902,226.126L254.029,197.998C254.029,197.998 282.157,226.126 282.157,226.126C294.486,238.455 297.023,256.892 289.77,271.732L300.554,271.732L300.674,271.732C310.85,271.667 319.099,263.418 319.164,253.242L319.164,253.122L319.164,364.782C319.164,385.324 302.486,402.002 281.944,402.002L263.334,402.002L263.334,420.612L244.724,420.612L244.724,402.002ZM244.724,383.392L244.724,364.782C244.724,354.511 236.385,346.172 226.114,346.172L207.504,346.172L207.504,364.782C207.504,375.053 215.843,383.392 226.114,383.392L244.724,383.392ZM263.334,364.782C263.334,354.511 271.673,346.172 281.944,346.172L300.554,346.172L300.554,364.782C300.554,375.053 292.215,383.392 281.944,383.392L263.334,383.392L263.334,364.782ZM263.334,308.952C263.334,298.681 271.673,290.342 281.944,290.342L300.554,290.342L300.554,308.952C300.554,319.223 292.215,327.562 281.944,327.562L263.334,327.562L263.334,308.952ZM244.724,308.952C244.724,298.681 236.385,290.342 226.114,290.342L207.504,290.342L207.504,308.952C207.504,319.223 215.843,327.562 226.114,327.562L244.724,327.562L244.724,308.952ZM267.188,267.412C274.451,260.15 274.451,248.357 267.188,241.094C267.188,241.094 254.029,227.935 254.029,227.935L240.87,241.094C233.607,248.357 233.607,260.15 240.87,267.412L254.029,280.572L267.188,267.412Z" style="fill:url(#_Linear1);"/>
</g>
<g transform="matrix(1,0,0,1.33333,95.1496,-261.61)">
<g transform="matrix(144,0,0,144,256.612,491.233)">
<path d="M0.231,-0.512C0.246,-0.522 0.263,-0.53 0.281,-0.535C0.301,-0.54 0.32,-0.543 0.339,-0.543C0.352,-0.543 0.363,-0.542 0.374,-0.54L0.374,-0.428C0.362,-0.431 0.349,-0.433 0.336,-0.433C0.309,-0.433 0.284,-0.427 0.262,-0.415C0.238,-0.402 0.22,-0.383 0.209,-0.359C0.197,-0.335 0.191,-0.307 0.191,-0.274L0.191,-0L0.07,-0L0.07,-0.54L0.177,-0.54L0.177,-0.454C0.192,-0.479 0.21,-0.499 0.231,-0.512Z" style="fill:white;fill-rule:nonzero;"/>
</g>
<g transform="matrix(144,0,0,144,314.068,491.233)">
<path d="M0.353,-0.555C0.438,-0.555 0.495,-0.528 0.524,-0.472C0.552,-0.418 0.566,-0.361 0.566,-0.302L0.566,-0L0.444,-0L0.444,-0.26C0.444,-0.381 0.402,-0.442 0.317,-0.442C0.281,-0.442 0.251,-0.43 0.227,-0.405C0.203,-0.38 0.191,-0.338 0.191,-0.278L0.191,-0L0.069,-0L0.069,-0.72L0.177,-0.72L0.177,-0.48C0.218,-0.53 0.277,-0.555 0.353,-0.555Z" style="fill:white;fill-rule:nonzero;"/>
</g>
<g transform="matrix(144,0,0,144,404.212,491.233)">
<path d="M0.496,-0.455C0.505,-0.438 0.51,-0.42 0.513,-0.402C0.515,-0.383 0.516,-0.36 0.516,-0.331L0.516,-0L0.411,-0L0.411,-0.073C0.388,-0.043 0.361,-0.021 0.331,-0.007C0.3,0.008 0.264,0.015 0.221,0.015C0.183,0.015 0.15,0.008 0.123,-0.007C0.096,-0.022 0.075,-0.041 0.061,-0.066C0.047,-0.091 0.04,-0.118 0.04,-0.148C0.04,-0.187 0.05,-0.221 0.07,-0.248C0.09,-0.275 0.121,-0.295 0.163,-0.31C0.189,-0.318 0.22,-0.325 0.256,-0.332C0.292,-0.338 0.339,-0.345 0.398,-0.353C0.396,-0.385 0.386,-0.408 0.369,-0.423C0.351,-0.438 0.324,-0.445 0.287,-0.445C0.26,-0.445 0.236,-0.439 0.215,-0.427C0.193,-0.414 0.178,-0.395 0.17,-0.369L0.059,-0.404C0.073,-0.451 0.099,-0.488 0.138,-0.515C0.176,-0.542 0.226,-0.555 0.288,-0.555C0.393,-0.555 0.462,-0.522 0.496,-0.455ZM0.384,-0.171C0.391,-0.188 0.396,-0.216 0.397,-0.255C0.358,-0.249 0.324,-0.243 0.295,-0.237C0.265,-0.232 0.241,-0.226 0.224,-0.221C0.202,-0.212 0.186,-0.203 0.174,-0.192C0.164,-0.181 0.158,-0.167 0.158,-0.15C0.158,-0.129 0.166,-0.113 0.181,-0.1C0.196,-0.087 0.217,-0.081 0.245,-0.081C0.282,-0.081 0.313,-0.09 0.338,-0.109C0.362,-0.128 0.377,-0.148 0.384,-0.171Z" style="fill:white;fill-rule:nonzero;"/>
</g>
<g transform="matrix(144,0,0,144,487.156,491.233)">
<path d="M0.08,-0.734L0.2,-0.734L0.2,-0.624L0.08,-0.624L0.08,-0.734ZM0.08,-0.54L0.2,-0.54L0.2,-0L0.08,-0L0.08,-0.54Z" style="fill:white;fill-rule:nonzero;"/>
</g>
</g>
</g>
</g>
<defs>
<linearGradient id="_Linear1" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.36312e-14,222.614,-222.614,1.36312e-14,254.029,197.998)"><stop offset="0" style="stop-color:rgb(255,215,118);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(246,117,0);stop-opacity:1"/></linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

View File

@ -1,25 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 424 224" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,-188,-113)">
<g transform="matrix(1,0,0,0.75,0,0)">
<g transform="matrix(1,0,0,1.33333,0,-112.407)">
<path d="M244.724,402.002L226.114,402.002C205.572,402.002 188.894,385.324 188.894,364.782L188.894,253.122L188.895,253.242C188.959,263.418 197.208,271.667 207.384,271.732L207.504,271.732L218.288,271.732C211.035,256.892 213.572,238.455 225.902,226.126L254.029,197.998C254.029,197.998 282.157,226.126 282.157,226.126C294.486,238.455 297.023,256.892 289.77,271.732L300.554,271.732L300.674,271.732C310.85,271.667 319.099,263.418 319.164,253.242L319.164,253.122L319.164,364.782C319.164,385.324 302.486,402.002 281.944,402.002L263.334,402.002L263.334,420.612L244.724,420.612L244.724,402.002ZM244.724,383.392L244.724,364.782C244.724,354.511 236.385,346.172 226.114,346.172L207.504,346.172L207.504,364.782C207.504,375.053 215.843,383.392 226.114,383.392L244.724,383.392ZM263.334,364.782C263.334,354.511 271.673,346.172 281.944,346.172L300.554,346.172L300.554,364.782C300.554,375.053 292.215,383.392 281.944,383.392L263.334,383.392L263.334,364.782ZM263.334,308.952C263.334,298.681 271.673,290.342 281.944,290.342L300.554,290.342L300.554,308.952C300.554,319.223 292.215,327.562 281.944,327.562L263.334,327.562L263.334,308.952ZM244.724,308.952C244.724,298.681 236.385,290.342 226.114,290.342L207.504,290.342L207.504,308.952C207.504,319.223 215.843,327.562 226.114,327.562L244.724,327.562L244.724,308.952ZM267.188,267.412C274.451,260.15 274.451,248.357 267.188,241.094C267.188,241.094 254.029,227.935 254.029,227.935L240.87,241.094C233.607,248.357 233.607,260.15 240.87,267.412L254.029,280.572L267.188,267.412Z"/>
</g>
<g transform="matrix(1,0,0,1.33333,95.1496,-261.61)">
<g transform="matrix(144,0,0,144,256.612,491.233)">
<path d="M0.231,-0.512C0.246,-0.522 0.263,-0.53 0.281,-0.535C0.301,-0.54 0.32,-0.543 0.339,-0.543C0.352,-0.543 0.363,-0.542 0.374,-0.54L0.374,-0.428C0.362,-0.431 0.349,-0.433 0.336,-0.433C0.309,-0.433 0.284,-0.427 0.262,-0.415C0.238,-0.402 0.22,-0.383 0.209,-0.359C0.197,-0.335 0.191,-0.307 0.191,-0.274L0.191,-0L0.07,-0L0.07,-0.54L0.177,-0.54L0.177,-0.454C0.192,-0.479 0.21,-0.499 0.231,-0.512Z" style="fill-rule:nonzero;"/>
</g>
<g transform="matrix(144,0,0,144,314.068,491.233)">
<path d="M0.353,-0.555C0.438,-0.555 0.495,-0.528 0.524,-0.472C0.552,-0.418 0.566,-0.361 0.566,-0.302L0.566,-0L0.444,-0L0.444,-0.26C0.444,-0.381 0.402,-0.442 0.317,-0.442C0.281,-0.442 0.251,-0.43 0.227,-0.405C0.203,-0.38 0.191,-0.338 0.191,-0.278L0.191,-0L0.069,-0L0.069,-0.72L0.177,-0.72L0.177,-0.48C0.218,-0.53 0.277,-0.555 0.353,-0.555Z" style="fill-rule:nonzero;"/>
</g>
<g transform="matrix(144,0,0,144,404.212,491.233)">
<path d="M0.496,-0.455C0.505,-0.438 0.51,-0.42 0.513,-0.402C0.515,-0.383 0.516,-0.36 0.516,-0.331L0.516,-0L0.411,-0L0.411,-0.073C0.388,-0.043 0.361,-0.021 0.331,-0.007C0.3,0.008 0.264,0.015 0.221,0.015C0.183,0.015 0.15,0.008 0.123,-0.007C0.096,-0.022 0.075,-0.041 0.061,-0.066C0.047,-0.091 0.04,-0.118 0.04,-0.148C0.04,-0.187 0.05,-0.221 0.07,-0.248C0.09,-0.275 0.121,-0.295 0.163,-0.31C0.189,-0.318 0.22,-0.325 0.256,-0.332C0.292,-0.338 0.339,-0.345 0.398,-0.353C0.396,-0.385 0.386,-0.408 0.369,-0.423C0.351,-0.438 0.324,-0.445 0.287,-0.445C0.26,-0.445 0.236,-0.439 0.215,-0.427C0.193,-0.414 0.178,-0.395 0.17,-0.369L0.059,-0.404C0.073,-0.451 0.099,-0.488 0.138,-0.515C0.176,-0.542 0.226,-0.555 0.288,-0.555C0.393,-0.555 0.462,-0.522 0.496,-0.455ZM0.384,-0.171C0.391,-0.188 0.396,-0.216 0.397,-0.255C0.358,-0.249 0.324,-0.243 0.295,-0.237C0.265,-0.232 0.241,-0.226 0.224,-0.221C0.202,-0.212 0.186,-0.203 0.174,-0.192C0.164,-0.181 0.158,-0.167 0.158,-0.15C0.158,-0.129 0.166,-0.113 0.181,-0.1C0.196,-0.087 0.217,-0.081 0.245,-0.081C0.282,-0.081 0.313,-0.09 0.338,-0.109C0.362,-0.128 0.377,-0.148 0.384,-0.171Z" style="fill-rule:nonzero;"/>
</g>
<g transform="matrix(144,0,0,144,487.156,491.233)">
<path d="M0.08,-0.734L0.2,-0.734L0.2,-0.624L0.08,-0.624L0.08,-0.734ZM0.08,-0.54L0.2,-0.54L0.2,-0L0.08,-0L0.08,-0.54Z" style="fill-rule:nonzero;"/>
</g>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

View File

@ -1,25 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 424 224" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,-188,-593)">
<g transform="matrix(1,0,0,0.75,0,480)">
<g transform="matrix(1,0,0,1.33333,0,-112.407)">
<path d="M244.724,402.002L226.114,402.002C205.572,402.002 188.894,385.324 188.894,364.782L188.894,253.122L188.895,253.242C188.959,263.418 197.208,271.667 207.384,271.732L207.504,271.732L218.288,271.732C211.035,256.892 213.572,238.455 225.902,226.126L254.029,197.998C254.029,197.998 282.157,226.126 282.157,226.126C294.486,238.455 297.023,256.892 289.77,271.732L300.554,271.732L300.674,271.732C310.85,271.667 319.099,263.418 319.164,253.242L319.164,253.122L319.164,364.782C319.164,385.324 302.486,402.002 281.944,402.002L263.334,402.002L263.334,420.612L244.724,420.612L244.724,402.002ZM244.724,383.392L244.724,364.782C244.724,354.511 236.385,346.172 226.114,346.172L207.504,346.172L207.504,364.782C207.504,375.053 215.843,383.392 226.114,383.392L244.724,383.392ZM263.334,364.782C263.334,354.511 271.673,346.172 281.944,346.172L300.554,346.172L300.554,364.782C300.554,375.053 292.215,383.392 281.944,383.392L263.334,383.392L263.334,364.782ZM263.334,308.952C263.334,298.681 271.673,290.342 281.944,290.342L300.554,290.342L300.554,308.952C300.554,319.223 292.215,327.562 281.944,327.562L263.334,327.562L263.334,308.952ZM244.724,308.952C244.724,298.681 236.385,290.342 226.114,290.342L207.504,290.342L207.504,308.952C207.504,319.223 215.843,327.562 226.114,327.562L244.724,327.562L244.724,308.952ZM267.188,267.412C274.451,260.15 274.451,248.357 267.188,241.094C267.188,241.094 254.029,227.935 254.029,227.935L240.87,241.094C233.607,248.357 233.607,260.15 240.87,267.412L254.029,280.572L267.188,267.412Z" style="fill:white;"/>
</g>
<g transform="matrix(1,0,0,1.33333,95.1496,-261.61)">
<g transform="matrix(144,0,0,144,256.612,491.233)">
<path d="M0.231,-0.512C0.246,-0.522 0.263,-0.53 0.281,-0.535C0.301,-0.54 0.32,-0.543 0.339,-0.543C0.352,-0.543 0.363,-0.542 0.374,-0.54L0.374,-0.428C0.362,-0.431 0.349,-0.433 0.336,-0.433C0.309,-0.433 0.284,-0.427 0.262,-0.415C0.238,-0.402 0.22,-0.383 0.209,-0.359C0.197,-0.335 0.191,-0.307 0.191,-0.274L0.191,-0L0.07,-0L0.07,-0.54L0.177,-0.54L0.177,-0.454C0.192,-0.479 0.21,-0.499 0.231,-0.512Z" style="fill:white;fill-rule:nonzero;"/>
</g>
<g transform="matrix(144,0,0,144,314.068,491.233)">
<path d="M0.353,-0.555C0.438,-0.555 0.495,-0.528 0.524,-0.472C0.552,-0.418 0.566,-0.361 0.566,-0.302L0.566,-0L0.444,-0L0.444,-0.26C0.444,-0.381 0.402,-0.442 0.317,-0.442C0.281,-0.442 0.251,-0.43 0.227,-0.405C0.203,-0.38 0.191,-0.338 0.191,-0.278L0.191,-0L0.069,-0L0.069,-0.72L0.177,-0.72L0.177,-0.48C0.218,-0.53 0.277,-0.555 0.353,-0.555Z" style="fill:white;fill-rule:nonzero;"/>
</g>
<g transform="matrix(144,0,0,144,404.212,491.233)">
<path d="M0.496,-0.455C0.505,-0.438 0.51,-0.42 0.513,-0.402C0.515,-0.383 0.516,-0.36 0.516,-0.331L0.516,-0L0.411,-0L0.411,-0.073C0.388,-0.043 0.361,-0.021 0.331,-0.007C0.3,0.008 0.264,0.015 0.221,0.015C0.183,0.015 0.15,0.008 0.123,-0.007C0.096,-0.022 0.075,-0.041 0.061,-0.066C0.047,-0.091 0.04,-0.118 0.04,-0.148C0.04,-0.187 0.05,-0.221 0.07,-0.248C0.09,-0.275 0.121,-0.295 0.163,-0.31C0.189,-0.318 0.22,-0.325 0.256,-0.332C0.292,-0.338 0.339,-0.345 0.398,-0.353C0.396,-0.385 0.386,-0.408 0.369,-0.423C0.351,-0.438 0.324,-0.445 0.287,-0.445C0.26,-0.445 0.236,-0.439 0.215,-0.427C0.193,-0.414 0.178,-0.395 0.17,-0.369L0.059,-0.404C0.073,-0.451 0.099,-0.488 0.138,-0.515C0.176,-0.542 0.226,-0.555 0.288,-0.555C0.393,-0.555 0.462,-0.522 0.496,-0.455ZM0.384,-0.171C0.391,-0.188 0.396,-0.216 0.397,-0.255C0.358,-0.249 0.324,-0.243 0.295,-0.237C0.265,-0.232 0.241,-0.226 0.224,-0.221C0.202,-0.212 0.186,-0.203 0.174,-0.192C0.164,-0.181 0.158,-0.167 0.158,-0.15C0.158,-0.129 0.166,-0.113 0.181,-0.1C0.196,-0.087 0.217,-0.081 0.245,-0.081C0.282,-0.081 0.313,-0.09 0.338,-0.109C0.362,-0.128 0.377,-0.148 0.384,-0.171Z" style="fill:white;fill-rule:nonzero;"/>
</g>
<g transform="matrix(144,0,0,144,487.156,491.233)">
<path d="M0.08,-0.734L0.2,-0.734L0.2,-0.624L0.08,-0.624L0.08,-0.734ZM0.08,-0.54L0.2,-0.54L0.2,-0L0.08,-0L0.08,-0.54Z" style="fill:white;fill-rule:nonzero;"/>
</g>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

View File

@ -1,36 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 800 450" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,0,-480)">
<g id="rhai-sil-black" transform="matrix(1,0,0,0.75,0,480)">
<rect x="0" y="0" width="800" height="600" style="fill:none;"/>
<clipPath id="_clip1">
<rect x="0" y="0" width="800" height="600"/>
</clipPath>
<g clip-path="url(#_clip1)">
<g transform="matrix(1,0,0,1.33333,0,-641.217)">
<rect x="0" y="480.913" width="800" height="450"/>
</g>
<g>
<g transform="matrix(1,0,0,1.33333,0,-112.407)">
<path d="M244.724,402.002L226.114,402.002C205.572,402.002 188.894,385.324 188.894,364.782L188.894,253.122L188.895,253.242C188.959,263.418 197.208,271.667 207.384,271.732L207.504,271.732L218.288,271.732C211.035,256.892 213.572,238.455 225.902,226.126L254.029,197.998C254.029,197.998 282.157,226.126 282.157,226.126C294.486,238.455 297.023,256.892 289.77,271.732L300.554,271.732L300.674,271.732C310.85,271.667 319.099,263.418 319.164,253.242L319.164,253.122L319.164,364.782C319.164,385.324 302.486,402.002 281.944,402.002L263.334,402.002L263.334,420.612L244.724,420.612L244.724,402.002ZM244.724,383.392L244.724,364.782C244.724,354.511 236.385,346.172 226.114,346.172L207.504,346.172L207.504,364.782C207.504,375.053 215.843,383.392 226.114,383.392L244.724,383.392ZM263.334,364.782C263.334,354.511 271.673,346.172 281.944,346.172L300.554,346.172L300.554,364.782C300.554,375.053 292.215,383.392 281.944,383.392L263.334,383.392L263.334,364.782ZM263.334,308.952C263.334,298.681 271.673,290.342 281.944,290.342L300.554,290.342L300.554,308.952C300.554,319.223 292.215,327.562 281.944,327.562L263.334,327.562L263.334,308.952ZM244.724,308.952C244.724,298.681 236.385,290.342 226.114,290.342L207.504,290.342L207.504,308.952C207.504,319.223 215.843,327.562 226.114,327.562L244.724,327.562L244.724,308.952ZM267.188,267.412C274.451,260.15 274.451,248.357 267.188,241.094C267.188,241.094 254.029,227.935 254.029,227.935L240.87,241.094C233.607,248.357 233.607,260.15 240.87,267.412L254.029,280.572L267.188,267.412Z" style="fill:white;"/>
</g>
<g transform="matrix(1,0,0,1.33333,95.1496,-261.61)">
<g transform="matrix(144,0,0,144,256.612,491.233)">
<path d="M0.231,-0.512C0.246,-0.522 0.263,-0.53 0.281,-0.535C0.301,-0.54 0.32,-0.543 0.339,-0.543C0.352,-0.543 0.363,-0.542 0.374,-0.54L0.374,-0.428C0.362,-0.431 0.349,-0.433 0.336,-0.433C0.309,-0.433 0.284,-0.427 0.262,-0.415C0.238,-0.402 0.22,-0.383 0.209,-0.359C0.197,-0.335 0.191,-0.307 0.191,-0.274L0.191,-0L0.07,-0L0.07,-0.54L0.177,-0.54L0.177,-0.454C0.192,-0.479 0.21,-0.499 0.231,-0.512Z" style="fill:white;fill-rule:nonzero;"/>
</g>
<g transform="matrix(144,0,0,144,314.068,491.233)">
<path d="M0.353,-0.555C0.438,-0.555 0.495,-0.528 0.524,-0.472C0.552,-0.418 0.566,-0.361 0.566,-0.302L0.566,-0L0.444,-0L0.444,-0.26C0.444,-0.381 0.402,-0.442 0.317,-0.442C0.281,-0.442 0.251,-0.43 0.227,-0.405C0.203,-0.38 0.191,-0.338 0.191,-0.278L0.191,-0L0.069,-0L0.069,-0.72L0.177,-0.72L0.177,-0.48C0.218,-0.53 0.277,-0.555 0.353,-0.555Z" style="fill:white;fill-rule:nonzero;"/>
</g>
<g transform="matrix(144,0,0,144,404.212,491.233)">
<path d="M0.496,-0.455C0.505,-0.438 0.51,-0.42 0.513,-0.402C0.515,-0.383 0.516,-0.36 0.516,-0.331L0.516,-0L0.411,-0L0.411,-0.073C0.388,-0.043 0.361,-0.021 0.331,-0.007C0.3,0.008 0.264,0.015 0.221,0.015C0.183,0.015 0.15,0.008 0.123,-0.007C0.096,-0.022 0.075,-0.041 0.061,-0.066C0.047,-0.091 0.04,-0.118 0.04,-0.148C0.04,-0.187 0.05,-0.221 0.07,-0.248C0.09,-0.275 0.121,-0.295 0.163,-0.31C0.189,-0.318 0.22,-0.325 0.256,-0.332C0.292,-0.338 0.339,-0.345 0.398,-0.353C0.396,-0.385 0.386,-0.408 0.369,-0.423C0.351,-0.438 0.324,-0.445 0.287,-0.445C0.26,-0.445 0.236,-0.439 0.215,-0.427C0.193,-0.414 0.178,-0.395 0.17,-0.369L0.059,-0.404C0.073,-0.451 0.099,-0.488 0.138,-0.515C0.176,-0.542 0.226,-0.555 0.288,-0.555C0.393,-0.555 0.462,-0.522 0.496,-0.455ZM0.384,-0.171C0.391,-0.188 0.396,-0.216 0.397,-0.255C0.358,-0.249 0.324,-0.243 0.295,-0.237C0.265,-0.232 0.241,-0.226 0.224,-0.221C0.202,-0.212 0.186,-0.203 0.174,-0.192C0.164,-0.181 0.158,-0.167 0.158,-0.15C0.158,-0.129 0.166,-0.113 0.181,-0.1C0.196,-0.087 0.217,-0.081 0.245,-0.081C0.282,-0.081 0.313,-0.09 0.338,-0.109C0.362,-0.128 0.377,-0.148 0.384,-0.171Z" style="fill:white;fill-rule:nonzero;"/>
</g>
<g transform="matrix(144,0,0,144,487.156,491.233)">
<path d="M0.08,-0.734L0.2,-0.734L0.2,-0.624L0.08,-0.624L0.08,-0.734ZM0.08,-0.54L0.2,-0.54L0.2,-0L0.08,-0L0.08,-0.54Z" style="fill:white;fill-rule:nonzero;"/>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

View File

@ -1,29 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 800 450" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g id="rhai-sil-white" transform="matrix(1,0,0,0.75,0,0)">
<rect x="0" y="0" width="800" height="600" style="fill:none;"/>
<g transform="matrix(1,0,0,1.33333,0,0)">
<rect x="0" y="0" width="800" height="450" style="fill:white;"/>
</g>
<g>
<g transform="matrix(1,0,0,1.33333,0,-112.407)">
<path d="M244.724,402.002L226.114,402.002C205.572,402.002 188.894,385.324 188.894,364.782L188.894,253.122L188.895,253.242C188.959,263.418 197.208,271.667 207.384,271.732L207.504,271.732L218.288,271.732C211.035,256.892 213.572,238.455 225.902,226.126L254.029,197.998C254.029,197.998 282.157,226.126 282.157,226.126C294.486,238.455 297.023,256.892 289.77,271.732L300.554,271.732L300.674,271.732C310.85,271.667 319.099,263.418 319.164,253.242L319.164,253.122L319.164,364.782C319.164,385.324 302.486,402.002 281.944,402.002L263.334,402.002L263.334,420.612L244.724,420.612L244.724,402.002ZM244.724,383.392L244.724,364.782C244.724,354.511 236.385,346.172 226.114,346.172L207.504,346.172L207.504,364.782C207.504,375.053 215.843,383.392 226.114,383.392L244.724,383.392ZM263.334,364.782C263.334,354.511 271.673,346.172 281.944,346.172L300.554,346.172L300.554,364.782C300.554,375.053 292.215,383.392 281.944,383.392L263.334,383.392L263.334,364.782ZM263.334,308.952C263.334,298.681 271.673,290.342 281.944,290.342L300.554,290.342L300.554,308.952C300.554,319.223 292.215,327.562 281.944,327.562L263.334,327.562L263.334,308.952ZM244.724,308.952C244.724,298.681 236.385,290.342 226.114,290.342L207.504,290.342L207.504,308.952C207.504,319.223 215.843,327.562 226.114,327.562L244.724,327.562L244.724,308.952ZM267.188,267.412C274.451,260.15 274.451,248.357 267.188,241.094C267.188,241.094 254.029,227.935 254.029,227.935L240.87,241.094C233.607,248.357 233.607,260.15 240.87,267.412L254.029,280.572L267.188,267.412Z"/>
</g>
<g transform="matrix(1,0,0,1.33333,95.1496,-261.61)">
<g transform="matrix(144,0,0,144,256.612,491.233)">
<path d="M0.231,-0.512C0.246,-0.522 0.263,-0.53 0.281,-0.535C0.301,-0.54 0.32,-0.543 0.339,-0.543C0.352,-0.543 0.363,-0.542 0.374,-0.54L0.374,-0.428C0.362,-0.431 0.349,-0.433 0.336,-0.433C0.309,-0.433 0.284,-0.427 0.262,-0.415C0.238,-0.402 0.22,-0.383 0.209,-0.359C0.197,-0.335 0.191,-0.307 0.191,-0.274L0.191,-0L0.07,-0L0.07,-0.54L0.177,-0.54L0.177,-0.454C0.192,-0.479 0.21,-0.499 0.231,-0.512Z" style="fill-rule:nonzero;"/>
</g>
<g transform="matrix(144,0,0,144,314.068,491.233)">
<path d="M0.353,-0.555C0.438,-0.555 0.495,-0.528 0.524,-0.472C0.552,-0.418 0.566,-0.361 0.566,-0.302L0.566,-0L0.444,-0L0.444,-0.26C0.444,-0.381 0.402,-0.442 0.317,-0.442C0.281,-0.442 0.251,-0.43 0.227,-0.405C0.203,-0.38 0.191,-0.338 0.191,-0.278L0.191,-0L0.069,-0L0.069,-0.72L0.177,-0.72L0.177,-0.48C0.218,-0.53 0.277,-0.555 0.353,-0.555Z" style="fill-rule:nonzero;"/>
</g>
<g transform="matrix(144,0,0,144,404.212,491.233)">
<path d="M0.496,-0.455C0.505,-0.438 0.51,-0.42 0.513,-0.402C0.515,-0.383 0.516,-0.36 0.516,-0.331L0.516,-0L0.411,-0L0.411,-0.073C0.388,-0.043 0.361,-0.021 0.331,-0.007C0.3,0.008 0.264,0.015 0.221,0.015C0.183,0.015 0.15,0.008 0.123,-0.007C0.096,-0.022 0.075,-0.041 0.061,-0.066C0.047,-0.091 0.04,-0.118 0.04,-0.148C0.04,-0.187 0.05,-0.221 0.07,-0.248C0.09,-0.275 0.121,-0.295 0.163,-0.31C0.189,-0.318 0.22,-0.325 0.256,-0.332C0.292,-0.338 0.339,-0.345 0.398,-0.353C0.396,-0.385 0.386,-0.408 0.369,-0.423C0.351,-0.438 0.324,-0.445 0.287,-0.445C0.26,-0.445 0.236,-0.439 0.215,-0.427C0.193,-0.414 0.178,-0.395 0.17,-0.369L0.059,-0.404C0.073,-0.451 0.099,-0.488 0.138,-0.515C0.176,-0.542 0.226,-0.555 0.288,-0.555C0.393,-0.555 0.462,-0.522 0.496,-0.455ZM0.384,-0.171C0.391,-0.188 0.396,-0.216 0.397,-0.255C0.358,-0.249 0.324,-0.243 0.295,-0.237C0.265,-0.232 0.241,-0.226 0.224,-0.221C0.202,-0.212 0.186,-0.203 0.174,-0.192C0.164,-0.181 0.158,-0.167 0.158,-0.15C0.158,-0.129 0.166,-0.113 0.181,-0.1C0.196,-0.087 0.217,-0.081 0.245,-0.081C0.282,-0.081 0.313,-0.09 0.338,-0.109C0.362,-0.128 0.377,-0.148 0.384,-0.171Z" style="fill-rule:nonzero;"/>
</g>
<g transform="matrix(144,0,0,144,487.156,491.233)">
<path d="M0.08,-0.734L0.2,-0.734L0.2,-0.624L0.08,-0.624L0.08,-0.734ZM0.08,-0.54L0.2,-0.54L0.2,-0L0.08,-0L0.08,-0.54Z" style="fill-rule:nonzero;"/>
</g>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.8 KiB

View File

@ -1,218 +0,0 @@
Arrays
======
{{#include ../links.md}}
Arrays are first-class citizens in Rhai. Like C, arrays are accessed with zero-based, non-negative integer indices:
> _array_ `[` _index_ `]`
Array literals are built within square brackets '`[`' ... '`]`' and separated by commas '`,`':
> `[` _value_ `,` _value_ `,` `...` `,` _value_ `]`
>
> `[` _value_ `,` _value_ `,` `...` `,` _value_ `,` `]` `// trailing comma is OK`
All elements stored in an array are [`Dynamic`], and the array can freely grow or shrink with elements added or removed.
The Rust type of a Rhai array is `rhai::Array`.
[`type_of()`] an array returns `"array"`.
Arrays are disabled via the [`no_index`] feature.
The maximum allowed size of an array can be controlled via `Engine::set_max_array_size`
(see [maximum size of arrays].
Built-in Functions
-----------------
The following methods (mostly defined in the [`BasicArrayPackage`][packages] but excluded if using a [raw `Engine`]) operate on arrays:
| Function | Parameter(s) | Description |
| ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `push` | element to insert | inserts an element at the end |
| `append` | array to append | concatenates the second array to the end of the first |
| `+=` operator | 1) array<br/>2) element to insert (not another array) | inserts an element at the end |
| `+=` operator | 1) array<br/>2) array to append | concatenates the second array to the end of the first |
| `+` operator | 1) first array<br/>2) second array | concatenates the first array with the second |
| `==` operator | 1) first array<br/>2) second array | are the two arrays the same (elements compared with the `==` operator, if defined)? |
| `!=` operator | 1) first array<br/>2) second array | are the two arrays different (elements compared with the `==` operator, if defined)? |
| `in` operator | item to find | does the array contain the item (compared with the `==` operator, if defined)? |
| `insert` | 1) element to insert<br/>2) position, beginning if < 0, end if > length | inserts an element at a certain index |
| `pop` | _none_ | removes the last element and returns it ([`()`] if empty) |
| `shift` | _none_ | removes the first element and returns it ([`()`] if empty) |
| `extract` | 1) start position, beginning if < 0, end if > length<br/>2) _(optional)_ number of items to extract, none if < 0 | extracts a portion of the array into a new array |
| `remove` | index | removes an element at a particular index and returns it ([`()`] if the index is not valid) |
| `reverse` | _none_ | reverses the array |
| `len` method and property | _none_ | returns the number of elements |
| `pad` | 1) target length<br/>2) element to pad | pads the array with an element to at least a specified length |
| `clear` | _none_ | empties the array |
| `truncate` | target length | cuts off the array at exactly a specified length (discarding all subsequent elements) |
| `chop` | target length | cuts off the head of the array, leaving the tail at exactly a specified length |
| `drain` | 1) [function pointer] to predicate (usually a [closure])<br/>2) _(optional)_ [function pointer] to function (usually a [closure]) that provides the initial value | removes all items (returning them) that return `true` when called with the predicate function:<br/>1st parameter: array item<br/>2nd parameter: _(optional)_ offset index |
| `drain` | 1) start position, beginning if < 0, end if > length<br/>2) number of items to remove, none if < 0 | removes a portion of the array, returning the removed items (not in original order) |
| `retain` | 1) [function pointer] to predicate (usually a [closure])<br/>2) _(optional)_ [function pointer] to function (usually a [closure]) that provides the initial value | removes all items (returning them) that do not return `true` when called with the predicate function:<br/>1st parameter: array item<br/>2nd parameter: _(optional)_ offset index |
| `retain` | 1) start position, beginning if < 0, end if > length<br/>2) number of items to retain, none if < 0 | retains a portion of the array, removes all other items and returning them (not in original order) |
| `splice` | 1) start position, beginning if < 0, end if > length<br/>2) number of items to remove, none if < 0<br/>3) array to insert | replaces a portion of the array with another (not necessarily of the same length as the replaced portion) |
| `filter` | [function pointer] to predicate (usually a [closure]) | constructs a new array with all items that return `true` when called with the predicate function:<br/>1st parameter: array item<br/>2nd parameter: _(optional)_ offset index |
| `index_of` | [function pointer] to predicate (usually a [closure]) | returns the index of the first item in the array that returns `true` when called with the predicate function, or -1 if not found:<br/>1st parameter: array item<br/>2nd parameter: _(optional)_ offset index |
| `map` | [function pointer] to conversion function (usually a [closure]) | constructs a new array with all items mapped to the result of applying the conversion function:<br/>1st parameter: array item<br/>2nd parameter: _(optional)_ offset index |
| `reduce` | 1) [function pointer] to accumulator function (usually a [closure])<br/>2) _(optional)_ [function pointer] to function (usually a [closure]) that provides the initial value | reduces the array into a single value via the accumulator function:<br/>1st parameter: accumulated value ([`()`] initially)<br/>2nd parameter: array item<br/>3rd parameter: _(optional)_ offset index |
| `reduce_rev` | 1) [function pointer] to accumulator function (usually a [closure])<br/>2) _(optional)_ [function pointer] to function (usually a [closure]) that provides the initial value | reduces the array (in reverse order) into a single value via the accumulator function:<br/>1st parameter: accumulated value ([`()`] initially)<br/>2nd parameter: array item<br/>3rd parameter: _(optional)_ offset index |
| `some` | [function pointer] to predicate (usually a [closure]) | returns `true` if any item returns `true` when called with the predicate function:<br/>1st parameter: array item<br/>2nd parameter: _(optional)_ offset index |
| `all` | [function pointer] to predicate (usually a [closure]) | returns `true` if all items return `true` when called with the predicate function:<br/>1st parameter: array item<br/>2nd parameter: _(optional)_ offset index |
| `sort` | [function pointer] to a comparison function (usually a [closure]) | sorts the array with a comparison function:<br/>1st parameter: first item<br/>2nd parameter: second item<br/>return value: `INT` < 0 if first < second, > 0 if first > second, 0 if first == second |
Use Custom Types With Arrays
---------------------------
To use a [custom type] with arrays, a number of array functions need to be manually implemented,
in particular `push`, `insert`, `pad` and the `+=` operator. In addition, the `==` operator must be
implemented for the [custom type] in order to support the `in` operator which uses `==` to
compare elements.
See the section on [custom types] for more details.
Examples
--------
```rust
let y = [2, 3]; // y == [2, 3]
let y = [2, 3,]; // y == [2, 3]
y.insert(0, 1); // y == [1, 2, 3]
y.insert(999, 4); // y == [1, 2, 3, 4]
y.len == 4;
y[0] == 1;
y[1] == 2;
y[2] == 3;
y[3] == 4;
(1 in y) == true; // use 'in' to test if an item exists in the array
(42 in y) == false; // 'in' uses the '==' operator (which users can override)
// to check if the target item exists in the array
y[1] = 42; // y == [1, 42, 3, 4]
(42 in y) == true;
y.remove(2) == 3; // y == [1, 42, 4]
y.len == 3;
y[2] == 4; // elements after the removed element are shifted
ts.list = y; // arrays can be assigned completely (by value copy)
ts.list[1] == 42;
[1, 2, 3][0] == 1; // indexing on array literal
fn abc() {
[42, 43, 44] // a function returning an array
}
abc()[0] == 42;
y.push(4); // y == [1, 42, 4, 4]
y += 5; // y == [1, 42, 4, 4, 5]
y.len == 5;
y.shift() == 1; // y == [42, 4, 4, 5]
y.chop(3); // y == [4, 4, 5]
y.len == 3;
y.pop() == 5; // y == [4, 4]
y.len == 2;
for item in y { // arrays can be iterated with a 'for' statement
print(item);
}
y.pad(6, "hello"); // y == [4, 4, "hello", "hello", "hello", "hello"]
y.len == 6;
y.truncate(4); // y == [4, 4, "hello", "hello"]
y.len == 4;
y.clear(); // y == []
y.len == 0;
let a = [42, 123, 99];
a.map(|v| v + 1); // returns [43, 124, 100]
a.map(|v, i| v + i); // returns [42, 124, 101]
a.filter(|v| v > 50); // returns [123, 99]
a.filter(|v, i| i == 1); // returns [123]
// Use a closure to provide the initial value
a.reduce(|sum, v| sum + v, || 0) == 264;
// Detect the initial value of '()'
a.reduce(
|sum, v| if sum.type_of() == "()" { v } else { sum + v }
) == 264;
// Detect the initial value via index
a.reduce(|sum, v, i|
if i == 0 { v } else { sum + v }
) == 264;
// Use a closure to provide the initial value
a.reduce_rev(|sum, v| sum + v, || 0) == 264;
// Detect the initial value of '()'
a.reduce_rev(
|sum, v| if sum.type_of() == "()" { v } else { sum + v }
) == 264;
// Detect the initial value via index
a.reduce_rev(|sum, v, i|
if i == 2 { v } else { sum + v }
) == 264;
a.some(|v| v > 50); // returns true
a.some(|v, i| v < i); // returns false
a.none(|v| v != 0); // returns false
a.none(|v, i| v == i); // returns true
a.all(|v| v > 50); // returns false
a.all(|v, i| v > i); // returns true
a.splice(1, 1, [1, 3, 2]); // a == [42, 1, 3, 2, 99]
a.extract(1, 3); // returns [1, 3, 2]
a.sort(|x, y| x - y); // a == [1, 2, 3, 42, 99]
a.drain(|v| v <= 1); // a == [2, 3, 42, 99]
a.drain(|v, i| i >= 3); // a == [2, 3, 42]
a.retain(|v| v > 10); // a == [42]
a.retain(|v, i| i > 0); // a == []
```

View File

@ -1,66 +0,0 @@
Compound Assignment Operators
=============================
{{#include ../links.md}}
```rust
let number = 9;
number += 8; // number = number + 8
number -= 7; // number = number - 7
number *= 6; // number = number * 6
number /= 5; // number = number / 5
number %= 4; // number = number % 4
number ~= 3; // number = number ~ 3
number <<= 2; // number = number << 2
number >>= 1; // number = number >> 1
number &= 0x00ff; // number = number & 0x00ff;
number |= 0x00ff; // number = number | 0x00ff;
number ^= 0x00ff; // number = number ^ 0x00ff;
```
The Flexible `+=`
----------------
The the `+` and `+=` operators are often [overloaded][function overloading] to perform
build-up operations for different data types.
For example, it is used to build [strings]:
```rust
let my_str = "abc";
my_str += "ABC";
my_str += 12345;
my_str == "abcABC12345"
```
to concatenate [arrays]:
```rust
let my_array = [1, 2, 3];
my_array += [4, 5];
my_array == [1, 2, 3, 4, 5];
```
and mix two [object maps] together:
```rust
let my_obj = #{a:1, b:2};
my_obj += #{c:3, d:4, e:5};
my_obj.len() == 5;
```

View File

@ -1,24 +0,0 @@
Comments
========
{{#include ../links.md}}
Comments are C-style, including '`/*` ... `*/`' pairs for block comments
and '`//`' for comments to the end of the line.
Comments can be nested.
```rust
let /* intruder comment */ name = "Bob";
// This is a very important one-line comment
/* This comment spans
multiple lines, so it
only makes sense that
it is even more important */
/* Fear not, Rhai satisfies all nesting needs with nested comments:
/*/*/*/*/**/*/*/*/*/
*/
```

View File

@ -1,97 +0,0 @@
Constants
=========
{{#include ../links.md}}
Constants can be defined using the `const` keyword and are immutable.
Constants follow the same naming rules as [variables].
```rust
const x = 42;
print(x * 2); // prints 84
x = 123; // <- syntax error: cannot assign to constant
```
```rust
const x; // 'x' is a constant '()'
const x = 40 + 2; // 'x' is a constant 42
```
Manually Add Constant into Custom Scope
--------------------------------------
It is possible to add a constant into a custom [`Scope`] so it'll be available to scripts
running with that [`Scope`].
When added to a custom [`Scope`], a constant can hold any value, not just a literal value.
It is very useful to have a constant value hold a [custom type], which essentially acts
as a [_singleton_](../patterns/singleton.md).
```rust
use rhai::{Engine, Scope, RegisterFn};
#[derive(Debug, Clone)]
struct TestStruct(i64); // custom type
let mut engine = Engine::new();
engine
.register_type_with_name::<TestStruct>("TestStruct") // register custom type
.register_get("value", |obj: &mut TestStruct| obj.0), // property getter
.register_fn("update_value",
|obj: &mut TestStruct, value: i64| obj.0 = value // mutating method
);
let mut scope = Scope::new(); // create custom scope
scope.push_constant("MY_NUMBER", TestStruct(123_i64)); // add constant variable
// Beware: constant objects can still be modified via a method call!
engine.consume_with_scope(&mut scope,
r"
MY_NUMBER.update_value(42);
print(MY_NUMBER.value); // prints 42
")?;
```
Caveat &ndash; Constants Can be Modified via Rust
------------------------------------------------
A custom type stored as a constant cannot be modified via script, but _can_ be modified via
a registered Rust function that takes a first `&mut` parameter &ndash; because there is no way for
Rhai to know whether the Rust function modifies its argument!
```rust
const x = 42; // a constant
x.increment(); // call 'increment' defined in Rust with '&mut' first parameter
x == 43; // value of 'x' is changed!
fn double() {
this *= 2; // function doubles 'this'
}
let y = 1; // 'y' is not constant and mutable
y.double(); // double it...
y == 2; // value of 'y' is changed as expected
x.double(); // <- error: cannot modify constant 'this'
x == 43; // value of 'x' is unchanged by script
```
This is important to keep in mind because the script [optimizer][script optimization]
by default does _constant propagation_ as a operation.
If a constant is eventually modified by a Rust function, the optimizer will not see
the updated value and will propagate the original initialization value instead.

View File

@ -1,56 +0,0 @@
Value Conversions
=================
{{#include ../links.md}}
Convert Between Integer and Floating-Point
-----------------------------------------
The `to_float` function converts a supported number to `FLOAT` (defaults to `f64`).
The `to_int` function converts a supported number to `INT` (`i32` or `i64` depending on [`only_i32`]).
That's it; for other conversions, register custom conversion functions.
```rust
let x = 42;
let y = x * 100.0; // <- error: cannot multiply i64 with f64
let y = x.to_float() * 100.0; // works
let z = y.to_int() + x; // works
let c = 'X'; // character
print("c is '" + c + "' and its code is " + c.to_int()); // prints "c is 'X' and its code is 88"
```
Parse String into Number
------------------------
The `parse_float` function converts a [string] into a `FLOAT` (defaults to `f64`).
The `parse_int` function converts a [string] into an `INT` (`i32` or `i64` depending on [`only_i32`]).
An optional radix (2-36) can be provided to parse the [string] into a number of the specified radix.
```rust
let x = parse_float("123.4"); // parse as floating-point
x == 123.4;
type_of(x) == "f64";
let dec = parse_int("42"); // parse as decimal
let dec = parse_int("42", 10); // radix = 10 is the default
dec == 42;
type_of(dec) == "i64";
let bin = parse_int("110", 2); // parse as binary (radix = 2)
bin == 0b110;
type_of(bin) == "i64";
let hex = parse_int("ab", 16); // parse as hex (radix = 16)
hex == 0xab;
type_of(hex) == "i64";
```

View File

@ -1,28 +0,0 @@
`do` Loop
=========
{{#include ../links.md}}
`do` loops have two opposite variants: `do` ... `while` and `do` ... `until`.
Like the `while` loop, `continue` can be used to skip to the next iteration, by-passing all following statements;
`break` can be used to break out of the loop unconditionally.
```rust
let x = 10;
do {
x -= 1;
if x < 6 { continue; } // skip to the next iteration
print(x);
if x == 5 { break; } // break out of do loop
} while x > 0;
do {
x -= 1;
if x < 6 { continue; } // skip to the next iteration
print(x);
if x == 5 { break; } // break out of do loop
} until x == 0;
```

View File

@ -1,77 +0,0 @@
Doc-Comments
============
{{#include ../links.md}}
Similar to Rust, comments starting with `///` (three slashes) or `/**` (two asterisks) are
_doc-comments_.
Doc-comments can only appear in front of [function] definitions, not any other elements:
```rust
/// This is a valid one-line doc-comment
fn foo() {}
/** This is a
** valid block
** doc-comment
**/
fn bar(x) {
/// Syntax error - this doc-comment is invalid
x + 1
}
/** Syntax error - this doc-comment is invalid */
let x = 42;
/// Syntax error - this doc-comment is also invalid
{
let x = 42;
}
```
Special Cases
-------------
Long streams of `//////...` and `/*****...` do _NOT_ form doc-comments.
This is consistent with popular comment block styles for C-like languages.
```rust
/////////////////////////////// <- this is not a doc-comment
// This is not a doc-comment // <- this is a normal comment
/////////////////////////////// <- this is not a doc-comment
// However, watch out for comment lines starting with '///'
////////////////////////////////////////// <- this is not a doc-comment
/// This, however, IS a doc-comment!!! /// <- this starts with '///'
////////////////////////////////////////// <- this is not a doc-comment
/****************************************
* *
* This is also not a doc-comment block *
* so we don't have to put this in *
* front of a function. *
* *
****************************************/
```
Using Doc-Comments
------------------
Doc-comments are stored within the script's [`AST`] after compilation.
The `AST::iter_functions` method provides a `ScriptFnMetadata` instance
for each function defined within the script, which includes doc-comments.
Doc-comments never affect the evaluation of a script nor do they incur
significant performance overhead. However, third party tools can take advantage
of this information to auto-generate documentation for Rhai script functions.
Disabling Doc-Comments
----------------------
Doc-comments can be disabled via the `Engine::set_doc_comments` method.

View File

@ -1,100 +0,0 @@
Dynamic Values
==============
{{#include ../links.md}}
A `Dynamic` value can be _any_ type. However, under [`sync`], all types must be `Send + Sync`.
Use `type_of()` to Get Value Type
--------------------------------
Because [`type_of()`] a `Dynamic` value returns the type of the actual value,
it is usually used to perform type-specific actions based on the actual value's type.
```c
let mystery = get_some_dynamic_value();
switch type_of(mystery) {
"i64" => print("Hey, I got an integer here!"),
"f64" => print("Hey, I got a float here!"),
"string" => print("Hey, I got a string here!"),
"bool" => print("Hey, I got a boolean here!"),
"array" => print("Hey, I got an array here!"),
"map" => print("Hey, I got an object map here!"),
"Fn" => print("Hey, I got a function pointer here!"),
"TestStruct" => print("Hey, I got the TestStruct custom type here!"),
_ => print("I don't know what this is: " + type_of(mystery))
}
```
Functions Returning `Dynamic`
----------------------------
In Rust, sometimes a `Dynamic` forms part of a returned value &ndash; a good example is an [array]
which contains `Dynamic` elements, or an [object map] which contains `Dynamic` property values.
To get the _real_ values, the actual value types _must_ be known in advance.
There is no easy way for Rust to decide, at run-time, what type the `Dynamic` value is
(short of using the `type_name` function and match against the name).
Type Checking and Casting
------------------------
A `Dynamic` value's actual type can be checked via the `is` method.
The `cast` method then converts the value into a specific, known type.
Alternatively, use the `try_cast` method which does not panic but returns `None` when the cast fails.
```rust
let list: Array = engine.eval("...")?; // return type is 'Array'
let item = list[0]; // an element in an 'Array' is 'Dynamic'
item.is::<i64>() == true; // 'is' returns whether a 'Dynamic' value is of a particular type
let value = item.cast::<i64>(); // if the element is 'i64', this succeeds; otherwise it panics
let value: i64 = item.cast(); // type can also be inferred
let value = item.try_cast::<i64>()?; // 'try_cast' does not panic when the cast fails, but returns 'None'
```
Type Name
---------
The `type_name` method gets the name of the actual type as a static string slice,
which can be `match`-ed against.
```rust
let list: Array = engine.eval("...")?; // return type is 'Array'
let item = list[0]; // an element in an 'Array' is 'Dynamic'
match item.type_name() { // 'type_name' returns the name of the actual Rust type
"i64" => ...
"alloc::string::String" => ...
"bool" => ...
"crate::path::to::module::TestStruct" => ...
}
```
**Note:** `type_name` always returns the _full_ Rust path name of the type, even when the type
has been registered with a friendly name via `Engine::register_type_with_name`. This behavior
is different from that of the [`type_of`][`type_of()`] function in Rhai.
Conversion Traits
----------------
The following conversion traits are implemented for `Dynamic`:
* `From<i64>` (`i32` if [`only_i32`])
* `From<f64>` (if not [`no_float`])
* `From<bool>`
* `From<rhai::ImmutableString>`
* `From<String>`
* `From<char>`
* `From<Vec<T>>` (into an [array])
* `From<HashMap<String, T>>` (into an [object map])
* `From<Instant>` (into a [timestamp] if not [`no_std`])

View File

@ -1,83 +0,0 @@
`eval` Function
===============
{{#include ../links.md}}
Or "How to Shoot Yourself in the Foot even Easier"
------------------------------------------------
Saving the best for last, there is the ever-dreaded... `eval` function!
```rust
let x = 10;
fn foo(x) { x += 12; x }
let script = "let y = x;"; // build a script
script += "y += foo(y);";
script += "x + y";
let result = eval(script); // <- look, JavaScript, we can also do this!
result == 42;
x == 10; // prints 10: functions call arguments are passed by value
y == 32; // prints 32: variables defined in 'eval' persist!
eval("{ let z = y }"); // to keep a variable local, use a statement block
print(z); // <- error: variable 'z' not found
"print(42)".eval(); // <- nope... method-call style doesn't work with 'eval'
```
Script segments passed to `eval` execute inside the current [`Scope`], so they can access and modify _everything_,
including all variables that are visible at that position in code! It is almost as if the script segments were
physically pasted in at the position of the `eval` call.
Cannot Define New Functions
--------------------------
New functions cannot be defined within an `eval` call, since functions can only be defined at the _global_ level,
not inside another function call!
```rust
let script = "x += 32";
let x = 10;
eval(script); // variable 'x' in the current scope is visible!
print(x); // prints 42
// The above is equivalent to:
let script = "x += 32";
let x = 10;
x += 32;
print(x);
```
`eval` is Evil
--------------
For those who subscribe to the (very sensible) motto of ["`eval` is evil"](http://linterrors.com/js/eval-is-evil),
disable `eval` using [`Engine::disable_symbol`][disable keywords and operators]:
```rust
engine.disable_symbol("eval"); // disable usage of 'eval'
```
`eval` can also be disabled by overloading it, probably with something that throws:
```rust
fn eval(script) { throw "eval is evil! I refuse to run " + script }
let x = eval("40 + 2"); // throws "eval is evil! I refuse to run 40 + 2"
```
Or overload it from Rust:
```rust
engine.register_result_fn("eval", |script: String| -> Result<(), Box<EvalAltResult>> {
Err(format!("eval is evil! I refuse to run {}", script).into())
});
```

View File

@ -1,60 +0,0 @@
Anonymous Functions
===================
{{#include ../links.md}}
Sometimes it gets tedious to define separate functions only to dispatch them via single [function pointers].
This scenario is especially common when simulating object-oriented programming ([OOP]).
```rust
// Define object
let obj = #{
data: 42,
increment: Fn("inc_obj"), // use function pointers to
decrement: Fn("dec_obj"), // refer to method functions
print: Fn("print_obj")
};
// Define method functions one-by-one
fn inc_obj(x) { this.data += x; }
fn dec_obj(x) { this.data -= x; }
fn print_obj() { print(this.data); }
```
The above can be replaced by using _anonymous functions_ which have the same syntax as Rust's closures
(but they are **NOT** real closures, merely syntactic sugar):
```rust
let obj = #{
data: 42,
increment: |x| this.data += x, // one-liner
decrement: |x| this.data -= x,
print_obj: || { print(this.data); } // full function body
};
```
The anonymous functions will be hoisted into separate functions in the global namespace.
The above is equivalent to:
```rust
let obj = #{
data: 42,
increment: Fn("anon_fn_1000"),
decrement: Fn("anon_fn_1001"),
print: Fn("anon_fn_1002")
};
fn anon_fn_1000(x) { this.data += x; }
fn anon_fn_1001(x) { this.data -= x; }
fn anon_fn_1002() { print this.data; }
```
WARNING &ndash; NOT Real Closures
--------------------------------
Remember: anonymous functions, though having the same syntax as Rust _closures_, are themselves
**not** real closures.
In particular, they capture their execution environment via [automatic currying]
(disabled via [`no_closure`]).

View File

@ -1,71 +0,0 @@
Capture The Calling Scope for Function Call
==========================================
{{#include ../links.md}}
Peeking Out of The Pure Box
---------------------------
Rhai functions are _pure_, meaning that they depend on on their arguments and have no
access to the calling environment.
When a function accesses a variable that is not defined within that function's scope,
it raises an evaluation error.
It is possible, through a special syntax, to capture the calling scope &ndash; i.e. the scope
that makes the function call &ndash; and access variables defined there.
```rust
fn foo(y) { // function accesses 'x' and 'y', but 'x' is not defined
x += y; // 'x' is modified in this function
x
}
let x = 1;
foo(41); // error: variable 'x' not found
// Calling a function with a '!' causes it to capture the calling scope
foo!(41) == 42; // the function can access the value of 'x', but cannot change it
x == 1; // 'x' is still the original value
x.method!(); // <- syntax error: capturing is not allowed in method-call style
// Capturing also works for function pointers
let f = Fn("foo");
call!(f, 41) == 42; // must use function-call style
f.call!(41); // <- syntax error: capturing is not allowed in method-call style
// Capturing is not available for module functions
import "hello" as h;
h::greet!(); // <- syntax error: capturing is not allowed in namespace-qualified calls
```
No Mutations
------------
Variables in the calling scope are captured as cloned copies.
Changes to them do **not** reflect back to the calling scope.
Rhai functions remain _pure_ in the sense that they can never mutate their environment.
Caveat Emptor
-------------
Functions relying on the calling scope is often a _Very Bad Idea™_ because it makes code
almost impossible to reason and maintain, as their behaviors are volatile and unpredictable.
They behave more like macros that are expanded inline than actual function calls, thus the
syntax is also similar to Rust's macro invocations.
This usage should be at the last resort. YOU HAVE BEEN WARNED.

View File

@ -1,192 +0,0 @@
Simulating Closures
===================
{{#include ../links.md}}
Capture External Variables via Automatic Currying
------------------------------------------------
Since [anonymous functions] de-sugar to standard function definitions, they retain all the behaviors of
Rhai functions, including being _pure_, having no access to external variables.
The anonymous function syntax, however, automatically _captures_ variables that are not defined within
the current scope, but are defined in the external scope &ndash; i.e. the scope where the anonymous function
is created.
Variables that are accessible during the time the [anonymous function] is created can be captured,
as long as they are not shadowed by local variables defined within the function's scope.
The captured variables are automatically converted into **reference-counted shared values**
(`Rc<RefCell<Dynamic>>` in normal builds, `Arc<RwLock<Dynamic>>` in [`sync`] builds).
Therefore, similar to closures in many languages, these captured shared values persist through
reference counting, and may be read or modified even after the variables that hold them
go out of scope and no longer exist.
Use the `Dynamic::is_shared` function to check whether a particular value is a shared value.
Automatic currying can be turned off via the [`no_closure`] feature.
Examples
--------
```rust
let x = 1; // a normal variable
x.is_shared() == false;
let f = |y| x + y; // variable 'x' is auto-curried (captured) into 'f'
x.is_shared() == true; // 'x' is now a shared value!
f.call(2) == 3; // 1 + 2 == 3
x = 40; // changing 'x'...
f.call(2) == 42; // the value of 'x' is 40 because 'x' is shared
// The above de-sugars into this:
fn anon$1001(x, y) { x + y } // parameter 'x' is inserted
$make_shared(x); // convert variable 'x' into a shared value
let f = Fn("anon$1001").curry(x); // shared 'x' is curried
f.call(2) == 42;
```
Beware: Captured Variables are Truly Shared
------------------------------------------
The example below is a typical tutorial sample for many languages to illustrate the traps
that may accompany capturing external scope variables in closures.
It prints `9`, `9`, `9`, ... `9`, `9`, not `0`, `1`, `2`, ... `8`, `9`, because there is
ever only _one_ captured variable, and all ten closures capture the _same_ variable.
```rust
let funcs = [];
for i in range(0, 10) {
funcs.push(|| print(i)); // the for loop variable 'i' is captured
}
funcs.len() == 10; // 10 closures stored in the array
funcs[0].type_of() == "Fn"; // make sure these are closures
for f in funcs {
f.call(); // all references to 'i' are the same variable!
}
```
Therefore &ndash; Be Careful to Prevent Data Races
-------------------------------------------------
Rust does not have data races, but that doesn't mean Rhai doesn't.
Avoid performing a method call on a captured shared variable (which essentially takes a
mutable reference to the shared object) while using that same variable as a parameter
in the method call &ndash; this is a sure-fire way to generate a data race error.
If a shared value is used as the `this` pointer in a method call to a closure function,
then the same shared value _must not_ be captured inside that function, or a data race
will occur and the script will terminate with an error.
```rust
let x = 20;
x.is_shared() == false; // 'x' is not shared, so no data race is possible
let f = |a| this += x + a; // 'x' is captured in this closure
x.is_shared() == true; // now 'x' is shared
x.call(f, 2); // <- error: data race detected on 'x'
```
Data Races in `sync` Builds Can Become Deadlocks
-----------------------------------------------
Under the [`sync`] feature, shared values are guarded with a `RwLock`, meaning that data race
conditions no longer raise an error.
Instead, they wait endlessly for the `RwLock` to be freed, and thus can become deadlocks.
On the other hand, since the same thread (i.e. the [`Engine`] thread) that is holding the lock
is attempting to read it again, this may also [panic](https://doc.rust-lang.org/std/sync/struct.RwLock.html#panics-1)
depending on the O/S.
```rust
let x = 20;
let f = |a| this += x + a; // 'x' is captured in this closure
// Under `sync`, the following may wait forever, or may panic,
// because 'x' is locked as the `this` pointer but also accessed
// via a captured shared value.
x.call(f, 2);
```
TL;DR
-----
### Q: How is it actually implemented?
The actual implementation of closures de-sugars to:
1. Keeping track of what variables are accessed inside the anonymous function,
2. If a variable is not defined within the anonymous function's scope, it is looked up _outside_ the function and
in the current execution scope &ndash; where the anonymous function is created.
3. The variable is added to the parameters list of the anonymous function, at the front.
4. The variable is then converted into a **reference-counted shared value**.
An [anonymous function] which captures an external variable is the only way to create a reference-counted shared value in Rhai.
5. The shared value is then [curried][currying] into the [function pointer] itself, essentially carrying a reference to that shared value
and inserting it into future calls of the function.
This process is called _Automatic Currying_, and is the mechanism through which Rhai simulates normal closures.
### Q: Why are closures implemented as automatic currying?
In concept, a closure _closes_ over captured variables from the outer scope &ndash; that's why
they are called _closures_. When this happen, a typical language implementation hoists
those variables that are captured away from the stack frame and into heap-allocated storage.
This is because those variables may be needed after the stack frame goes away.
These heap-allocated captured variables only go away when all the closures that need them
are finished with them. A garbage collector makes this trivial to implement &ndash; they are
automatically collected as soon as all closures needing them are destroyed.
In Rust, this can be done by reference counting instead, with the potential pitfall of creating
reference loops that will prevent those variables from being deallocated forever.
Rhai avoids this by clone-copying most data values, so reference loops are hard to create.
Rhai does the hoisting of captured variables into the heap by converting those values
into reference-counted locked values, also allocated on the heap. The process is identical.
Closures are usually implemented as a data structure containing two items:
1) A function pointer to the function body of the closure,
2) A data structure containing references to the captured shared variables on the heap.
Usually a language implementation passes the structure containing references to captured
shared variables into the function pointer, the function body taking this data structure
as an additional parameter.
This is essentially what Rhai does, except that Rhai passes each variable individually
as separate parameters to the function, instead of creating a structure and passing that
structure as a single parameter. This is the only difference.
Therefore, in most languages, essentially all closures are implemented as automatic currying of
shared variables hoisted into the heap, automatically passing those variables as parameters into
the function. Rhai just brings this directly up to the front.

View File

@ -1,39 +0,0 @@
Function Pointer Currying
========================
{{#include ../links.md}}
It is possible to _curry_ a [function pointer] by providing partial (or all) arguments.
Currying is done via the `curry` keyword and produces a new [function pointer] which carries
the curried arguments.
When the curried [function pointer] is called, the curried arguments are inserted starting from the left.
The actual call arguments should be reduced by the number of curried arguments.
```rust
fn mul(x, y) { // function with two parameters
x * y
}
let func = Fn("mul");
func.call(21, 2) == 42; // two arguments are required for 'mul'
let curried = func.curry(21); // currying produces a new function pointer which
// carries 21 as the first argument
let curried = curry(func, 21); // function-call style also works
curried.call(2) == 42; // <- de-sugars to 'func.call(21, 2)'
// only one argument is now required
```
Automatic Currying
------------------
[Anonymous functions] defined via a closure syntax _capture_ external variables
that are not shadowed inside the function's scope.
This is accomplished via [automatic currying].

View File

@ -1,119 +0,0 @@
Function Namespaces
==================
{{#include ../links.md}}
Each Function is a Separate Compilation Unit
-------------------------------------------
[Functions] in Rhai are _pure_ and they form individual _compilation units_.
This means that individual functions can be separated, exported, re-grouped, imported,
and generally mix-'n-match-ed with other completely unrelated scripts.
For example, the `AST::merge` and `AST::combine` methods (or the equivalent `+` and `+=` operators)
allow combining all functions in one [`AST`] into another, forming a new, unified, group of functions.
In general, there are two types of _namespaces_ where functions are looked up:
| Namespace | How Many | Source | Lookup | Sub-modules? | Variables? |
| --------- | :------: | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------ | :----------: | :--------: |
| Global | One | 1) [`AST`] being evaluated<br/>2) `Engine::register_XXX` API<br/>3) global [modules] registered via `Engine::register_global_module`<br/>4) functions in static [modules] registered via `Engine::register_static_module` and marked _global_ | simple name | ignored | ignored |
| Module | Many | 1) [Module] registered via `Engine::register_static_module`<br/>2) [Module] loaded via [`import`] statement | namespace-qualified name | yes | yes |
Module Namespaces
-----------------
There can be multiple module namespaces at any time during a script evaluation, usually loaded via the
[`import`] statement.
_Static_ module namespaces can also be registered into an [`Engine`] via `Engine::register_static_module`.
Functions and variables in module namespaces are isolated and encapsulated within their own environments.
They must be called or accessed in a _namespace-qualified_ manner.
```rust
import "my_module" as m; // new module namespace 'm' created via 'import'
let x = m::calc_result(); // namespace-qualified function call
let y = m::MY_NUMBER; // namespace-qualified variable (constant) access
let x = calc_result(); // <- error: function 'calc_result' not found
// in global namespace!
```
Global Namespace
----------------
There is one _global_ namespace for every [`Engine`], which includes (in the following search order):
* All functions defined in the [`AST`] currently being evaluated.
* All native Rust functions and iterators registered via the `Engine::register_XXX` API.
* All functions and iterators defined in global [modules] that are registered into the [`Engine`] via
`Engine::register_global_module`.
* Functions defined in [modules] registered via `Engine::register_static_module` that are specifically
marked for exposure to the global namespace (e.g. via the `#[rhai(global)]` attribute in a [plugin module]).
Anywhere in a Rhai script, when a function call is made, the function is searched within the
global namespace, in the above search order.
Therefore, function calls in Rhai are _late_ bound &ndash; meaning that the function called cannot be
determined or guaranteed and there is no way to _lock down_ the function being called.
This aspect is very similar to JavaScript before ES6 modules.
```rust
// Compile a script into AST
let ast1 = engine.compile(
r#"
fn get_message() {
"Hello!" // greeting message
}
fn say_hello() {
print(get_message()); // prints message
}
say_hello();
"#
)?;
// Compile another script with an overriding function
let ast2 = engine.compile(r#"fn get_message() { "Boo!" }"#)?;
// Combine the two AST's
ast1 += ast2; // 'message' will be overwritten
engine.consume_ast(&ast1)?; // prints 'Boo!'
```
Therefore, care must be taken when _cross-calling_ functions to make sure that the correct
functions are called.
The only practical way to ensure that a function is a correct one is to use [modules] -
i.e. define the function in a separate module and then [`import`] it:
```rust
----------------
| message.rhai |
----------------
fn get_message() { "Hello!" }
---------------
| script.rhai |
---------------
import "message" as msg;
fn say_hello() {
print(msg::get_message());
}
say_hello();
```

View File

@ -1,271 +0,0 @@
Function Pointers
=================
{{#include ../links.md}}
It is possible to store a _function pointer_ in a variable just like a normal value.
In fact, internally a function pointer simply stores the _name_ of the function as a string.
A function pointer is created via the `Fn` function, which takes a [string] parameter.
Call a function pointer using the `call` method.
Built-in methods
----------------
The following standard methods (mostly defined in the [`BasicFnPackage`][packages] but excluded if
using a [raw `Engine`]) operate on function pointers:
| Function | Parameter(s) | Description |
| ---------------------------------- | ------------ | ------------------------------------------------------------------------------------------------ |
| `name` method and property | _none_ | returns the name of the function encapsulated by the function pointer |
| `is_anonymous` method and property | _none_ | does the function pointer refer to an [anonymous function]? Not available under [`no_function`]. |
| `call` | _arguments_ | calls the function matching the function pointer's name with the _arguments_ |
Examples
--------
```rust
fn foo(x) { 41 + x }
let func = Fn("foo"); // use the 'Fn' function to create a function pointer
print(func); // prints 'Fn(foo)'
let func = fn_name.Fn(); // <- error: 'Fn' cannot be called in method-call style
func.type_of() == "Fn"; // type_of() as function pointer is 'Fn'
func.name == "foo";
func.call(1) == 42; // call a function pointer with the 'call' method
foo(1) == 42; // <- the above de-sugars to this
call(func, 1); // normal function call style also works for 'call'
let len = Fn("len"); // 'Fn' also works with registered native Rust functions
len.call("hello") == 5;
let add = Fn("+"); // 'Fn' works with built-in operators also
add.call(40, 2) == 42;
let fn_name = "hello"; // the function name does not have to exist yet
let hello = Fn(fn_name + "_world");
hello.call(0); // error: function not found - 'hello_world (i64)'
```
Global Namespace Only
--------------------
Because of their dynamic nature, function pointers cannot refer to functions in [`import`]-ed [modules].
They can only refer to functions within the global [namespace][function namespace].
See _[Function Namespaces]_ for more details.
```rust
import "foo" as f; // assume there is 'f::do_work()'
f::do_work(); // works!
let p = Fn("f::do_work"); // error: invalid function name
fn do_work_now() { // call it from a local function
f::do_work();
}
let p = Fn("do_work_now");
p.call(); // works!
```
Dynamic Dispatch
----------------
The purpose of function pointers is to enable rudimentary _dynamic dispatch_, meaning to determine,
at runtime, which function to call among a group.
Although it is possible to simulate dynamic dispatch via a number and a large `if-then-else-if` statement,
using function pointers significantly simplifies the code.
```rust
let x = some_calculation();
// These are the functions to call depending on the value of 'x'
fn method1(x) { ... }
fn method2(x) { ... }
fn method3(x) { ... }
// Traditional - using decision variable
let func = sign(x);
// Dispatch with if-statement
if func == -1 {
method1(42);
} else if func == 0 {
method2(42);
} else if func == 1 {
method3(42);
}
// Using pure function pointer
let func = if x < 0 {
Fn("method1")
} else if x == 0 {
Fn("method2")
} else if x > 0 {
Fn("method3")
}
// Dynamic dispatch
func.call(42);
// Using functions map
let map = [ Fn("method1"), Fn("method2"), Fn("method3") ];
let func = sign(x) + 1;
// Dynamic dispatch
map[func].call(42);
```
Bind the `this` Pointer
----------------------
When `call` is called as a _method_ but not on a function pointer, it is possible to dynamically dispatch
to a function call while binding the object in the method call to the `this` pointer of the function.
To achieve this, pass the function pointer as the _first_ argument to `call`:
```rust
fn add(x) { // define function which uses 'this'
this += x;
}
let func = Fn("add"); // function pointer to 'add'
func.call(1); // error: 'this' pointer is not bound
let x = 41;
func.call(x, 1); // error: function 'add (i64, i64)' not found
call(func, x, 1); // error: function 'add (i64, i64)' not found
x.call(func, 1); // 'this' is bound to 'x', dispatched to 'func'
x == 42;
```
Beware that this only works for _method-call_ style. Normal function-call style cannot bind
the `this` pointer (for syntactic reasons).
Therefore, obviously, binding the `this` pointer is unsupported under [`no_object`].
Call a Function Pointer in Rust
------------------------------
It is completely normal to register a Rust function with an [`Engine`] that takes parameters
whose types are function pointers. The Rust type in question is `rhai::FnPtr`.
A function pointer in Rhai is essentially syntactic sugar wrapping the _name_ of a function
to call in script. Therefore, the script's [`AST`] is required to call a function pointer,
as well as the entire _execution context_ that the script is running in.
For a rust function taking a function pointer as parameter, the [Low-Level API](../rust/register-raw.md)
must be used to register the function.
Essentially, use the low-level `Engine::register_raw_fn` method to register the function.
`FnPtr::call_dynamic` is used to actually call the function pointer, passing to it the
current _native call context_, the `this` pointer, and other necessary arguments.
```rust
use rhai::{Engine, Module, Dynamic, FnPtr, NativeCallContext};
let mut engine = Engine::new();
// Define Rust function in required low-level API signature
fn call_fn_ptr_with_value(context: NativeCallContext, args: &mut [&mut Dynamic])
-> Result<Dynamic, Box<EvalAltResult>>
{
// 'args' is guaranteed to contain enough arguments of the correct types
let fp = std::mem::take(args[1]).cast::<FnPtr>(); // 2nd argument - function pointer
let value = args[2].clone(); // 3rd argument - function argument
let this_ptr = args.get_mut(0).unwrap(); // 1st argument - this pointer
// Use 'FnPtr::call_dynamic' to call the function pointer.
// Beware, private script-defined functions will not be found.
fp.call_dynamic(context, Some(this_ptr), [value])
}
// Register a Rust function using the low-level API
engine.register_raw_fn("super_call",
&[ // parameter types
std::any::TypeId::of::<i64>(),
std::any::TypeId::of::<FnPtr>(),
std::any::TypeId::of::<i64>()
],
call_fn_ptr_with_value
);
```
`NativeCallContext`
------------------
`FnPtr::call_dynamic` takes a parameter of type `NativeCallContext` which holds the _native call context_
of the particular call to a registered Rust function. It is a type that exposes the following:
| Field | Type | Description |
| ------------------- | :-------------------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `engine()` | `&Engine` | the current [`Engine`], with all configurations and settings.<br/>This is sometimes useful for calling a script-defined function within the same evaluation context using [`Engine::call_fn`][`call_fn`], or calling a [function pointer]. |
| `source()` | `Option<&str>` | reference to the current source, if any |
| `iter_imports()` | `impl Iterator<Item = (&str, &Module)>` | iterator of the current stack of [modules] imported via `import` statements |
| `imports()` | `&Imports` | reference to the current stack of [modules] imported via `import` statements; requires the [`internals`] feature |
| `iter_namespaces()` | `impl Iterator<Item = &Module>` | iterator of the namespaces (as [modules]) containing all script-defined functions |
| `namespaces()` | `&[&Module]` | reference to the namespaces (as [modules]) containing all script-defined functions; requires the [`internals`] feature |
This type is normally provided by the [`Engine`] (e.g. when using [`Engine::register_fn_raw`](../rust/register-raw.md)).
However, it may also be manually constructed from a tuple:
```rust
use rhai::{Engine, FnPtr, NativeCallContext};
let engine = Engine::new();
// Compile script to AST
let mut ast = engine.compile(
r#"
let test = "hello";
|x| test + x // this creates an closure
"#,
)?;
// Save the closure together with captured variables
let fn_ptr = engine.eval_ast::<FnPtr>(&ast)?;
// Get rid of the script, retaining only functions
ast.retain_functions(|_, _, _| true);
// Create function namespace from the 'AST'
let lib = [ast.as_ref()];
// Create native call context
let context = NativeCallContext::new(&engine, &lib);
// 'f' captures: the engine, the AST, and the closure
let f = move |x: i64| fn_ptr.call_dynamic(context, None, [x.into()]);
// 'f' can be called like a normal function
let result = f(42)?;
```

View File

@ -1,103 +0,0 @@
`for` Loop
==========
{{#include ../links.md}}
Iterating through a range or an [array], or any type with a registered [type iterator],
is provided by the `for` ... `in` loop.
Like C, `continue` can be used to skip to the next iteration, by-passing all following statements;
`break` can be used to break out of the loop unconditionally.
To loop through a number sequence (with or without steps), use the `range` function to
return a numeric iterator.
Iterate Through Strings
-----------------------
Iterating through a [string] yields characters.
```rust
let s = "hello, world!";
for ch in s {
if ch > 'z' { continue; } // skip to the next iteration
print(ch);
if x == '@' { break; } // break out of for loop
}
```
Iterate Through Arrays
----------------------
Iterating through an [array] yields cloned _copies_ of each element.
```rust
let array = [1, 3, 5, 7, 9, 42];
for x in array {
if x > 10 { continue; } // skip to the next iteration
print(x);
if x == 42 { break; } // break out of for loop
}
```
Iterate Through Numeric Ranges
-----------------------------
The `range` function allows iterating through a range of numbers
(not including the last number).
```rust
// Iterate starting from 0 and stopping at 49.
for x in range(0, 50) {
if x > 10 { continue; } // skip to the next iteration
print(x);
if x == 42 { break; } // break out of for loop
}
// The 'range' function also takes a step.
for x in range(0, 50, 3) { // step by 3
if x > 10 { continue; } // skip to the next iteration
print(x);
if x == 42 { break; } // break out of for loop
}
```
Iterate Through Object Maps
--------------------------
Two methods, `keys` and `values`, return [arrays] containing cloned _copies_
of all property names and values of an [object map], respectively.
These [arrays] can be iterated.
```rust
let map = #{a:1, b:3, c:5, d:7, e:9};
// Property names are returned in unsorted, random order
for x in map.keys() {
if x > 10 { continue; } // skip to the next iteration
print(x);
if x == 42 { break; } // break out of for loop
}
// Property values are returned in unsorted, random order
for val in map.values() {
print(val);
}
```

View File

@ -1,190 +0,0 @@
Functions
=========
{{#include ../links.md}}
Rhai supports defining functions in script (unless disabled with [`no_function`]):
```rust
fn add(x, y) {
return x + y;
}
fn sub(x, y,) { // trailing comma in parameters list is OK
return x - y;
}
add(2, 3) == 5;
sub(2, 3,) == -1; // trailing comma in arguments list is OK
```
Implicit Return
---------------
Just like in Rust, an implicit return can be used. In fact, the last statement of a block is _always_ the block's return value
regardless of whether it is terminated with a semicolon `';'`. This is different from Rust.
```rust
fn add(x, y) { // implicit return:
x + y; // value of the last statement (no need for ending semicolon)
// is used as the return value
}
fn add2(x) {
return x + 2; // explicit return
}
add(2, 3) == 5;
add2(42) == 44;
```
Global Definitions Only
----------------------
Functions can only be defined at the global level, never inside a block or another function.
```rust
// Global level is OK
fn add(x, y) {
x + y
}
// The following will not compile
fn do_addition(x) {
fn add_y(n) { // <- syntax error: functions cannot be defined inside another function
n + y
}
add_y(x)
}
```
No Access to External Scope
--------------------------
Functions are not _closures_. They do not capture the calling environment
and can only access their own parameters.
They cannot access variables external to the function itself.
```rust
let x = 42;
fn foo() { x } // <- syntax error: variable 'x' doesn't exist
```
But Can Call Other Functions
---------------------------
All functions in the same [`AST`] can call each other.
```rust
fn foo(x) { x + 1 } // function defined in the global namespace
fn bar(x) { foo(x) } // OK! function 'foo' can be called
```
Use Before Definition Allowed
----------------------------
Unlike C/C++, functions in Rhai can be defined _anywhere_ at global level.
A function does not need to be defined prior to being used in a script;
a statement in the script can freely call a function defined afterwards.
This is similar to Rust and many other modern languages, such as JavaScript's `function` keyword.
Arguments are Passed by Value
----------------------------
Functions defined in script always take [`Dynamic`] parameters (i.e. they can be of any types).
Therefore, functions with the same name and same _number_ of parameters are equivalent.
All arguments are passed by _value_, so all Rhai script-defined functions are _pure_
(i.e. they never modify their arguments).
Any update to an argument will **not** be reflected back to the caller.
```rust
fn change(s) { // 's' is passed by value
s = 42; // only a COPY of 's' is changed
}
let x = 500;
change(x);
x == 500; // 'x' is NOT changed!
```
`this` &ndash; Simulating an Object Method
-----------------------------------------
Script-defined functions can also be called in method-call style.
When this happens, the keyword '`this`' binds to the object in the method call and can be changed.
```rust
fn change() { // not that the object does not need a parameter
this = 42; // 'this' binds to the object in method-call
}
let x = 500;
x.change(); // call 'change' in method-call style, 'this' binds to 'x'
x == 42; // 'x' is changed!
change(); // <- error: `this` is unbound
```
`is_def_fn`
-----------
Use `is_def_fn` to detect if a Rhai function is defined (and therefore callable),
based on its name and the number of parameters.
```rust
fn foo(x) { x + 1 }
is_def_fn("foo", 1) == true;
is_def_fn("foo", 0) == false;
is_def_fn("foo", 2) == false;
is_def_fn("bar", 1) == false;
```
Metadata
--------
The function `get_fn_metadata_list` is a _reflection_ API that returns an array of the metadata
of all script-defined functions in scope.
Functions from the following sources are returned, in order:
1) Encapsulated script environment (e.g. when loading a [module] from a script file),
2) Current script,
3) [Modules] imported via the [`import`] statement (latest imports first),
4) [Modules] added via [`Engine::register_static_module`]({{rootUrl}}/rust/modules/create.md) (latest registrations first)
The return value is an [array] of [object maps] (so `get_fn_metadata_list` is not available under
[`no_index`] or [`no_object`]), containing the following fields:
| Field | Type | Optional? | Description |
| -------------- | :------------------: | :-------: | ---------------------------------------------------------------------- |
| `namespace` | [string] | yes | the module _namespace_ if the function is defined within a module |
| `access` | [string] | no | `"public"` if the function is public,<br/>`"private"` if it is private |
| `name` | [string] | no | function name |
| `params` | [array] of [strings] | no | parameter names |
| `is_anonymous` | `bool` | no | is this function an anonymous function? |

View File

@ -1,51 +0,0 @@
`if` Statement
==============
{{#include ../links.md}}
`if` statements follow C syntax:
```rust
if foo(x) {
print("It's true!");
} else if bar == baz {
print("It's true again!");
} else if baz.is_foo() {
print("Yet again true.");
} else if foo(bar - baz) {
print("True again... this is getting boring.");
} else {
print("It's finally false!");
}
```
Braces Are Mandatory
--------------------
Unlike C, the condition expression does _not_ need to be enclosed in parentheses '`(`' .. '`)`', but
all branches of the `if` statement must be enclosed within braces '`{`' .. '`}`',
even when there is only one statement inside the branch.
Like Rust, there is no ambiguity regarding which `if` clause a branch belongs to.
```rust
// Rhai is not C!
if (decision) print("I've decided!");
// ^ syntax error, expecting '{' in statement block
```
`if`-Expressions
---------------
Like Rust, `if` statements can also be used as _expressions_, replacing the `? :` conditional operators
in other C-like languages.
```rust
// The following is equivalent to C: int x = 1 + (decision ? 42 : 123) / 2;
let x = 1 + if decision { 42 } else { 123 } / 2;
x == 22;
let x = if decision { 42 }; // no else branch defaults to '()'
x == ();
```

View File

@ -1,7 +0,0 @@
Rhai Language Reference
======================
{{#include ../links.md}}
This section outlines the Rhai language.

View File

@ -1,45 +0,0 @@
Iterators for Custom Types
==========================
{{#include ../links.md}}
If a [custom type] is iterable, the [`for`](for.md) loop can be used to iterate through
its items in sequence.
In order to use a [`for`](for.md) statement, a _type iterator_ must be registered for
the [custom type] in question.
`Engine::register_iterator<T>` allows registration of a _type iterator_ for any type
that implements `IntoIterator`:
```rust
// Custom type
#[derive(Debug, Clone)]
struct TestStruct { ... }
// Implement 'IntoIterator' trait
impl IntoIterator<Item = ...> for TestStruct {
type Item = ...;
type IntoIter = SomeIterType<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
...
}
}
engine
.register_type_with_name::<TestStruct>("TestStruct")
.register_fn("new_ts", || TestStruct { ... })
.register_iterator::<TestStruct>(); // register type iterator
```
With a type iterator registered, the [custom type] can be iterated through:
```rust
let ts = new_ts();
// Use 'for' statement to loop through items in 'ts'
for item in ts {
...
}
```

View File

@ -1,95 +0,0 @@
Parse an Object Map from JSON
============================
{{#include ../links.md}}
The syntax for an [object map] is extremely similar to the JSON representation of a object hash,
with the exception of `null` values which can technically be mapped to [`()`].
A valid JSON string does not start with a hash character `#` while a Rhai [object map] does &ndash; that's the major difference!
Use the `Engine::parse_json` method to parse a piece of JSON into an object map.
The JSON text must represent a single object hash (i.e. must be wrapped within "`{ .. }`")
otherwise it returns a syntax error.
```rust
// JSON string - notice that JSON property names are always quoted
// notice also that comments are acceptable within the JSON string
let json = r#"{
"a": 1, // <- this is an integer number
"b": true,
"c": 123.0, // <- this is a floating-point number
"$d e f!": "hello", // <- any text can be a property name
"^^^!!!": [1,42,"999"], // <- value can be array or another hash
"z": null // <- JSON 'null' value
}
"#;
// Parse the JSON expression as an object map
// Set the second boolean parameter to true in order to map 'null' to '()'
let map = engine.parse_json(json, true)?;
map.len() == 6; // 'map' contains all properties in the JSON string
// Put the object map into a 'Scope'
let mut scope = Scope::new();
scope.push("map", map);
let result = engine.eval_with_scope::<INT>(r#"map["^^^!!!"].len()"#)?;
result == 3; // the object map is successfully used in the script
```
Representation of Numbers
------------------------
JSON numbers are all floating-point while Rhai supports integers (`INT`) and floating-point (`FLOAT`) if
the [`no_float`] feature is not used.
Most common generators of JSON data distinguish between integer and floating-point values by always
serializing a floating-point number with a decimal point (i.e. `123.0` instead of `123` which is
assumed to be an integer).
This style can be used successfully with Rhai [object maps].
Parse JSON with Sub-Objects
--------------------------
`Engine::parse_json` depends on the fact that the [object map] literal syntax in Rhai is _almost_
the same as a JSON object. However, it is _almost_ because the syntax for a sub-object in JSON
(i.e. "`{ ... }`") is different from a Rhai [object map] literal (i.e. "`#{ ... }`").
When `Engine::parse_json` encounters JSON with sub-objects, it fails with a syntax error.
If it is certain that no text string in the JSON will ever contain the character '`{`',
then it is possible to parse it by first replacing all occupance of '`{`' with "`#{`".
A JSON object hash starting with `#{` is handled transparently by `Engine::parse_json`.
```rust
// JSON with sub-object 'b'.
let json = r#"{"a":1, "b":{"x":true, "y":false}}"#;
// Our JSON text does not contain the '{' character, so off we go!
let new_json = json.replace("{", "#{");
// The leading '{' will also be replaced to '#{', but 'parse_json' handles this just fine.
let map = engine.parse_json(&new_json, false)?;
map.len() == 2; // 'map' contains two properties: 'a' and 'b'
```
Use `serde` to Serialize/Deserialize to/from JSON
------------------------------------------------
Remember, `Engine::parse_json` is nothing more than a _cheap_ alternative to true JSON parsing.
If correctness is needed, or for more configuration possibilities, turn on the [`serde`][features]
feature to pull in the [`serde`](https://crates.io/crates/serde) crate which enables
serialization and deserialization to/from multiple formats, including JSON.
Beware, though... the [`serde`](https://crates.io/crates/serde) crate is quite heavy.
See _[Serialization/Deserialization of `Dynamic` with `serde`][`serde`]_ for more details.

View File

@ -1,26 +0,0 @@
Keywords
========
{{#include ../links.md}}
The following are reserved keywords in Rhai:
| Active keywords | Reserved keywords | Usage | Inactive under feature |
| ---------------------------------------------------------------- | ---------------------------------------------------------- | ---------------------- | :--------------------: |
| `true`, `false` | | constants | |
| `let`, `const` | `var`, `static` | variables | |
| | `begin`, `end` | block scopes | |
| `is_shared` | | shared values | [`no_closure`] |
| `if`, `else` | `then`, `unless`, `goto`, `exit` | control flow | |
| `switch` | `match`, `case` | switching and matching | |
| `do`, `while`, `loop`, `until`, `for`, `in`, `continue`, `break` | `each` | looping | |
| `fn`, `private` | `public`, `new` | functions | [`no_function`] |
| `return` | | return values | |
| `throw`, `try`, `catch` | | throw/catch exceptions | |
| `import`, `export`, `as` | `use`, `with`, `module`, `package` | modules/packages | [`no_module`] |
| `Fn`, `call`, `curry` | | function pointers | |
| | `spawn`, `thread`, `go`, `sync`, `async`, `await`, `yield` | threading/async | |
| `type_of`, `print`, `debug`, `eval` | | special functions | |
| | `default`, `void`, `null`, `nil` | special values | |
Keywords cannot become the name of a [function] or [variable], even when they are disabled.

Some files were not shown because too many files have changed in this diff Show More