More benchmarks and examples.
This commit is contained in:
parent
331513f5e0
commit
c6e5f672c9
49
README.md
49
README.md
@ -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
|
||||
--------------------
|
||||
@ -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]
|
||||
@ -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 |
|
||||
| [`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 |
|
||||
| [`while.rhai`](scripts/while.rhai) | while loop |
|
||||
| [`strings_map.rhai`](scripts/strings_map.rhai) | [string] and [object map] operations |
|
||||
| [`while.rhai`](scripts/while.rhai) | [`while`](#while-loop) loop |
|
||||
|
||||
| Example scripts | Description |
|
||||
| -------------------------------------------- | ---------------------------------------------------------------------------------- |
|
||||
@ -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
|
||||
|
||||
@ -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]).
|
||||
|
||||
@ -1870,8 +1875,8 @@ my_str += 12345;
|
||||
my_str == "abcABC12345"
|
||||
```
|
||||
|
||||
`if` statements
|
||||
---------------
|
||||
`if` statement
|
||||
--------------
|
||||
|
||||
```rust
|
||||
if foo(x) {
|
||||
@ -1906,8 +1911,8 @@ let x = if decision { 42 }; // no else branch defaults to '()'
|
||||
x == ();
|
||||
```
|
||||
|
||||
`while` loops
|
||||
-------------
|
||||
`while` loop
|
||||
------------
|
||||
|
||||
```rust
|
||||
let x = 10;
|
||||
@ -1934,8 +1939,8 @@ loop {
|
||||
}
|
||||
```
|
||||
|
||||
`for` loops
|
||||
-----------
|
||||
`for` loop
|
||||
----------
|
||||
|
||||
Iterating through a range or an [array] is provided by the `for` ... `in` loop.
|
||||
|
||||
@ -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**).
|
||||
|
||||
@ -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};
|
||||
|
@ -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
scripts/for2.rhai
Normal file
22
scripts/for2.rhai
Normal file
@ -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
scripts/strings_map.rhai
Normal file
103
scripts/strings_map.rhai
Normal file
@ -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.");
|
@ -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 =>
|
||||
@ -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))),
|
||||
},
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user