Merge branch 'master' into plugins

This commit is contained in:
Stephen Chung 2020-07-26 10:05:56 +08:00
commit 8e33cbfe34
35 changed files with 364 additions and 179 deletions

View File

@ -1,11 +0,0 @@
#!/bin/bash
set -ex
cargo build --verbose
cargo test --verbose
if [[ $TRAVIS_RUST_VERSION == "nightly" ]]; then
cargo build --verbose --features no_std
cargo test --verbose --features no_std
fi

76
.github/workflows/build.yml vendored Normal file
View File

@ -0,0 +1,76 @@
name: Build
on:
push:
branches:
- master
pull_request: {}
jobs:
# typical build with various feature combinations
build:
name: Build
runs-on: ${{ matrix.os }}
continue-on-error: ${{ matrix.experimental }}
strategy:
matrix:
os: [ubuntu-latest]
flags:
- ""
- "--features serde"
- "--features plugins"
- "--features unchecked"
- "--features sync"
- "--features no_optimize"
- "--features no_float"
- "--features only_i32"
- "--features only_i64"
- "--features no_index"
- "--features no_object"
- "--features no_function"
- "--features no_module"
toolchain: [stable]
experimental: [false]
include:
# smoketests for future and experimental toolchains
- {toolchain: stable, os: windows-latest, experimental: false, flags: ""}
- {toolchain: stable, os: macos-latest, experimental: false, flags: ""}
- {toolchain: beta, os: ubuntu-latest, experimental: false, flags: ""}
- {toolchain: nightly, os: ubuntu-latest, experimental: true, flags: ""}
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup Toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: ${{matrix.toolchain}}
override: true
- name: Test
uses: actions-rs/cargo@v1
with:
command: test
args: --all {{matrix.flags}}
# no-std builds are a bit more extensive to test
no_std_build:
name: NoStdBuild
runs-on: ${{matrix.os}}
continue-on-error: ${{matrix.experimental}}
strategy:
matrix:
include:
- {os: ubuntu-latest, flags: "--profile unix -Z unstable-options", experimental: false}
- {os: windows-latest, flags: "--profile windows -Z unstable-options", experimental: true}
- {os: macos-latest, flags: "--profile macos -Z unstable-options", experimental: false}
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup Toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: nightly
override: true
- name: Build Project
uses: actions-rs/cargo@v1
with:
command: build
args: --manifest-path=no_std/no_std_test/Cargo.toml ${{matrix.flags}}

View File

@ -1,10 +0,0 @@
language: rust
rust:
- stable
- beta
- nightly
matrix:
allow_failures:
- rust: nightly
script: bash ./.ci/build.sh

View File

