Bump version to 0.12.0.

This commit is contained in:
Stephen Chung
2020-04-09 18:45:49 +08:00
parent 34ef2d6e00
commit 3609150dcf
8 changed files with 67 additions and 63 deletions

View File

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

View File

@@ -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),*);

View File

@@ -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
//! );

View File

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