Skip to content

Commit

Permalink
More benchmarks and examples.
Browse files Browse the repository at this point in the history
  • Loading branch information
schungx committed May 31, 2020
1 parent 331513f commit c6e5f67
Show file tree
Hide file tree
Showing 5 changed files with 189 additions and 39 deletions.
63 changes: 34 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ Features
to do checked arithmetic operations); for [`no-std`](#optional-features) builds, a number of additional dependencies are
pulled in to provide for functionalities that used to be in `std`.

**Note:** Currently, the version is 0.15.0, so the language and API's may change before they stabilize.
**Note:** Currently, the version is `0.15.0`, so the language and API's may change before they stabilize.

What Rhai doesn't do
--------------------
Expand Down Expand Up @@ -67,7 +67,7 @@ This is similar to some dynamic languages where most of the core functionalities
Installation
------------

Install the Rhai crate by adding this line to `dependencies`:
Install the Rhai crate on [`crates.io`](https::/crates.io/crates/rhai/) by adding this line to `dependencies`:

```toml
[dependencies]
Expand Down Expand Up @@ -191,33 +191,35 @@ A number of examples can be found in the `examples` folder:
Examples can be run with the following command:

```bash
cargo run --example name
cargo run --example {example_name}
```

The `repl` example is a particularly good one as it allows one to interactively try out Rhai's
language features in a standard REPL (**R**ead-**E**val-**P**rint **L**oop).

Example Scripts
Example scripts
---------------

There are also a number of examples scripts that showcase Rhai's features, all in the `scripts` folder:

| Language feature scripts | Description |
| ---------------------------------------------------- | ------------------------------------------------------------- |
| [`array.rhai`](scripts/array.rhai) | [arrays] in Rhai |
| [`assignment.rhai`](scripts/assignment.rhai) | variable declarations |
| [`comments.rhai`](scripts/comments.rhai) | just comments |
| [`for1.rhai`](scripts/for1.rhai) | for loops |
| [`function_decl1.rhai`](scripts/function_decl1.rhai) | a function without parameters |
| [`function_decl2.rhai`](scripts/function_decl2.rhai) | a function with two parameters |
| [`function_decl3.rhai`](scripts/function_decl3.rhai) | a function with many parameters |
| [`if1.rhai`](scripts/if1.rhai) | if example |
| [`loop.rhai`](scripts/loop.rhai) | endless loop in Rhai, this example emulates a do..while cycle |
| [`op1.rhai`](scripts/op1.rhai) | just a simple addition |
| [`op2.rhai`](scripts/op2.rhai) | simple addition and multiplication |
| [`op3.rhai`](scripts/op3.rhai) | change evaluation order with parenthesis |
| [`string.rhai`](scripts/string.rhai) | [string] operations |
| [`while.rhai`](scripts/while.rhai) | while loop |
| Language feature scripts | Description |
| ---------------------------------------------------- | ----------------------------------------------------------------------------- |
| [`array.rhai`](scripts/array.rhai) | [arrays] in Rhai |
| [`assignment.rhai`](scripts/assignment.rhai) | variable declarations |
| [`comments.rhai`](scripts/comments.rhai) | just comments |
| [`for1.rhai`](scripts/for1.rhai) | [`for`](#for-loop) loops |
| [`for2.rhai`](scripts/for2.rhai) | [`for`](#for-loop) loops on [arrays] |
| [`function_decl1.rhai`](scripts/function_decl1.rhai) | a [function] without parameters |
| [`function_decl2.rhai`](scripts/function_decl2.rhai) | a [function] with two parameters |
| [`function_decl3.rhai`](scripts/function_decl3.rhai) | a [function] with many parameters |
| [`if1.rhai`](scripts/if1.rhai) | [`if`](#if-statement) example |
| [`loop.rhai`](scripts/loop.rhai) | count-down [`loop`](#infinite-loop) in Rhai, emulating a `do` .. `while` loop |
| [`op1.rhai`](scripts/op1.rhai) | just simple addition |
| [`op2.rhai`](scripts/op2.rhai) | simple addition and multiplication |
| [`op3.rhai`](scripts/op3.rhai) | change evaluation order with parenthesis |
| [`string.rhai`](scripts/string.rhai) | [string] operations |
| [`strings_map.rhai`](scripts/strings_map.rhai) | [string] and [object map] operations |
| [`while.rhai`](scripts/while.rhai) | [`while`](#while-loop) loop |

| Example scripts | Description |
| -------------------------------------------- | ---------------------------------------------------------------------------------- |
Expand Down Expand Up @@ -247,6 +249,7 @@ fn main() -> Result<(), Box<EvalAltResult>>
let engine = Engine::new();

let result = engine.eval::<i64>("40 + 2")?;
// ^^^^^^^ cast the result to an 'i64', this is required

println!("Answer: {}", result); // prints 42

Expand Down Expand Up @@ -303,6 +306,8 @@ let ast = engine.compile_file("hello_world.rhai".into())?;

### Calling Rhai functions from Rust

[`private`]: #calling-rhai-functions-from-rust

Rhai also allows working _backwards_ from the other direction - i.e. calling a Rhai-scripted function from Rust via `Engine::call_fn`.
Functions declared with `private` are hidden and cannot be called from Rust (see also [modules]).

Expand Down Expand Up @@ -1870,8 +1875,8 @@ my_str += 12345;
my_str == "abcABC12345"
```

`if` statements
---------------
`if` statement
--------------

```rust
if foo(x) {
Expand Down Expand Up @@ -1906,8 +1911,8 @@ let x = if decision { 42 }; // no else branch defaults to '()'
x == ();
```

`while` loops
-------------
`while` loop
------------

```rust
let x = 10;
Expand All @@ -1934,8 +1939,8 @@ loop {
}
```

`for` loops
-----------
`for` loop
----------

Iterating through a range or an [array] is provided by the `for` ... `in` loop.

Expand Down Expand Up @@ -2206,8 +2211,8 @@ Modules can be disabled via the [`no_module`] feature.
A _module_ is a single script (or pre-compiled `AST`) containing global variables and functions.
The `export` statement, which can only be at global level, exposes selected variables as members of a module.
Variables not exported are _private_ and invisible to the outside.
On the other hand, all functions are automatically exported, _unless_ it is explicitly opt-out with the `private` prefix.
Functions declared `private` are invisible to the outside.
On the other hand, all functions are automatically exported, _unless_ it is explicitly opt-out with the [`private`] prefix.
Functions declared [`private`] are invisible to the outside.

Everything exported from a module is **constant** (**read-only**).

Expand Down Expand Up @@ -2301,7 +2306,7 @@ engine.eval_expression_with_scope::<i64>(&scope, "question::inc(question::answer

It is easy to convert a pre-compiled `AST` into a module: just use `Module::eval_ast_as_new`.
Don't forget the `export` statement, otherwise there will be no variables exposed by the module
other than non-`private` functions (unless that's intentional).
other than non-[`private`] functions (unless that's intentional).

```rust
use rhai::{Engine, Module};
Expand Down
24 changes: 24 additions & 0 deletions benches/eval_array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,27 @@ fn bench_eval_array_large_set(bench: &mut Bencher) {

bench.iter(|| engine.consume_ast(&ast).unwrap());
}

#[bench]
fn bench_eval_array_loop(bench: &mut Bencher) {
let script = r#"
let list = [];
for i in range(0, 10_000) {
list.push(i);
}
let sum = 0;
for i in list {
sum += i;
}
"#;

let mut engine = Engine::new();
engine.set_optimization_level(OptimizationLevel::None);

let ast = engine.compile(script).unwrap();

bench.iter(|| engine.consume_ast(&ast).unwrap());
}
22 changes: 22 additions & 0 deletions scripts/for2.rhai
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const MAX = 1_000_000;

print("Iterating an array with " + MAX + " items...");

print("Ready... Go!");

let now = timestamp();

let list = [];

for i in range(0, MAX) {
list.push(i);
}

let sum = 0;

for i in list {
sum += i;
}

print("Sum = " + sum);
print("Finished. Run time = " + now.elapsed + " seconds.");
103 changes: 103 additions & 0 deletions scripts/strings_map.rhai
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
print("Ready... Go!");

let now = timestamp();

let adverbs = [ "moderately", "really", "slightly", "very" ];

let adjectives = [
"abandoned", "able", "absolute", "academic", "acceptable", "acclaimed",
"accomplished", "accurate", "aching", "acidic", "acrobatic", "active",
"actual", "adept", "admirable", "admired", "adolescent", "adorable", "adored",
"advanced", "adventurous", "affectionate", "afraid", "aged", "aggravating",
"aggressive", "agile", "agitated", "agonizing", "agreeable", "ajar",
"alarmed", "alarming", "alert", "alienated", "alive", "all", "altruistic",
"amazing", "ambitious", "ample", "amused", "amusing", "anchored", "ancient",
"angelic", "angry", "anguished", "animated", "annual", "another", "antique",
"anxious", "any", "apprehensive", "appropriate", "apt", "arctic", "arid",
"aromatic", "artistic", "ashamed", "assured", "astonishing", "athletic",
"attached", "attentive", "attractive", "austere", "authentic", "authorized",
"automatic", "avaricious", "average", "aware", "awesome", "awful", "awkward",
"babyish", "back", "bad", "baggy", "bare", "barren", "basic", "beautiful",
"belated", "beloved", "beneficial", "best", "better", "bewitched", "big",
"big-hearted", "biodegradable", "bite-sized", "bitter", "black",
"black-and-white", "bland", "blank", "blaring", "bleak", "blind", "blissful",
"blond", "blue", "blushing", "bogus", "boiling", "bold", "bony", "boring",
"bossy", "both", "bouncy", "bountiful", "bowed", "brave", "breakable",
"brief", "bright", "brilliant", "brisk", "broken", "bronze", "brown",
"bruised", "bubbly", "bulky", "bumpy", "buoyant", "burdensome", "burly",
"bustling", "busy", "buttery", "buzzing", "calculating", "calm", "candid",
"canine", "capital", "carefree", "careful", "careless", "caring", "cautious",
"cavernous", "celebrated", "charming", "cheap", "cheerful", "cheery", "chief",
"chilly", "chubby", "circular", "classic", "clean", "clear", "clear-cut",
"clever", "close", "closed", "cloudy", "clueless", "clumsy", "cluttered",
"coarse", "cold", "colorful", "colorless", "colossal", "comfortable",
"common", "compassionate", "competent", "complete", "complex", "complicated",
"composed", "concerned", "concrete", "confused", "conscious", "considerate",
"constant", "content", "conventional", "cooked", "cool", "cooperative",
"coordinated", "corny", "corrupt", "costly", "courageous", "courteous",
"crafty"
];

let animals = [
"aardvark", "african buffalo", "albatross", "alligator", "alpaca", "ant",
"anteater", "antelope", "ape", "armadillo", "baboon", "badger", "barracuda",
"bat", "bear", "beaver", "bee", "bison", "black panther", "blue jay", "boar",
"butterfly", "camel", "capybara", "carduelis", "caribou", "cassowary", "cat",
"caterpillar", "cattle", "chamois", "cheetah", "chicken", "chimpanzee",
"chinchilla", "chough", "clam", "cobra", "cockroach", "cod", "cormorant",
"coyote", "crab", "crane", "crocodile", "crow", "curlew", "deer", "dinosaur",
"dog", "dolphin", "domestic pig", "donkey", "dotterel", "dove", "dragonfly",
"duck", "dugong", "dunlin", "eagle", "echidna", "eel", "elephant seal",
"elephant", "elk", "emu", "falcon", "ferret", "finch", "fish", "flamingo",
"fly", "fox", "frog", "gaur", "gazelle", "gerbil", "giant panda", "giraffe",
"gnat", "goat", "goldfish", "goose", "gorilla", "goshawk", "grasshopper",
"grouse", "guanaco", "guinea fowl", "guinea pig", "gull", "hamster", "hare",
"hawk", "hedgehog", "heron", "herring", "hippopotamus", "hornet", "horse",
"human", "hummingbird", "hyena", "ibex", "ibis", "jackal", "jaguar", "jay",
"jellyfish", "kangaroo", "kingfisher", "koala", "komodo dragon", "kookabura",
"kouprey", "kudu", "lapwing", "lark", "lemur", "leopard", "lion", "llama",
"lobster", "locust", "loris", "louse", "lyrebird", "magpie", "mallard",
"manatee", "mandrill", "mantis", "marten", "meerkat", "mink", "mole",
"mongoose", "monkey", "moose", "mosquito", "mouse", "mule", "narwhal", "newt",
"nightingale", "octopus", "okapi", "opossum", "oryx", "ostrich", "otter",
"owl", "oyster", "parrot", "partridge", "peafowl", "pelican", "penguin",
"pheasant", "pigeon", "pinniped", "polar bear", "pony", "porcupine",
"porpoise", "prairie dog", "quail", "quelea", "quetzal", "rabbit", "raccoon",
"ram", "rat", "raven", "red deer", "red panda", "reindeer", "rhinoceros",
"rook", "salamander", "salmon", "sand dollar", "sandpiper", "sardine",
"scorpion", "sea lion", "sea urchin", "seahorse", "shark", "sheep", "shrew",
"skunk", "snail", "snake", "sparrow", "spider", "spoonbill", "squid",
"wallaby", "wildebeest"
];

let keys = [];

for animal in animals {
for adjective in adjectives {
for adverb in adverbs {
keys.push(adverb + " " + adjective + " " + animal)
}
}
}

let map = #{};

let i = 0;

for key in keys {
map[key] = i;
i += 1;
}

let sum = 0;

for key in keys {
sum += map[key];
}

for key in keys {
map.remove(key);
}

print("Sum = " + sum);
print("Finished. Run time = " + now.elapsed + " seconds.");
16 changes: 6 additions & 10 deletions src/optimize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -385,10 +385,10 @@ fn optimize_expr(expr: Expr, state: &mut State) -> Expr {
// ( stmt )
stmt => Expr::Stmt(Box::new((stmt, x.1))),
},
// id = expr
// id op= expr
Expr::Assignment(x) => match x.2 {
//id = id2 op= expr2
Expr::Assignment(x2) if x.1 == "=" => match (x.0, x2.0) {
//id = id2 op= rhs
Expr::Assignment(x2) if x.1.is_empty() => match (x.0, &x2.0) {
// var = var op= expr2 -> var op= expr2
(Expr::Variable(a), Expr::Variable(b))
if a.1.is_none() && b.1.is_none() && a.0 == b.0 && a.3 == b.3 =>
Expand All @@ -397,14 +397,10 @@ fn optimize_expr(expr: Expr, state: &mut State) -> Expr {
state.set_dirty();
Expr::Assignment(Box::new((Expr::Variable(a), x2.1, optimize_expr(x2.2, state), x.3)))
}
// id1 = id2 op= expr2
(id1, id2) => {
Expr::Assignment(Box::new((
id1, x.1, Expr::Assignment(Box::new((id2, x2.1, optimize_expr(x2.2, state), x2.3))), x.3,
)))
}
// expr1 = expr2 op= rhs
(expr1, _) => Expr::Assignment(Box::new((expr1, x.1, optimize_expr(Expr::Assignment(x2), state), x.3))),
},
// id op= expr
// expr = rhs
expr => Expr::Assignment(Box::new((x.0, x.1, optimize_expr(expr, state), x.3))),
},

Expand Down

0 comments on commit c6e5f67

Please sign in to comment.