@ -2,7 +2,7 @@ Rhai - Embedded Scripting for Rust
=================================
![GitHub last commit](https://img.shields.io/github/last-commit/jonathandturner/rhai)
[![Travis (.org)](https://img.shields.io/travis/jonathandturner/rhai)](http://travis-ci.org/jonathandturner/rhai)
[![Build Status](https://github.com/jonathandturner/rhai/workflows/Build/badge.svg)](https://github.com/jonathandturner/rhai/actions)
[![license](https://img.shields.io/github/license/jonathandturner/rhai)](https://github.com/license/jonathandturner/rhai)
[![crates.io](https://img.shields.io/crates/v/rhai.svg)](https://crates.io/crates/rhai/)
[![crates.io](https://img.shields.io/crates/d/rhai)](https://crates.io/crates/rhai/)
@ -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

View File

@ -5,8 +5,9 @@ The Rhai Scripting Language
1. [Features](about/features.md)
2. [Supported Targets and Builds](about/targets.md)
3. [What Rhai Isn't](about/non-design.md)
4. [Related Resources](about/related.md)
3. [Getting Started](start/index.md)
4. [Licensing](about/license.md)
5. [Related Resources](about/related.md)
2. [Getting Started](start/index.md)
1. [Online Playground](start/playground.md)
2. [Install the Rhai Crate](start/install.md)
3. [Optional Features](start/features.md)
@ -18,14 +19,14 @@ The Rhai Scripting Language
5. [Examples](start/examples/index.md)
1. [Rust](start/examples/rust.md)
2. [Scripts](start/examples/scripts.md)
4. [Using the `Engine`](engine/index.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)
6. [Raw Engine](engine/raw.md)
5. [Extend Rhai with Rust](rust/index.md)
4. [Extend Rhai with Rust](rust/index.md)
1. [Traits](rust/traits.md)
2. [Register a Rust Function](rust/functions.md)
1. [String Parameters in Rust Functions](rust/strings.md)
@ -43,7 +44,7 @@ The Rhai Scripting Language
4. [Printing Custom Types](rust/print-custom.md)
9. [Scope - Initializing and Maintaining State](rust/scope.md)
10. [Engine Configuration Options](rust/options.md)
6. [Rhai Language Reference](language/index.md)
5. [Rhai Language Reference](language/index.md)
1. [Comments](language/comments.md)
2. [Values and Types](language/values-and-types.md)
1. [Dynamic Values](language/dynamic.md)
@ -64,28 +65,29 @@ 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)
4. [Create from AST](language/modules/ast.md)
5. [Module Resolvers](rust/modules/resolvers.md)
1. [Custom Implementation](rust/modules/imp-resolver.md)
7. [Safety and Protection](safety/index.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)
@ -96,7 +98,7 @@ The Rhai Scripting Language
7. [Maximum Number of Modules](safety/max-modules.md)
8. [Maximum Call Stack Depth](safety/max-call-stack.md)
9. [Maximum Statement Depth](safety/max-stmt-depth.md)
8. [Advanced Topics](advanced.md)
7. [Advanced Topics](advanced.md)
1. [Object-Oriented Programming (OOP)](language/oop.md)
2. [Serialization/Deserialization of `Dynamic` with `serde`](rust/serde.md)
3. [Script Optimization](engine/optimize/index.md)
@ -112,7 +114,7 @@ The Rhai Scripting Language
2. [Custom Operators](engine/custom-op.md)
3. [Extending with Custom Syntax](engine/custom-syntax.md)
6. [Eval Statement](language/eval.md)
9. [Appendix](appendix/index.md)
8. [Appendix](appendix/index.md)
1. [Keywords](appendix/keywords.md)
2. [Operators and Symbols](appendix/operators.md)
3. [Literals](appendix/literals.md)

View File

@ -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/).

16
doc/src/about/license.md Normal file
View File

@ -0,0 +1,16 @@
Licensing
=========
{{#include ../links.md}}
Rhai is licensed under either:
* [Apache License, Version 2.0]({{repoHome}}/LICENSE-APACHE.txt), or
* [MIT license]({{repoHome}}/LICENSE-MIT.txt)
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,
without any additional terms or conditions.

View File

@ -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.

View File

@ -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.

View File

@ -1,5 +1,7 @@
{
"version": "0.18.0",
"repoHome": "https://github.com/jonathandturner/rhai/blob/master",
"repoTree": "https://github.com/jonathandturner/rhai/tree/master",
"rootUrl": "",
"rootUrlX": "/rhai",
"rootUrlXX": "/rhai/vnext"

View File

@ -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'
```

View File

@ -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` |

View File

@ -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.

View File

@ -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.

View File

@ -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"
```

View File

@ -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).

View 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;
```

View File

@ -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.

View File

@ -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) {

View File

@ -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

View File

@ -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.

View File

@ -6,16 +6,16 @@ Rust Examples
A number of examples can be found in the `examples` directory:
| Example | Description |
| ---------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| [`arrays_and_structs`](https://github.com/jonathandturner/rhai/tree/master/examples/arrays_and_structs.rs) | Shows how to register a custom Rust type and using [arrays] on it. |
| [`custom_types_and_methods`](https://github.com/jonathandturner/rhai/tree/master/examples/custom_types_and_methods.rs) | Shows how to register a custom Rust type and methods for it. |
| [`hello`](https://github.com/jonathandturner/rhai/tree/master/examples/hello.rs) | Simple example that evaluates an expression and prints the result. |
| [`reuse_scope`](https://github.com/jonathandturner/rhai/tree/master/examples/reuse_scope.rs) | Evaluates two pieces of code in separate runs, but using a common [`Scope`]. |
| [`rhai_runner`](https://github.com/jonathandturner/rhai/tree/master/examples/rhai_runner.rs) | Runs each filename passed to it as a Rhai script. |
| [`serde`](https://github.com/jonathandturner/rhai/tree/master/examples/serde.rs) | Example to serialize and deserialize Rust types with [`serde`](https://crates.io/crates/serde).<br/>The [`serde`] feature is required to run. |
| [`simple_fn`](https://github.com/jonathandturner/rhai/tree/master/examples/simple_fn.rs) | Shows how to register a simple function. |
| [`strings`](https://github.com/jonathandturner/rhai/tree/master/examples/strings.rs) | Shows different ways to register functions taking string arguments. |
| [`repl`](https://github.com/jonathandturner/rhai/tree/master/examples/repl.rs) | A simple REPL, interactively evaluate statements from stdin. |
| ------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| [`arrays_and_structs`]({{repoTree}}/examples/arrays_and_structs.rs) | Shows how to register a custom Rust type and using [arrays] on it. |
| [`custom_types_and_methods`]({{repoTree}}/examples/custom_types_and_methods.rs) | Shows how to register a custom Rust type and methods for it. |
| [`hello`]({{repoTree}}/examples/hello.rs) | Simple example that evaluates an expression and prints the result. |
| [`reuse_scope`]({{repoTree}}/examples/reuse_scope.rs) | Evaluates two pieces of code in separate runs, but using a common [`Scope`]. |
| [`rhai_runner`]({{repoTree}}/examples/rhai_runner.rs) | Runs each filename passed to it as a Rhai script. |
| [`serde`]({{repoTree}}/examples/serde.rs) | Example to serialize and deserialize Rust types with [`serde`](https://crates.io/crates/serde).<br/>The [`serde`] feature is required to run. |
| [`simple_fn`]({{repoTree}}/examples/simple_fn.rs) | Shows how to register a simple function. |
| [`strings`]({{repoTree}}/examples/strings.rs) | Shows different ways to register functions taking string arguments. |
| [`repl`]({{repoTree}}/examples/repl.rs) | A simple REPL, interactively evaluate statements from stdin. |
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).
@ -36,8 +36,8 @@ cargo run --example {example_name}
To illustrate `no-std` builds, a number of sample applications are available under the `no_std` directory:
| Sample | Description | Optimization | Allocator | Panics |
| --------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | :----------: | :-----------------------------------------------: | :----: |
| [`no_std_test`](https://github.com/jonathandturner/rhai/tree/master/no_std/no_std_test) | Bare-bones test application that evaluates a Rhai expression and sets the result as the return value. | Size | [`wee_alloc`](https://crates.io/crates/wee_alloc) | Abort |
| ------------------------------------------------ | ----------------------------------------------------------------------------------------------------- | :----------: | :-----------------------------------------------: | :----: |
| [`no_std_test`]({{repoTree}}/no_std/no_std_test) | Bare-bones test application that evaluates a Rhai expression and sets the result as the return value. | Size | [`wee_alloc`](https://crates.io/crates/wee_alloc) | Abort |
`cargo run` cannot be used to run a `no-std` sample. It must first be built:

View File

@ -9,24 +9,24 @@ Language Feature Scripts
There are also a number of examples scripts that showcase Rhai's features, all in the `scripts` directory:
| Script | Description |
| -------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
| [`array.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/array.rhai) | [Arrays] |
| [`assignment.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/assignment.rhai) | Variable declarations |
| [`comments.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/comments.rhai) | Just comments |
| [`for1.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/for1.rhai) | [`for`]({{rootUrl}}/language/for.md) loops |
| [`for2.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/for2.rhai) | [`for`]({{rootUrl}}/language/for.md) loops on [arrays] |
| [`function_decl1.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/function_decl1.rhai) | A [function] without parameters |
| [`function_decl2.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/function_decl2.rhai) | A [function] with two parameters |
| [`function_decl3.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/function_decl3.rhai) | A [function] with many parameters |
| [`if1.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/if1.rhai) | [`if`]({{rootUrl}}/language/if.md) example |
| [`loop.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/loop.rhai) | Count-down [`loop`]({{rootUrl}}/language/loop.md) in Rhai, emulating a `do` .. `while` loop |
| [`oop.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/oop.rhai) | Simulate [object-oriented programming (OOP)][OOP] |
| [`op1.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/op1.rhai) | Just simple addition |
| [`op2.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/op2.rhai) | Simple addition and multiplication |
| [`op3.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/op3.rhai) | Change evaluation order with parenthesis |
| [`string.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/string.rhai) | [String] operations |
| [`strings_map.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/strings_map.rhai) | [String] and [object map] operations |
| [`while.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/while.rhai) | [`while`]({{rootUrl}}/language/while.md) loop |
| ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
| [`array.rhai`]({{repoTree}}/scripts/array.rhai) | [Arrays] |
| [`assignment.rhai`]({{repoTree}}/scripts/assignment.rhai) | Variable declarations |
| [`comments.rhai`]({{repoTree}}/scripts/comments.rhai) | Just comments |
| [`for1.rhai`]({{repoTree}}/scripts/for1.rhai) | [`for`]({{rootUrl}}/language/for.md) loops |
| [`for2.rhai`]({{repoTree}}/scripts/for2.rhai) | [`for`]({{rootUrl}}/language/for.md) loops on [arrays] |
| [`function_decl1.rhai`]({{repoTree}}/scripts/function_decl1.rhai) | A [function] without parameters |
| [`function_decl2.rhai`]({{repoTree}}/scripts/function_decl2.rhai) | A [function] with two parameters |
| [`function_decl3.rhai`]({{repoTree}}/scripts/function_decl3.rhai) | A [function] with many parameters |
| [`if1.rhai`]({{repoTree}}/scripts/if1.rhai) | [`if`]({{rootUrl}}/language/if.md) example |
| [`loop.rhai`]({{repoTree}}/scripts/loop.rhai) | Count-down [`loop`]({{rootUrl}}/language/loop.md) in Rhai, emulating a `do` .. `while` loop |
| [`oop.rhai`]({{repoTree}}/scripts/oop.rhai) | Simulate [object-oriented programming (OOP)][OOP] |
| [`op1.rhai`]({{repoTree}}/scripts/op1.rhai) | Just simple addition |
| [`op2.rhai`]({{repoTree}}/scripts/op2.rhai) | Simple addition and multiplication |
| [`op3.rhai`]({{repoTree}}/scripts/op3.rhai) | Change evaluation order with parenthesis |
| [`string.rhai`]({{repoTree}}/scripts/string.rhai) | [String] operations |
| [`strings_map.rhai`]({{repoTree}}/scripts/strings_map.rhai) | [String] and [object map] operations |
| [`while.rhai`]({{repoTree}}/scripts/while.rhai) | [`while`]({{rootUrl}}/language/while.md) loop |
Benchmark Scripts
@ -35,11 +35,11 @@ Benchmark Scripts
The following scripts are for benchmarking the speed of Rhai:
| Scripts | Description |
| ------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------- |
| [`speed_test.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/speed_test.rhai) | A simple application to measure the speed of Rhai's interpreter (1 million iterations). |
| [`primes.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/primes.rhai) | Use Sieve of Eratosthenes to find all primes smaller than a limit. |
| [`fibonacci.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/fibonacci.rhai) | Calculate the n-th Fibonacci number using a really dumb algorithm. |
| [`mat_mul.rhai`](https://github.com/jonathandturner/rhai/tree/master/scripts/mat_mul.rhai) | Matrix multiplication test to measure the speed of multi-dimensional array access. |
| --------------------------------------------------------- | --------------------------------------------------------------------------------------- |
| [`speed_test.rhai`]({{repoTree}}/scripts/speed_test.rhai) | A simple application to measure the speed of Rhai's interpreter (1 million iterations). |
| [`primes.rhai`]({{repoTree}}/scripts/primes.rhai) | Use Sieve of Eratosthenes to find all primes smaller than a limit. |
| [`fibonacci.rhai`]({{repoTree}}/scripts/fibonacci.rhai) | Calculate the n-th Fibonacci number using a really dumb algorithm. |
| [`mat_mul.rhai`]({{repoTree}}/scripts/mat_mul.rhai) | Matrix multiplication test to measure the speed of multi-dimensional array access. |
Running Example Scripts

View File

@ -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.

View File

@ -1,10 +1,12 @@
cargo-features = ["named-profiles"]
[package]
name = "no_std_test"
version = "0.1.0"
edition = "2018"
authors = ["Stephen Chung"]
description = "no-std test application"
homepage = "https://github.com/jonathandturner/rhai/tree/master/no_std/no_std_test"
homepage = "https://github.com/jonathandturner/rhai/tree/no_std/no_std_test"
repository = "https://github.com/jonathandturner/rhai"
[dependencies]
@ -18,7 +20,17 @@ panic = "abort"
opt-level = "z" # optimize for size
debug = false
rpath = false
lto = "fat"
debug-assertions = false
codegen-units = 1
panic = "abort"
[profile.unix]
inherits = "release"
lto = true
[profile.windows]
inherits = "release"
[profile.macos]
inherits = "release"
lto = "fat"

View File

@ -12,7 +12,9 @@ To Compile
The nightly compiler is required:
```bash
cargo +nightly build --release
cargo +nightly build --release --profile unix -Z unstable-features
```
Available profiles are: `unix`, `windows` and `macos`.
The release build is optimized for size. It can be changed to optimize on speed instead.

View File

@ -2,7 +2,7 @@
//! a simple expression and uses the result as the return value.
#![no_std]
#![feature(alloc_error_handler, start, core_intrinsics, lang_items)]
#![feature(alloc_error_handler, start, core_intrinsics, lang_items, link_cfg)]
extern crate alloc;
extern crate wee_alloc;
@ -10,6 +10,12 @@ extern crate wee_alloc;
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
// NB: Rust needs a CRT runtime on Windows MSVC.
#[cfg(all(windows, target_env = "msvc"))]
#[link(name = "msvcrt")]
#[link(name = "libcmt")]
extern {}
use rhai::{Engine, INT};
#[start]

View File

@ -639,9 +639,7 @@ impl Engine {
)
.or_else(|err| match *err {
// If there is no index setter, no need to set it back because the indexer is read-only
EvalAltResult::ErrorFunctionNotFound(s, _)
if s == FN_IDX_SET =>
{
EvalAltResult::ErrorFunctionNotFound(_, _) => {
Ok(Default::default())
}
_ => Err(err),

View File

@ -865,10 +865,22 @@ impl Engine {
EvalAltResult::ErrorFunctionNotFound(_, _) if def_val.is_some() => {
Ok(def_val.unwrap().into())
}
EvalAltResult::ErrorFunctionNotFound(_, _) => {
EvalAltResult::ErrorFunctionNotFound(_, pos) => {
Err(Box::new(EvalAltResult::ErrorFunctionNotFound(
format!("{}{}", modules, name),
Position::none(),
format!(
"{}{} ({})",
modules,
name,
args.iter()
.map(|a| if a.is::<ImmutableString>() {
"&str | ImmutableString | String"
} else {
self.map_type_name((*a).type_name())
})
.collect::<Vec<_>>()
.join(", ")
),
pos,
)))
}
_ => Err(err),

View File

@ -10,9 +10,12 @@ use crate::token::{is_valid_identifier, Position};
use crate::utils::{ImmutableString, StaticVec};
use crate::Scope;
use crate::stdlib::{
boxed::Box, convert::TryFrom, fmt, mem, rc::Rc, string::String, sync::Arc, vec::Vec,
};
use crate::stdlib::{boxed::Box, convert::TryFrom, fmt, mem, string::String, vec::Vec};
#[cfg(not(feature = "sync"))]
use crate::stdlib::rc::Rc;
#[cfg(feature = "sync")]
use crate::stdlib::sync::Arc;
/// Trait that maps to `Send + Sync` only under the `sync` feature.
#[cfg(feature = "sync")]

View File

@ -20,9 +20,12 @@ use crate::stdlib::{
boxed::Box,
fmt::Display,
format,
ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Rem, Shl, Shr, Sub},
ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Rem, Sub},
};
#[cfg(feature = "unchecked")]
use crate::stdlib::ops::{Shl, Shr};
// Checked add
pub(crate) fn add<T: Display + CheckedAdd>(x: T, y: T) -> FuncReturn<T> {
x.checked_add(&y).ok_or_else(|| {
@ -171,10 +174,12 @@ pub(crate) fn shr<T: Display + CheckedShr>(x: T, y: INT) -> FuncReturn<T> {
})
}
// Unchecked left-shift - may panic if shifting by a negative number of bits
#[cfg(feature = "unchecked")]
pub(crate) fn shl_u<T: Shl<T>>(x: T, y: T) -> FuncReturn<<T as Shl<T>>::Output> {
Ok(x.shl(y))
}
// Unchecked right-shift - may panic if shifting by a negative number of bits
#[cfg(feature = "unchecked")]
pub(crate) fn shr_u<T: Shr<T>>(x: T, y: T) -> FuncReturn<<T as Shr<T>>::Output> {
Ok(x.shr(y))
}
@ -229,6 +234,7 @@ pub(crate) fn pow_i_i(x: INT, y: INT) -> FuncReturn<INT> {
}
}
// Unchecked integer power - may panic on overflow or if the power index is too high (> u32::MAX)
#[cfg(feature = "unchecked")]
pub(crate) fn pow_i_i_u(x: INT, y: INT) -> FuncReturn<INT> {
Ok(x.pow(y as u32))
}

View File

@ -74,6 +74,7 @@ impl PackagesCollection {
.flatten()
}
/// Does the specified TypeId iterator exist in the `PackagesCollection`?
#[allow(dead_code)]
pub fn contains_iter(&self, id: TypeId) -> bool {
self.0.iter().any(|p| p.contains_iter(id))
}

View File

@ -1,12 +1,17 @@
#![cfg(not(feature = "no_std"))]
use super::logic::{eq, gt, gte, lt, lte, ne};
#[cfg(feature = "no_float")]
use super::math_basic::MAX_INT;
use crate::def_package;
use crate::module::FuncReturn;
use crate::parser::INT;
use crate::result::EvalAltResult;
use crate::token::Position;
#[cfg(not(feature = "no_float"))]
use crate::parser::FLOAT;
#[cfg(feature = "no_float")]
use crate::{module::FuncReturn, parser::INT, token::Position};
#[cfg(not(target_arch = "wasm32"))]
use crate::stdlib::time::Instant;
@ -14,9 +19,6 @@ use crate::stdlib::time::Instant;
#[cfg(target_arch = "wasm32")]
use instant::Instant;
#[cfg(not(feature = "no_float"))]
use crate::parser::FLOAT;
def_package!(crate:BasicTimePackage:"Basic timing utilities.", lib, {
// Register date/time functions
lib.set_fn_0("timestamp", || Ok(Instant::now()));

View File

@ -14,11 +14,14 @@ use crate::utils::StaticVec;
use crate::stdlib::{
boxed::Box,
fmt, format,
rc::Rc,
string::{String, ToString},
sync::Arc,
};
#[cfg(not(feature = "sync"))]
use crate::stdlib::rc::Rc;
#[cfg(feature = "sync")]
use crate::stdlib::sync::Arc;
/// A general expression evaluation trait object.
#[cfg(not(feature = "sync"))]
pub type FnCustomSyntaxEval = dyn Fn(