Edit documentation.
This commit is contained in:
parent
7cc1a3f5dc
commit
d728ac6758
@ -42,4 +42,4 @@ Features
|
||||
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)
|
||||
1. [Install the Rhai Crate](start/install.md)
|
||||
2. [Optional Features](start/features.md)
|
||||
3. [Special Builds](start/builds.md)
|
||||
1. [Performance Build](start/builds/performance.md)
|
||||
2. [Minimal Build](start/builds/minimal.md)
|
||||
3. [no-std Build](start/builds/no-std.md)
|
||||
3. [Special Builds](start/builds/index.md)
|
||||
1. [Performance](start/builds/performance.md)
|
||||
2. [Minimal](start/builds/minimal.md)
|
||||
3. [no-std](start/builds/no-std.md)
|
||||
4. [WebAssembly (WASM)](start/builds/wasm.md)
|
||||
4. [Examples](start/examples.md)
|
||||
4. [Examples](start/examples/index.md)
|
||||
1. [Rust](start/examples/rust.md)
|
||||
2. [Scripts](start/examples/scripts.md)
|
||||
3. [Using the `Engine`](engine.md)
|
||||
@ -30,7 +30,7 @@ The Rhai Scripting Language
|
||||
1. [String Parameters in Rust Functions](rust/strings.md)
|
||||
3. [Register a Generic Rust Function](rust/generic.md)
|
||||
4. [Register a Fallible Rust Function](rust/fallible.md)
|
||||
5. [Packages](rust/packages.md)
|
||||
5. [Packages](rust/packages/index.md)
|
||||
1. [Built-in Packages](rust/packages/builtin.md)
|
||||
2. [Create a Custom Package](rust/packages/create.md)
|
||||
6. [Override a Built-in Function](rust/override.md)
|
||||
@ -72,14 +72,14 @@ The Rhai Scripting Language
|
||||
1. [Function Overloading](language/overload.md)
|
||||
2. [Call Method as Function](language/method.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)
|
||||
2. [Import Modules](language/modules/import.md)
|
||||
3. [Create from Rust](language/modules/rust.md)
|
||||
4. [Create from AST](language/modules/ast.md)
|
||||
5. [Module Resolvers](language/modules/resolvers.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)
|
||||
2. [Sand-Boxing](safety/sandbox.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)
|
||||
9. [Maximum Statement Depth](safety/max-stmt-depth.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)
|
||||
2. [Re-Optimize an AST](engine/optimize/reoptimize.md)
|
||||
3. [Eager Function Evaluation](engine/optimize/eager.md)
|
||||
@ -99,3 +99,7 @@ The Rhai Scripting Language
|
||||
5. [Volatility Considerations](engine/optimize/volatility.md)
|
||||
6. [Subtle Semantic Changes](engine/optimize/semantics.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:
|
||||
|
||||
* [`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:
|
||||
|
||||
|
@ -7,4 +7,4 @@ This section covers advanced features such as:
|
||||
|
||||
* [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": "",
|
||||
"rootUrlX": "/rhai"
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
Script Optimization
|
||||
===================
|
||||
|
||||
{{#include ../links.md}}
|
||||
{{#include ../../links.md}}
|
||||
|
||||
Rhai includes an _optimizer_ that tries to optimize a script after parsing.
|
||||
This can reduce resource utilization and increase execution speed.
|
@ -3,10 +3,7 @@ Optimization Levels
|
||||
|
||||
{{#include ../../links.md}}
|
||||
|
||||
Set Optimization Level
|
||||
---------------------
|
||||
|
||||
There are actually three levels of optimizations: `None`, `Simple` and `Full`.
|
||||
There are three levels of optimization: `None`, `Simple` and `Full`.
|
||||
|
||||
* `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.
|
||||
One benefit to this is that many more optimization opportunities arise, especially with regards to comparison operators.
|
||||
|
||||
|
||||
Set Optimization Level
|
||||
---------------------
|
||||
|
||||
An [`Engine`]'s optimization level is set via a call to `Engine::set_optimization_level`:
|
||||
|
||||
```rust
|
||||
|
@ -3,15 +3,38 @@ Re-Optimize an AST
|
||||
|
||||
{{#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
|
||||
// Compile script to AST
|
||||
let ast = engine.compile("40 + 2")?;
|
||||
// Compile master script to AST
|
||||
let master_ast = engine.compile(
|
||||
r"
|
||||
if SCENARIO_1 {
|
||||
do_work();
|
||||
} else if SCENARIO_2 {
|
||||
do_something();
|
||||
} else if SCENARIO_3 {
|
||||
do_something_else();
|
||||
} else {
|
||||
do_nothing();
|
||||
}
|
||||
")?;
|
||||
|
||||
// Create a new 'Scope' - put constants in it to aid optimization if using 'OptimizationLevel::Full'
|
||||
let scope = Scope::new();
|
||||
// Create a new 'Scope' - put constants in it to aid optimization
|
||||
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
|
||||
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
|
||||
```
|
||||
|
||||
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
|
||||
const x = 40 + 2; // <- syntax error: cannot assign expression to constant
|
||||
|
@ -6,7 +6,7 @@
|
||||
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
|
||||
let x = 10;
|
||||
|
@ -5,6 +5,9 @@
|
||||
|
||||
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
|
||||
// Iterate through string, yielding characters
|
||||
let s = "hello, world!";
|
||||
@ -41,14 +44,14 @@ for x in range(0, 50, 3) { // step by 3
|
||||
// Iterate through object map
|
||||
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) {
|
||||
if x > 10 { continue; } // skip to the next iteration
|
||||
print(x);
|
||||
if x == 42 { break; } // break out of for loop
|
||||
}
|
||||
|
||||
// Property values are returned in random order
|
||||
// Property values are returned in unsorted, random order
|
||||
for val in values(map) {
|
||||
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
|
||||
```
|
||||
|
||||
|
||||
Implicit Return
|
||||
---------------
|
||||
|
||||
@ -38,6 +39,7 @@ print(add(2, 3)); // prints 5
|
||||
print(add2(42)); // prints 44
|
||||
```
|
||||
|
||||
|
||||
No Access to External Scope
|
||||
--------------------------
|
||||
|
||||
@ -50,13 +52,15 @@ let x = 42;
|
||||
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).
|
||||
It is important to remember that all arguments are passed by _value_, so all functions are _pure_
|
||||
(i.e. they never modify their arguments).
|
||||
Therefore, functions with the same name and same _number_ of parameters are equivalent.
|
||||
|
||||
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.
|
||||
|
||||
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!
|
||||
```
|
||||
|
||||
|
||||
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.
|
||||
This is similar to Rust and many other modern languages.
|
||||
|
||||
Use Before Definition
|
||||
--------------------
|
||||
|
||||
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}}
|
||||
|
||||
`if` statements follow C syntax:
|
||||
|
||||
```rust
|
||||
if foo(x) {
|
||||
print("It's true!");
|
||||
} else if bar == baz {
|
||||
print("It's true again!");
|
||||
} else if ... {
|
||||
:
|
||||
} else if ... {
|
||||
:
|
||||
} else if baz.is_foo() {
|
||||
print("Yet again true.");
|
||||
} else if foo(bar - baz) {
|
||||
print("True again... this is getting boring.");
|
||||
} else {
|
||||
print("It's finally false!");
|
||||
}
|
||||
```
|
||||
|
||||
All branches of an `if` statement must be enclosed within braces '`{`' .. '`}`', even when there is only one statement.
|
||||
Like Rust, there is no ambiguity regarding which `if` clause a statement belongs to.
|
||||
Unlike C, the condition expression does _not_ need to be enclosed in parentheses '`(`' .. '`)`', but
|
||||
all branches of the `if` statement must be enclosed within braces '`{`' .. '`}`',
|
||||
even when there is only one statement inside the branch.
|
||||
|
||||
Like Rust, there is no ambiguity regarding which `if` clause a branch belongs to.
|
||||
|
||||
```rust
|
||||
// Rhai is not C!
|
||||
if (decision) print("I've decided!");
|
||||
// ^ syntax error, expecting '{' in statement block
|
||||
```
|
||||
|
@ -3,6 +3,11 @@ Infinite `loop`
|
||||
|
||||
{{#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
|
||||
let x = 10;
|
||||
|
||||
@ -13,3 +18,6 @@ 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}}
|
||||
|
||||
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_),
|
||||
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.
|
||||
|
||||
```rust
|
||||
@ -21,8 +26,8 @@ update(a); // <- this de-sugars to 'a.update()' thus if 'a' is a simple
|
||||
let array = [ a ];
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
=======
|
||||
|
||||
{{#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.
|
||||
# Modules
|
||||
|
@ -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,
|
||||
not in the file system.
|
||||
|
||||
A module resolver must implement the trait `rhai::ModuleResolver`, which contains only one function:
|
||||
`resolve`.
|
||||
A module resolver must implement the trait [`rhai::ModuleResolver`]({{rootUrl}}/rust/traits.md),
|
||||
which contains only one function: `resolve`.
|
||||
|
||||
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
|
||||
|
@ -3,6 +3,9 @@ Import a Module
|
||||
|
||||
{{#include ../../links.md}}
|
||||
|
||||
`import` Statement
|
||||
-----------------
|
||||
|
||||
A module can be _imported_ via the `import` statement, and its members are accessed via '`::`' similar to C++.
|
||||
|
||||
```rust
|
||||
@ -17,10 +20,14 @@ print(lock::status); // module variables are constants
|
||||
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.
|
||||
|
||||
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™_.
|
||||
|
||||
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);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
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}}
|
||||
|
||||
The `return` statement is used to immediately stop evaluation and exist the current context
|
||||
(typically a function call) yielding a _return value_.
|
||||
|
||||
```rust
|
||||
return; // equivalent to return ();
|
||||
|
||||
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}}
|
||||
|
||||
Terminated by '`;`'
|
||||
------------------
|
||||
|
||||
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.
|
||||
|
||||
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 [`()`].
|
||||
Semicolons can also be omitted if the statement contains a block itself
|
||||
(e.g. the `if`, `while`, `for` and `loop` statements).
|
||||
|
||||
```rust
|
||||
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)
|
||||
// ^ 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
|
||||
```
|
||||
|
||||
|
||||
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}}
|
||||
|
||||
Valid Names
|
||||
-----------
|
||||
|
||||
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,
|
||||
@ -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.
|
||||
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
|
||||
let x; // ok - value is '()'
|
||||
let x = 3; // ok
|
||||
let _x = 42; // ok
|
||||
let x_ = 42; // also ok
|
||||
|
@ -3,6 +3,11 @@
|
||||
|
||||
{{#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
|
||||
let x = 10;
|
||||
|
||||
|
@ -23,8 +23,8 @@
|
||||
[`eval_expression_with_scope`]: {{rootUrl}}/engine/expressions.md
|
||||
[raw `Engine`]: {{rootUrl}}/engine/raw.md
|
||||
[built-in operators]: {{rootUrl}}/engine/raw.md#built-in-operators
|
||||
[package]: {{rootUrl}}/rust/packages.md
|
||||
[packages]: {{rootUrl}}/rust/packages.md
|
||||
[package]: {{rootUrl}}/rust/packages/index.md
|
||||
[packages]: {{rootUrl}}/rust/packages/index.md
|
||||
[`Scope`]: {{rootUrl}}/rust/scope.md
|
||||
|
||||
[`type_of()`]: {{rootUrl}}/language/type-of.md
|
||||
@ -41,6 +41,9 @@
|
||||
[`print`]: {{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
|
||||
[variables]: {{rootUrl}}/language/variables.md
|
||||
|
||||
@ -63,9 +66,9 @@
|
||||
[function]: {{rootUrl}}/language/functions.md
|
||||
[functions]: {{rootUrl}}/language/functions.md
|
||||
|
||||
[`Module`]: {{rootUrl}}/language/modules.md
|
||||
[module]: {{rootUrl}}/language/modules.md
|
||||
[modules]: {{rootUrl}}/language/modules.md
|
||||
[`Module`]: {{rootUrl}}/language/modules/index.md
|
||||
[module]: {{rootUrl}}/language/modules/index.md
|
||||
[modules]: {{rootUrl}}/language/modules/index.md
|
||||
[`export`]: {{rootUrl}}/language/modules/export.md
|
||||
[`import`]: {{rootUrl}}/language/modules/import.md
|
||||
|
||||
@ -80,7 +83,7 @@
|
||||
[maximum size of object maps]: {{rootUrl}}/safety/max-map-size.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::Simple`]: {{rootUrl}}/engine/optimize/optimize-levels.md
|
||||
[`OptimizationLevel::None`]: {{rootUrl}}/engine/optimize/optimize-levels.md
|
||||
|
@ -1,7 +1,7 @@
|
||||
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`.
|
||||
|
@ -1,31 +1 @@
|
||||
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.
|
||||
|
||||
* **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.
|
||||
# Safety and Protection
|
||||
|
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.
|
||||
|
||||
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
|
||||
(but higher risks as well).
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
Special Builds
|
||||
==============
|
||||
|
||||
{{#include ../links.md}}
|
||||
{{#include ../../links.md}}
|
||||
|
||||
It is possible to mix-and-match various [features] of the Rhai crate to make
|
||||
specialized builds with specific characteristics and behaviors.
|
@ -1,7 +1,7 @@
|
||||
Examples
|
||||
========
|
||||
|
||||
{{#include ../links.md}}
|
||||
{{#include ../../links.md}}
|
||||
|
||||
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.
|
@ -4,10 +4,12 @@ Optional Features
|
||||
{{#include ../links.md}}
|
||||
|
||||
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
|
||||
as well as more control over what a script can (or cannot) do.
|
||||
Most features are here to opt-**out** of certain functionalities that are not needed.
|
||||
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 |
|
||||
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
@ -38,7 +40,7 @@ The `Cargo.toml` configuration below turns on these six features:
|
||||
|
||||
```toml
|
||||
[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`),
|
||||
|
@ -3,15 +3,15 @@ Install the Rhai Crate
|
||||
|
||||
{{#include ../links.md}}
|
||||
|
||||
Install the Rhai crate from [`crates.io`](https:/crates.io/crates/rhai/) by adding this line
|
||||
under `dependencies` in `Cargo.toml`:
|
||||
Install the Rhai crate from [`crates.io`](https:/crates.io/crates/rhai/), start by looking up the
|
||||
latest version and adding this line under `dependencies` in `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[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
|
||||
[dependencies]
|
||||
|
@ -44,13 +44,13 @@ fn test_side_effects_command() -> Result<(), Box<EvalAltResult>> {
|
||||
let mut engine = Engine::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 }));
|
||||
assert_eq!(command.lock().unwrap().get(), 12);
|
||||
|
||||
// Create the wrapper.
|
||||
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.
|
||||
|
Loading…
Reference in New Issue
Block a user