Fix MarkDown style.

This commit is contained in:
Stephen Chung 2020-02-25 15:01:50 +08:00
parent 7893a9734b
commit 2e296ff9d7

100
README.md
View File

@ -27,44 +27,51 @@ Beware that to use pre-releases (alpha and beta) you need to specify the exact v
## Related ## Related
Other cool projects to check out: Other cool projects to check out:
* [ChaiScript](http://chaiscript.com/) - A strong inspiration for Rhai. An embedded scripting language for C++ that I helped created many moons ago, now being lead by my cousin. * [ChaiScript](http://chaiscript.com/) - A strong inspiration for Rhai. An embedded scripting language for C++ that I helped created many moons ago, now being lead by my cousin.
* You can also check out the list of [scripting languages for Rust](https://github.com/rust-unofficial/awesome-rust#scripting) on [awesome-rust](https://github.com/rust-unofficial/awesome-rust) * You can also check out the list of [scripting languages for Rust](https://github.com/rust-unofficial/awesome-rust#scripting) on [awesome-rust](https://github.com/rust-unofficial/awesome-rust)
## Examples ## Examples
The repository contains several examples in the `examples` folder: The repository contains several examples in the `examples` folder:
- `arrays_and_structs` demonstrates registering a new type to Rhai and the usage of arrays on it
- `custom_types_and_methods` shows how to register a type and methods for it * `arrays_and_structs` demonstrates registering a new type to Rhai and the usage of arrays on it
- `hello` simple example that evaluates an expression and prints the result * `custom_types_and_methods` shows how to register a type and methods for it
- `reuse_scope` evaluates two pieces of code in separate runs, but using a common scope * `hello` simple example that evaluates an expression and prints the result
- `rhai_runner` runs each filename passed to it as a Rhai script * `reuse_scope` evaluates two pieces of code in separate runs, but using a common scope
- `simple_fn` shows how to register a Rust function to a Rhai engine * `rhai_runner` runs each filename passed to it as a Rhai script
- `repl` a simple REPL, see source code for what it can do at the moment * `simple_fn` shows how to register a Rust function to a Rhai engine
* `repl` a simple REPL, see source code for what it can do at the moment
Examples can be run with the following command: Examples can be run with the following command:
```bash ```bash
cargo run --example name cargo run --example name
``` ```
## Example Scripts ## Example Scripts
We also have a few examples scripts that showcase Rhai's features, all stored in the `scripts` folder: We also have a few examples scripts that showcase Rhai's features, all stored in the `scripts` folder:
- `array.rhai` - arrays in Rhai
- `assignment.rhai` - variable declarations * `array.rhai` - arrays in Rhai
- `comments.rhai` - just comments * `assignment.rhai` - variable declarations
- `for1.rhai` - for loops * `comments.rhai` - just comments
- `function_decl1.rhai` - a function without parameters * `for1.rhai` - for loops
- `function_decl2.rhai` - a function with two parameters * `function_decl1.rhai` - a function without parameters
- `function_decl3.rhai` - a function with many parameters * `function_decl2.rhai` - a function with two parameters
- `if1.rhai` - if example * `function_decl3.rhai` - a function with many parameters
- `loop.rhai` - endless loop in Rhai, this example emulates a do..while cycle * `if1.rhai` - if example
- `op1.rhai` - just a simple addition * `loop.rhai` - endless loop in Rhai, this example emulates a do..while cycle
- `op2.rhai` - simple addition and multiplication * `op1.rhai` - just a simple addition
- `op3.rhai` - change evaluation order with parenthesis * `op2.rhai` - simple addition and multiplication
- `speed_test.rhai` - a simple program to measure the speed of Rhai's interpreter * `op3.rhai` - change evaluation order with parenthesis
- `string.rhai`- string operations * `speed_test.rhai` - a simple program to measure the speed of Rhai's interpreter
- `while.rhai` - while loop * `string.rhai`- string operations
* `while.rhai` - while loop
To run the scripts, you can either make your own tiny program, or make use of the `rhai_runner` To run the scripts, you can either make your own tiny program, or make use of the `rhai_runner`
example program: example program:
```bash ```bash
cargo run --example rhai_runner scripts/any_script.rhai cargo run --example rhai_runner scripts/any_script.rhai
``` ```
@ -95,7 +102,8 @@ if let Ok(result) = engine.eval_file::<i64>("hello_world.rhai") { ... }
If you want to repeatedly evaluate a script, you can compile it first into an AST form: If you want to repeatedly evaluate a script, you can compile it first into an AST form:
```rust ```rust
let ast = Engine::compile("40 + 2").unwrap(); // AST generated can be stored for later evaluations // Compile to an AST and store it for later evaluations
let ast = Engine::compile("40 + 2").unwrap();
for _ in 0..42 { for _ in 0..42 {
if let Ok(result) = engine.eval_ast::<i64>(&ast) { if let Ok(result) = engine.eval_ast::<i64>(&ast) {
@ -116,15 +124,15 @@ Rhai's scripting engine is very lightweight. It gets its ability from the funct
```rust ```rust
extern crate rhai; extern crate rhai;
use rhai::{Engine, RegisterFn}; use rhai::{Dynamic, Engine, RegisterFn};
// Normal function // Normal function
fn add(x: i64, y: i64) -> i64 { fn add(x: i64, y: i64) -> i64 {
x + y x + y
} }
// Function that returns a dynamic value (i.e. Box<dyn Any>) // Function that returns a Dynamic value
fn get_an_any() -> Box<dyn Any> { fn get_an_any() -> Dynamic {
Box::new(42_i64) Box::new(42_i64)
} }
@ -137,8 +145,8 @@ fn main() {
println!("Answer: {}", result); // prints 42 println!("Answer: {}", result); // prints 42
} }
// Functions that return dynamic values (i.e. Box<any Any>) must use register_box_fn() // Functions that return Dynamic values must use register_dynamic_fn()
engine.register_box_fn("get_an_any", get_an_any); engine.register_dynamic_fn("get_an_any", get_an_any);
if let Ok(result) = engine.eval::<i64>("get_an_any()") { if let Ok(result) = engine.eval::<i64>("get_an_any()") {
println!("Answer: {}", result); // prints 42 println!("Answer: {}", result); // prints 42
@ -218,6 +226,7 @@ struct TestStruct {
``` ```
Next, we create a few methods that we'll later use in our scripts. Notice that we register our custom type with the engine. Next, we create a few methods that we'll later use in our scripts. Notice that we register our custom type with the engine.
```rust ```rust
impl TestStruct { impl TestStruct {
fn update(&mut self) { fn update(&mut self) {
@ -244,12 +253,28 @@ engine.register_fn("new_ts", TestStruct::new);
``` ```
Finally, we call our script. The script can see the function and method we registered earlier. We need to get the result back out from script land just as before, this time casting to our custom struct type. Finally, we call our script. The script can see the function and method we registered earlier. We need to get the result back out from script land just as before, this time casting to our custom struct type.
```rust ```rust
if let Ok(result) = engine.eval::<TestStruct>("let x = new_ts(); x.update(); x") { if let Ok(result) = engine.eval::<TestStruct>("let x = new_ts(); x.update(); x") {
println!("result: {}", result.x); // prints 1001 println!("result: {}", result.x); // prints 1001
} }
``` ```
In fact, any function with a first argument (either by copy or via a `&mut` reference) can be used as a method-call on that type because internally they are the same thing: methods on a type is implemented as a functions taking an first argument.
```rust
fn foo(ts: &mut TestStruct) -> i64 {
ts.x
}
engine.register_fn("foo", foo);
if let Ok(result) = engine.eval::<i64>("let x = new_ts(); x.foo()") {
println!("result: {}", result); // prints 1
}
```
# Getters and setters # Getters and setters
Similarly, you can work with members of your custom types. This works by registering a 'get' or a 'set' function for working with your struct. Similarly, you can work with members of your custom types. This works by registering a 'get' or a 'set' function for working with your struct.
@ -325,6 +350,7 @@ let x = (1 + 2) * (6 - 4) / 2;
``` ```
## If ## If
```rust ```rust
if true { if true {
print("it's true!"); print("it's true!");
@ -335,6 +361,7 @@ else {
``` ```
## While ## While
```rust ```rust
let x = 10; let x = 10;
while x > 0 { while x > 0 {
@ -347,6 +374,7 @@ while x > 0 {
``` ```
## Loop ## Loop
```rust ```rust
let x = 10; let x = 10;
@ -379,10 +407,10 @@ fn add(x, y) {
print(add(2, 3)) print(add(2, 3))
``` ```
To return a dynamic value, box it and return it as `Box<dyn Any>`. To return a `Dynamic` value, simply box it and return it.
```rust ```rust
fn decide(yes_no: bool) -> Box<dyn Any> { fn decide(yes_no: bool) -> Dynamic {
if yes_no { if yes_no {
Box::new(42_i64) Box::new(42_i64)
} else { } else {
@ -417,11 +445,15 @@ last == 5;
`push` is only defined for standard built-in types. If you want to use `push` with `push` is only defined for standard built-in types. If you want to use `push` with
your own custom type, you need to define a specific override: your own custom type, you need to define a specific override:
```rust ```rust
engine.register_fn("push", |list: &mut Array, item: MyType| list.push(Box::new(item))); engine.register_fn("push", |list: &mut rhai::Array, item: MyType| list.push(Box::new(item)));
``` ```
## For The type of a Rhai array is `rhai::Array`.
## For loops
```rust ```rust
let array = [1, 3, 5, 7, 9, 42]; let array = [1, 3, 5, 7, 9, 42];
@ -461,6 +493,7 @@ name_and_age == "Bob C. Davis: age 42";
``` ```
## Print and Debug ## Print and Debug
```rust ```rust
print("hello"); // prints hello to stdout print("hello"); // prints hello to stdout
print(1 + 2 + 3); // prints 6 to stdout print(1 + 2 + 3); // prints 6 to stdout
@ -468,7 +501,8 @@ print("hello" + 42); // prints hello42 to stdout
debug("world!"); // prints "world!" to stdout using debug formatting debug("world!"); // prints "world!" to stdout using debug formatting
``` ```
## Overriding Print and Debug ### Overriding Print and Debug with Callback functions
```rust ```rust
// Any function that takes a &str argument can be used to override print and debug // Any function that takes a &str argument can be used to override print and debug
engine.on_print(|x: &str| println!("hello: {}", x)); engine.on_print(|x: &str| println!("hello: {}", x));