Improve writeup.
This commit is contained in:
parent
353df6bea1
commit
5e48478496
@ -73,7 +73,7 @@ Licensed under either:
|
||||
* [Apache License, Version 2.0](https://github.com/jonathandturner/rhai/blob/master/LICENSE-APACHE.txt), or
|
||||
* [MIT license](https://github.com/jonathandturner/rhai/blob/master/LICENSE-MIT.txt)
|
||||
|
||||
at your option.
|
||||
at your choice.
|
||||
|
||||
Unless explicitly stated otherwise, any contribution intentionally submitted
|
||||
for inclusion in this crate, as defined in the Apache-2.0 license, shall
|
||||
|
@ -21,7 +21,7 @@ The Rhai Scripting Language
|
||||
2. [Scripts](start/examples/scripts.md)
|
||||
3. [Using the `Engine`](engine/index.md)
|
||||
1. [Hello World in Rhai - Evaluate a Script](engine/hello-world.md)
|
||||
2. [Compile a Script to AST for Repeated Evaluations](engine/compile.md)
|
||||
2. [Compile to AST for Repeated Evaluations](engine/compile.md)
|
||||
3. [Call a Rhai Function from Rust](engine/call-fn.md)
|
||||
4. [Create a Rust Anonymous Function from a Rhai Function](engine/func.md)
|
||||
5. [Evaluate Expressions Only](engine/expressions.md)
|
||||
@ -65,21 +65,22 @@ The Rhai Scripting Language
|
||||
5. [Variables](language/variables.md)
|
||||
6. [Constants](language/constants.md)
|
||||
7. [Logic Operators](language/logic.md)
|
||||
8. [If Statement](language/if.md)
|
||||
9. [While Loop](language/while.md)
|
||||
10. [Loop Statement](language/loop.md)
|
||||
11. [For Loop](language/for.md)
|
||||
12. [Return Values](language/return.md)
|
||||
13. [Throw Exception on Error](language/throw.md)
|
||||
14. [Functions](language/functions.md)
|
||||
8. [Other Operators](language/other-op.md)
|
||||
9. [If Statement](language/if.md)
|
||||
10. [While Loop](language/while.md)
|
||||
11. [Loop Statement](language/loop.md)
|
||||
12. [For Loop](language/for.md)
|
||||
13. [Return Values](language/return.md)
|
||||
14. [Throw Exception on Error](language/throw.md)
|
||||
15. [Functions](language/functions.md)
|
||||
1. [Call Method as Function](language/method.md)
|
||||
2. [Overloading](language/overload.md)
|
||||
3. [Namespaces](language/fn-namespaces.md)
|
||||
4. [Function Pointers](language/fn-ptr.md)
|
||||
5. [Anonymous Functions](language/fn-anon.md)
|
||||
6. [Currying](language/fn-curry.md)
|
||||
15. [Print and Debug](language/print-debug.md)
|
||||
16. [Modules](language/modules/index.md)
|
||||
16. [Print and Debug](language/print-debug.md)
|
||||
17. [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](rust/modules/index.md)
|
||||
|
@ -7,6 +7,9 @@ Rhai is an embedded scripting language and evaluation engine for Rust that gives
|
||||
to add scripting to any application.
|
||||
|
||||
|
||||
This Book is for version {{version}} of Rhai.
|
||||
Versions
|
||||
--------
|
||||
|
||||
This Book is for version **{{version}}** of Rhai.
|
||||
|
||||
For the latest development version, see [here]({{rootUrl}}/vnext/).
|
||||
|
@ -6,9 +6,10 @@ Licensing
|
||||
Rhai is licensed under either:
|
||||
|
||||
* [Apache License, Version 2.0]({{repoHome}}/LICENSE-APACHE.txt), or
|
||||
|
||||
* [MIT license]({{repoHome}}/LICENSE-MIT.txt)
|
||||
|
||||
at your option.
|
||||
at your choice.
|
||||
|
||||
Unless explicitly stated otherwise, any contribution intentionally submitted for inclusion in this crate,
|
||||
as defined in the Apache-2.0 license, shall be dual-licensed as above,
|
||||
|
@ -18,21 +18,38 @@ It doesn't attempt to be a new language. For example:
|
||||
|
||||
* No first-class functions - Code your functions in Rust instead, and register them with Rhai.
|
||||
|
||||
There is, however, support for simple [function pointers] allowing runtime dispatch by function name.
|
||||
There is, however, support for simple [function pointers] to allow runtime dispatch by function name.
|
||||
|
||||
* No garbage collection - this should be expected, so...
|
||||
|
||||
* No closures - do your closure magic in Rust instead; [turn a Rhai scripted function into a Rust closure]({{rootUrl}}/engine/call-fn.md).
|
||||
|
||||
But you can [curry][currying] a [function pointer] with arguments to simulate it somewhat.
|
||||
|
||||
* No byte-codes/JIT - Rhai has an AST-walking interpreter which will not win any speed races. The purpose of Rhai is not
|
||||
to be extremely _fast_, but to make it as easy as possible to integrate with native Rust applications.
|
||||
|
||||
|
||||
Do Not Write The Next 4D VR Game in Rhai
|
||||
---------------------------------------
|
||||
|
||||
Due to this intended usage, Rhai deliberately keeps the language simple and small by omitting advanced language features
|
||||
such as classes, inheritance, first-class functions, closures, concurrency, byte-codes, JIT etc.
|
||||
|
||||
Avoid the temptation to write full-fledge application logic entirely in Rhai - that use case is best fulfilled by
|
||||
more complete languages such as JavaScript or Lua.
|
||||
|
||||
Therefore, in actual practice, it is usually best to expose a Rust API into Rhai for scripts to call.
|
||||
All your core functionalities should be in Rust.
|
||||
|
||||
Thin Dynamic Wrapper Layer Over Rust Code
|
||||
----------------------------------------
|
||||
|
||||
In actual practice, it is usually best to expose a Rust API into Rhai for scripts to call.
|
||||
|
||||
All the core functionalities should be written in Rust, with Rhai being the dynamic _control_ layer.
|
||||
|
||||
This is similar to some dynamic languages where most of the core functionalities reside in a C/C++ standard library.
|
||||
|
||||
Another similar scenario is a web front-end driving back-end services written in a systems language.
|
||||
In this case, JavaScript takes the role of Rhai while the back-end language, well... it can actually also be Rust.
|
||||
Except that Rhai integrates with Rust _much_ more tightly, removing the need for interfaces such
|
||||
as XHR calls and payload encoding such as JSON.
|
||||
|
@ -5,7 +5,7 @@ Advanced Topics
|
||||
|
||||
This section covers advanced features such as:
|
||||
|
||||
* Simulated [Object Oriented Programming][OOP].
|
||||
* Simulated [Object Oriented Programming (OOP)][OOP].
|
||||
|
||||
* [`serde`] integration.
|
||||
|
||||
@ -13,4 +13,6 @@ This section covers advanced features such as:
|
||||
|
||||
* [Domain-Specific Languages][DSL].
|
||||
|
||||
* Low-level [function registration API]({{rootUrl}}/rust/register-raw.md)
|
||||
|
||||
* The dreaded (or beloved for those with twisted tastes) [`eval`] statement.
|
||||
|
@ -22,19 +22,31 @@ fn main() -> Result<(), Box<EvalAltResult>>
|
||||
}
|
||||
```
|
||||
|
||||
`rhai::EvalAltResult` is a Rust `enum` containing all errors encountered during the parsing or evaluation process.
|
||||
Evaluate a script file directly:
|
||||
|
||||
```rust
|
||||
// 'eval_file' takes a 'PathBuf'
|
||||
let result = engine.eval_file::<i64>("hello_world.rhai".into())?;
|
||||
```
|
||||
|
||||
|
||||
Evaluate a Script
|
||||
----------------
|
||||
Error Type
|
||||
----------
|
||||
|
||||
The type parameter is used to specify the type of the return value, which _must_ match the actual type or an error is returned.
|
||||
Rhai is very strict here.
|
||||
`rhai::EvalAltResult` is the standard Rhai error type, which is a Rust `enum` containing all errors encountered
|
||||
during the parsing or evaluation process.
|
||||
|
||||
Use [`Dynamic`] for uncertain return types.
|
||||
|
||||
Return Type
|
||||
-----------
|
||||
|
||||
The type parameter for `Engine::eval` is used to specify the type of the return value,
|
||||
which _must_ match the actual type or an error is returned. Rhai is very strict here.
|
||||
|
||||
There are two ways to specify the return type - _turbofish_ notation, or type inference.
|
||||
|
||||
Use [`Dynamic`] for uncertain return types.
|
||||
|
||||
```rust
|
||||
let result = engine.eval::<i64>("40 + 2")?; // return type is i64, specified using 'turbofish' notation
|
||||
|
||||
@ -46,9 +58,3 @@ let result: Dynamic = engine.eval("boo()")?; // use 'Dynamic' if you're not s
|
||||
|
||||
let result = engine.eval::<String>("40 + 2")?; // returns an error because the actual return type is i64, not String
|
||||
```
|
||||
|
||||
Evaluate a script file directly:
|
||||
|
||||
```rust
|
||||
let result = engine.eval_file::<i64>("hello_world.rhai".into())?; // 'eval_file' takes a 'PathBuf'
|
||||
```
|
||||
|
@ -10,7 +10,10 @@ In many controlled embedded environments, however, these may not be needed and u
|
||||
application code storage space.
|
||||
|
||||
Use `Engine::new_raw` to create a _raw_ `Engine`, in which only a minimal set of
|
||||
basic arithmetic and logical operators are supported.
|
||||
basic arithmetic and logical operators are supported (see below).
|
||||
|
||||
To add more functionalities to a _raw_ `Engine`, load [packages] into it.
|
||||
|
||||
|
||||
Built-in Operators
|
||||
------------------
|
||||
@ -20,7 +23,7 @@ Built-in Operators
|
||||
| `+`, | `+=` | `INT`, `FLOAT` (if not [`no_float`]), `ImmutableString` |
|
||||
| `-`, `*`, `/`, `%`, `~`, | `-=`, `*=`, `/=`, `%=`, `~=` | `INT`, `FLOAT` (if not [`no_float`]) |
|
||||
| `<<`, `>>`, `^`, | `<<=`, `>>=`, `^=` | `INT` |
|
||||
| `&`, `|`, | `&=`, `|=` | `INT`, `bool` |
|
||||
| `&&`, `||` | | `bool` |
|
||||
| `&`, <code>\|</code>, | `&=`, <code>\|=</code> | `INT`, `bool` |
|
||||
| `&&`, <code>\|\|</code> | | `bool` |
|
||||
| `==`, `!=` | | `INT`, `FLOAT` (if not [`no_float`]), `bool`, `char`, `()`, `ImmutableString` |
|
||||
| `>`, `>=`, `<`, `<=` | | `INT`, `FLOAT` (if not [`no_float`]), `char`, `()`, `ImmutableString` |
|
||||
|
@ -3,7 +3,8 @@
|
||||
|
||||
{{#include ../links.md}}
|
||||
|
||||
Iterating through a range or an [array] is provided by the `for` ... `in` loop.
|
||||
Iterating through a range or an [array], or any type with a registered _iterator_,
|
||||
is provided by the `for` ... `in` loop.
|
||||
|
||||
Like C, `continue` can be used to skip to the next iteration, by-passing all following statements;
|
||||
`break` can be used to break out of the loop unconditionally.
|
||||
|
@ -19,6 +19,9 @@ if foo(x) {
|
||||
}
|
||||
```
|
||||
|
||||
Braces Are Mandatory
|
||||
--------------------
|
||||
|
||||
Unlike C, the condition expression does _not_ need to be enclosed in parentheses '`(`' .. '`)`', but
|
||||
all branches of the `if` statement must be enclosed within braces '`{`' .. '`}`',
|
||||
even when there is only one statement inside the branch.
|
||||
|
@ -65,42 +65,3 @@ a() | b(); // both a() and b() are evaluated
|
||||
|
||||
a() & b(); // both a() and b() are evaluated
|
||||
```
|
||||
|
||||
Compound Assignment Operators
|
||||
----------------------------
|
||||
|
||||
```rust
|
||||
let number = 9;
|
||||
|
||||
number += 8; // number = number + 8
|
||||
|
||||
number -= 7; // number = number - 7
|
||||
|
||||
number *= 6; // number = number * 6
|
||||
|
||||
number /= 5; // number = number / 5
|
||||
|
||||
number %= 4; // number = number % 4
|
||||
|
||||
number ~= 3; // number = number ~ 3
|
||||
|
||||
number <<= 2; // number = number << 2
|
||||
|
||||
number >>= 1; // number = number >> 1
|
||||
|
||||
number &= 0x00ff; // number = number & 0x00ff;
|
||||
|
||||
number |= 0x00ff; // number = number | 0x00ff;
|
||||
|
||||
number ^= 0x00ff; // number = number ^ 0x00ff;
|
||||
```
|
||||
|
||||
The `+=` operator can also be used to build [strings]:
|
||||
|
||||
```rust
|
||||
let my_str = "abc";
|
||||
my_str += "ABC";
|
||||
my_str += 12345;
|
||||
|
||||
my_str == "abcABC12345"
|
||||
```
|
||||
|
@ -4,8 +4,8 @@ Call Method as Function
|
||||
{{#include ../links.md}}
|
||||
|
||||
|
||||
First `&mut` Reference Parameter
|
||||
-------------------------------
|
||||
First `&mut` Parameter
|
||||
----------------------
|
||||
|
||||
Property [getters/setters] and [methods][custom types] 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
|
||||
@ -37,19 +37,20 @@ array[0].update(); // <- call in method-call style will update 'a'
|
||||
```
|
||||
|
||||
|
||||
Encouraged Usage
|
||||
----------------
|
||||
`&mut` is Efficient
|
||||
------------------
|
||||
|
||||
Using a `&mut` first parameter is highly encouraged when using types that are expensive to clone,
|
||||
even when the intention is not to mutate that argument, because it avoids cloning that argument value.
|
||||
|
||||
For primary types that are cheap to clone, including `ImmutableString`, this is not necessary.
|
||||
For primary types that are cheap to clone (e.g. those that implement `Copy`),
|
||||
including `ImmutableString`, this is not necessary.
|
||||
|
||||
|
||||
Avoid `&mut ImmutableString`
|
||||
---------------------------
|
||||
|
||||
`ImmutableString`, Rhai internal [string] type, is an exception.
|
||||
`ImmutableString`, Rhai's internal [string] type, is an exception.
|
||||
|
||||
`ImmutableString` is cheap to clone, but expensive to take a mutable reference (because the underlying
|
||||
string must be cloned to make a private copy).
|
||||
|
66
doc/src/language/other-op.md
Normal file
66
doc/src/language/other-op.md
Normal file
@ -0,0 +1,66 @@
|
||||
Other Operators
|
||||
===============
|
||||
|
||||
{{#include ../links.md}}
|
||||
|
||||
|
||||
Compound Assignment Operators
|
||||
----------------------------
|
||||
|
||||
```rust
|
||||
let number = 9;
|
||||
|
||||
number += 8; // number = number + 8
|
||||
|
||||
number -= 7; // number = number - 7
|
||||
|
||||
number *= 6; // number = number * 6
|
||||
|
||||
number /= 5; // number = number / 5
|
||||
|
||||
number %= 4; // number = number % 4
|
||||
|
||||
number ~= 3; // number = number ~ 3
|
||||
|
||||
number <<= 2; // number = number << 2
|
||||
|
||||
number >>= 1; // number = number >> 1
|
||||
|
||||
number &= 0x00ff; // number = number & 0x00ff;
|
||||
|
||||
number |= 0x00ff; // number = number | 0x00ff;
|
||||
|
||||
number ^= 0x00ff; // number = number ^ 0x00ff;
|
||||
```
|
||||
|
||||
|
||||
The Flexible `+=`
|
||||
----------------
|
||||
|
||||
The `+=` operator can also be used to build [strings]:
|
||||
|
||||
```rust
|
||||
let my_str = "abc";
|
||||
my_str += "ABC";
|
||||
my_str += 12345;
|
||||
|
||||
my_str == "abcABC12345"
|
||||
```
|
||||
|
||||
It may also be used to concatenate [arrays]:
|
||||
|
||||
```rust
|
||||
let my_array = [1, 2, 3];
|
||||
my_array += [4, 5];
|
||||
|
||||
my_array == [1, 2, 3, 4, 5];
|
||||
```
|
||||
|
||||
or mix two [object maps] together:
|
||||
|
||||
```rust
|
||||
let my_obj = #{a:1, b:2};
|
||||
my_obj += #{c:3, d:4, e:5};
|
||||
|
||||
my_obj.len() == 5;
|
||||
```
|
@ -66,8 +66,8 @@ let mut engine = Engine::new();
|
||||
engine.register_type::<TestStruct>();
|
||||
```
|
||||
|
||||
Methods on Custom Type
|
||||
---------------------
|
||||
Methods on The Custom Type
|
||||
-------------------------
|
||||
|
||||
To use native custom types, methods and functions in Rhai scripts, simply register them
|
||||
using one of the `Engine::register_XXX` API.
|
||||
|
@ -30,7 +30,7 @@ impl ModuleResolver for MyModuleResolver {
|
||||
&self,
|
||||
engine: &Engine, // reference to the current 'Engine'
|
||||
path: &str, // the module path
|
||||
pos: Position, // location of the 'import' statement
|
||||
pos: Position, // position of the 'import' statement
|
||||
) -> Result<Module, Box<EvalAltResult>> {
|
||||
// Check module path.
|
||||
if is_valid_module_path(path) {
|
||||
|
@ -12,7 +12,9 @@ fn to_int(num) {
|
||||
print("Ha! Gotcha! " + num);
|
||||
}
|
||||
|
||||
print(to_int(123)); // what happens?
|
||||
let x = (123).to_int();
|
||||
|
||||
print(x); // what happens?
|
||||
```
|
||||
|
||||
A registered native Rust function, in turn, overrides any built-in function of the
|
||||
|
@ -37,8 +37,8 @@ Use `ImmutableString`
|
||||
Internally, Rhai uses _immutable_ [strings] instead of the Rust `String` type. This is mainly to avoid excessive
|
||||
cloning when passing function arguments.
|
||||
|
||||
The encapsulated immutable string type is `ImmutableString`. It is cheap to clone (just an `Rc` or `Arc` reference
|
||||
count increment depending on the [`sync`] feature).
|
||||
Rhai's internal string type is `ImmutableString` (basically `Rc<String>` or `Arc<String>` depending on the [`sync`] feature).
|
||||
It is cheap to clone, but expensive to modify (a new copy of the string must be made in order to change it).
|
||||
|
||||
Therefore, functions taking `String` parameters should use `ImmutableString` or `&str` (which maps to `ImmutableString`)
|
||||
for the best performance with Rhai.
|
||||
|
@ -25,7 +25,7 @@ more control over what a script can (or cannot) do.
|
||||
| `no_module` | Disable loading external [modules]. |
|
||||
| `no_std` | Build for `no-std`. Notice that additional dependencies will be pulled in to replace `std` features. |
|
||||
| `serde` | Enable serialization/deserialization via [`serde`]. Notice that the [`serde`](https://crates.io/crates/serde) crate will be pulled in together with its dependencies. |
|
||||
| `internals` | Expose internal data structures (e.g. [`AST`] nodes) and enable defining [custom syntax]. Beware that Rhai internals are volatile and may change from version to version. |
|
||||
| `internals` | Expose internal data structures (e.g. [`AST`] nodes). Beware that Rhai internals are volatile and may change from version to version. |
|
||||
|
||||
|
||||
Example
|
||||
@ -46,7 +46,7 @@ rhai = { version = "{{version}}", features = [ "sync", "unchecked", "only_i32",
|
||||
```
|
||||
|
||||
The resulting scripting engine supports only the `i32` integer numeral type (and no others like `u32`, `i16` or `i64`),
|
||||
no floating-point, is `Send + Sync` (so it can be safely used across threads), does not support defining [functions]
|
||||
no floating-point, is `Send + Sync` (so it can be safely used across threads), and does not support defining [functions]
|
||||
nor loading external [modules].
|
||||
|
||||
This configuration is perfect for an expression parser in a 32-bit embedded system without floating-point hardware.
|
||||
|
Loading…
Reference in New Issue
Block a user