Refine docs.
This commit is contained in:
parent
b08f85a8b1
commit
a9b168ba99
@ -21,7 +21,7 @@ Supported targets and builds
|
||||
Features
|
||||
--------
|
||||
|
||||
* Easy-to-use language similar to JS+Rust with dynamic typing.
|
||||
* Easy-to-use language similar to JavaScript+Rust with dynamic typing.
|
||||
* 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).
|
||||
* Easily [call a script-defined function](https://schungx.github.io/rhai/engine/call-fn.html) from Rust.
|
||||
|
@ -6,7 +6,7 @@ Features
|
||||
Easy
|
||||
----
|
||||
|
||||
* Easy-to-use language similar to JS+Rust with dynamic typing.
|
||||
* Easy-to-use language similar to JavaScript+Rust with dynamic typing.
|
||||
|
||||
* Tight integration with native Rust [functions]({{rootUrl}}/rust/functions.md) and [types]({{rootUrl}}/rust/custom.md), including [getters/setters]({{rootUrl}}/rust/getters-setters.md), [methods]({{rootUrl}}/rust/custom.md) and [indexers]({{rootUrl}}/rust/indexers.md).
|
||||
|
||||
|
@ -26,7 +26,7 @@ Due to this intended usage, Rhai deliberately keeps the language simple and smal
|
||||
such as classes, inheritance, first-class functions, closures, concurrency, byte-codes, JIT etc.
|
||||
|
||||
Avoid the temptation to write full-fledge program logic entirely in Rhai - that use case is best fulfilled by
|
||||
more complete languages such as JS or Lua.
|
||||
more complete languages such as JavaScript or Lua.
|
||||
|
||||
Therefore, in actual practice, it is usually best to expose a Rust API into Rhai for scripts to call.
|
||||
All your core functionalities should be in Rust.
|
||||
|
@ -4,8 +4,8 @@ Literals Syntax
|
||||
{{#include ../links.md}}
|
||||
|
||||
| Type | Literal syntax |
|
||||
| :--------------------------------: | :---------------------------------------: |
|
||||
| `INT` | `42`, `-123`, `0` |
|
||||
| :--------------------------------: | :------------------------------------------------------------------------------: |
|
||||
| `INT` | `42`, `-123`, `0`,<br/>`0x????..` (hex), `0b????..` (binary), `0o????..` (octal) |
|
||||
| `FLOAT` | `42.0`, `-123.456`, `0.0` |
|
||||
| [String] | `"... \x?? \u???? \U???????? ..."` |
|
||||
| Character | `"... \x?? \u???? \U???????? ..."` |
|
||||
|
@ -4,7 +4,7 @@ Operators
|
||||
{{#include ../links.md}}
|
||||
|
||||
| Operator | Description | Binary? |
|
||||
| :---------------: | ---------------------------- | :-----: |
|
||||
| :---------------: | ------------------------------ | :-----: |
|
||||
| `+` | Add | Yes |
|
||||
| `-` | Subtract, Minus | Yes/No |
|
||||
| `*` | Multiply | Yes |
|
||||
@ -13,9 +13,9 @@ Operators
|
||||
| `~` | Power | Yes |
|
||||
| `>>` | Right bit-shift | Yes |
|
||||
| `<<` | Left bit-shift | Yes |
|
||||
| `&` | Bit-wise AND, Boolean AND | Yes |
|
||||
| <code>\|</code> | Bit-wise OR, Boolean OR | Yes |
|
||||
| `^` | Bit-wise XOR | Yes |
|
||||
| `&` | Bit-wise _And_, Boolean _And_ | Yes |
|
||||
| <code>\|</code> | Bit-wise _Or_, Boolean _Or_ | Yes |
|
||||
| `^` | Bit-wise _Xor_ | Yes |
|
||||
| `==` | Equals to | Yes |
|
||||
| `~=` | Not equals to | Yes |
|
||||
| `>` | Greater than | Yes |
|
||||
@ -23,8 +23,8 @@ Operators
|
||||
| `<` | Less than | Yes |
|
||||
| `<=` | Less than or equals to | Yes |
|
||||
| `>=` | Greater than or equals to | Yes |
|
||||
| `&&` | Boolean AND (short-circuits) | Yes |
|
||||
| <code>\|\|</code> | Boolean OR (short-circuits) | Yes |
|
||||
| `~` | Boolean NOT | No |
|
||||
| `&&` | Boolean _And_ (short-circuits) | Yes |
|
||||
| <code>\|\|</code> | Boolean _Or_ (short-circuits) | Yes |
|
||||
| `!` | Boolean _Not_ | No |
|
||||
| `[` .. `]` | Indexing | Yes |
|
||||
| `.` | Property access, Method call | Yes |
|
||||
|
@ -38,6 +38,7 @@ The following methods (mostly defined in the [`BasicArrayPackage`]({{rootUrl}}/r
|
||||
| `clear` | _none_ | empties the array |
|
||||
| `truncate` | target length | cuts off the array at exactly a specified length (discarding all subsequent elements) |
|
||||
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
|
@ -17,7 +17,7 @@ let script = "let y = x;"; // build a script
|
||||
script += "y += foo(y);";
|
||||
script += "x + y";
|
||||
|
||||
let result = eval(script); // <- look, JS, we can also do this!
|
||||
let result = eval(script); // <- look, JavaScript, we can also do this!
|
||||
|
||||
print("Answer: " + result); // prints 42
|
||||
|
||||
|
@ -105,4 +105,4 @@ 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 JS's `function` keyword.
|
||||
This is similar to Rust and many other modern languages, such as JavaScript's `function` keyword.
|
||||
|
@ -43,7 +43,6 @@ impl ModuleResolver for MyModuleResolver {
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<EvalAltResult>> {
|
||||
let mut engine = Engine::new();
|
||||
|
||||
// Set the custom module resolver into the 'Engine'.
|
||||
@ -54,7 +53,4 @@ fn main() -> Result<(), Box<EvalAltResult>> {
|
||||
// 'MyModuleResolver::resolve' with "hello" as path
|
||||
foo:bar();
|
||||
"#)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
@ -23,16 +23,16 @@ Binary Operators
|
||||
----------------
|
||||
|
||||
| Operator | Description | Integers only |
|
||||
| -------- | ---------------------------------------------------- | :-----------: |
|
||||
| --------------- | ---------------------------------------------------- | :-----------: |
|
||||
| `+` | Plus | |
|
||||
| `-` | Minus | |
|
||||
| `*` | Multiply | |
|
||||
| `/` | Divide (integer division if acting on integer types) | |
|
||||
| `%` | Modulo (remainder) | |
|
||||
| `~` | Power | |
|
||||
| `&` | Binary _And_ bit-mask | Yes |
|
||||
| `|` | Binary _Or_ bit-mask | Yes |
|
||||
| `^` | Binary _Xor_ bit-mask | Yes |
|
||||
| `&` | Bit-wise _And_ | Yes |
|
||||
| <code>\|</code> | Bit-wise _Or_ | Yes |
|
||||
| `^` | Bit-wise _Xor_ | Yes |
|
||||
| `<<` | Left bit-shift | Yes |
|
||||
| `>>` | Right bit-shift | Yes |
|
||||
|
||||
|
@ -61,7 +61,7 @@ Examples
|
||||
let y = #{ // object map literal with 3 properties
|
||||
a: 1,
|
||||
bar: "hello",
|
||||
"baz!$@": 123.456, // like JS, you can use any string as property names...
|
||||
"baz!$@": 123.456, // like JavaScript, you can use any string as property names...
|
||||
"": false, // even the empty string!
|
||||
|
||||
a: 42 // <- syntax error: duplicated property name
|
||||
|
@ -14,7 +14,7 @@ The following primitive types are supported natively:
|
||||
| **Immutable Unicode string** | `rhai::ImmutableString` (implemented as `Rc<String>` or `Arc<String>`) | `"string"` | `"hello"` etc. |
|
||||
| **Array** (disabled with [`no_index`]) | `rhai::Array` | `"array"` | `"[ ?, ?, ? ]"` |
|
||||
| **Object map** (disabled with [`no_object`]) | `rhai::Map` | `"map"` | `#{ "a": 1, "b": 2 }` |
|
||||
| **Timestamp** (implemented in the [`BasicTimePackage`]({{rootUrl}}/rust/packages.md), disabled with [`no_std`]) | `std::time::Instant` ([instant::Instant](https://crates.io/crates/instant) if not [WASM] build) | `"timestamp"` | _not supported_ |
|
||||
| **Timestamp** (implemented in the [`BasicTimePackage`]({{rootUrl}}/rust/packages.md), disabled with [`no_std`]) | `std::time::Instant` ([`instant::Instant`](https://crates.io/crates/instant) if not [WASM] build) | `"timestamp"` | _not supported_ |
|
||||
| **Dynamic value** (i.e. can be anything) | `rhai::Dynamic` | _the actual type_ | _actual value_ |
|
||||
| **System integer** (current configuration) | `rhai::INT` (`i32` or `i64`) | `"i32"` or `"i64"` | `"42"`, `"123"` etc. |
|
||||
| **System floating-point** (current configuration, disabled with [`no_float`]) | `rhai::FLOAT` (`f32` or `f64`) | `"f32"` or `"f64"` | `"123.456"` etc. |
|
||||
|
@ -69,6 +69,7 @@
|
||||
[`Module`]: {{rootUrl}}/language/modules/index.md
|
||||
[module]: {{rootUrl}}/language/modules/index.md
|
||||
[modules]: {{rootUrl}}/language/modules/index.md
|
||||
[module resolver]: {{rootUrl}}/language/modules/imp-resolver.md
|
||||
[`export`]: {{rootUrl}}/language/modules/export.md
|
||||
[`import`]: {{rootUrl}}/language/modules/import.md
|
||||
|
||||
|
@ -1 +0,0 @@
|
||||
# Built-in Packages
|
@ -26,9 +26,7 @@ impl TestStruct {
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<EvalAltResult>>
|
||||
{
|
||||
let engine = Engine::new();
|
||||
let mut engine = Engine::new();
|
||||
|
||||
engine.register_type::<TestStruct>();
|
||||
|
||||
@ -38,9 +36,6 @@ fn main() -> Result<(), Box<EvalAltResult>>
|
||||
let result = engine.eval::<TestStruct>("let x = new_ts(); x.update(); x")?;
|
||||
|
||||
println!("result: {}", result.field); // prints 42
|
||||
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
Register a Custom Type
|
||||
@ -66,7 +61,7 @@ impl TestStruct {
|
||||
}
|
||||
}
|
||||
|
||||
let engine = Engine::new();
|
||||
let mut engine = Engine::new();
|
||||
|
||||
engine.register_type::<TestStruct>();
|
||||
```
|
||||
@ -102,8 +97,9 @@ println!("result: {}", result.field); // prints 42
|
||||
Method-Call Style vs. Function-Call Style
|
||||
----------------------------------------
|
||||
|
||||
In fact, any function with a first argument that is a `&mut` reference can be used as method calls because
|
||||
internally they are the same thing: methods on a type is implemented as a functions taking a `&mut` first argument.
|
||||
In fact, any function with a first argument that is a `&mut` reference can be used
|
||||
as method calls because internally they are the same thing: methods on a type is
|
||||
implemented as a functions taking a `&mut` first argument.
|
||||
|
||||
```rust
|
||||
fn foo(ts: &mut TestStruct) -> i64 {
|
||||
@ -119,8 +115,8 @@ let result = engine.eval::<i64>(
|
||||
println!("result: {}", result); // prints 1
|
||||
```
|
||||
|
||||
Under [`no_object`], however, the _method_ style of function calls (i.e. calling a function as an object-method)
|
||||
is no longer supported.
|
||||
Under [`no_object`], however, the _method_ style of function calls
|
||||
(i.e. calling a function as an object-method) is no longer supported.
|
||||
|
||||
```rust
|
||||
// Below is a syntax error under 'no_object' because 'clear' cannot be called in method style.
|
||||
|
@ -8,11 +8,6 @@ If a function is _fallible_ (i.e. it returns a `Result<_, Error>`), it can be re
|
||||
|
||||
The function must return `Result<Dynamic, Box<EvalAltResult>>`.
|
||||
|
||||
`Box<EvalAltResult>` implements `From<&str>` and `From<String>` etc.
|
||||
and the error text gets converted into `Box<EvalAltResult::ErrorRuntime>`.
|
||||
|
||||
The error values are `Box`-ed in order to reduce memory footprint of the error path, which should be hit rarely.
|
||||
|
||||
```rust
|
||||
use rhai::{Engine, EvalAltResult, Position};
|
||||
use rhai::RegisterResultFn; // use 'RegisterResultFn' trait for 'register_result_fn'
|
||||
@ -27,9 +22,7 @@ fn safe_divide(x: i64, y: i64) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
}
|
||||
}
|
||||
|
||||
fn main()
|
||||
{
|
||||
let engine = Engine::new();
|
||||
let mut engine = Engine::new();
|
||||
|
||||
// Fallible functions that return Result values must use register_result_fn()
|
||||
engine.register_result_fn("divide", safe_divide);
|
||||
@ -37,5 +30,12 @@ fn main()
|
||||
if let Err(error) = engine.eval::<i64>("divide(40, 0)") {
|
||||
println!("Error: {:?}", *error); // prints ErrorRuntime("Division by zero detected!", (1, 1)")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Create a `Box<EvalAltResult>`
|
||||
----------------------------
|
||||
|
||||
`Box<EvalAltResult>` implements `From<&str>` and `From<String>` etc.
|
||||
and the error text gets converted into `Box<EvalAltResult::ErrorRuntime>`.
|
||||
|
||||
The error values are `Box`-ed in order to reduce memory footprint of the error path, which should be hit rarely.
|
||||
|
@ -29,9 +29,7 @@ fn get_any_value() -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
Ok((42_i64).into()) // standard types can use 'into()'
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<EvalAltResult>>
|
||||
{
|
||||
let engine = Engine::new();
|
||||
let mut engine = Engine::new();
|
||||
|
||||
engine.register_fn("add", add_len);
|
||||
engine.register_fn("add_str", add_len_str);
|
||||
@ -50,9 +48,6 @@ fn main() -> Result<(), Box<EvalAltResult>>
|
||||
let result = engine.eval::<i64>("get_any_value()")?;
|
||||
|
||||
println!("Answer: {}", result); // prints 42
|
||||
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
To create a [`Dynamic`] value, use the `Dynamic::from` method.
|
||||
|
@ -17,14 +17,11 @@ fn show_it<T: Display>(x: &mut T) {
|
||||
println!("put up a good show: {}!", x)
|
||||
}
|
||||
|
||||
fn main()
|
||||
{
|
||||
let engine = Engine::new();
|
||||
let mut engine = Engine::new();
|
||||
|
||||
engine.register_fn("print", show_it::<i64>);
|
||||
engine.register_fn("print", show_it::<bool>);
|
||||
engine.register_fn("print", show_it::<ImmutableString>);
|
||||
}
|
||||
```
|
||||
|
||||
The above example shows how to register multiple functions
|
||||
|
@ -28,7 +28,7 @@ impl TestStruct {
|
||||
}
|
||||
}
|
||||
|
||||
let engine = Engine::new();
|
||||
let mut engine = Engine::new();
|
||||
|
||||
engine.register_type::<TestStruct>();
|
||||
|
||||
|
@ -9,6 +9,9 @@ A custom type with an indexer function defined can use the bracket '`[]`' notati
|
||||
|
||||
Indexers are disabled when the [`no_index`] feature is used.
|
||||
|
||||
For efficiency reasons, indexers **cannot** be used to overload (i.e. override) built-in indexing operations for
|
||||
[arrays] and [object maps].
|
||||
|
||||
```rust
|
||||
#[derive(Clone)]
|
||||
struct TestStruct {
|
||||
@ -28,7 +31,7 @@ impl TestStruct {
|
||||
}
|
||||
}
|
||||
|
||||
let engine = Engine::new();
|
||||
let mut engine = Engine::new();
|
||||
|
||||
engine.register_type::<TestStruct>();
|
||||
|
||||
@ -42,6 +45,3 @@ let result = engine.eval::<i64>("let a = new_ts(); a[2] = 42; a[2]")?;
|
||||
|
||||
println!("Answer: {}", result); // prints 42
|
||||
```
|
||||
|
||||
For efficiency reasons, indexers **cannot** be used to overload (i.e. override) built-in indexing operations for
|
||||
[arrays] and [object maps].
|
||||
|
@ -17,6 +17,10 @@ Similarly, comparison operators including `==`, `!=` etc. are all implemented as
|
||||
with the stark exception of `&&` and `||`. Because they [_short-circuit_]({{rootUrl}}/language/logic.md#boolean-operators),
|
||||
`&&` and `||` are handled specially and _not_ via a function; as a result, overriding them has no effect at all.
|
||||
|
||||
|
||||
Overload Operator via Rust Function
|
||||
----------------------------------
|
||||
|
||||
Operator functions cannot be defined as a script function (because operators syntax are not valid function names).
|
||||
|
||||
However, operator functions _can_ be registered to the [`Engine`] via the methods
|
||||
@ -48,6 +52,10 @@ engine.register_fn("+", mixed_add); // register '+' operator for
|
||||
let result: i64 = engine.eval("1 + 1.0"); // prints 2.0 (normally an error)
|
||||
```
|
||||
|
||||
|
||||
Considerations
|
||||
--------------
|
||||
|
||||
Normally, use operator overloading for [custom types] only.
|
||||
|
||||
Be very careful when overriding built-in operators because script authors expect standard operators to behave in a
|
||||
|
@ -3,8 +3,9 @@ Printing for Custom Types
|
||||
|
||||
{{#include ../links.md}}
|
||||
|
||||
To use custom types for [`print`] and [`debug`], or convert its value into a [string], it is necessary that the following
|
||||
functions be registered (assuming the custom type is `T : Display + Debug`):
|
||||
To use custom types for [`print`] and [`debug`], or convert its value into a [string],
|
||||
it is necessary that the following functions be registered (assuming the custom type
|
||||
is `T : Display + Debug`):
|
||||
|
||||
| Function | Signature | Typical implementation | Usage |
|
||||
| ----------- | ------------------------------------------------------------- | ------------------------------------- | --------------------------------------------------------------------------------------- |
|
||||
|
@ -20,8 +20,6 @@ then the same state is threaded through multiple invocations:
|
||||
```rust
|
||||
use rhai::{Engine, Scope, EvalAltResult};
|
||||
|
||||
fn main() -> Result<(), Box<EvalAltResult>>
|
||||
{
|
||||
let engine = Engine::new();
|
||||
|
||||
// First create the state
|
||||
@ -53,7 +51,4 @@ fn main() -> Result<(), Box<EvalAltResult>>
|
||||
// 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);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
@ -8,28 +8,28 @@ resources used by a script so that it does not consume more resources that it is
|
||||
|
||||
The most important resources to watch out for are:
|
||||
|
||||
* **Memory**: A malicous script may continuously grow a [string], an [array] or [object map] until all memory is consumed.
|
||||
* **Memory**: A malicious script may continuously grow a [string], an [array] or [object map] until all memory is consumed.
|
||||
|
||||
It may also create a large [array] or [object map] literal that exhausts all memory during parsing.
|
||||
|
||||
* **CPU**: A malicous script may run an infinite tight loop that consumes all CPU cycles.
|
||||
* **CPU**: A malicious script may run an infinite tight loop that consumes all CPU cycles.
|
||||
|
||||
* **Time**: A malicous script may run indefinitely, thereby blocking the calling system which is waiting for a result.
|
||||
* **Time**: A malicious script may run indefinitely, thereby blocking the calling system which is waiting for a result.
|
||||
|
||||
* **Stack**: A malicous script may attempt an infinite recursive call that exhausts the call stack.
|
||||
* **Stack**: A malicious script may attempt an infinite recursive call that exhausts the call stack.
|
||||
|
||||
Alternatively, it may create a degenerated deep expression with so many levels that the parser exhausts the call stack
|
||||
when parsing the expression; or even deeply-nested statement blocks, if nested deep enough.
|
||||
|
||||
Another way to cause a stack overflow is to load a [self-referencing module]({{rootUrl}}/language/modules/import.md).
|
||||
|
||||
* **Overflows**: A malicous script may deliberately cause numeric over-flows and/or under-flows, divide by zero, and/or
|
||||
* **Overflows**: A malicious script may deliberately cause numeric over-flows and/or under-flows, divide by zero, and/or
|
||||
create bad floating-point representations, in order to crash the system.
|
||||
|
||||
* **Files**: A malicous script may continuously [`import`] an external module within an infinite loop,
|
||||
* **Files**: A malicious script may continuously [`import`] an external module within an infinite loop,
|
||||
thereby putting heavy load on the file-system (or even the network if the file is not local).
|
||||
|
||||
Even when modules are not created from files, they still typically consume a lot of resources to load.
|
||||
|
||||
* **Data**: A malicous script may attempt to read from and/or write to data that it does not own. If this happens,
|
||||
* **Data**: A malicious script may attempt to read from and/or write to data that it does not own. If this happens,
|
||||
it is a severe security breach and may put the entire system at risk.
|
||||
|
@ -17,6 +17,16 @@ opt-level = "z" # optimize for size
|
||||
```
|
||||
|
||||
|
||||
Use `i32` Only
|
||||
--------------
|
||||
|
||||
For embedded systems that must optimize for code size, the architecture is commonly 32-bit.
|
||||
Use [`only_i32`] to prune away large sections of code implementing functions for other numeric types
|
||||
(including `i64`).
|
||||
|
||||
If, for some reason, 64-bit long integers must be supported, use [`only_i64`] instead of [`only_i32`].
|
||||
|
||||
|
||||
Opt-Out of Features
|
||||
------------------
|
||||
|
||||
@ -28,13 +38,17 @@ Omitting arrays ([`no_index`]) yields the most code-size savings, followed by fl
|
||||
([`no_float`]), checked arithmetic/script resource limits ([`unchecked`]) and finally object maps and custom types ([`no_object`]).
|
||||
|
||||
Where the usage scenario does not call for loading externally-defined modules, use [`no_module`] to save some bytes.
|
||||
Disable script-defined functions ([`no_function`]) only when the feature is not needed because code size savings is minimal.
|
||||
Disable script-defined functions ([`no_function`]) when the feature is not needed.
|
||||
Both of these have little code size savings.
|
||||
|
||||
|
||||
Use a Raw [`Engine`]
|
||||
-------------------
|
||||
|
||||
[`Engine::new_raw`](#raw-engine) creates a _raw_ engine.
|
||||
A _raw_ engine supports, out of the box, only a very [restricted set](#built-in-operators) of basic arithmetic and logical operators.
|
||||
A _raw_ engine supports, out of the box, only a very [restricted set]({{rootUrl}}/engine/raw.md#built-in-operators)
|
||||
of basic arithmetic and logical operators.
|
||||
|
||||
Selectively include other necessary functionalities by loading specific [packages] to minimize the footprint.
|
||||
|
||||
Packages are sharable (even across threads via the [`sync`] feature), so they only have to be created once.
|
||||
|
@ -7,14 +7,17 @@ Use Only One Integer Type
|
||||
------------------------
|
||||
|
||||
Some features are for performance. For example, using [`only_i32`] or [`only_i64`] disables all other integer types (such as `u16`).
|
||||
|
||||
If only a single integer type is needed in scripts - most of the time this is the case - it is best to avoid registering
|
||||
lots of functions related to other integer types that will never be used. As a result, performance should improve.
|
||||
lots of functions related to other integer types that will never be used. As a result, [`Engine`] creation will be faster
|
||||
because fewer functions need to be loaded.
|
||||
|
||||
|
||||
Use Only 32-Bit Numbers
|
||||
----------------------
|
||||
|
||||
If only 32-bit integers are needed - again, most of the time this is the case - using [`only_i32`] disables also `i64`.
|
||||
|
||||
On 64-bit targets this may not gain much, but on some 32-bit targets this improves performance due to 64-bit arithmetic
|
||||
requiring more CPU cycles to complete.
|
||||
|
||||
@ -24,4 +27,5 @@ Minimize Size of [`Dynamic`]
|
||||
|
||||
Turning on [`no_float`], and [`only_i32`] makes the key [`Dynamic`] data type only 8 bytes small on 32-bit targets
|
||||
while normally it can be up to 16 bytes (e.g. on x86/x64 CPU's) in order to hold an `i64` or `f64`.
|
||||
|
||||
Making [`Dynamic`] small helps performance due to better cache efficiency.
|
||||
|
@ -14,8 +14,40 @@ But anyhow, do it because you _can_!
|
||||
When building for WASM, certain features will not be available, such as the script file API's and loading modules
|
||||
from external script files.
|
||||
|
||||
Also look into [minimal builds] to reduce generated WASM size. As of this version, a typical, full-featured
|
||||
Rhai scripting engine compiles to a single WASM file less than 200KB gzipped. When excluding features that are
|
||||
marginal in WASM environment, the gzipped payload can be further shrunk to 160KB.
|
||||
|
||||
Size
|
||||
----
|
||||
|
||||
Also look into [minimal builds] to reduce generated WASM size.
|
||||
|
||||
As of this version, a typical, full-featured Rhai scripting engine compiles to a single WASM file
|
||||
less than 200KB gzipped.
|
||||
|
||||
When excluding features that are marginal in WASM environment, the gzipped payload can be
|
||||
further shrunk to 160KB.
|
||||
|
||||
|
||||
Speed
|
||||
-----
|
||||
|
||||
In benchmark tests, a WASM build runs scripts roughly 1.7-2.2x slower than a native optimized release build.
|
||||
|
||||
|
||||
Common Features
|
||||
---------------
|
||||
|
||||
Some Rhai functionalities are not necessary in a WASM environment, so the following features
|
||||
are typically used for a WASM build:
|
||||
|
||||
| Feature | Description |
|
||||
| :-----------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [`unchecked`] | When a WASM module panics, it doesn't crash the entire web app; however this also disables [maximum number of operations] and [progress] tracking so a script can still run indefinitely - the web app must terminate it itself. |
|
||||
| [`only_i32`] | JavaScript has only one `number` type and we're only supporting `wasm32` here (so far). |
|
||||
| [`no_module`] | A WASM module cannot load modules from the file system, so usually this is not needed, but the savings are minimal; alternatively, a custom [module resolver] can be provided that loads other Rhai scripts. |
|
||||
|
||||
The following features are typically _not_ used because they don't make sense in a WASM build:
|
||||
|
||||
| Feature | Why unnecessary |
|
||||
| :--------: | ------------------------------- |
|
||||
| [`sync`] | WASM is single-threaded. |
|
||||
| [`no_std`] | `std` lib works fine with WASM. |
|
||||
|
@ -6,16 +6,16 @@ Rust Examples
|
||||
A number of examples can be found in the `examples` folder:
|
||||
|
||||
| Example | Description |
|
||||
| ---------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- |
|
||||
| [`arrays_and_structs`](https://github.com/jonathandturner/rhai/tree/master/examples/arrays_and_structs.rs) | shows how to register a custom Rust type and using [arrays] on it |
|
||||
| [`custom_types_and_methods`](https://github.com/jonathandturner/rhai/tree/master/examples/custom_types_and_methods.rs) | shows how to register a custom Rust type and methods for it |
|
||||
| [`hello`](https://github.com/jonathandturner/rhai/tree/master/examples/hello.rs) | simple example that evaluates an expression and prints the result |
|
||||
| [`no_std`](https://github.com/jonathandturner/rhai/tree/master/examples/no_std.rs) | example to test out `no-std` builds |
|
||||
| [`reuse_scope`](https://github.com/jonathandturner/rhai/tree/master/examples/reuse_scope.rs) | evaluates two pieces of code in separate runs, but using a common [`Scope`] |
|
||||
| [`rhai_runner`](https://github.com/jonathandturner/rhai/tree/master/examples/rhai_runner.rs) | runs each filename passed to it as a Rhai script |
|
||||
| [`simple_fn`](https://github.com/jonathandturner/rhai/tree/master/examples/simple_fn.rs) | shows how to register a simple function |
|
||||
| [`strings`](https://github.com/jonathandturner/rhai/tree/master/examples/strings.rs) | shows different ways to register functions taking string arguments |
|
||||
| [`repl`](https://github.com/jonathandturner/rhai/tree/master/examples/repl.rs) | a simple REPL, interactively evaluate statements from stdin |
|
||||
| ---------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
|
||||
| [`arrays_and_structs`](https://github.com/jonathandturner/rhai/tree/master/examples/arrays_and_structs.rs) | Shows how to register a custom Rust type and using [arrays] on it. |
|
||||
| [`custom_types_and_methods`](https://github.com/jonathandturner/rhai/tree/master/examples/custom_types_and_methods.rs) | Shows how to register a custom Rust type and methods for it. |
|
||||
| [`hello`](https://github.com/jonathandturner/rhai/tree/master/examples/hello.rs) | Simple example that evaluates an expression and prints the result. |
|
||||
| [`no_std`](https://github.com/jonathandturner/rhai/tree/master/examples/no_std.rs) | Example to test out `no-std` builds. |
|
||||
| [`reuse_scope`](https://github.com/jonathandturner/rhai/tree/master/examples/reuse_scope.rs) | Evaluates two pieces of code in separate runs, but using a common [`Scope`]. |
|
||||
| [`rhai_runner`](https://github.com/jonathandturner/rhai/tree/master/examples/rhai_runner.rs) | Runs each filename passed to it as a Rhai script. |
|
||||
| [`simple_fn`](https://github.com/jonathandturner/rhai/tree/master/examples/simple_fn.rs) | Shows how to register a simple function. |
|
||||
| [`strings`](https://github.com/jonathandturner/rhai/tree/master/examples/strings.rs) | Shows different ways to register functions taking string arguments. |
|
||||
| [`repl`](https://github.com/jonathandturner/rhai/tree/master/examples/repl.rs) | A simple REPL, interactively evaluate statements from stdin. |
|
||||
|
||||
The `repl` example is a particularly good one as it allows one to interactively try out Rhai's
|
||||
language features in a standard REPL (**R**ead-**E**val-**P**rint **L**oop).
|
||||
|
@ -10,21 +10,21 @@ There are also a number of examples scripts that showcase Rhai's features, all i
|
||||
|
||||
| Script | Description |
|
||||
| -------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
|
||||
| [`array.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/array.rhai) | [arrays] in Rhai |
|
||||
| [`assignment.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/assignment.rhai) | variable declarations |
|
||||
| [`comments.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/comments.rhai) | just comments |
|
||||
| [`array.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/array.rhai) | [Arrays] |
|
||||
| [`assignment.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/assignment.rhai) | Variable declarations |
|
||||
| [`comments.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/comments.rhai) | Just comments |
|
||||
| [`for1.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/for1.rhai) | [`for`](#for-loop) loops |
|
||||
| [`for2.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/for2.rhai) | [`for`](#for-loop) loops on [arrays] |
|
||||
| [`function_decl1.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/function_decl1.rhai) | a [function] without parameters |
|
||||
| [`function_decl2.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/function_decl2.rhai) | a [function] with two parameters |
|
||||
| [`function_decl3.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/function_decl3.rhai) | a [function] with many parameters |
|
||||
| [`function_decl1.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/function_decl1.rhai) | A [function] without parameters |
|
||||
| [`function_decl2.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/function_decl2.rhai) | A [function] with two parameters |
|
||||
| [`function_decl3.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/function_decl3.rhai) | A [function] with many parameters |
|
||||
| [`if1.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/if1.rhai) | [`if`](#if-statement) example |
|
||||
| [`loop.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/loop.rhai) | count-down [`loop`](#infinite-loop) in Rhai, emulating a `do` .. `while` loop |
|
||||
| [`op1.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/op1.rhai) | just simple addition |
|
||||
| [`op2.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/op2.rhai) | simple addition and multiplication |
|
||||
| [`op3.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/op3.rhai) | change evaluation order with parenthesis |
|
||||
| [`string.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/string.rhai) | [string] operations |
|
||||
| [`strings_map.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/strings_map.rhai) | [string] and [object map] operations |
|
||||
| [`loop.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/loop.rhai) | Count-down [`loop`](#infinite-loop) in Rhai, emulating a `do` .. `while` loop |
|
||||
| [`op1.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/op1.rhai) | Just simple addition |
|
||||
| [`op2.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/op2.rhai) | Simple addition and multiplication |
|
||||
| [`op3.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/op3.rhai) | Change evaluation order with parenthesis |
|
||||
| [`string.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/string.rhai) | [String] operations |
|
||||
| [`strings_map.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/strings_map.rhai) | [String] and [object map] operations |
|
||||
| [`while.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/while.rhai) | [`while`](#while-loop) loop |
|
||||
|
||||
|
||||
@ -34,11 +34,11 @@ Benchmark Scripts
|
||||
The following scripts are for benchmarking the speed of Rhai:
|
||||
|
||||
| Scripts | Description |
|
||||
| ------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------- |
|
||||
| [`speed_test.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/speed_test.rhai) | a simple program to measure the speed of Rhai's interpreter (1 million iterations) |
|
||||
| [`primes.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/primes.rhai) | use Sieve of Eratosthenes to find all primes smaller than a limit |
|
||||
| [`fibonacci.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/fibonacci.rhai) | calculate the n-th Fibonacci number using a really dumb algorithm |
|
||||
| [`mat_mul.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/mat_mul.rhai) | matrix multiplication test to measure the speed of multi-dimensional array access |
|
||||
| ------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------- |
|
||||
| [`speed_test.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/speed_test.rhai) | A simple program to measure the speed of Rhai's interpreter (1 million iterations). |
|
||||
| [`primes.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/primes.rhai) | Use Sieve of Eratosthenes to find all primes smaller than a limit. |
|
||||
| [`fibonacci.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/fibonacci.rhai) | Calculate the n-th Fibonacci number using a really dumb algorithm. |
|
||||
| [`mat_mul.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/mat_mul.rhai) | Matrix multiplication test to measure the speed of multi-dimensional array access. |
|
||||
|
||||
|
||||
Running Example Scripts
|
||||
|
@ -12,17 +12,17 @@ Excluding unneeded functionalities can result in smaller, faster builds as well
|
||||
more control over what a script can (or cannot) do.
|
||||
|
||||
| Feature | Description |
|
||||
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `unchecked` | Disable arithmetic checking (such as over-flows and division by zero), call stack depth limit, operations count limit and modules loading limit. Beware that a bad script may panic the entire system! |
|
||||
| ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `unchecked` | Disable arithmetic checking (such as over-flows and division by zero), call stack depth limit, operations count limit and modules loading limit.<br/>Beware that a bad script may panic the entire system! |
|
||||
| `sync` | Restrict all values types to those that are `Send + Sync`. Under this feature, all Rhai types, including [`Engine`], [`Scope`] and `AST`, are all `Send + Sync`. |
|
||||
| `no_optimize` | Disable the script optimizer. |
|
||||
| `no_optimize` | Disable [script optimization]. |
|
||||
| `no_float` | Disable floating-point numbers and math. |
|
||||
| `only_i32` | Set the system integer type to `i32` and disable all other integer types. `INT` is set to `i32`. |
|
||||
| `only_i64` | Set the system integer type to `i64` and disable all other integer types. `INT` is set to `i64`. |
|
||||
| `no_index` | Disable [arrays] and indexing features. |
|
||||
| `no_object` | Disable support for custom types and [object maps]. |
|
||||
| `no_function` | Disable script-defined functions. |
|
||||
| `no_module` | Disable loading external modules. |
|
||||
| `no_object` | Disable support for [custom types] and [object maps]. |
|
||||
| `no_function` | Disable script-defined [functions]. |
|
||||
| `no_module` | Disable loading external [modules]. |
|
||||
| `no_std` | Build for `no-std`. Notice that additional dependencies will be pulled in to replace `std` features. |
|
||||
|
||||
|
||||
@ -32,19 +32,19 @@ Example
|
||||
The `Cargo.toml` configuration below turns on these six features:
|
||||
|
||||
* `sync` (everything `Send + Sync`)
|
||||
* `unchecked` (no checked arithmetic - should not be used with untrusted user scripts)
|
||||
* `unchecked` (disable all checking - should not be used with untrusted user scripts)
|
||||
* `only_i32` (only 32-bit signed integers)
|
||||
* `no_float` (no floating point numbers)
|
||||
* `no_module` (no loading external modules)
|
||||
* `no_function` (no defining functions)
|
||||
* `no_module` (no loading external [modules])
|
||||
* `no_function` (no defining [functions])
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
rhai = { version = "{{version}}", features = [ "sync", "unchecked", "only_i32", "no_float", "no_module", "no_function" ] }
|
||||
```
|
||||
|
||||
The resulting scripting engine supports only the `i32` integer numeral type (and no others like `u32` or `i16`),
|
||||
no floating-point, is `Send + Sync` (so it can be safely used across threads), does not support defining functions
|
||||
nor loading external modules.
|
||||
The resulting scripting engine supports only the `i32` integer numeral type (and no others like `u32`, `i16` or `i64`),
|
||||
no floating-point, is `Send + Sync` (so it can be safely used across threads), does not support defining [functions]
|
||||
nor loading external [modules].
|
||||
|
||||
This configuration is perfect for an expression parser in a 32-bit embedded system without floating-point hardware.
|
||||
|
@ -2,7 +2,7 @@
|
||||
//!
|
||||
//! Rhai is a tiny, simple and very fast embedded scripting language for Rust
|
||||
//! that gives you a safe and easy way to add scripting to your applications.
|
||||
//! It provides a familiar syntax based on JS and Rust and a simple Rust interface.
|
||||
//! It provides a familiar syntax based on JavaScript and Rust and a simple Rust interface.
|
||||
//! Here is a quick example.
|
||||
//!
|
||||
//! First, the contents of `my_script.rhai`:
|
||||
|
@ -677,12 +677,12 @@ impl<'a> TokenIterator<'a> {
|
||||
_ => unreachable!(),
|
||||
});
|
||||
|
||||
while let Some(next_char_in_hex) = self.peek_next() {
|
||||
if !valid.contains(&next_char_in_hex) {
|
||||
while let Some(next_char_in_escape_seq) = self.peek_next() {
|
||||
if !valid.contains(&next_char_in_escape_seq) {
|
||||
break;
|
||||
}
|
||||
|
||||
result.push(next_char_in_hex);
|
||||
result.push(next_char_in_escape_seq);
|
||||
self.eat_next();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user