Bump version to 0.12.0.
This commit is contained in:
parent
34ef2d6e00
commit
3609150dcf
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "rhai"
|
||||
version = "0.11.0"
|
||||
version = "0.12.0"
|
||||
edition = "2018"
|
||||
authors = ["Jonathan Turner", "Lukáš Hozda", "Stephen Chung"]
|
||||
description = "Embedded scripting for Rust"
|
||||
|
22
README.md
22
README.md
@ -27,7 +27,7 @@ Rhai's current features set:
|
||||
to do checked arithmetic operations); for [`no_std`] 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.11.0, so the language and API's may change before they stabilize.
|
||||
**Note:** Currently, the version is 0.12.0, so the language and API's may change before they stabilize.
|
||||
|
||||
Installation
|
||||
------------
|
||||
@ -36,7 +36,7 @@ Install the Rhai crate by adding this line to `dependencies`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
rhai = "0.11.0"
|
||||
rhai = "0.12.0"
|
||||
```
|
||||
|
||||
Use the latest released crate version on [`crates.io`](https::/crates.io/crates/rhai/):
|
||||
@ -207,7 +207,7 @@ let ast = engine.compile("40 + 2")?;
|
||||
for _ in 0..42 {
|
||||
let result: i64 = engine.eval_ast(&ast)?;
|
||||
|
||||
println!("Answer #{}: {}", i, result); // prints 42
|
||||
println!("Answer #{}: {}", i, result); // prints 42
|
||||
}
|
||||
```
|
||||
|
||||
@ -263,9 +263,10 @@ let result: i64 = engine.call_fn(&mut scope, &ast, "hello", () )?
|
||||
|
||||
[`Func`]: #creating-rust-anonymous-functions-from-rhai-script
|
||||
|
||||
It is possible to further encapsulate a script in Rust such that it essentially becomes a normal Rust function.
|
||||
This is accomplished via the `Func` trait which contains `create_from_script` (as well as its associate
|
||||
method `create_from_ast`):
|
||||
It is possible to further encapsulate a script in Rust such that it becomes a normal Rust function.
|
||||
Such an _anonymous function_ is basically a boxed closure, very useful as call-back functions.
|
||||
Creating them is accomplished via the `Func` trait which contains `create_from_script`
|
||||
(as well as its companion method `create_from_ast`):
|
||||
|
||||
```rust
|
||||
use rhai::{Engine, Func}; // use 'Func' for 'create_from_script'
|
||||
@ -288,6 +289,15 @@ let func = Func::<(i64, String), bool>::create_from_script(
|
||||
)?;
|
||||
|
||||
func(123, "hello".to_string())? == false; // call the anonymous function
|
||||
|
||||
schedule_callback(func); // pass it as a callback to another function
|
||||
|
||||
// Although there is nothing you can't do by manually writing out the closure yourself...
|
||||
let engine = Engine::new();
|
||||
let ast = engine.compile(script)?;
|
||||
schedule_callback(Box::new(move |x: i64, y: String| -> Result<bool, EvalAltResult> {
|
||||
engine.call_fn(&mut Scope::new(), &ast, "calc", (x, y))
|
||||
}));
|
||||
```
|
||||
|
||||
Raw `Engine`
|
||||
|
@ -50,7 +50,7 @@ type IteratorFn = dyn Fn(&Dynamic) -> Box<dyn Iterator<Item = Dynamic>> + Send +
|
||||
type IteratorFn = dyn Fn(&Dynamic) -> Box<dyn Iterator<Item = Dynamic>>;
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
pub const MAX_CALL_STACK_DEPTH: usize = 42;
|
||||
pub const MAX_CALL_STACK_DEPTH: usize = 32;
|
||||
|
||||
#[cfg(not(debug_assertions))]
|
||||
pub const MAX_CALL_STACK_DEPTH: usize = 256;
|
||||
@ -277,7 +277,7 @@ pub struct Engine<'e> {
|
||||
|
||||
/// Maximum levels of call-stack to prevent infinite recursion.
|
||||
///
|
||||
/// Defaults to 42 for debug builds and 256 for non-debug builds.
|
||||
/// Defaults to 32 for debug builds and 256 for non-debug builds.
|
||||
pub(crate) max_call_stack_depth: usize,
|
||||
}
|
||||
|
||||
@ -372,11 +372,6 @@ impl Engine<'_> {
|
||||
|
||||
/// Create a new `Engine`
|
||||
pub fn new() -> Self {
|
||||
// fn abc<F: Fn() + Send + Sync>(f: F) {
|
||||
// f();
|
||||
// }
|
||||
// abc(|| ());
|
||||
|
||||
Default::default()
|
||||
}
|
||||
|
||||
@ -420,32 +415,6 @@ impl Engine<'_> {
|
||||
self.max_call_stack_depth = levels
|
||||
}
|
||||
|
||||
/// Call a registered function
|
||||
#[cfg(not(feature = "no_optimize"))]
|
||||
pub(crate) fn call_ext_fn_raw(
|
||||
&self,
|
||||
fn_name: &str,
|
||||
args: &mut FnCallArgs,
|
||||
pos: Position,
|
||||
) -> Result<Option<Dynamic>, EvalAltResult> {
|
||||
let spec = FnSpec {
|
||||
name: fn_name.into(),
|
||||
args: args.iter().map(|a| Any::type_id(*a)).collect(),
|
||||
};
|
||||
|
||||
// Search built-in's and external functions
|
||||
if let Some(functions) = &self.functions {
|
||||
if let Some(func) = functions.get(&spec) {
|
||||
// Run external function
|
||||
Ok(Some(func(args, pos)?))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
/// Universal method for calling functions either registered with the `Engine` or written in Rhai
|
||||
pub(crate) fn call_fn_raw(
|
||||
&self,
|
||||
|
@ -132,9 +132,9 @@ macro_rules! def_register {
|
||||
def_register!(imp);
|
||||
};
|
||||
(imp $($par:ident => $mark:ty => $param:ty => $clone:expr),*) => {
|
||||
// ^ function parameter generic type name
|
||||
// ^ function parameter generic type name (A, B, C etc.)
|
||||
// ^ function parameter marker type (T, Ref<T> or Mut<T>)
|
||||
// ^ function parameter actual type
|
||||
// ^ function parameter actual type (T, &T or &mut T)
|
||||
// ^ dereferencing function
|
||||
impl<
|
||||
$($par: Any + Clone,)*
|
||||
@ -171,6 +171,7 @@ macro_rules! def_register {
|
||||
let r = f($(($clone)($par)),*);
|
||||
Ok(Box::new(r) as Dynamic)
|
||||
};
|
||||
|
||||
self.register_fn_raw(name, vec![$(TypeId::of::<$par>()),*], Box::new(func));
|
||||
}
|
||||
}
|
||||
@ -255,9 +256,10 @@ macro_rules! def_register {
|
||||
def_register!(imp $p0 => $p0 => $p0 => Clone::clone $(, $p => $p => $p => Clone::clone)*);
|
||||
def_register!(imp $p0 => Mut<$p0> => &mut $p0 => identity $(, $p => $p => $p => Clone::clone)*);
|
||||
// handle the first parameter ^ first parameter passed through
|
||||
// others passed by value (cloned) ^
|
||||
// ^ others passed by value (cloned)
|
||||
|
||||
// No support for functions where the first argument is a reference
|
||||
// Currently does not support first argument which is a reference, as there will be
|
||||
// conflicting implementations since &T: Any and T: Any cannot be distinguished
|
||||
//def_register!(imp $p0 => Ref<$p0> => &$p0 => identity $(, $p => $p => $p => Clone::clone)*);
|
||||
|
||||
def_register!($($p),*);
|
||||
|
@ -38,6 +38,7 @@
|
||||
//!
|
||||
//! # #[cfg(not(feature = "no_std"))]
|
||||
//! assert_eq!(
|
||||
//! // Evaluate the script, expects a 'bool' return
|
||||
//! engine.eval_file::<bool>("my_script.rhai".into())?,
|
||||
//! true
|
||||
//! );
|
||||
|
@ -2,14 +2,16 @@
|
||||
|
||||
use crate::any::{Any, Dynamic};
|
||||
use crate::engine::{
|
||||
Engine, FunctionsLib, KEYWORD_DEBUG, KEYWORD_DUMP_AST, KEYWORD_EVAL, KEYWORD_PRINT,
|
||||
KEYWORD_TYPE_OF,
|
||||
Engine, FnAny, FnCallArgs, FnSpec, FunctionsLib, KEYWORD_DEBUG, KEYWORD_DUMP_AST, KEYWORD_EVAL,
|
||||
KEYWORD_PRINT, KEYWORD_TYPE_OF,
|
||||
};
|
||||
use crate::parser::{map_dynamic_to_expr, Expr, FnDef, ReturnType, Stmt, AST};
|
||||
use crate::parser::{map_dynamic_to_expr, Expr, FnDef, Position, ReturnType, Stmt, AST};
|
||||
use crate::result::EvalAltResult;
|
||||
use crate::scope::{Entry as ScopeEntry, EntryType as ScopeEntryType, Scope};
|
||||
|
||||
use crate::stdlib::{
|
||||
boxed::Box,
|
||||
collections::HashMap,
|
||||
rc::Rc,
|
||||
string::{String, ToString},
|
||||
sync::Arc,
|
||||
@ -96,6 +98,25 @@ impl<'a> State<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Call a registered function
|
||||
fn call_fn(
|
||||
functions: Option<&HashMap<FnSpec, Box<FnAny>>>,
|
||||
fn_name: &str,
|
||||
args: &mut FnCallArgs,
|
||||
pos: Position,
|
||||
) -> Result<Option<Dynamic>, EvalAltResult> {
|
||||
let spec = FnSpec {
|
||||
name: fn_name.into(),
|
||||
args: args.iter().map(|a| Any::type_id(*a)).collect(),
|
||||
};
|
||||
|
||||
// Search built-in's and external functions
|
||||
functions
|
||||
.and_then(|f| f.get(&spec))
|
||||
.map(|func| func(args, pos))
|
||||
.transpose()
|
||||
}
|
||||
|
||||
/// Optimize a statement.
|
||||
fn optimize_stmt<'a>(stmt: Stmt, state: &mut State<'a>, preserve_result: bool) -> Stmt {
|
||||
match stmt {
|
||||
@ -528,21 +549,25 @@ fn optimize_expr<'a>(expr: Expr, state: &mut State<'a>) -> Expr {
|
||||
""
|
||||
};
|
||||
|
||||
state.engine.call_ext_fn_raw(&id, &mut call_args, pos).ok().map(|result|
|
||||
result.or_else(|| {
|
||||
if !arg_for_type_of.is_empty() {
|
||||
// Handle `type_of()`
|
||||
Some(arg_for_type_of.to_string().into_dynamic())
|
||||
} else {
|
||||
// Otherwise use the default value, if any
|
||||
def_value.clone()
|
||||
}
|
||||
}).and_then(|result| map_dynamic_to_expr(result, pos))
|
||||
call_fn(state.engine.functions.as_ref(), &id, &mut call_args, pos).ok()
|
||||
.and_then(|result|
|
||||
result.or_else(|| {
|
||||
if !arg_for_type_of.is_empty() {
|
||||
// Handle `type_of()`
|
||||
Some(arg_for_type_of.to_string().into_dynamic())
|
||||
} else {
|
||||
// Otherwise use the default value, if any
|
||||
def_value.clone()
|
||||
}
|
||||
}).and_then(|result| map_dynamic_to_expr(result, pos))
|
||||
.map(|expr| {
|
||||
state.set_dirty();
|
||||
expr
|
||||
})
|
||||
).flatten().unwrap_or_else(|| Expr::FunctionCall(id, args, def_value, pos))
|
||||
).unwrap_or_else(||
|
||||
// Optimize function call arguments
|
||||
Expr::FunctionCall(id, args.into_iter().map(|a| optimize_expr(a, state)).collect(), def_value, pos)
|
||||
)
|
||||
}
|
||||
|
||||
// id(args ..) -> optimize function call arguments
|
||||
|
@ -62,9 +62,6 @@ fn test_call_fn() -> Result<(), EvalAltResult> {
|
||||
|
||||
#[test]
|
||||
fn test_anonymous_fn() -> Result<(), EvalAltResult> {
|
||||
let calc_func: Box<dyn Fn(INT, INT, INT) -> Result<INT, EvalAltResult>> =
|
||||
Engine::new().create_from_script("fn calc() { 42 }", "calc")?;
|
||||
|
||||
let calc_func = Func::<(INT, INT, INT), INT>::create_from_script(
|
||||
Engine::new(),
|
||||
"fn calc(x, y, z) { (x + y) * z }",
|
||||
|
@ -9,10 +9,10 @@ fn test_stack_overflow() -> Result<(), EvalAltResult> {
|
||||
engine.eval::<i64>(
|
||||
r"
|
||||
fn foo(n) { if n == 0 { 0 } else { n + foo(n-1) } }
|
||||
foo(38)
|
||||
foo(30)
|
||||
",
|
||||
)?,
|
||||
741
|
||||
465
|
||||
);
|
||||
|
||||
match engine.eval::<()>(
|
||||
|
Loading…
Reference in New Issue
Block a user