Edit documentation.
This commit is contained in:
parent
7cc1a3f5dc
commit
d728ac6758
@ -42,4 +42,4 @@ Features
|
|||||||
Documentation
|
Documentation
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
See [The Rhai Book](https://schungx.github.io/rhai) for details on the Rhai script engine and language.
|
See [The Rhai Book](https://schungx.github.io/rhai) for details on the Rhai scripting engine and language.
|
||||||
|
@ -9,12 +9,12 @@ The Rhai Scripting Language
|
|||||||
2. [Getting Started](start.md)
|
2. [Getting Started](start.md)
|
||||||
1. [Install the Rhai Crate](start/install.md)
|
1. [Install the Rhai Crate](start/install.md)
|
||||||
2. [Optional Features](start/features.md)
|
2. [Optional Features](start/features.md)
|
||||||
3. [Special Builds](start/builds.md)
|
3. [Special Builds](start/builds/index.md)
|
||||||
1. [Performance Build](start/builds/performance.md)
|
1. [Performance](start/builds/performance.md)
|
||||||
2. [Minimal Build](start/builds/minimal.md)
|
2. [Minimal](start/builds/minimal.md)
|
||||||
3. [no-std Build](start/builds/no-std.md)
|
3. [no-std](start/builds/no-std.md)
|
||||||
4. [WebAssembly (WASM)](start/builds/wasm.md)
|
4. [WebAssembly (WASM)](start/builds/wasm.md)
|
||||||
4. [Examples](start/examples.md)
|
4. [Examples](start/examples/index.md)
|
||||||
1. [Rust](start/examples/rust.md)
|
1. [Rust](start/examples/rust.md)
|
||||||
2. [Scripts](start/examples/scripts.md)
|
2. [Scripts](start/examples/scripts.md)
|
||||||
3. [Using the `Engine`](engine.md)
|
3. [Using the `Engine`](engine.md)
|
||||||
@ -30,7 +30,7 @@ The Rhai Scripting Language
|
|||||||
1. [String Parameters in Rust Functions](rust/strings.md)
|
1. [String Parameters in Rust Functions](rust/strings.md)
|
||||||
3. [Register a Generic Rust Function](rust/generic.md)
|
3. [Register a Generic Rust Function](rust/generic.md)
|
||||||
4. [Register a Fallible Rust Function](rust/fallible.md)
|
4. [Register a Fallible Rust Function](rust/fallible.md)
|
||||||
5. [Packages](rust/packages.md)
|
5. [Packages](rust/packages/index.md)
|
||||||
1. [Built-in Packages](rust/packages/builtin.md)
|
1. [Built-in Packages](rust/packages/builtin.md)
|
||||||
2. [Create a Custom Package](rust/packages/create.md)
|
2. [Create a Custom Package](rust/packages/create.md)
|
||||||
6. [Override a Built-in Function](rust/override.md)
|
6. [Override a Built-in Function](rust/override.md)
|
||||||
@ -40,7 +40,7 @@ The Rhai Scripting Language
|
|||||||
2. [Indexers](rust/indexers.md)
|
2. [Indexers](rust/indexers.md)
|
||||||
3. [Disable Custom Types](rust/disable-custom.md)
|
3. [Disable Custom Types](rust/disable-custom.md)
|
||||||
4. [Printing Custom Types](rust/print-custom.md)
|
4. [Printing Custom Types](rust/print-custom.md)
|
||||||
9. [Scope - Initializing and Maintaining State](rust/scope.md)
|
9. [Scope - Initializing and Maintaining State](rust/scope.md)
|
||||||
10. [Engine Configuration Options](rust/options.md)
|
10. [Engine Configuration Options](rust/options.md)
|
||||||
5. [Rhai Language Reference](language.md)
|
5. [Rhai Language Reference](language.md)
|
||||||
1. [Comments](language/comments.md)
|
1. [Comments](language/comments.md)
|
||||||
@ -72,14 +72,14 @@ The Rhai Scripting Language
|
|||||||
1. [Function Overloading](language/overload.md)
|
1. [Function Overloading](language/overload.md)
|
||||||
2. [Call Method as Function](language/method.md)
|
2. [Call Method as Function](language/method.md)
|
||||||
15. [Print and Debug](language/print-debug.md)
|
15. [Print and Debug](language/print-debug.md)
|
||||||
16. [Modules](language/modules.md)
|
16. [Modules](language/modules/index.md)
|
||||||
1. [Export Variables, Functions and Sub-Modules](language/modules/export.md)
|
1. [Export Variables, Functions and Sub-Modules](language/modules/export.md)
|
||||||
2. [Import Modules](language/modules/import.md)
|
2. [Import Modules](language/modules/import.md)
|
||||||
3. [Create from Rust](language/modules/rust.md)
|
3. [Create from Rust](language/modules/rust.md)
|
||||||
4. [Create from AST](language/modules/ast.md)
|
4. [Create from AST](language/modules/ast.md)
|
||||||
5. [Module Resolvers](language/modules/resolvers.md)
|
5. [Module Resolvers](language/modules/resolvers.md)
|
||||||
1. [Implement a Custom Module Resolver](language/modules/imp-resolver.md)
|
1. [Implement a Custom Module Resolver](language/modules/imp-resolver.md)
|
||||||
6. [Safety and Protection](safety.md)
|
6. [Safety and Protection](safety/index.md)
|
||||||
1. [Checked Arithmetic](safety/checked.md)
|
1. [Checked Arithmetic](safety/checked.md)
|
||||||
2. [Sand-Boxing](safety/sandbox.md)
|
2. [Sand-Boxing](safety/sandbox.md)
|
||||||
3. [Maximum Length of Strings](safety/max-string-size.md)
|
3. [Maximum Length of Strings](safety/max-string-size.md)
|
||||||
@ -91,7 +91,7 @@ The Rhai Scripting Language
|
|||||||
8. [Maximum Call Stack Depth](safety/max-call-stack.md)
|
8. [Maximum Call Stack Depth](safety/max-call-stack.md)
|
||||||
9. [Maximum Statement Depth](safety/max-stmt-depth.md)
|
9. [Maximum Statement Depth](safety/max-stmt-depth.md)
|
||||||
7. [Advanced Topics](advanced.md)
|
7. [Advanced Topics](advanced.md)
|
||||||
1. [Script Optimization](engine/optimize.md)
|
1. [Script Optimization](engine/optimize/index.md)
|
||||||
1. [Optimization Levels](engine/optimize/optimize-levels.md)
|
1. [Optimization Levels](engine/optimize/optimize-levels.md)
|
||||||
2. [Re-Optimize an AST](engine/optimize/reoptimize.md)
|
2. [Re-Optimize an AST](engine/optimize/reoptimize.md)
|
||||||
3. [Eager Function Evaluation](engine/optimize/eager.md)
|
3. [Eager Function Evaluation](engine/optimize/eager.md)
|
||||||
@ -99,3 +99,7 @@ The Rhai Scripting Language
|
|||||||
5. [Volatility Considerations](engine/optimize/volatility.md)
|
5. [Volatility Considerations](engine/optimize/volatility.md)
|
||||||
6. [Subtle Semantic Changes](engine/optimize/semantics.md)
|
6. [Subtle Semantic Changes](engine/optimize/semantics.md)
|
||||||
2. [Eval Statement](language/eval.md)
|
2. [Eval Statement](language/eval.md)
|
||||||
|
8. [Appendix](appendix/index.md)
|
||||||
|
1. [Keywords](appendix/keywords.md)
|
||||||
|
2. [Operators](appendix/operators.md)
|
||||||
|
3. [Literals](appendix/literals.md)
|
||||||
|
@ -5,8 +5,11 @@ Related Resources
|
|||||||
|
|
||||||
Other online documentation resources for Rhai:
|
Other online documentation resources for Rhai:
|
||||||
|
|
||||||
* [`DOCS.RS`](https://docs.rs/rhai)
|
* [`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
|
||||||
|
|
||||||
Other cool projects to check out:
|
Other cool projects to check out:
|
||||||
|
|
||||||
|
@ -7,4 +7,4 @@ This section covers advanced features such as:
|
|||||||
|
|
||||||
* [Script optimization]
|
* [Script optimization]
|
||||||
|
|
||||||
* The dreaded (or beloved depending on your taste) [`eval`] statement
|
* The dreaded (or beloved for those with twisted tastes) [`eval`] statement
|
||||||
|
6
doc/src/appendix/index.md
Normal file
6
doc/src/appendix/index.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
Appendix
|
||||||
|
========
|
||||||
|
|
||||||
|
{{#include ../links.md}}
|
||||||
|
|
||||||
|
This section contains miscellaneous reference materials.
|
30
doc/src/appendix/keywords.md
Normal file
30
doc/src/appendix/keywords.md
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
Keywords List
|
||||||
|
=============
|
||||||
|
|
||||||
|
{{#include ../links.md}}
|
||||||
|
|
||||||
|
| Keyword | Description |
|
||||||
|
| :--------: | ------------------------------------- |
|
||||||
|
| `true` | Boolean true literal |
|
||||||
|
| `false` | Boolean false literal |
|
||||||
|
| `let` | Variable declaration |
|
||||||
|
| `const` | Constant declaration |
|
||||||
|
| `if` | If statement |
|
||||||
|
| `else` | else block of if statement |
|
||||||
|
| `while` | While loop |
|
||||||
|
| `loop` | Infinite loop |
|
||||||
|
| `for` | For loop |
|
||||||
|
| `in` | Containment test, part of for loop |
|
||||||
|
| `continue` | Continue a loop at the next iteration |
|
||||||
|
| `break` | Loop breaking |
|
||||||
|
| `return` | Return value |
|
||||||
|
| `throw` | Throw exception |
|
||||||
|
| `private` | Mark function private |
|
||||||
|
| `import` | Import module |
|
||||||
|
| `export` | Export variable |
|
||||||
|
| `as` | Alias for variable export |
|
||||||
|
| `fn` | Function definition |
|
||||||
|
| `type_of` | Get type name of value |
|
||||||
|
| `print` | Print value |
|
||||||
|
| `debug` | Print value in debug format |
|
||||||
|
| `eval` | Evaluate script |
|
16
doc/src/appendix/literals.md
Normal file
16
doc/src/appendix/literals.md
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
Literals Syntax
|
||||||
|
===============
|
||||||
|
|
||||||
|
{{#include ../links.md}}
|
||||||
|
|
||||||
|
| Type | Literal syntax |
|
||||||
|
| :--------------------------------: | :---------------------------------------: |
|
||||||
|
| `INT` | `42`, `-123`, `0` |
|
||||||
|
| `FLOAT` | `42.0`, `-123.456`, `0.0` |
|
||||||
|
| [String] | `"... \x?? \u???? \U???????? ..."` |
|
||||||
|
| Character | `"... \x?? \u???? \U???????? ..."` |
|
||||||
|
| [`Array`] | `[ ???, ???, ??? ]` |
|
||||||
|
| [Object map] | `#{ a: ???, b: ???, c: ???, "def": ??? }` |
|
||||||
|
| Boolean true | `true` |
|
||||||
|
| Boolean false | `false` |
|
||||||
|
| `Nothing`/`null`/`nil`/`void`/Unit | `()` |
|
30
doc/src/appendix/operators.md
Normal file
30
doc/src/appendix/operators.md
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
Operators
|
||||||
|
=========
|
||||||
|
|
||||||
|
{{#include ../links.md}}
|
||||||
|
|
||||||
|
| Operator | Description | Binary? |
|
||||||
|
| :---------------: | ---------------------------- | :-----: |
|
||||||
|
| `+` | Add | Yes |
|
||||||
|
| `-` | Subtract, Minus | Yes/No |
|
||||||
|
| `*` | Multiply | Yes |
|
||||||
|
| `/` | Divide | Yes |
|
||||||
|
| `%` | Modulo | Yes |
|
||||||
|
| `~` | 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 |
|
||||||
|
| `==` | Equals to | Yes |
|
||||||
|
| `~=` | Not equals to | Yes |
|
||||||
|
| `>` | Greater than | Yes |
|
||||||
|
| `>=` | Greater than or equals to | Yes |
|
||||||
|
| `<` | 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 |
|
||||||
|
| `[` .. `]` | Indexing | Yes |
|
||||||
|
| `.` | Property access, Method call | Yes |
|
@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"version": "0.15.1",
|
||||||
"rootUrl": "",
|
"rootUrl": "",
|
||||||
"rootUrlX": "/rhai"
|
"rootUrlX": "/rhai"
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
Script Optimization
|
Script Optimization
|
||||||
===================
|
===================
|
||||||
|
|
||||||
{{#include ../links.md}}
|
{{#include ../../links.md}}
|
||||||
|
|
||||||
Rhai includes an _optimizer_ that tries to optimize a script after parsing.
|
Rhai includes an _optimizer_ that tries to optimize a script after parsing.
|
||||||
This can reduce resource utilization and increase execution speed.
|
This can reduce resource utilization and increase execution speed.
|
@ -3,10 +3,7 @@ Optimization Levels
|
|||||||
|
|
||||||
{{#include ../../links.md}}
|
{{#include ../../links.md}}
|
||||||
|
|
||||||
Set Optimization Level
|
There are three levels of optimization: `None`, `Simple` and `Full`.
|
||||||
---------------------
|
|
||||||
|
|
||||||
There are actually three levels of optimizations: `None`, `Simple` and `Full`.
|
|
||||||
|
|
||||||
* `None` is obvious - no optimization on the AST is performed.
|
* `None` is obvious - no optimization on the AST is performed.
|
||||||
|
|
||||||
@ -16,6 +13,10 @@ There are actually three levels of optimizations: `None`, `Simple` and `Full`.
|
|||||||
* `Full` is _much_ more aggressive, _including_ running functions on constant arguments to determine their result.
|
* `Full` is _much_ more aggressive, _including_ running 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.
|
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`:
|
An [`Engine`]'s optimization level is set via a call to `Engine::set_optimization_level`:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
|
@ -3,15 +3,38 @@ Re-Optimize an AST
|
|||||||
|
|
||||||
{{#include ../../links.md}}
|
{{#include ../../links.md}}
|
||||||
|
|
||||||
If it is ever needed to _re_-optimize an `AST`, use the `optimize_ast` method:
|
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
|
```rust
|
||||||
// Compile script to AST
|
// Compile master script to AST
|
||||||
let ast = engine.compile("40 + 2")?;
|
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 if using 'OptimizationLevel::Full'
|
// Create a new 'Scope' - put constants in it to aid optimization
|
||||||
let scope = Scope::new();
|
let mut scope = Scope::new();
|
||||||
|
scope.push_constant("SCENARIO_1", true);
|
||||||
|
scope.push_constant("SCENARIO_2", false);
|
||||||
|
scope.push_constant("SCENARIO_3", false);
|
||||||
|
|
||||||
// Re-optimize the AST
|
// Re-optimize the AST
|
||||||
let ast = engine.optimize_ast(&scope, &ast, OptimizationLevel::Full);
|
let new_ast = engine.optimize_ast(&scope, master_ast.clone(), OptimizationLevel::Simple);
|
||||||
|
|
||||||
|
// 'new_ast' is essentially: 'do_work()'
|
||||||
```
|
```
|
||||||
|
@ -13,7 +13,8 @@ print(x * 2); // prints 84
|
|||||||
x = 123; // <- syntax error: cannot assign to constant
|
x = 123; // <- syntax error: cannot assign to constant
|
||||||
```
|
```
|
||||||
|
|
||||||
Constants must be assigned a _value_, not an expression.
|
Unlike variables which need not have initial values (default to [`()`]),
|
||||||
|
constants must be assigned one, and it must be a constant _value_, not an expression.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
const x = 40 + 2; // <- syntax error: cannot assign expression to constant
|
const x = 40 + 2; // <- syntax error: cannot assign expression to constant
|
||||||
|
@ -6,29 +6,29 @@
|
|||||||
Or "How to Shoot Yourself in the Foot even Easier"
|
Or "How to Shoot Yourself in the Foot even Easier"
|
||||||
------------------------------------------------
|
------------------------------------------------
|
||||||
|
|
||||||
Saving the best for last: in addition to script optimizations, there is the ever-dreaded... `eval` function!
|
Saving the best for last, there is the ever-dreaded... `eval` function!
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let x = 10;
|
let x = 10;
|
||||||
|
|
||||||
fn foo(x) { x += 12; x }
|
fn foo(x) { x += 12; x }
|
||||||
|
|
||||||
let script = "let y = x;"; // build a script
|
let script = "let y = x;"; // build a script
|
||||||
script += "y += foo(y);";
|
script += "y += foo(y);";
|
||||||
script += "x + y";
|
script += "x + y";
|
||||||
|
|
||||||
let result = eval(script); // <- look, JS, we can also do this!
|
let result = eval(script); // <- look, JS, we can also do this!
|
||||||
|
|
||||||
print("Answer: " + result); // prints 42
|
print("Answer: " + result); // prints 42
|
||||||
|
|
||||||
print("x = " + x); // prints 10: functions call arguments are passed by value
|
print("x = " + x); // prints 10: functions call arguments are passed by value
|
||||||
print("y = " + y); // prints 32: variables defined in 'eval' persist!
|
print("y = " + y); // prints 32: variables defined in 'eval' persist!
|
||||||
|
|
||||||
eval("{ let z = y }"); // to keep a variable local, use a statement block
|
eval("{ let z = y }"); // to keep a variable local, use a statement block
|
||||||
|
|
||||||
print("z = " + z); // <- error: variable 'z' not found
|
print("z = " + z); // <- error: variable 'z' not found
|
||||||
|
|
||||||
"print(42)".eval(); // <- nope... method-call style doesn't work
|
"print(42)".eval(); // <- nope... method-call style doesn't work
|
||||||
```
|
```
|
||||||
|
|
||||||
Script segments passed to `eval` execute inside the current [`Scope`], so they can access and modify _everything_,
|
Script segments passed to `eval` execute inside the current [`Scope`], so they can access and modify _everything_,
|
||||||
@ -45,8 +45,8 @@ not inside another function call!
|
|||||||
```rust
|
```rust
|
||||||
let script = "x += 32";
|
let script = "x += 32";
|
||||||
let x = 10;
|
let x = 10;
|
||||||
eval(script); // variable 'x' in the current scope is visible!
|
eval(script); // variable 'x' in the current scope is visible!
|
||||||
print(x); // prints 42
|
print(x); // prints 42
|
||||||
|
|
||||||
// The above is equivalent to:
|
// The above is equivalent to:
|
||||||
let script = "x += 32";
|
let script = "x += 32";
|
||||||
@ -65,7 +65,7 @@ disable `eval` by overloading it, probably with something that throws.
|
|||||||
```rust
|
```rust
|
||||||
fn eval(script) { throw "eval is evil! I refuse to run " + script }
|
fn eval(script) { throw "eval is evil! I refuse to run " + script }
|
||||||
|
|
||||||
let x = eval("40 + 2"); // 'eval' here throws "eval is evil! I refuse to run 40 + 2"
|
let x = eval("40 + 2"); // 'eval' here throws "eval is evil! I refuse to run 40 + 2"
|
||||||
```
|
```
|
||||||
|
|
||||||
Or overload it from Rust:
|
Or overload it from Rust:
|
||||||
@ -86,11 +86,11 @@ There is even a package named [`EvalPackage`]({{rootUrl}}/rust/packages.md) whic
|
|||||||
|
|
||||||
```rust
|
```rust
|
||||||
use rhai::Engine;
|
use rhai::Engine;
|
||||||
use rhai::packages::Package // load the 'Package' trait to use packages
|
use rhai::packages::Package // load the 'Package' trait to use packages
|
||||||
use rhai::packages::EvalPackage; // the 'eval' package disables 'eval'
|
use rhai::packages::EvalPackage; // the 'eval' package disables 'eval'
|
||||||
|
|
||||||
let mut engine = Engine::new();
|
let mut engine = Engine::new();
|
||||||
let package = EvalPackage::new(); // create the package
|
let package = EvalPackage::new(); // create the package
|
||||||
|
|
||||||
engine.load_package(package.get()); // load the package
|
engine.load_package(package.get()); // load the package
|
||||||
```
|
```
|
||||||
|
@ -5,50 +5,53 @@
|
|||||||
|
|
||||||
Iterating through a range or an [array] is provided by the `for` ... `in` loop.
|
Iterating through a range or an [array] 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.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
// Iterate through string, yielding characters
|
// Iterate through string, yielding characters
|
||||||
let s = "hello, world!";
|
let s = "hello, world!";
|
||||||
|
|
||||||
for ch in s {
|
for ch in s {
|
||||||
if ch > 'z' { continue; } // skip to the next iteration
|
if ch > 'z' { continue; } // skip to the next iteration
|
||||||
print(ch);
|
print(ch);
|
||||||
if x == '@' { break; } // break out of for loop
|
if x == '@' { break; } // break out of for loop
|
||||||
}
|
}
|
||||||
|
|
||||||
// Iterate through array
|
// Iterate through array
|
||||||
let array = [1, 3, 5, 7, 9, 42];
|
let array = [1, 3, 5, 7, 9, 42];
|
||||||
|
|
||||||
for x in array {
|
for x in array {
|
||||||
if x > 10 { continue; } // skip to the next iteration
|
if x > 10 { continue; } // skip to the next iteration
|
||||||
print(x);
|
print(x);
|
||||||
if x == 42 { break; } // break out of for loop
|
if x == 42 { break; } // break out of for loop
|
||||||
}
|
}
|
||||||
|
|
||||||
// The 'range' function allows iterating from first to last-1
|
// The 'range' function allows iterating from first to last-1
|
||||||
for x in range(0, 50) {
|
for x in range(0, 50) {
|
||||||
if x > 10 { continue; } // skip to the next iteration
|
if x > 10 { continue; } // skip to the next iteration
|
||||||
print(x);
|
print(x);
|
||||||
if x == 42 { break; } // break out of for loop
|
if x == 42 { break; } // break out of for loop
|
||||||
}
|
}
|
||||||
|
|
||||||
// The 'range' function also takes a step
|
// The 'range' function also takes a step
|
||||||
for x in range(0, 50, 3) { // step by 3
|
for x in range(0, 50, 3) { // step by 3
|
||||||
if x > 10 { continue; } // skip to the next iteration
|
if x > 10 { continue; } // skip to the next iteration
|
||||||
print(x);
|
print(x);
|
||||||
if x == 42 { break; } // break out of for loop
|
if x == 42 { break; } // break out of for loop
|
||||||
}
|
}
|
||||||
|
|
||||||
// Iterate through object map
|
// Iterate through object map
|
||||||
let map = #{a:1, b:3, c:5, d:7, e:9};
|
let map = #{a:1, b:3, c:5, d:7, e:9};
|
||||||
|
|
||||||
// Property names are returned in random order
|
// Property names are returned in unsorted, random order
|
||||||
for x in keys(map) {
|
for x in keys(map) {
|
||||||
if x > 10 { continue; } // skip to the next iteration
|
if x > 10 { continue; } // skip to the next iteration
|
||||||
print(x);
|
print(x);
|
||||||
if x == 42 { break; } // break out of for loop
|
if x == 42 { break; } // break out of for loop
|
||||||
}
|
}
|
||||||
|
|
||||||
// Property values are returned in random order
|
// Property values are returned in unsorted, random order
|
||||||
for val in values(map) {
|
for val in values(map) {
|
||||||
print(val);
|
print(val);
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ print(add(2, 3)); // prints 5
|
|||||||
print(sub(2, 3,)); // prints -1 - trailing comma in arguments list is OK
|
print(sub(2, 3,)); // prints -1 - trailing comma in arguments list is OK
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
Implicit Return
|
Implicit Return
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
@ -38,6 +39,7 @@ print(add(2, 3)); // prints 5
|
|||||||
print(add2(42)); // prints 44
|
print(add2(42)); // prints 44
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
No Access to External Scope
|
No Access to External Scope
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
@ -50,13 +52,15 @@ let x = 42;
|
|||||||
fn foo() { x } // <- syntax error: variable 'x' doesn't exist
|
fn foo() { x } // <- syntax error: variable 'x' doesn't exist
|
||||||
```
|
```
|
||||||
|
|
||||||
Passing Arguments by Value
|
|
||||||
-------------------------
|
Arguments Passed by Value
|
||||||
|
------------------------
|
||||||
|
|
||||||
Functions defined in script always take [`Dynamic`] parameters (i.e. the parameter can be of any type).
|
Functions defined in script always take [`Dynamic`] parameters (i.e. the parameter can be of any type).
|
||||||
It is important to remember that all arguments are passed by _value_, so all functions are _pure_
|
Therefore, functions with the same name and same _number_ of parameters are equivalent.
|
||||||
(i.e. they never modify their arguments).
|
|
||||||
|
|
||||||
|
It is important to remember that 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.
|
Any update to an argument will **not** be reflected back to the caller.
|
||||||
|
|
||||||
This can introduce subtle bugs, if not careful, especially when using the _method-call_ style.
|
This can introduce subtle bugs, if not careful, especially when using the _method-call_ style.
|
||||||
@ -71,6 +75,7 @@ x.change(); // de-sugars to 'change(x)'
|
|||||||
x == 500; // 'x' is NOT changed!
|
x == 500; // 'x' is NOT changed!
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
Global Definitions Only
|
Global Definitions Only
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
@ -92,6 +97,12 @@ fn do_addition(x) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Unlike C/C++, functions can be defined _anywhere_ within the 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.
|
Use Before Definition
|
||||||
This is similar to Rust and many other modern languages.
|
--------------------
|
||||||
|
|
||||||
|
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.
|
||||||
|
@ -3,24 +3,30 @@
|
|||||||
|
|
||||||
{{#include ../links.md}}
|
{{#include ../links.md}}
|
||||||
|
|
||||||
|
`if` statements follow C syntax:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
if foo(x) {
|
if foo(x) {
|
||||||
print("It's true!");
|
print("It's true!");
|
||||||
} else if bar == baz {
|
} else if bar == baz {
|
||||||
print("It's true again!");
|
print("It's true again!");
|
||||||
} else if ... {
|
} else if baz.is_foo() {
|
||||||
:
|
print("Yet again true.");
|
||||||
} else if ... {
|
} else if foo(bar - baz) {
|
||||||
:
|
print("True again... this is getting boring.");
|
||||||
} else {
|
} else {
|
||||||
print("It's finally false!");
|
print("It's finally false!");
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
All branches of an `if` statement must be enclosed within braces '`{`' .. '`}`', even when there is only one statement.
|
Unlike C, the condition expression does _not_ need to be enclosed in parentheses '`(`' .. '`)`', but
|
||||||
Like Rust, there is no ambiguity regarding which `if` clause a statement belongs to.
|
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
|
```rust
|
||||||
|
// Rhai is not C!
|
||||||
if (decision) print("I've decided!");
|
if (decision) print("I've decided!");
|
||||||
// ^ syntax error, expecting '{' in statement block
|
// ^ syntax error, expecting '{' in statement block
|
||||||
```
|
```
|
||||||
|
@ -3,6 +3,11 @@ Infinite `loop`
|
|||||||
|
|
||||||
{{#include ../links.md}}
|
{{#include ../links.md}}
|
||||||
|
|
||||||
|
Infinite loops follow C syntax.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let x = 10;
|
let x = 10;
|
||||||
|
|
||||||
@ -13,3 +18,6 @@ loop {
|
|||||||
if x == 0 { break; } // break out of loop
|
if x == 0 { break; } // break out of loop
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Beware: a `loop` statement without a `break` statement inside its loop block is infinite -
|
||||||
|
there is no way for the loop to stop iterating.
|
||||||
|
@ -3,11 +3,16 @@ Call Method as Function
|
|||||||
|
|
||||||
{{#include ../links.md}}
|
{{#include ../links.md}}
|
||||||
|
|
||||||
Properties and methods in a Rust custom type registered with the [`Engine`] can be called just like a regular function in Rust.
|
Property getters/setters and methods in a Rust custom type registered with the [`Engine`] can be called
|
||||||
|
just like a regular function. In fact, like Rust, property getters/setters and object methods
|
||||||
|
are registered as regular functions in Rhai that take a first `&mut` parameter.
|
||||||
|
|
||||||
Unlike functions defined in script (for which all arguments are passed by _value_),
|
Unlike functions defined in script (for which all arguments are passed by _value_),
|
||||||
native Rust functions may mutate the object (or the first argument if called in normal function call style).
|
native Rust functions may mutate the object (or the first argument if called in normal function call style).
|
||||||
|
|
||||||
|
However, sometimes it is not as straight-forward, and methods called in function-call style may end up
|
||||||
|
not muting the object - see the example below. Therefore, it is best to always use method-call style.
|
||||||
|
|
||||||
Custom types, properties and methods can be disabled via the [`no_object`] feature.
|
Custom types, properties and methods can be disabled via the [`no_object`] feature.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
@ -21,8 +26,8 @@ update(a); // <- this de-sugars to 'a.update()' thus if 'a' is a simple
|
|||||||
let array = [ a ];
|
let array = [ a ];
|
||||||
|
|
||||||
update(array[0]); // <- 'array[0]' is an expression returning a calculated value,
|
update(array[0]); // <- 'array[0]' is an expression returning a calculated value,
|
||||||
// a transient (i.e. a copy) so this statement has no effect
|
// a transient (i.e. a copy), so this statement has no effect
|
||||||
// except waste a lot of time cloning
|
// except waste a lot of time cloning
|
||||||
|
|
||||||
array[0].update(); // <- call this method-call style will update 'a'
|
array[0].update(); // <- call in method-call style will update 'a'
|
||||||
```
|
```
|
||||||
|
@ -1,18 +1 @@
|
|||||||
Modules
|
# Modules
|
||||||
=======
|
|
||||||
|
|
||||||
{{#include ../links.md}}
|
|
||||||
|
|
||||||
Rhai allows organizing code (functions, both Rust-based or script-based, and variables) into _modules_.
|
|
||||||
Modules can be disabled via the [`no_module`] feature.
|
|
||||||
|
|
||||||
A module is of the type `Module` and encapsulates a Rhai script together with the functions defined
|
|
||||||
by that script.
|
|
||||||
|
|
||||||
The script text is run, variables are then selectively exposed via the [`export`] statement.
|
|
||||||
Functions defined by the script are automatically exported.
|
|
||||||
|
|
||||||
Modules loaded within this module at the global level become _sub-modules_ and are also automatically exported.
|
|
||||||
|
|
||||||
Other scripts can then load this module and use the variables and functions exported
|
|
||||||
as if they were defined inside the same script.
|
|
||||||
|
@ -7,8 +7,8 @@ For many applications in which Rhai is embedded, it is necessary to customize th
|
|||||||
are resolved. For instance, modules may need to be loaded from script texts stored in a database,
|
are resolved. For instance, modules may need to be loaded from script texts stored in a database,
|
||||||
not in the file system.
|
not in the file system.
|
||||||
|
|
||||||
A module resolver must implement the trait `rhai::ModuleResolver`, which contains only one function:
|
A module resolver must implement the trait [`rhai::ModuleResolver`]({{rootUrl}}/rust/traits.md),
|
||||||
`resolve`.
|
which contains only one function: `resolve`.
|
||||||
|
|
||||||
When Rhai prepares to load a module, `ModuleResolver::resolve` is called with the name
|
When Rhai prepares to load a module, `ModuleResolver::resolve` is called with the name
|
||||||
of the _module path_ (i.e. the path specified in the [`import`] statement). Upon success, it should
|
of the _module path_ (i.e. the path specified in the [`import`] statement). Upon success, it should
|
||||||
|
@ -3,6 +3,9 @@ Import a Module
|
|||||||
|
|
||||||
{{#include ../../links.md}}
|
{{#include ../../links.md}}
|
||||||
|
|
||||||
|
`import` Statement
|
||||||
|
-----------------
|
||||||
|
|
||||||
A module can be _imported_ via the `import` statement, and its members are accessed via '`::`' similar to C++.
|
A module can be _imported_ via the `import` statement, and its members are accessed via '`::`' similar to C++.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
@ -17,10 +20,14 @@ print(lock::status); // module variables are constants
|
|||||||
lock::status = "off"; // <- runtime error - cannot modify a constant
|
lock::status = "off"; // <- runtime error - cannot modify a constant
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
Scoped Imports
|
||||||
|
--------------
|
||||||
|
|
||||||
`import` statements are _scoped_, meaning that they are only accessible inside the scope that they're imported.
|
`import` statements are _scoped_, meaning that they are only accessible inside the scope that they're imported.
|
||||||
|
|
||||||
They can appear anywhere a normal statement can be, but in the vast majority of cases `import` statements are
|
They can appear anywhere a normal statement can be, but in the vast majority of cases `import` statements are
|
||||||
group at the beginning of a script. It is, however, not advised to deviate from this common practice unless
|
group at the beginning of a script. It is not advised to deviate from this common practice unless
|
||||||
there is a _Very Good Reason™_.
|
there is a _Very Good Reason™_.
|
||||||
|
|
||||||
Especially, do not place an `import` statement within a loop; doing so will repeatedly re-load the same module
|
Especially, do not place an `import` statement within a loop; doing so will repeatedly re-load the same module
|
||||||
@ -44,3 +51,32 @@ for x in range(0, 1000) {
|
|||||||
c.encrypt(something);
|
c.encrypt(something);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
Recursive Imports
|
||||||
|
----------------
|
||||||
|
|
||||||
|
Beware of _import cycles_ - i.e. recursively loading the same module. This is a sure-fire way to
|
||||||
|
cause a stack overflow in the [`Engine`], unless stopped by setting a limit for [maximum number of modules].
|
||||||
|
|
||||||
|
For instance, importing itself always causes an infinite recursion:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// This file is 'hello.rhai'
|
||||||
|
|
||||||
|
import "hello" as foo; // import itself - infinite recursion!
|
||||||
|
|
||||||
|
foo::do_something();
|
||||||
|
```
|
||||||
|
|
||||||
|
Modules cross-referencing also cause infinite recursion:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// This file is 'hello.rhai' - references 'world.rhai'
|
||||||
|
import "world" as foo;
|
||||||
|
foo::do_something();
|
||||||
|
|
||||||
|
// This file is 'world.rhai' - references 'hello.rhai'
|
||||||
|
import "hello" as bar;
|
||||||
|
bar::do_something_else();
|
||||||
|
```
|
||||||
|
18
doc/src/language/modules/index.md
Normal file
18
doc/src/language/modules/index.md
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
Modules
|
||||||
|
=======
|
||||||
|
|
||||||
|
{{#include ../../links.md}}
|
||||||
|
|
||||||
|
Rhai allows organizing code (functions, both Rust-based or script-based, and variables) into _modules_.
|
||||||
|
Modules can be disabled via the [`no_module`] feature.
|
||||||
|
|
||||||
|
A module is of the type `Module` and encapsulates a Rhai script together with the functions defined
|
||||||
|
by that script.
|
||||||
|
|
||||||
|
The script text is run, variables are then selectively exposed via the [`export`] statement.
|
||||||
|
Functions defined by the script are automatically exported.
|
||||||
|
|
||||||
|
Modules loaded within this module at the global level become _sub-modules_ and are also automatically exported.
|
||||||
|
|
||||||
|
Other scripts can then load this module and use the variables and functions exported
|
||||||
|
as if they were defined inside the same script.
|
@ -3,8 +3,14 @@ Return Values
|
|||||||
|
|
||||||
{{#include ../links.md}}
|
{{#include ../links.md}}
|
||||||
|
|
||||||
|
The `return` statement is used to immediately stop evaluation and exist the current context
|
||||||
|
(typically a function call) yielding a _return value_.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
return; // equivalent to return ();
|
return; // equivalent to return ();
|
||||||
|
|
||||||
return 123 + 456; // returns 579
|
return 123 + 456; // returns 579
|
||||||
```
|
```
|
||||||
|
|
||||||
|
A `return` statement at _global_ level stop the entire script evaluation,
|
||||||
|
the return value is taken as the result of the script evaluation.
|
||||||
|
@ -3,13 +3,14 @@ Statements
|
|||||||
|
|
||||||
{{#include ../links.md}}
|
{{#include ../links.md}}
|
||||||
|
|
||||||
|
Terminated by '`;`'
|
||||||
|
------------------
|
||||||
|
|
||||||
Statements are terminated by semicolons '`;`' and they are mandatory,
|
Statements are terminated by semicolons '`;`' and they are mandatory,
|
||||||
except for the _last_ statement in a _block_ (enclosed by '`{`' .. '`}`' pairs) where it can be omitted.
|
except for the _last_ statement in a _block_ (enclosed by '`{`' .. '`}`' pairs) where it can be omitted.
|
||||||
|
|
||||||
A statement can be used anywhere where an expression is expected. These are called, for lack of a more
|
Semicolons can also be omitted if the statement contains a block itself
|
||||||
creative name, "statement expressions." The _last_ statement of a statement block is _always_ the block's
|
(e.g. the `if`, `while`, `for` and `loop` statements).
|
||||||
return value when used as a statement.
|
|
||||||
If the last statement has no return value (e.g. variable definitions, assignments) then it is assumed to be [`()`].
|
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let a = 42; // normal assignment statement
|
let a = 42; // normal assignment statement
|
||||||
@ -20,6 +21,20 @@ let a = { 40 + 2 }; // 'a' is set to the value of the statement block, which
|
|||||||
// ^ the last statement does not require a terminating semicolon (although it also works with it)
|
// ^ the last statement does not require a terminating semicolon (although it also works with it)
|
||||||
// ^ semicolon required here to terminate the assignment statement; it is a syntax error without it
|
// ^ semicolon required here to terminate the assignment statement; it is a syntax error without it
|
||||||
|
|
||||||
4 * 10 + 2 // a statement which is just one expression; no ending semicolon is OK
|
if foo { a = 42 }
|
||||||
|
// ^ there is no need to terminate an if-statement with a semicolon
|
||||||
|
|
||||||
|
4 * 10 + 2 // a statement which is just one expression - no ending semicolon is OK
|
||||||
// because it is the last statement of the whole block
|
// because it is the last statement of the whole block
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
Statement Expression
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
A statement can be used anywhere where an expression is expected. These are called, for lack of a more
|
||||||
|
creative name, "statement expressions."
|
||||||
|
|
||||||
|
The _last_ statement of a statement block is _always_ the block's return value when used as a statement.
|
||||||
|
|
||||||
|
If the last statement has no return value (e.g. variable definitions, assignments) then it is assumed to be [`()`].
|
||||||
|
@ -3,6 +3,9 @@ Variables
|
|||||||
|
|
||||||
{{#include ../links.md}}
|
{{#include ../links.md}}
|
||||||
|
|
||||||
|
Valid Names
|
||||||
|
-----------
|
||||||
|
|
||||||
Variables in Rhai follow normal C naming rules (i.e. must contain only ASCII letters, digits and underscores '`_`').
|
Variables in Rhai follow normal C naming rules (i.e. must contain only ASCII letters, digits and underscores '`_`').
|
||||||
|
|
||||||
Variable names must start with an ASCII letter or an underscore '`_`', must contain at least one ASCII letter,
|
Variable names must start with an ASCII letter or an underscore '`_`', must contain at least one ASCII letter,
|
||||||
@ -11,9 +14,21 @@ and must start with an ASCII letter before a digit.
|
|||||||
Therefore, names like '`_`', '`_42`', '`3a`' etc. are not legal variable names, but '`_c3po`' and '`r2d2`' are.
|
Therefore, names like '`_`', '`_42`', '`3a`' etc. are not legal variable names, but '`_c3po`' and '`r2d2`' are.
|
||||||
Variable names are also case _sensitive_.
|
Variable names are also case _sensitive_.
|
||||||
|
|
||||||
Variables are defined using the `let` keyword. A variable defined within a statement block is _local_ to that block.
|
Variable names cannot be the same as a [keyword].
|
||||||
|
|
||||||
|
|
||||||
|
Declare a Variable
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Variables are declared using the `let` keyword.
|
||||||
|
|
||||||
|
Variables do not have to be given an initial value.
|
||||||
|
If none is provided, then it defaults to [`()`].
|
||||||
|
|
||||||
|
A variable defined within a statement block is _local_ to that block.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
|
let x; // ok - value is '()'
|
||||||
let x = 3; // ok
|
let x = 3; // ok
|
||||||
let _x = 42; // ok
|
let _x = 42; // ok
|
||||||
let x_ = 42; // also ok
|
let x_ = 42; // also ok
|
||||||
|
@ -3,6 +3,11 @@
|
|||||||
|
|
||||||
{{#include ../links.md}}
|
{{#include ../links.md}}
|
||||||
|
|
||||||
|
`while` loops follow C syntax.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let x = 10;
|
let x = 10;
|
||||||
|
|
||||||
|
@ -23,8 +23,8 @@
|
|||||||
[`eval_expression_with_scope`]: {{rootUrl}}/engine/expressions.md
|
[`eval_expression_with_scope`]: {{rootUrl}}/engine/expressions.md
|
||||||
[raw `Engine`]: {{rootUrl}}/engine/raw.md
|
[raw `Engine`]: {{rootUrl}}/engine/raw.md
|
||||||
[built-in operators]: {{rootUrl}}/engine/raw.md#built-in-operators
|
[built-in operators]: {{rootUrl}}/engine/raw.md#built-in-operators
|
||||||
[package]: {{rootUrl}}/rust/packages.md
|
[package]: {{rootUrl}}/rust/packages/index.md
|
||||||
[packages]: {{rootUrl}}/rust/packages.md
|
[packages]: {{rootUrl}}/rust/packages/index.md
|
||||||
[`Scope`]: {{rootUrl}}/rust/scope.md
|
[`Scope`]: {{rootUrl}}/rust/scope.md
|
||||||
|
|
||||||
[`type_of()`]: {{rootUrl}}/language/type-of.md
|
[`type_of()`]: {{rootUrl}}/language/type-of.md
|
||||||
@ -41,6 +41,9 @@
|
|||||||
[`print`]: {{rootUrl}}/language/print-debug.md
|
[`print`]: {{rootUrl}}/language/print-debug.md
|
||||||
[`debug`]: {{rootUrl}}/language/print-debug.md
|
[`debug`]: {{rootUrl}}/language/print-debug.md
|
||||||
|
|
||||||
|
[keywords]: {{rootUrl}}/appendix/keywords.md
|
||||||
|
[keyword]: {{rootUrl}}/appendix/keywords.md
|
||||||
|
|
||||||
[variable]: {{rootUrl}}/language/variables.md
|
[variable]: {{rootUrl}}/language/variables.md
|
||||||
[variables]: {{rootUrl}}/language/variables.md
|
[variables]: {{rootUrl}}/language/variables.md
|
||||||
|
|
||||||
@ -63,9 +66,9 @@
|
|||||||
[function]: {{rootUrl}}/language/functions.md
|
[function]: {{rootUrl}}/language/functions.md
|
||||||
[functions]: {{rootUrl}}/language/functions.md
|
[functions]: {{rootUrl}}/language/functions.md
|
||||||
|
|
||||||
[`Module`]: {{rootUrl}}/language/modules.md
|
[`Module`]: {{rootUrl}}/language/modules/index.md
|
||||||
[module]: {{rootUrl}}/language/modules.md
|
[module]: {{rootUrl}}/language/modules/index.md
|
||||||
[modules]: {{rootUrl}}/language/modules.md
|
[modules]: {{rootUrl}}/language/modules/index.md
|
||||||
[`export`]: {{rootUrl}}/language/modules/export.md
|
[`export`]: {{rootUrl}}/language/modules/export.md
|
||||||
[`import`]: {{rootUrl}}/language/modules/import.md
|
[`import`]: {{rootUrl}}/language/modules/import.md
|
||||||
|
|
||||||
@ -80,7 +83,7 @@
|
|||||||
[maximum size of object maps]: {{rootUrl}}/safety/max-map-size.md
|
[maximum size of object maps]: {{rootUrl}}/safety/max-map-size.md
|
||||||
[progress]:/safety/progress.md
|
[progress]:/safety/progress.md
|
||||||
|
|
||||||
[script optimization]: {{rootUrl}}/engine/optimize.md
|
[script optimization]: {{rootUrl}}/engine/optimize/index.md
|
||||||
[`OptimizationLevel::Full`]: {{rootUrl}}/engine/optimize/optimize-levels.md
|
[`OptimizationLevel::Full`]: {{rootUrl}}/engine/optimize/optimize-levels.md
|
||||||
[`OptimizationLevel::Simple`]: {{rootUrl}}/engine/optimize/optimize-levels.md
|
[`OptimizationLevel::Simple`]: {{rootUrl}}/engine/optimize/optimize-levels.md
|
||||||
[`OptimizationLevel::None`]: {{rootUrl}}/engine/optimize/optimize-levels.md
|
[`OptimizationLevel::None`]: {{rootUrl}}/engine/optimize/optimize-levels.md
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
Packages
|
Packages
|
||||||
========
|
========
|
||||||
|
|
||||||
{{#include ../links.md}}
|
{{#include ../../links.md}}
|
||||||
|
|
||||||
Standard built-in Rhai features are provided in various _packages_ that can be loaded via a call to `Engine::load_package`.
|
Standard built-in Rhai features are provided in various _packages_ that can be loaded via a call to `Engine::load_package`.
|
||||||
|
|
@ -1,31 +1 @@
|
|||||||
Safety and Protection Against DoS Attacks
|
# Safety and Protection
|
||||||
========================================
|
|
||||||
|
|
||||||
{{#include links.md}}
|
|
||||||
|
|
||||||
For scripting systems open to untrusted user-land scripts, it is always best to limit the amount of
|
|
||||||
resources used by a script so that it does not consume more resources that it is allowed to.
|
|
||||||
|
|
||||||
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.
|
|
||||||
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.
|
|
||||||
|
|
||||||
* **Time**: A malicous 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.
|
|
||||||
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.
|
|
||||||
|
|
||||||
* **Overflows**: A malicous 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,
|
|
||||||
thereby putting heavy load on the file-system (or even the network if the file is not local).
|
|
||||||
Furthermore, the module script may simply [`import`] itself in an infinite recursion.
|
|
||||||
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,
|
|
||||||
it is a severe security breach and may put the entire system at risk.
|
|
||||||
|
35
doc/src/safety/index.md
Normal file
35
doc/src/safety/index.md
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
Safety and Protection Against DoS Attacks
|
||||||
|
========================================
|
||||||
|
|
||||||
|
{{#include ../links.md}}
|
||||||
|
|
||||||
|
For scripting systems open to untrusted user-land scripts, it is always best to limit the amount of
|
||||||
|
resources used by a script so that it does not consume more resources that it is allowed to.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
* **Time**: A malicous 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.
|
||||||
|
|
||||||
|
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
|
||||||
|
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,
|
||||||
|
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,
|
||||||
|
it is a severe security breach and may put the entire system at risk.
|
@ -10,6 +10,9 @@ of modules to zero does _not_ indicate unlimited modules, but disallows loading
|
|||||||
|
|
||||||
A script attempting to load more than the maximum number of modules will terminate with an error result.
|
A script attempting to load more than the maximum number of modules will terminate with an error result.
|
||||||
|
|
||||||
|
This limit can also be used to stop [`import`-loops]({{rootUrl}}/language/modules/import.md)
|
||||||
|
(i.e. cycles of modules referring to each other).
|
||||||
|
|
||||||
This check can be disabled via the [`unchecked`] feature for higher performance
|
This check can be disabled via the [`unchecked`] feature for higher performance
|
||||||
(but higher risks as well).
|
(but higher risks as well).
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
Special Builds
|
Special Builds
|
||||||
==============
|
==============
|
||||||
|
|
||||||
{{#include ../links.md}}
|
{{#include ../../links.md}}
|
||||||
|
|
||||||
It is possible to mix-and-match various [features] of the Rhai crate to make
|
It is possible to mix-and-match various [features] of the Rhai crate to make
|
||||||
specialized builds with specific characteristics and behaviors.
|
specialized builds with specific characteristics and behaviors.
|
@ -1,7 +1,7 @@
|
|||||||
Examples
|
Examples
|
||||||
========
|
========
|
||||||
|
|
||||||
{{#include ../links.md}}
|
{{#include ../../links.md}}
|
||||||
|
|
||||||
Rhai comes with a number of examples showing how to integrate the scripting [`Engine`] within
|
Rhai comes with a number of examples showing how to integrate the scripting [`Engine`] within
|
||||||
a Rust application, as well as a number of sample scripts that showcase different Rhai language features.
|
a Rust application, as well as a number of sample scripts that showcase different Rhai language features.
|
@ -4,10 +4,12 @@ Optional Features
|
|||||||
{{#include ../links.md}}
|
{{#include ../links.md}}
|
||||||
|
|
||||||
By default, Rhai includes all the standard functionalities in a small, tight package.
|
By default, Rhai includes all the standard functionalities in a small, tight package.
|
||||||
Most features are here to opt-**out** of certain functionalities that are not needed.
|
|
||||||
|
|
||||||
Excluding unneeded functionalities can result in smaller, faster builds
|
Most features are here to opt-**out** of certain functionalities that are not needed.
|
||||||
as well as more control over what a script can (or cannot) do.
|
Notice that this deviates from Rust norm where features are _additive_.
|
||||||
|
|
||||||
|
Excluding unneeded functionalities can result in smaller, faster builds as well as
|
||||||
|
more control over what a script can (or cannot) do.
|
||||||
|
|
||||||
| Feature | Description |
|
| Feature | Description |
|
||||||
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||||
@ -38,7 +40,7 @@ The `Cargo.toml` configuration below turns on these six features:
|
|||||||
|
|
||||||
```toml
|
```toml
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rhai = { version = "0.15.2", features = [ "sync", "unchecked", "only_i32", "no_float", "no_module", "no_function" ] }
|
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`),
|
The resulting scripting engine supports only the `i32` integer numeral type (and no others like `u32` or `i16`),
|
||||||
|
@ -3,15 +3,15 @@ Install the Rhai Crate
|
|||||||
|
|
||||||
{{#include ../links.md}}
|
{{#include ../links.md}}
|
||||||
|
|
||||||
Install the Rhai crate from [`crates.io`](https:/crates.io/crates/rhai/) by adding this line
|
Install the Rhai crate from [`crates.io`](https:/crates.io/crates/rhai/), start by looking up the
|
||||||
under `dependencies` in `Cargo.toml`:
|
latest version and adding this line under `dependencies` in `Cargo.toml`:
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rhai = "0.15.2"
|
rhai = "{{version}}" # assuming {{version}} is the latest version
|
||||||
```
|
```
|
||||||
|
|
||||||
Use the latest released crate version on [`crates.io`](https:/crates.io/crates/rhai/):
|
Or to automatically use the latest released crate version on [`crates.io`](https:/crates.io/crates/rhai/):
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
@ -44,13 +44,13 @@ fn test_side_effects_command() -> Result<(), Box<EvalAltResult>> {
|
|||||||
let mut engine = Engine::new();
|
let mut engine = Engine::new();
|
||||||
let mut scope = Scope::new();
|
let mut scope = Scope::new();
|
||||||
|
|
||||||
// Create the command object with initial state, handled by an `Rc`.
|
// Create the command object with initial state, handled by an `Arc`.
|
||||||
let command = Arc::new(Mutex::new(Command { state: 12 }));
|
let command = Arc::new(Mutex::new(Command { state: 12 }));
|
||||||
assert_eq!(command.lock().unwrap().get(), 12);
|
assert_eq!(command.lock().unwrap().get(), 12);
|
||||||
|
|
||||||
// Create the wrapper.
|
// Create the wrapper.
|
||||||
let wrapper = CommandWrapper {
|
let wrapper = CommandWrapper {
|
||||||
command: command.clone(), // Notice this clones the `Rc` only
|
command: command.clone(), // Notice this clones the `Arc` only
|
||||||
};
|
};
|
||||||
|
|
||||||
// Make the wrapper a singleton in the script environment.
|
// Make the wrapper a singleton in the script environment.
|
||||||
|
Loading…
Reference in New Issue
Block a user