Add better funcion call syntax

This commit is contained in:
torkleyy 2017-12-20 22:16:53 +01:00
parent 71ebd0d4d1
commit 76a1e3056b
3 changed files with 56 additions and 7 deletions

36
src/call.rs Normal file
View File

@ -0,0 +1,36 @@
//! Helper module which defines `FnArgs`
//! to make function calling easier.
use any::Any;
pub trait FunArgs<'a> {
fn into_vec(self) -> Vec<&'a mut Any>;
}
macro_rules! impl_args {
($($p:ident),*) => {
impl<'a, $($p),*> FunArgs<'a> for ($(&'a mut $p,)*)
where
$($p: Any + Clone),*
{
fn into_vec(self) -> Vec<&'a mut Any> {
let ($($p,)*) = self;
let mut v = Vec::new();
$(v.push($p as &mut Any);)*
v
}
}
impl_args!(@pop $($p),*);
};
(@pop) => {
};
(@pop $head:ident $(, $tail:ident)*) => {
impl_args!($($tail),*);
};
}
#[cfg_attr(rustfmt, rustfmt_skip)]
impl_args!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S);

View File

@ -9,6 +9,7 @@ use std::ops::{Add, BitAnd, BitOr, BitXor, Deref, Div, Mul, Neg, Rem, Shl, Shr,
use any::{Any, AnyExt}; use any::{Any, AnyExt};
use fn_register::{Mut, RegisterFn}; use fn_register::{Mut, RegisterFn};
use parser::{lex, parse, Expr, FnDef, Stmt}; use parser::{lex, parse, Expr, FnDef, Stmt};
use call::FunArgs;
#[derive(Debug)] #[derive(Debug)]
pub enum EvalAltResult { pub enum EvalAltResult {
@ -136,6 +137,20 @@ pub type FnAny = Fn(Vec<&mut Any>) -> Result<Box<Any>, EvalAltResult>;
pub type Scope = Vec<(String, Box<Any>)>; pub type Scope = Vec<(String, Box<Any>)>;
impl Engine { impl Engine {
pub fn call_fn<'a, I, A, T>(&self, ident: I, args: A) -> Result<T, EvalAltResult>
where
I: Into<String>,
A: FunArgs<'a>,
T: Any + Clone,
{
self.call_fn_raw(ident.into(), args.into_vec())
.and_then(|b| {
b.downcast()
.map(|b| *b)
.map_err(|_| EvalAltResult::ErrorMismatchOutputType)
})
}
/// Universal method for calling functions, that are either /// Universal method for calling functions, that are either
/// registered with the `Engine` or written in Rhai /// registered with the `Engine` or written in Rhai
pub fn call_fn_raw( pub fn call_fn_raw(
@ -151,11 +166,7 @@ impl Engine {
let spec = FnSpec { let spec = FnSpec {
ident: ident.clone(), ident: ident.clone(),
args: Some( args: Some(args.iter().map(|a| <Any as Any>::type_id(&**a)).collect()),
args.iter()
.map(|a| <Any as Any>::type_id(&**a))
.collect(),
),
}; };
let spec1 = FnSpec { ident, args: None }; let spec1 = FnSpec { ident, args: None };
@ -241,7 +252,9 @@ impl Engine {
let mut args: Vec<Box<Any>> = args.iter() let mut args: Vec<Box<Any>> = args.iter()
.map(|arg| self.eval_expr(scope, arg)) .map(|arg| self.eval_expr(scope, arg))
.collect::<Result<Vec<_>, _>>()?; .collect::<Result<Vec<_>, _>>()?;
let args = once(this_ptr).chain(args.iter_mut().map(|b| b.as_mut())).collect(); let args = once(this_ptr)
.chain(args.iter_mut().map(|b| b.as_mut()))
.collect();
self.call_fn_raw(fn_name.to_owned(), args) self.call_fn_raw(fn_name.to_owned(), args)
} }

View File

@ -65,4 +65,4 @@ macro_rules! def_register {
} }
#[cfg_attr(rustfmt, rustfmt_skip)] #[cfg_attr(rustfmt, rustfmt_skip)]
def_register!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z); def_register!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S);