Add for statement and range function; New register_box_fn for functions returning Box<dyn Any> (which should not be boxed again); Register standard utility functions in library (e.g. print, string concat).

This commit is contained in:
Stephen Chung
2020-02-23 22:48:46 +08:00
parent b2747b076e
commit 157aa2be94
7 changed files with 276 additions and 29 deletions

View File

@@ -6,6 +6,9 @@ use crate::engine::{Engine, EvalAltResult};
pub trait RegisterFn<FN, ARGS, RET> {
fn register_fn(&mut self, name: &str, f: FN);
}
pub trait RegisterBoxFn<FN, ARGS> {
fn register_box_fn(&mut self, name: &str, f: FN);
}
pub struct Ref<A>(A);
pub struct Mut<A>(A);
@@ -44,7 +47,37 @@ macro_rules! def_register {
// Call the user-supplied function using ($clone) to
// potentially clone the value, otherwise pass the reference.
Ok(Box::new(f($(($clone)($par)),*)) as Box<dyn Any>)
let r = f($(($clone)($par)),*);
Ok(Box::new(r) as Box<dyn Any>)
};
self.register_fn_raw(name.to_owned(), Some(vec![$(TypeId::of::<$par>()),*]), Box::new(fun));
}
}
impl<$($par,)* FN> RegisterBoxFn<FN, ($($mark,)*)> for Engine
where
$($par: Any + Clone,)*
FN: Fn($($param),*) -> Box<dyn Any> + 'static
{
fn register_box_fn(&mut self, name: &str, f: FN) {
let fun = move |mut args: Vec<&mut dyn Any>| {
// Check for length at the beginning to avoid
// per-element bound checks.
if args.len() != count_args!($($par)*) {
return Err(EvalAltResult::ErrorFunctionArgMismatch);
}
#[allow(unused_variables, unused_mut)]
let mut drain = args.drain(..);
$(
// Downcast every element, return in case of a type mismatch
let $par = ((*drain.next().unwrap()).downcast_mut() as Option<&mut $par>)
.ok_or(EvalAltResult::ErrorFunctionArgMismatch)?;
)*
// Call the user-supplied function using ($clone) to
// potentially clone the value, otherwise pass the reference.
Ok(f($(($clone)($par)),*))
};
self.register_fn_raw(name.to_owned(), Some(vec![$(TypeId::of::<$par>()),*]), Box::new(fun));
}