diff --git a/examples/arrays_and_structs.rs b/examples/arrays_and_structs.rs index 4cd22b31..af7246fb 100644 --- a/examples/arrays_and_structs.rs +++ b/examples/arrays_and_structs.rs @@ -1,9 +1,9 @@ extern crate rhai; -use rhai::{Engine, FnRegister}; +use rhai::{Engine, RegisterFn}; #[derive(Clone, Debug)] struct TestStruct { - x: i64 + x: i64, } impl TestStruct { @@ -24,5 +24,12 @@ fn main() { engine.register_fn("update", TestStruct::update); engine.register_fn("new_ts", TestStruct::new); - println!("{:?}", engine.eval::("let x = [new_ts()]; x[0].update(); x[0]")); + println!( + "{:?}", + engine.eval::("let x = new_ts(); x.update(); x") + ); + println!( + "{:?}", + engine.eval::("let x = [new_ts()]; x[0].update(); x[0]") + ); } diff --git a/examples/custom_types_and_methods.rs b/examples/custom_types_and_methods.rs index 7b70914f..65cf3225 100644 --- a/examples/custom_types_and_methods.rs +++ b/examples/custom_types_and_methods.rs @@ -1,9 +1,9 @@ extern crate rhai; -use rhai::{Engine, FnRegister}; +use rhai::{Engine, RegisterFn}; #[derive(Clone)] struct TestStruct { - x: i64 + x: i64, } impl TestStruct { diff --git a/examples/hello.rs b/examples/hello.rs index 7f493b24..925902b8 100644 --- a/examples/hello.rs +++ b/examples/hello.rs @@ -5,6 +5,6 @@ fn main() { let mut engine = Engine::new(); if let Ok(result) = engine.eval::("40 + 2") { - println!("Answer: {}", result); // prints 42 + println!("Answer: {}", result); // prints 42 } -} \ No newline at end of file +} diff --git a/examples/repl.rs b/examples/repl.rs index bc2ee802..145c288b 100644 --- a/examples/repl.rs +++ b/examples/repl.rs @@ -3,38 +3,40 @@ extern crate rhai; use std::fmt::Display; use std::process::exit; use std::io::{stdin, stdout, Write}; -use rhai::{Engine, Scope, FnRegister}; +use rhai::{Engine, RegisterFn, Scope}; fn showit(x: &mut T) -> () { println!("{}", x) } -fn quit() { exit(0); } +fn quit() { + exit(0); +} pub fn main() { - let mut engine = Engine::new(); - let mut scope = Scope::new(); + let mut engine = Engine::new(); + let mut scope = Scope::new(); - engine.register_fn("print", showit as fn(x: &mut i32)->()); - engine.register_fn("print", showit as fn(x: &mut i64)->()); - engine.register_fn("print", showit as fn(x: &mut u32)->()); - engine.register_fn("print", showit as fn(x: &mut u64)->()); - engine.register_fn("print", showit as fn(x: &mut f32)->()); - engine.register_fn("print", showit as fn(x: &mut f64)->()); - engine.register_fn("print", showit as fn(x: &mut bool)->()); - engine.register_fn("print", showit as fn(x: &mut String)->()); + engine.register_fn("print", showit as fn(x: &mut i32) -> ()); + engine.register_fn("print", showit as fn(x: &mut i64) -> ()); + engine.register_fn("print", showit as fn(x: &mut u32) -> ()); + engine.register_fn("print", showit as fn(x: &mut u64) -> ()); + engine.register_fn("print", showit as fn(x: &mut f32) -> ()); + engine.register_fn("print", showit as fn(x: &mut f64) -> ()); + engine.register_fn("print", showit as fn(x: &mut bool) -> ()); + engine.register_fn("print", showit as fn(x: &mut String) -> ()); engine.register_fn("exit", quit); - loop { - print!("> "); - let mut input = String::new(); - stdout().flush().expect("couldn't flush stdout"); - if let Err(e) = stdin().read_line(&mut input) { - println!("input error: {}", e); - } + loop { + print!("> "); + let mut input = String::new(); + stdout().flush().expect("couldn't flush stdout"); + if let Err(e) = stdin().read_line(&mut input) { + println!("input error: {}", e); + } - if let Err(e) = engine.consume_with_scope(&mut scope, &input) { - println!("error: {}", e); - } - } + if let Err(e) = engine.consume_with_scope(&mut scope, &input) { + println!("error: {}", e); + } + } } diff --git a/examples/reuse_scope.rs b/examples/reuse_scope.rs index 9d2459c7..c7a8726b 100644 --- a/examples/reuse_scope.rs +++ b/examples/reuse_scope.rs @@ -5,10 +5,14 @@ fn main() { let mut engine = Engine::new(); let mut scope: Scope = Vec::new(); - if !engine.eval_with_scope::<()>(&mut scope, "let x = 4 + 5").is_ok() { assert!(false); } + if !engine + .eval_with_scope::<()>(&mut scope, "let x = 4 + 5") + .is_ok() + { + assert!(false); + } if let Ok(result) = engine.eval_with_scope::(&mut scope, "x") { - println!("result: {}", result); + println!("result: {}", result); } } - diff --git a/examples/rhai_runner.rs b/examples/rhai_runner.rs index abffb6ed..6637844a 100644 --- a/examples/rhai_runner.rs +++ b/examples/rhai_runner.rs @@ -2,7 +2,7 @@ use std::env; use std::fmt::Display; extern crate rhai; -use rhai::{Engine, FnRegister}; +use rhai::{Engine, RegisterFn}; fn showit(x: &mut T) -> () { println!("{}", x) @@ -12,19 +12,18 @@ fn main() { for fname in env::args().skip(1) { let mut engine = Engine::new(); - engine.register_fn("print", showit as fn(x: &mut i32)->()); - engine.register_fn("print", showit as fn(x: &mut i64)->()); - engine.register_fn("print", showit as fn(x: &mut u32)->()); - engine.register_fn("print", showit as fn(x: &mut u64)->()); - engine.register_fn("print", showit as fn(x: &mut f32)->()); - engine.register_fn("print", showit as fn(x: &mut f64)->()); - engine.register_fn("print", showit as fn(x: &mut bool)->()); - engine.register_fn("print", showit as fn(x: &mut String)->()); + engine.register_fn("print", showit as fn(x: &mut i32) -> ()); + engine.register_fn("print", showit as fn(x: &mut i64) -> ()); + engine.register_fn("print", showit as fn(x: &mut u32) -> ()); + engine.register_fn("print", showit as fn(x: &mut u64) -> ()); + engine.register_fn("print", showit as fn(x: &mut f32) -> ()); + engine.register_fn("print", showit as fn(x: &mut f64) -> ()); + engine.register_fn("print", showit as fn(x: &mut bool) -> ()); + engine.register_fn("print", showit as fn(x: &mut String) -> ()); match engine.eval_file::<()>(&fname) { Ok(_) => (), - Err(e) => {println!("Error: {}", e)} + Err(e) => println!("Error: {}", e), } } } - diff --git a/examples/simple_fn.rs b/examples/simple_fn.rs index 541edf1e..04b55b68 100644 --- a/examples/simple_fn.rs +++ b/examples/simple_fn.rs @@ -1,5 +1,5 @@ extern crate rhai; -use rhai::{Engine, FnRegister}; +use rhai::{Engine, RegisterFn}; fn add(x: i64, y: i64) -> i64 { x + y @@ -9,8 +9,7 @@ fn main() { let mut engine = Engine::new(); engine.register_fn("add", add); - if let Ok(result) = engine.eval::("add(40, 2)") { - println!("Answer: {}", result); // prints 42 + println!("Answer: {}", result); // prints 42 } } diff --git a/src/any.rs b/src/any.rs new file mode 100644 index 00000000..114dad9b --- /dev/null +++ b/src/any.rs @@ -0,0 +1,102 @@ +use std::any::{Any as StdAny, TypeId}; +use std::fmt; + +pub trait Any: StdAny { + fn type_id(&self) -> TypeId; + + fn box_clone(&self) -> Box; + + /// This type may only be implemented by `rhai`. + #[doc(hidden)] + fn _closed(&self) -> _Private; +} + +impl Any for T + where + T: Clone + StdAny + ?Sized +{ + #[inline] + fn type_id(&self) -> TypeId { + TypeId::of::() + } + + #[inline] + fn box_clone(&self) -> Box { + Box::new(self.clone()) + } + + fn _closed(&self) -> _Private { + _Private + } +} + +impl Any { + #[inline] + fn box_clone(&self) -> Box { + Any::box_clone(self) + } + + #[inline] + pub fn is(&self) -> bool { + let t = TypeId::of::(); + let boxed = self.type_id(); + + t == boxed + } + + #[inline] + pub fn downcast_ref(&self) -> Option<&T> { + if self.is::() { + unsafe { + Some(&*(self as *const Any as *const T)) + } + } else { + None + } + } + + #[inline] + pub fn downcast_mut(&mut self) -> Option<&mut T> { + if self.is::() { + unsafe { + Some(&mut *(self as *mut Any as *mut T)) + } + } else { + None + } + } +} + +impl Clone for Box { + fn clone(&self) -> Self { + Any::box_clone(self.as_ref() as &Any) + } +} + +impl fmt::Debug for Any { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("Any") + } +} + +pub trait AnyExt: Sized { + fn downcast(self) -> Result, Self>; +} + +impl AnyExt for Box { + fn downcast(self) -> Result, Self> { + if self.is::() { + unsafe { + let raw: *mut Any = Box::into_raw(self); + Ok(Box::from_raw(raw as *mut T)) + } + } else { + Err(self) + } + } +} + +/// Private type which ensures that `rhai::Any` can only +/// be implemented by this crate. +#[doc(hidden)] +pub struct _Private; diff --git a/src/call.rs b/src/call.rs new file mode 100644 index 00000000..cf3313e3 --- /dev/null +++ b/src/call.rs @@ -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); diff --git a/src/engine.rs b/src/engine.rs index 18aa0ce6..88563a45 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -1,14 +1,15 @@ +use std::any::TypeId; +use std::borrow::Borrow; +use std::cmp::{PartialEq, PartialOrd}; use std::collections::HashMap; use std::error::Error; -use std::any::Any; -use std::boxed::Box; use std::fmt; +use std::ops::{Add, BitAnd, BitOr, BitXor, Deref, Div, Mul, Neg, Rem, Shl, Shr, Sub}; -use parser::{lex, parse, Expr, Stmt, FnDef}; -use fn_register::FnRegister; - -use std::ops::{Add, Sub, Mul, Div, Neg, BitAnd, BitOr, BitXor, Shl, Shr, Rem}; -use std::cmp::{PartialOrd, PartialEq}; +use any::{Any, AnyExt}; +use fn_register::{Mut, RegisterFn}; +use parser::{lex, parse, Expr, FnDef, Stmt}; +use call::FunArgs; #[derive(Debug)] pub enum EvalAltResult { @@ -27,6 +28,27 @@ pub enum EvalAltResult { Return(Box), } +impl PartialEq for EvalAltResult { + fn eq(&self, other: &Self) -> bool { + use EvalAltResult::*; + + match (self, other) { + (&ErrorFunctionNotFound, &ErrorFunctionNotFound) => true, + (&ErrorFunctionArgMismatch, &ErrorFunctionArgMismatch) => true, + (&ErrorFunctionCallNotSupported, &ErrorFunctionCallNotSupported) => true, + (&ErrorIndexMismatch, &ErrorIndexMismatch) => true, + (&ErrorIfGuardMismatch, &ErrorIfGuardMismatch) => true, + (&ErrorVariableNotFound(ref a), &ErrorVariableNotFound(ref b)) => a == b, + (&ErrorFunctionArityNotSupported, &ErrorFunctionArityNotSupported) => true, + (&ErrorAssignmentToUnknownLHS, &ErrorAssignmentToUnknownLHS) => true, + (&ErrorMismatchOutputType, &ErrorMismatchOutputType) => true, + (&ErrorCantOpenScriptFile, &ErrorCantOpenScriptFile) => true, + (&InternalErrorMalformedDotExpression, &InternalErrorMalformedDotExpression) => true, + (&LoopBreak, &LoopBreak) => true, + _ => false, + } + } +} impl Error for EvalAltResult { fn description(&self) -> &str { @@ -66,29 +88,10 @@ impl fmt::Display for EvalAltResult { } } -pub enum FnType { - ExternalFn0(Box Result, EvalAltResult>>), - ExternalFn1(Box) -> Result, EvalAltResult>>), - ExternalFn2(Box, &mut Box) -> Result, EvalAltResult>>), - ExternalFn3(Box, &mut Box, &mut Box) - -> Result, EvalAltResult>>), - ExternalFn4(Box, &mut Box, &mut Box, &mut Box) - -> Result, EvalAltResult>>), - ExternalFn5(Box, - &mut Box, - &mut Box, - &mut Box, - &mut Box) - -> Result, EvalAltResult>>), - ExternalFn6(Box, - &mut Box, - &mut Box, - &mut Box, - &mut Box, - &mut Box) - -> Result, EvalAltResult>>), - - InternalFn(FnDef), +#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] +pub struct FnSpec { + ident: String, + args: Option>, } /// Rhai's engine type. This is what you use to run Rhai scripts @@ -107,9 +110,16 @@ pub enum FnType { /// ``` pub struct Engine { /// A hashmap containing all functions know to the engine - pub fns: HashMap>, + pub fns: HashMap, } +pub enum FnIntExt { + Ext(Box), + Int(FnDef), +} + +pub type FnAny = Fn(Vec<&mut Any>) -> Result, EvalAltResult>; + /// A type containing information about current scope. /// Useful for keeping state between `Engine` runs /// @@ -127,820 +137,280 @@ pub struct Engine { pub type Scope = Vec<(String, Box)>; impl Engine { + pub fn call_fn<'a, I, A, T>(&self, ident: I, args: A) -> Result + where + I: Into, + 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 /// registered with the `Engine` or written in Rhai - pub fn call_fn(&self, - name: &str, - arg1: Option<&mut Box>, - arg2: Option<&mut Box>, - arg3: Option<&mut Box>, - arg4: Option<&mut Box>, - arg5: Option<&mut Box>, - arg6: Option<&mut Box>) - -> Result, EvalAltResult> { + pub fn call_fn_raw( + &self, + ident: String, + args: Vec<&mut Any>, + ) -> Result, EvalAltResult> { + println!( + "Trying to call function {:?} with args {:?}", + ident, + args.iter().map(|x| (&**x).type_id()).collect::>() + ); - match self.fns.get(name) { - Some(vf) => { - match (arg1, arg2, arg3, arg4, arg5, arg6) { - (Some(ref mut a1), - Some(ref mut a2), - Some(ref mut a3), - Some(ref mut a4), - Some(ref mut a5), - Some(ref mut a6)) => { - for arr_f in vf { - match *arr_f { - FnType::ExternalFn6(ref f) => { - if let Ok(v) = f(*a1, *a2, *a3, *a4, *a5, *a6) { - return Ok(v); - } - } - FnType::InternalFn(ref f) => { - if f.params.len() != 6 { - return Err(EvalAltResult::ErrorFunctionArgMismatch); - } + let spec = FnSpec { + ident: ident.clone(), + args: Some(args.iter().map(|a| ::type_id(&**a)).collect()), + }; + let spec1 = FnSpec { ident, args: None }; - let mut new_scope: Scope = Vec::new(); - let result1 = self.call_fn("clone", - Some(a1), - None, - None, - None, - None, - None); - let result2 = self.call_fn("clone", - Some(a2), - None, - None, - None, - None, - None); - let result3 = self.call_fn("clone", - Some(a3), - None, - None, - None, - None, - None); - let result4 = self.call_fn("clone", - Some(a4), - None, - None, - None, - None, - None); - let result5 = self.call_fn("clone", - Some(a5), - None, - None, - None, - None, - None); - let result6 = self.call_fn("clone", - Some(a6), - None, - None, - None, - None, - None); + self.fns + .get(&spec) + .or_else(|| self.fns.get(&spec1)) + .ok_or(EvalAltResult::ErrorFunctionNotFound) + .and_then(move |f| match *f { + FnIntExt::Ext(ref f) => f(args), + FnIntExt::Int(ref f) => { + let mut scope = Scope::new(); + scope.extend( + f.params + .iter() + .cloned() + .zip(args.iter().map(|x| (&**x).box_clone())), + ); - match (result1, result2, result3, result4, result5, result6) { - (Ok(r1), Ok(r2), Ok(r3), Ok(r4), Ok(r5), Ok(r6)) => { - new_scope.push((f.params[0].clone(), r1)); - new_scope.push((f.params[1].clone(), r2)); - new_scope.push((f.params[2].clone(), r3)); - new_scope.push((f.params[3].clone(), r4)); - new_scope.push((f.params[4].clone(), r5)); - new_scope.push((f.params[5].clone(), r6)); - } - _ => return Err(EvalAltResult::ErrorFunctionArgMismatch), - } - match self.eval_stmt(&mut new_scope, &*f.body) { - Err(EvalAltResult::Return(x)) => return Ok(x), - x => return x, - } - } - _ => (), - } - } - Err(EvalAltResult::ErrorFunctionArgMismatch) - } - (Some(ref mut a1), - Some(ref mut a2), - Some(ref mut a3), - Some(ref mut a4), - Some(ref mut a5), - None) => { - for arr_f in vf { - match *arr_f { - FnType::ExternalFn5(ref f) => { - if let Ok(v) = f(*a1, *a2, *a3, *a4, *a5) { - return Ok(v); - } - } - FnType::InternalFn(ref f) => { - if f.params.len() != 5 { - return Err(EvalAltResult::ErrorFunctionArgMismatch); - } - - let mut new_scope: Scope = Vec::new(); - let result1 = self.call_fn("clone", - Some(a1), - None, - None, - None, - None, - None); - let result2 = self.call_fn("clone", - Some(a2), - None, - None, - None, - None, - None); - let result3 = self.call_fn("clone", - Some(a3), - None, - None, - None, - None, - None); - let result4 = self.call_fn("clone", - Some(a4), - None, - None, - None, - None, - None); - let result5 = self.call_fn("clone", - Some(a5), - None, - None, - None, - None, - None); - - match (result1, result2, result3, result4, result5) { - (Ok(r1), Ok(r2), Ok(r3), Ok(r4), Ok(r5)) => { - new_scope.push((f.params[0].clone(), r1)); - new_scope.push((f.params[1].clone(), r2)); - new_scope.push((f.params[2].clone(), r3)); - new_scope.push((f.params[3].clone(), r4)); - new_scope.push((f.params[4].clone(), r5)); - } - _ => return Err(EvalAltResult::ErrorFunctionArgMismatch), - } - match self.eval_stmt(&mut new_scope, &*f.body) { - Err(EvalAltResult::Return(x)) => return Ok(x), - x => return x, - } - } - _ => (), - } - } - Err(EvalAltResult::ErrorFunctionArgMismatch) - } - (Some(ref mut a1), - Some(ref mut a2), - Some(ref mut a3), - Some(ref mut a4), - None, - None) => { - for arr_f in vf { - match *arr_f { - FnType::ExternalFn4(ref f) => { - if let Ok(v) = f(*a1, *a2, *a3, *a4) { - return Ok(v) - } - } - FnType::InternalFn(ref f) => { - if f.params.len() != 4 { - return Err(EvalAltResult::ErrorFunctionArgMismatch); - } - - let mut new_scope: Scope = Vec::new(); - let result1 = self.call_fn("clone", - Some(a1), - None, - None, - None, - None, - None); - let result2 = self.call_fn("clone", - Some(a2), - None, - None, - None, - None, - None); - let result3 = self.call_fn("clone", - Some(a3), - None, - None, - None, - None, - None); - let result4 = self.call_fn("clone", - Some(a4), - None, - None, - None, - None, - None); - match (result1, result2, result3, result4) { - (Ok(r1), Ok(r2), Ok(r3), Ok(r4)) => { - new_scope.push((f.params[0].clone(), r1)); - new_scope.push((f.params[1].clone(), r2)); - new_scope.push((f.params[2].clone(), r3)); - new_scope.push((f.params[3].clone(), r4)); - } - _ => return Err(EvalAltResult::ErrorFunctionArgMismatch), - } - match self.eval_stmt(&mut new_scope, &*f.body) { - Err(EvalAltResult::Return(x)) => return Ok(x), - x => return x, - } - } - _ => (), - } - } - Err(EvalAltResult::ErrorFunctionArgMismatch) - } - (Some(ref mut a1), Some(ref mut a2), Some(ref mut a3), None, None, None) => { - for arr_f in vf { - match *arr_f { - FnType::ExternalFn3(ref f) => { - if let Ok(v) = f(*a1, *a2, *a3) { - return Ok(v); - } - } - FnType::InternalFn(ref f) => { - if f.params.len() != 3 { - return Err(EvalAltResult::ErrorFunctionArgMismatch); - } - - let mut new_scope: Scope = Vec::new(); - let result1 = self.call_fn("clone", - Some(a1), - None, - None, - None, - None, - None); - let result2 = self.call_fn("clone", - Some(a2), - None, - None, - None, - None, - None); - let result3 = self.call_fn("clone", - Some(a3), - None, - None, - None, - None, - None); - match (result1, result2, result3) { - (Ok(r1), Ok(r2), Ok(r3)) => { - new_scope.push((f.params[0].clone(), r1)); - new_scope.push((f.params[1].clone(), r2)); - new_scope.push((f.params[2].clone(), r3)); - } - _ => return Err(EvalAltResult::ErrorFunctionArgMismatch), - } - match self.eval_stmt(&mut new_scope, &*f.body) { - Err(EvalAltResult::Return(x)) => return Ok(x), - x => return x, - } - } - _ => (), - } - } - Err(EvalAltResult::ErrorFunctionArgMismatch) - } - (Some(ref mut a1), Some(ref mut a2), None, None, None, None) => { - for arr_f in vf { - match *arr_f { - FnType::ExternalFn2(ref f) => { - if let Ok(v) = f(*a1, *a2) { - return Ok(v); - } - } - FnType::InternalFn(ref f) => { - if f.params.len() != 2 { - return Err(EvalAltResult::ErrorFunctionArgMismatch); - } - - let mut new_scope: Scope = Vec::new(); - let result1 = self.call_fn("clone", - Some(a1), - None, - None, - None, - None, - None); - let result2 = self.call_fn("clone", - Some(a2), - None, - None, - None, - None, - None); - match (result1, result2) { - (Ok(r1), Ok(r2)) => { - new_scope.push((f.params[0].clone(), r1)); - new_scope.push((f.params[1].clone(), r2)); - } - _ => return Err(EvalAltResult::ErrorFunctionArgMismatch), - } - match self.eval_stmt(&mut new_scope, &*f.body) { - Err(EvalAltResult::Return(x)) => return Ok(x), - x => return x, - } - } - _ => (), - } - } - Err(EvalAltResult::ErrorFunctionArgMismatch) - } - (Some(ref mut a1), None, None, None, None, None) => { - for arr_f in vf { - match *arr_f { - FnType::ExternalFn1(ref f) => { - if let Ok(v) = f(*a1) { - return Ok(v); - } - } - FnType::InternalFn(ref f) => { - if f.params.len() != 1 { - return Err(EvalAltResult::ErrorFunctionArgMismatch); - } - - let mut new_scope: Scope = Vec::new(); - let result1 = self.call_fn("clone", - Some(a1), - None, - None, - None, - None, - None); - match result1 { - Ok(r1) => { - new_scope.push((f.params[0].clone(), r1)); - } - _ => return Err(EvalAltResult::ErrorFunctionArgMismatch), - } - match self.eval_stmt(&mut new_scope, &*f.body) { - Err(EvalAltResult::Return(x)) => return Ok(x), - x => return x, - } - } - _ => (), - } - } - Err(EvalAltResult::ErrorFunctionArgMismatch) - } - _ => { - for arr_f in vf { - match *arr_f { - FnType::ExternalFn0(ref f) => { - if let Ok(v) = f() { - return Ok(v); - } - } - FnType::InternalFn(ref f) => { - if !f.params.is_empty() { - return Err(EvalAltResult::ErrorFunctionArgMismatch); - } - - let mut new_scope: Scope = Vec::new(); - match self.eval_stmt(&mut new_scope, &*f.body) { - Err(EvalAltResult::Return(x)) => return Ok(x), - x => return x, - } - } - _ => (), - } - } - Err(EvalAltResult::ErrorFunctionArgMismatch) + match self.eval_stmt(&mut scope, &*f.body) { + Err(EvalAltResult::Return(x)) => Ok(x), + other => other, } } - } - None => Err(EvalAltResult::ErrorFunctionNotFound), - } + }) + } + + pub fn register_fn_raw(&mut self, ident: String, args: Option>, f: Box) { + println!("Register; {:?} with args {:?}", ident, args,); + + let spec = FnSpec { ident, args }; + + self.fns.insert(spec, FnIntExt::Ext(f)); } /// Register a type for use with Engine. Keep in mind that /// your type must implement Clone. - pub fn register_type(&mut self) { - fn clone_helper(t: T) -> T { - t.clone() - }; - - self.register_fn("clone", clone_helper as fn(T) -> T); + pub fn register_type(&mut self) { + // currently a no-op, exists for future extensibility } /// Register a get function for a member of a registered type pub fn register_get(&mut self, name: &str, get_fn: F) - where F: 'static + Fn(&mut T) -> U + where + F: 'static + Fn(&mut T) -> U, { - let get_name = "get$".to_string() + name; self.register_fn(&get_name, get_fn); } /// Register a set function for a member of a registered type pub fn register_set(&mut self, name: &str, set_fn: F) - where F: 'static + Fn(&mut T, U) -> () + where + F: 'static + Fn(&mut T, U) -> (), { - let set_name = "set$".to_string() + name; self.register_fn(&set_name, set_fn); } /// Shorthand for registering both getters and setters - pub fn register_get_set(&mut self, - name: &str, - get_fn: F, - set_fn: G) - where F: 'static + Fn(&mut T) -> U, - G: 'static + Fn(&mut T, U) -> () + pub fn register_get_set( + &mut self, + name: &str, + get_fn: F, + set_fn: G, + ) where + F: 'static + Fn(&mut T) -> U, + G: 'static + Fn(&mut T, U) -> (), { - self.register_get(name, get_fn); self.register_set(name, set_fn); } - fn get_dot_val_helper(&self, - scope: &mut Scope, - this_ptr: &mut Box, - dot_rhs: &Expr) - -> Result, EvalAltResult> { + fn get_dot_val_helper( + &self, + scope: &mut Scope, + this_ptr: &mut Any, + dot_rhs: &Expr, + ) -> Result, EvalAltResult> { + use std::iter::once; + match *dot_rhs { Expr::FnCall(ref fn_name, ref args) => { - if args.is_empty() { - self.call_fn(fn_name, Some(this_ptr), None, None, None, None, None) - } else if args.len() == 1 { - let mut arg = self.eval_expr(scope, &args[0])?; + let mut args: Vec> = args.iter() + .map(|arg| self.eval_expr(scope, arg)) + .collect::, _>>()?; + let args = once(this_ptr) + .chain(args.iter_mut().map(|b| b.as_mut())) + .collect(); - self.call_fn(fn_name, - Some(this_ptr), - Some(&mut arg), - None, - None, - None, - None) - } else if args.len() == 2 { - let mut arg1 = self.eval_expr(scope, &args[0])?; - let mut arg2 = self.eval_expr(scope, &args[1])?; - - self.call_fn(fn_name, - Some(this_ptr), - Some(&mut arg1), - Some(&mut arg2), - None, - None, - None) - } else if args.len() == 3 { - let mut arg1 = self.eval_expr(scope, &args[0])?; - let mut arg2 = self.eval_expr(scope, &args[1])?; - let mut arg3 = self.eval_expr(scope, &args[2])?; - - self.call_fn(fn_name, - Some(this_ptr), - Some(&mut arg1), - Some(&mut arg2), - Some(&mut arg3), - None, - None) - } else if args.len() == 4 { - let mut arg1 = self.eval_expr(scope, &args[0])?; - let mut arg2 = self.eval_expr(scope, &args[1])?; - let mut arg3 = self.eval_expr(scope, &args[2])?; - let mut arg4 = self.eval_expr(scope, &args[3])?; - - self.call_fn(fn_name, - Some(this_ptr), - Some(&mut arg1), - Some(&mut arg2), - Some(&mut arg3), - Some(&mut arg4), - None) - } else if args.len() == 5 { - let mut arg1 = self.eval_expr(scope, &args[0])?; - let mut arg2 = self.eval_expr(scope, &args[1])?; - let mut arg3 = self.eval_expr(scope, &args[2])?; - let mut arg4 = self.eval_expr(scope, &args[3])?; - let mut arg5 = self.eval_expr(scope, &args[4])?; - - self.call_fn(fn_name, - Some(this_ptr), - Some(&mut arg1), - Some(&mut arg2), - Some(&mut arg3), - Some(&mut arg4), - Some(&mut arg5)) - } else { - Err(EvalAltResult::ErrorFunctionCallNotSupported) - } + self.call_fn_raw(fn_name.to_owned(), args) } Expr::Identifier(ref id) => { let get_fn_name = "get$".to_string() + id; - self.call_fn(&get_fn_name, Some(this_ptr), None, None, None, None, None) + + self.call_fn_raw(get_fn_name, vec![this_ptr]) } Expr::Index(ref id, ref idx_raw) => { let idx = self.eval_expr(scope, idx_raw)?; - let get_fn_name = "get$".to_string() + id; - if let Ok(mut val) = self.call_fn(&get_fn_name, - Some(this_ptr), - None, - None, - None, - None, - None) { - if let Ok(i) = idx.downcast::() { - if let Some(arr_typed) = - (*val).downcast_mut() as Option<&mut Vec>> { - return self.call_fn("clone", - Some(&mut arr_typed[*i as usize]), - None, - None, - None, - None, - None); - } else { - return Err(EvalAltResult::ErrorIndexMismatch); - } - } else { - return Err(EvalAltResult::ErrorIndexMismatch); - } - } else { - return Err(EvalAltResult::ErrorIndexMismatch); - } - } - Expr::Dot(ref inner_lhs, ref inner_rhs) => { - match **inner_lhs { - Expr::Identifier(ref id) => { - let get_fn_name = "get$".to_string() + id; - let result = self.call_fn(&get_fn_name, - Some(this_ptr), - None, - None, - None, - None, - None); + let mut val = self.call_fn_raw(get_fn_name, vec![this_ptr])?; - match result { - Ok(mut v) => self.get_dot_val_helper(scope, &mut v, inner_rhs), - e => e, - } - } - _ => Err(EvalAltResult::InternalErrorMalformedDotExpression), - } + ((*val).downcast_mut() as Option<&mut Vec>>) + .and_then(|arr| idx.downcast_ref::().map(|idx| (arr, *idx as usize))) + .map(|(arr, idx)| arr[idx].clone()) + .ok_or(EvalAltResult::ErrorIndexMismatch) } + Expr::Dot(ref inner_lhs, ref inner_rhs) => match **inner_lhs { + Expr::Identifier(ref id) => { + let get_fn_name = "get$".to_string() + id; + self.call_fn_raw(get_fn_name, vec![this_ptr]) + .and_then(|mut v| self.get_dot_val_helper(scope, v.as_mut(), inner_rhs)) + } + _ => Err(EvalAltResult::InternalErrorMalformedDotExpression), + }, _ => Err(EvalAltResult::InternalErrorMalformedDotExpression), } } - fn get_dot_val(&self, - scope: &mut Scope, - dot_lhs: &Expr, - dot_rhs: &Expr) - -> Result, EvalAltResult> { + fn search_scope<'a, F, T>( + scope: &'a mut Scope, + id: &str, + map: F, + ) -> Result<(usize, T), EvalAltResult> + where + F: FnOnce(&'a mut Any) -> Result, + { + scope + .iter_mut() + .enumerate() + .rev() + .find(|&(_, &mut (ref name, _))| *id == *name) + .ok_or_else(|| EvalAltResult::ErrorVariableNotFound(id.to_owned())) + .and_then(move |(idx, &mut (_, ref mut val))| map(val.as_mut()).map(|val| (idx, val))) + } + + fn array_value( + &self, + scope: &mut Scope, + id: &str, + idx: &Expr, + ) -> Result<(usize, usize, Box), EvalAltResult> { + let idx_boxed = self.eval_expr(scope, idx)? + .downcast::() + .map_err(|_| EvalAltResult::ErrorIndexMismatch)?; + let idx = *idx_boxed as usize; + let (idx_sc, val) = Self::search_scope(scope, id, |val| { + ((*val).downcast_mut() as Option<&mut Vec>>) + .map(|arr| arr[idx].clone()) + .ok_or(EvalAltResult::ErrorIndexMismatch) + })?; + + Ok((idx_sc, idx, val)) + } + + fn get_dot_val( + &self, + scope: &mut Scope, + dot_lhs: &Expr, + dot_rhs: &Expr, + ) -> Result, EvalAltResult> { match *dot_lhs { Expr::Identifier(ref id) => { - let mut target: Option> = None; + let (sc_idx, mut target) = Self::search_scope(scope, id, |x| Ok(x.box_clone()))?; + let value = self.get_dot_val_helper(scope, target.as_mut(), dot_rhs); - for &mut (ref name, ref mut val) in &mut scope.iter_mut().rev() { - if *id == *name { - let result = self.call_fn("clone", Some(val), None, None, None, None, None); + // In case the expression mutated `target`, we need to reassign it because + // of the above `clone`. + scope[sc_idx].1 = target; - if let Ok(clone) = result { - target = Some(clone); - break; - } else { - return result; - } - } - } - - if let Some(mut t) = target { - let result = self.get_dot_val_helper(scope, &mut t, dot_rhs); - - for &mut (ref name, ref mut val) in &mut scope.iter_mut().rev() { - if *id == *name { - *val = t; - break; - } - } - return result; - } - - Err(EvalAltResult::ErrorVariableNotFound(id.clone())) + value } Expr::Index(ref id, ref idx_raw) => { - let idx_boxed = self.eval_expr(scope, idx_raw)?; - let idx = if let Ok(i) = idx_boxed.downcast::() { - i - } else { - return Err(EvalAltResult::ErrorIndexMismatch); - }; + let (sc_idx, idx, mut target) = self.array_value(scope, id, idx_raw)?; + let value = self.get_dot_val_helper(scope, target.as_mut(), dot_rhs); - let mut target: Option> = None; + // In case the expression mutated `target`, we need to reassign it because + // of the above `clone`. + scope[sc_idx].1.downcast_mut::>>().unwrap()[idx] = target; - for &mut (ref name, ref mut val) in &mut scope.iter_mut().rev() { - if *id == *name { - if let Some(arr_typed) = - (*val).downcast_mut() as Option<&mut Vec>> { - let result = self.call_fn("clone", - Some(&mut arr_typed[*idx as usize]), - None, - None, - None, - None, - None); - - if let Ok(clone) = result { - target = Some(clone); - break; - } else { - return result; - } - } else { - return Err(EvalAltResult::ErrorIndexMismatch); - } - } - } - - if let Some(mut t) = target { - let result = self.get_dot_val_helper(scope, &mut t, dot_rhs); - for &mut (ref name, ref mut val) in &mut scope.iter_mut().rev() { - if *id == *name { - if let Some(arr_typed) = - (*val).downcast_mut() as Option<&mut Vec>> { - arr_typed[*idx as usize] = t; - break; - } - } - } - return result; - } - - Err(EvalAltResult::ErrorVariableNotFound(id.clone())) + value } _ => Err(EvalAltResult::InternalErrorMalformedDotExpression), } } - fn set_dot_val_helper(&self, - this_ptr: &mut Box, - dot_rhs: &Expr, - mut source_val: Box) - -> Result, EvalAltResult> { + fn set_dot_val_helper( + &self, + this_ptr: &mut Any, + dot_rhs: &Expr, + mut source_val: Box, + ) -> Result, EvalAltResult> { match *dot_rhs { Expr::Identifier(ref id) => { let set_fn_name = "set$".to_string() + id; - self.call_fn(&set_fn_name, - Some(this_ptr), - Some(&mut source_val), - None, - None, - None, - None) + self.call_fn_raw(set_fn_name, vec![this_ptr, source_val.as_mut()]) } - Expr::Dot(ref inner_lhs, ref inner_rhs) => { - match **inner_lhs { - Expr::Identifier(ref id) => { - let get_fn_name = "get$".to_string() + id; - let result = self.call_fn(&get_fn_name, - Some(this_ptr), - None, - None, - None, - None, - None); + Expr::Dot(ref inner_lhs, ref inner_rhs) => match **inner_lhs { + Expr::Identifier(ref id) => { + let get_fn_name = "get$".to_string() + id; + self.call_fn_raw(get_fn_name, vec![this_ptr]) + .and_then(|mut v| { + self.set_dot_val_helper(v.as_mut(), inner_rhs, source_val) + .map(|_| v) // Discard Ok return value + }) + .and_then(|mut v| { + let set_fn_name = "set$".to_string() + id; - match result { - Ok(mut v) => { - match self.set_dot_val_helper(&mut v, inner_rhs, source_val) { - Ok(_) => { - let set_fn_name = "set$".to_string() + id; - - self.call_fn(&set_fn_name, - Some(this_ptr), - Some(&mut v), - None, - None, - None, - None) - } - e => e, - } - } - e => e, - } - - } - _ => Err(EvalAltResult::InternalErrorMalformedDotExpression), + self.call_fn_raw(set_fn_name, vec![this_ptr, v.as_mut()]) + }) } - } + _ => Err(EvalAltResult::InternalErrorMalformedDotExpression), + }, _ => Err(EvalAltResult::InternalErrorMalformedDotExpression), } } - fn set_dot_val(&self, - scope: &mut Scope, - dot_lhs: &Expr, - dot_rhs: &Expr, - source_val: Box) - -> Result, EvalAltResult> { + fn set_dot_val( + &self, + scope: &mut Scope, + dot_lhs: &Expr, + dot_rhs: &Expr, + source_val: Box, + ) -> Result, EvalAltResult> { match *dot_lhs { Expr::Identifier(ref id) => { - let mut target: Option> = None; + let (sc_idx, mut target) = Self::search_scope(scope, id, |x| Ok(x.box_clone()))?; + let value = self.set_dot_val_helper(target.as_mut(), dot_rhs, source_val); - for &mut (ref name, ref mut val) in &mut scope.iter_mut().rev() { - if *id == *name { - if let Ok(clone) = self.call_fn("clone", - Some(val), - None, - None, - None, - None, - None) { - target = Some(clone); - break; - } else { - return Err(EvalAltResult::ErrorVariableNotFound(id.clone())); - } - } - } + // In case the expression mutated `target`, we need to reassign it because + // of the above `clone`. + scope[sc_idx].1 = target; - if let Some(mut t) = target { - let result = self.set_dot_val_helper(&mut t, dot_rhs, source_val); - - for &mut (ref name, ref mut val) in &mut scope.iter_mut().rev() { - if *id == *name { - *val = t; - break; - } - } - return result; - } - - Err(EvalAltResult::ErrorAssignmentToUnknownLHS) + value } Expr::Index(ref id, ref idx_raw) => { - let idx_boxed = self.eval_expr(scope, idx_raw)?; - let idx = if let Ok(i) = idx_boxed.downcast::() { - i - } else { - return Err(EvalAltResult::ErrorIndexMismatch); - }; + let (sc_idx, idx, mut target) = self.array_value(scope, id, idx_raw)?; + let value = self.set_dot_val_helper(target.as_mut(), dot_rhs, source_val); - let mut target: Option> = None; + // In case the expression mutated `target`, we need to reassign it because + // of the above `clone`. + scope[sc_idx].1.downcast_mut::>>().unwrap()[idx] = target; - for &mut (ref name, ref mut val) in &mut scope.iter_mut().rev() { - if *id == *name { - if let Some(arr_typed) = - (*val).downcast_mut() as Option<&mut Vec>> { - let result = self.call_fn("clone", - Some(&mut arr_typed[*idx as usize]), - None, - None, - None, - None, - None); - - if let Ok(clone) = result { - target = Some(clone); - break; - } else { - return result; - } - } else { - return Err(EvalAltResult::ErrorIndexMismatch); - } - } - } - - if let Some(mut t) = target { - let result = self.set_dot_val_helper(&mut t, dot_rhs, source_val); - for &mut (ref name, ref mut val) in &mut scope.iter_mut().rev() { - if *id == *name { - if let Some(arr_typed) = - (*val).downcast_mut() as Option<&mut Vec>> { - arr_typed[*idx as usize] = t; - break; - } - } - } - return result; - } - - Err(EvalAltResult::ErrorVariableNotFound(id.clone())) + value } _ => Err(EvalAltResult::InternalErrorMalformedDotExpression), } @@ -955,36 +425,13 @@ impl Engine { Expr::Identifier(ref id) => { for &mut (ref name, ref mut val) in &mut scope.iter_mut().rev() { if *id == *name { - return self.call_fn("clone", Some(val), None, None, None, None, None); + return Ok(val.clone()); } } Err(EvalAltResult::ErrorVariableNotFound(id.clone())) } Expr::Index(ref id, ref idx_raw) => { - let idx = self.eval_expr(scope, idx_raw)?; - - for &mut (ref name, ref mut val) in &mut scope.iter_mut().rev() { - if *id == *name { - if let Ok(i) = idx.downcast::() { - if let Some(arr_typed) = - (*val).downcast_mut() as Option<&mut Vec>> { - return self.call_fn("clone", - Some(&mut arr_typed[*i as usize]), - None, - None, - None, - None, - None); - } else { - return Err(EvalAltResult::ErrorIndexMismatch); - } - } else { - return Err(EvalAltResult::ErrorIndexMismatch); - } - } - } - - Err(EvalAltResult::ErrorVariableNotFound(id.clone())) + self.array_value(scope, id, idx_raw).map(|(_, _, x)| x) } Expr::Assignment(ref id, ref rhs) => { let rhs_val = self.eval_expr(scope, rhs)?; @@ -993,7 +440,6 @@ impl Engine { Expr::Identifier(ref n) => { for &mut (ref name, ref mut val) in &mut scope.iter_mut().rev() { if *n == *name { - *val = rhs_val; return Ok(Box::new(())); @@ -1006,9 +452,10 @@ impl Engine { for &mut (ref name, ref mut val) in &mut scope.iter_mut().rev() { if *id == *name { - if let Ok(i) = idx.downcast::() { + if let Some(i) = idx.downcast_ref::() { if let Some(arr_typed) = - (*val).downcast_mut() as Option<&mut Vec>> { + (*val).downcast_mut() as Option<&mut Vec>> + { arr_typed[*i as usize] = rhs_val; return Ok(Box::new(())); } else { @@ -1039,82 +486,15 @@ impl Engine { Ok(Box::new(arr)) } - Expr::FnCall(ref fn_name, ref args) => { - if args.is_empty() { - self.call_fn(fn_name, None, None, None, None, None, None) - } else if args.len() == 1 { - let mut arg = self.eval_expr(scope, &args[0])?; - - self.call_fn(fn_name, Some(&mut arg), None, None, None, None, None) - } else if args.len() == 2 { - let mut arg1 = self.eval_expr(scope, &args[0])?; - let mut arg2 = self.eval_expr(scope, &args[1])?; - - self.call_fn(fn_name, - Some(&mut arg1), - Some(&mut arg2), - None, - None, - None, - None) - } else if args.len() == 3 { - let mut arg1 = self.eval_expr(scope, &args[0])?; - let mut arg2 = self.eval_expr(scope, &args[1])?; - let mut arg3 = self.eval_expr(scope, &args[2])?; - - self.call_fn(fn_name, - Some(&mut arg1), - Some(&mut arg2), - Some(&mut arg3), - None, - None, - None) - } else if args.len() == 4 { - let mut arg1 = self.eval_expr(scope, &args[0])?; - let mut arg2 = self.eval_expr(scope, &args[1])?; - let mut arg3 = self.eval_expr(scope, &args[2])?; - let mut arg4 = self.eval_expr(scope, &args[3])?; - - self.call_fn(fn_name, - Some(&mut arg1), - Some(&mut arg2), - Some(&mut arg3), - Some(&mut arg4), - None, - None) - } else if args.len() == 5 { - let mut arg1 = self.eval_expr(scope, &args[0])?; - let mut arg2 = self.eval_expr(scope, &args[1])?; - let mut arg3 = self.eval_expr(scope, &args[2])?; - let mut arg4 = self.eval_expr(scope, &args[3])?; - let mut arg5 = self.eval_expr(scope, &args[4])?; - - self.call_fn(fn_name, - Some(&mut arg1), - Some(&mut arg2), - Some(&mut arg3), - Some(&mut arg4), - Some(&mut arg5), - None) - } else if args.len() == 6 { - let mut arg1 = self.eval_expr(scope, &args[0])?; - let mut arg2 = self.eval_expr(scope, &args[1])?; - let mut arg3 = self.eval_expr(scope, &args[2])?; - let mut arg4 = self.eval_expr(scope, &args[3])?; - let mut arg5 = self.eval_expr(scope, &args[4])?; - let mut arg6 = self.eval_expr(scope, &args[5])?; - - self.call_fn(fn_name, - Some(&mut arg1), - Some(&mut arg2), - Some(&mut arg3), - Some(&mut arg4), - Some(&mut arg5), - Some(&mut arg6)) - } else { - Err(EvalAltResult::ErrorFunctionCallNotSupported) - } - } + Expr::FnCall(ref fn_name, ref args) => self.call_fn_raw( + fn_name.to_owned(), + args.iter() + .map(|ex| self.eval_expr(scope, ex)) + .collect::>, _>>()? + .iter_mut() + .map(|b| b.as_mut()) + .collect(), + ), Expr::True => Ok(Box::new(true)), Expr::False => Ok(Box::new(false)), } @@ -1167,42 +547,38 @@ impl Engine { Err(_) => Err(EvalAltResult::ErrorIfGuardMismatch), } } - Stmt::While(ref guard, ref body) => { - loop { - let guard_result = self.eval_expr(scope, guard)?; - match guard_result.downcast::() { - Ok(g) => { - if *g { - match self.eval_stmt(scope, body) { - Err(EvalAltResult::LoopBreak) => { - return Ok(Box::new(())); - } - Err(x) => { - return Err(x); - } - _ => (), + Stmt::While(ref guard, ref body) => loop { + let guard_result = self.eval_expr(scope, guard)?; + match guard_result.downcast::() { + Ok(g) => { + if *g { + match self.eval_stmt(scope, body) { + Err(EvalAltResult::LoopBreak) => { + return Ok(Box::new(())); } - } else { - return Ok(Box::new(())); + Err(x) => { + return Err(x); + } + _ => (), } - } - Err(_) => return Err(EvalAltResult::ErrorIfGuardMismatch), - } - } - } - Stmt::Loop(ref body) => { - loop { - match self.eval_stmt(scope, body) { - Err(EvalAltResult::LoopBreak) => { + } else { return Ok(Box::new(())); } - Err(x) => { - return Err(x); - } - _ => (), } + Err(_) => return Err(EvalAltResult::ErrorIfGuardMismatch), } - } + }, + Stmt::Loop(ref body) => loop { + match self.eval_stmt(scope, body) { + Err(EvalAltResult::LoopBreak) => { + return Ok(Box::new(())); + } + Err(x) => { + return Err(x); + } + _ => (), + } + }, Stmt::Break => Err(EvalAltResult::LoopBreak), Stmt::Return => Err(EvalAltResult::Return(Box::new(()))), Stmt::ReturnWithVal(ref a) => { @@ -1250,10 +626,11 @@ impl Engine { } /// Evaluate with own scope - pub fn eval_with_scope(&mut self, - scope: &mut Scope, - input: &str) - -> Result { + pub fn eval_with_scope( + &mut self, + scope: &mut Scope, + input: &str, + ) -> Result { let tokens = lex(input); let mut peekables = tokens.peekable(); @@ -1264,13 +641,15 @@ impl Engine { let mut x: Result, EvalAltResult> = Ok(Box::new(())); for f in fns { - if f.params.len() > 6 { - return Err(EvalAltResult::ErrorFunctionArityNotSupported); - } let name = f.name.clone(); let local_f = f.clone(); - let ent = self.fns.entry(name).or_insert_with(Vec::new); - (*ent).push(FnType::InternalFn(local_f)); + + let spec = FnSpec { + ident: name, + args: None, + }; + + self.fns.insert(spec, FnIntExt::Int(local_f)); } for o in os { @@ -1280,14 +659,11 @@ impl Engine { } } - match x { - Ok(v) => { - match v.downcast::() { - Ok(out) => Ok(*out), - Err(_) => Err(EvalAltResult::ErrorMismatchOutputType), - } - } - Err(e) => Err(e), + let x = x?; + + match x.downcast::() { + Ok(out) => Ok(*out), + Err(_) => Err(EvalAltResult::ErrorMismatchOutputType), } } Err(_) => Err(EvalAltResult::ErrorFunctionArgMismatch), @@ -1307,7 +683,9 @@ impl Engine { if f.read_to_string(&mut contents).is_ok() { if let e @ Err(_) = self.consume(&contents) { return e; - } else { return Ok(()); } + } else { + return Ok(()); + } } else { Err(EvalAltResult::ErrorCantOpenScriptFile) } @@ -1330,7 +708,11 @@ impl Engine { /// Evaluate a string with own scoppe, but only return errors, if there are any. /// Useful for when you don't need the result, but still need /// to keep track of possible errors - pub fn consume_with_scope(&mut self, scope: &mut Scope, input: &str) -> Result<(), EvalAltResult> { + pub fn consume_with_scope( + &mut self, + scope: &mut Scope, + input: &str, + ) -> Result<(), EvalAltResult> { let tokens = lex(input); let mut peekables = tokens.peekable(); @@ -1344,8 +726,13 @@ impl Engine { } let name = f.name.clone(); let local_f = f.clone(); - let ent = self.fns.entry(name).or_insert_with(Vec::new); - (*ent).push(FnType::InternalFn(local_f)); + + let spec = FnSpec { + ident: name, + args: None, + }; + + self.fns.insert(spec, FnIntExt::Int(local_f)); } for o in os { @@ -1355,7 +742,7 @@ impl Engine { } Ok(()) - }, + } Err(_) => Err(EvalAltResult::ErrorFunctionArgMismatch), } } @@ -1397,30 +784,78 @@ impl Engine { ) } - fn add(x: T, y: T) -> ::Output { x + y } - fn sub(x: T, y: T) -> ::Output { x - y } - fn mul(x: T, y: T) -> ::Output { x * y } - fn div(x: T, y: T) -> ::Output { x / y } - fn neg(x: T) -> ::Output { -x } - fn lt(x: T, y: T) -> bool { x < y } - fn lte(x: T, y: T) -> bool { x <= y } - fn gt(x: T, y: T) -> bool { x > y } - fn gte(x: T, y: T) -> bool { x >= y } - fn eq(x: T, y: T) -> bool { x == y } - fn ne(x: T, y: T) -> bool { x != y } - fn and(x: bool, y: bool) -> bool { x && y } - fn or(x: bool, y: bool) -> bool { x || y } - fn not(x: bool) -> bool { !x } - fn concat(x: String, y: String) -> String { x + &y } - fn binary_and(x: T, y: T) -> ::Output { x & y } - fn binary_or(x: T, y: T) -> ::Output { x | y } - fn binary_xor(x: T, y: T) -> ::Output { x ^ y } - fn left_shift>(x: T, y: T) -> >::Output { x.shl(y) } - fn right_shift>(x: T, y: T) -> >::Output { x.shr(y) } - fn modulo>(x: T, y: T) -> >::Output { x % y} - fn pow_i64_i64(x: i64, y: i64) -> i64 { x.pow(y as u32) } - fn pow_f64_f64(x: f64, y: f64) -> f64 { x.powf(y) } - fn pow_f64_i64(x: f64, y: i64) -> f64 { x.powi(y as i32) } + fn add(x: T, y: T) -> ::Output { + x + y + } + fn sub(x: T, y: T) -> ::Output { + x - y + } + fn mul(x: T, y: T) -> ::Output { + x * y + } + fn div(x: T, y: T) -> ::Output { + x / y + } + fn neg(x: T) -> ::Output { + -x + } + fn lt(x: T, y: T) -> bool { + x < y + } + fn lte(x: T, y: T) -> bool { + x <= y + } + fn gt(x: T, y: T) -> bool { + x > y + } + fn gte(x: T, y: T) -> bool { + x >= y + } + fn eq(x: T, y: T) -> bool { + x == y + } + fn ne(x: T, y: T) -> bool { + x != y + } + fn and(x: bool, y: bool) -> bool { + x && y + } + fn or(x: bool, y: bool) -> bool { + x || y + } + fn not(x: bool) -> bool { + !x + } + fn concat(x: String, y: String) -> String { + x + &y + } + fn binary_and(x: T, y: T) -> ::Output { + x & y + } + fn binary_or(x: T, y: T) -> ::Output { + x | y + } + fn binary_xor(x: T, y: T) -> ::Output { + x ^ y + } + fn left_shift>(x: T, y: T) -> >::Output { + x.shl(y) + } + fn right_shift>(x: T, y: T) -> >::Output { + x.shr(y) + } + fn modulo>(x: T, y: T) -> >::Output { + x % y + } + fn pow_i64_i64(x: i64, y: i64) -> i64 { + x.pow(y as u32) + } + fn pow_f64_f64(x: f64, y: f64) -> f64 { + x.powf(y) + } + fn pow_f64_i64(x: f64, y: i64) -> f64 { + x.powi(y as i32) + } reg_op!(engine, "+", add, i32, i64, u32, u64, f32, f64); reg_op!(engine, "-", sub, i32, i64, u32, u64, f32, f64); @@ -1461,7 +896,9 @@ impl Engine { /// Make a new engine pub fn new() -> Engine { - let mut engine = Engine { fns: HashMap::new() }; + let mut engine = Engine { + fns: HashMap::new(), + }; Engine::register_default_lib(&mut engine); diff --git a/src/fn_register.rs b/src/fn_register.rs index d6d062f8..ad4fbe03 100644 --- a/src/fn_register.rs +++ b/src/fn_register.rs @@ -1,421 +1,68 @@ -use std::any::Any; -use std::boxed::Box; +use std::any::TypeId; -use engine::{EvalAltResult, Engine, FnType}; +use any::Any; +use engine::{Engine, EvalAltResult}; -/// A trait used for registering functions to an Engine -/// Currently, Rhai supports functions with up to 6 parameters -pub trait FnRegister { - /// A method used for registering functions and methods to a Engine - fn register_fn(&mut self, name: &str, f: A); +pub trait RegisterFn { + fn register_fn(&mut self, name: &str, f: FN); } -impl<'a, A, T, U, V, W, X, Y, Z> FnRegister for Engine - where A: 'static + Fn(&mut T, U, V, W, X, Y) -> Z, - T: Any, - U: Clone + Any, - V: Clone + Any, - W: Clone + Any, - X: Clone + Any, - Y: Clone + Any, - Z: Any -{ - fn register_fn(&mut self, name: &str, fun: A) { - let wrapped: Box, - &mut Box, - &mut Box, - &mut Box, - &mut Box, - &mut Box) - -> Result, EvalAltResult>> = - Box::new(move |arg1: &mut Box, - arg2: &mut Box, - arg3: &mut Box, - arg4: &mut Box, - arg5: &mut Box, - arg6: &mut Box| { +pub struct Ref(A); +pub struct Mut(A); - let inside1 = (*arg1).downcast_mut() as Option<&mut T>; - let inside2 = (*arg2).downcast_mut() as Option<&mut U>; - let inside3 = (*arg3).downcast_mut() as Option<&mut V>; - let inside4 = (*arg4).downcast_mut() as Option<&mut W>; - let inside5 = (*arg5).downcast_mut() as Option<&mut X>; - let inside6 = (*arg6).downcast_mut() as Option<&mut Y>; +macro_rules! count_args { + () => {0usize}; + ($head:ident $($tail:ident)*) => {1usize + count_args!($($tail)*)}; +} - match (inside1, inside2, inside3, inside4, inside5, inside6) { - (Some(b), Some(c), Some(d), Some(e), Some(f), Some(g)) => { - Ok(Box::new(fun(b, - c.clone(), - d.clone(), - e.clone(), - f.clone(), - g.clone())) as Box) +macro_rules! def_register { + () => { + def_register!(imp); + }; + (imp $($par:ident => $mark:ty => $param:ty => $clone:expr),*) => { + impl<$($par,)* FN, RET> RegisterFn for Engine + where + $($par: Any + Clone,)* + FN: Fn($($param),*) -> RET + 'static, + RET: Any, + { + fn register_fn(&mut self, name: &str, f: FN) { + let fun = move |mut args: Vec<&mut Any>| { + // Check for length at the beginning to avoid + // per-element bound checks. + if args.len() != count_args!($($par)*) { + return Err(EvalAltResult::ErrorFunctionArgMismatch); } - _ => Err(EvalAltResult::ErrorFunctionArgMismatch), - } - }); - let ent = self.fns.entry(name.to_string()).or_insert_with(Vec::new); - (*ent).push(FnType::ExternalFn6(wrapped)); - } + 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(Box::new(f($(($clone)($par)),*)) as Box) + }; + self.register_fn_raw(name.to_owned(), Some(vec![$(TypeId::of::<$par>()),*]), Box::new(fun)); + } + } + + //def_register!(imp_pop $($par => $mark => $param),*); + }; + ($p0:ident $(, $p:ident)*) => { + def_register!(imp $p0 => $p0 => $p0 => Clone::clone $(, $p => $p => $p => Clone::clone)*); + def_register!(imp $p0 => Ref<$p0> => &$p0 => |x| { x } $(, $p => $p => $p => Clone::clone)*); + def_register!(imp $p0 => Mut<$p0> => &mut $p0 => |x| { x } $(, $p => $p => $p => Clone::clone)*); + + def_register!($($p),*); + }; +// (imp_pop) => {}; +// (imp_pop $head:ident => $head_mark:ty => $head_param:ty $(,$tail:ident => $tail_mark:ty => $tp:ty)*) => { +// def_register!(imp $($tail => $tail_mark => $tp),*); +// }; } -impl<'a, A, T, U, V, W, X, Y, Z> FnRegister for Engine - where A: 'static + Fn(T, U, V, W, X, Y) -> Z, - T: Clone + Any, - U: Clone + Any, - V: Clone + Any, - W: Clone + Any, - X: Clone + Any, - Y: Clone + Any, - Z: Any -{ - fn register_fn(&mut self, name: &str, fun: A) { - let wrapped: Box, - &mut Box, - &mut Box, - &mut Box, - &mut Box, - &mut Box) - -> Result, EvalAltResult>> = - Box::new(move |arg1: &mut Box, - arg2: &mut Box, - arg3: &mut Box, - arg4: &mut Box, - arg5: &mut Box, - arg6: &mut Box| { - - let inside1 = (*arg1).downcast_mut() as Option<&mut T>; - let inside2 = (*arg2).downcast_mut() as Option<&mut U>; - let inside3 = (*arg3).downcast_mut() as Option<&mut V>; - let inside4 = (*arg4).downcast_mut() as Option<&mut W>; - let inside5 = (*arg5).downcast_mut() as Option<&mut X>; - let inside6 = (*arg6).downcast_mut() as Option<&mut Y>; - - match (inside1, inside2, inside3, inside4, inside5, inside6) { - (Some(b), Some(c), Some(d), Some(e), Some(f), Some(g)) => { - Ok(Box::new(fun(b.clone(), - c.clone(), - d.clone(), - e.clone(), - f.clone(), - g.clone())) as Box) - } - _ => Err(EvalAltResult::ErrorFunctionArgMismatch), - } - }); - - let ent = self.fns.entry(name.to_string()).or_insert_with(Vec::new); - (*ent).push(FnType::ExternalFn6(wrapped)); - } -} - -impl<'a, A, T, U, V, W, X, Y> FnRegister for Engine - where A: 'static + Fn(&mut T, U, V, W, X) -> Y, - T: Any, - U: Clone + Any, - V: Clone + Any, - W: Clone + Any, - X: Clone + Any, - Y: Any -{ - fn register_fn(&mut self, name: &str, fun: A) { - let wrapped: Box, - &mut Box, - &mut Box, - &mut Box, - &mut Box) - -> Result, EvalAltResult>> = - Box::new(move |arg1: &mut Box, - arg2: &mut Box, - arg3: &mut Box, - arg4: &mut Box, - arg5: &mut Box| { - - let inside1 = (*arg1).downcast_mut() as Option<&mut T>; - let inside2 = (*arg2).downcast_mut() as Option<&mut U>; - let inside3 = (*arg3).downcast_mut() as Option<&mut V>; - let inside4 = (*arg4).downcast_mut() as Option<&mut W>; - let inside5 = (*arg5).downcast_mut() as Option<&mut X>; - - match (inside1, inside2, inside3, inside4, inside5) { - (Some(b), Some(c), Some(d), Some(e), Some(f)) => { - Ok(Box::new(fun(b, c.clone(), d.clone(), e.clone(), f.clone())) as Box) - } - _ => Err(EvalAltResult::ErrorFunctionArgMismatch), - } - }); - - let ent = self.fns.entry(name.to_string()).or_insert_with(Vec::new); - (*ent).push(FnType::ExternalFn5(wrapped)); - } -} - -impl<'a, A, T, U, V, W, X, Y> FnRegister for Engine - where A: 'static + Fn(T, U, V, W, X) -> Y, - T: Clone + Any, - U: Clone + Any, - V: Clone + Any, - W: Clone + Any, - X: Clone + Any, - Y: Any -{ - fn register_fn(&mut self, name: &str, fun: A) { - let wrapped: Box, - &mut Box, - &mut Box, - &mut Box, - &mut Box) - -> Result, EvalAltResult>> = - Box::new(move |arg1: &mut Box, - arg2: &mut Box, - arg3: &mut Box, - arg4: &mut Box, - arg5: &mut Box| { - - let inside1 = (*arg1).downcast_mut() as Option<&mut T>; - let inside2 = (*arg2).downcast_mut() as Option<&mut U>; - let inside3 = (*arg3).downcast_mut() as Option<&mut V>; - let inside4 = (*arg4).downcast_mut() as Option<&mut W>; - let inside5 = (*arg5).downcast_mut() as Option<&mut X>; - - match (inside1, inside2, inside3, inside4, inside5) { - (Some(b), Some(c), Some(d), Some(e), Some(f)) => { - Ok(Box::new(fun(b.clone(), - c.clone(), - d.clone(), - e.clone(), - f.clone())) as Box) - } - _ => Err(EvalAltResult::ErrorFunctionArgMismatch), - } - }); - - let ent = self.fns.entry(name.to_string()).or_insert_with(Vec::new); - (*ent).push(FnType::ExternalFn5(wrapped)); - } -} - -impl<'a, A, T, U, V, W, X> FnRegister for Engine - where A: 'static + Fn(&mut T, U, V, W) -> X, - T: Any, - U: Clone + Any, - V: Clone + Any, - W: Clone + Any, - X: Any -{ - fn register_fn(&mut self, name: &str, fun: A) { - let wrapped: Box, &mut Box, &mut Box, &mut Box) - -> Result, EvalAltResult>> = - Box::new(move |arg1: &mut Box, - arg2: &mut Box, - arg3: &mut Box, - arg4: &mut Box| { - let inside1 = (*arg1).downcast_mut() as Option<&mut T>; - let inside2 = (*arg2).downcast_mut() as Option<&mut U>; - let inside3 = (*arg3).downcast_mut() as Option<&mut V>; - let inside4 = (*arg4).downcast_mut() as Option<&mut W>; - - match (inside1, inside2, inside3, inside4) { - (Some(b), Some(c), Some(d), Some(e)) => { - Ok(Box::new(fun(b, c.clone(), d.clone(), e.clone())) as Box) - } - _ => Err(EvalAltResult::ErrorFunctionArgMismatch), - } - }); - - let ent = self.fns.entry(name.to_string()).or_insert_with(Vec::new); - (*ent).push(FnType::ExternalFn4(wrapped)); - } -} - -impl<'a, A, T, U, V, W, X> FnRegister for Engine - where A: 'static + Fn(T, U, V, W) -> X, - T: Clone + Any, - U: Clone + Any, - V: Clone + Any, - W: Clone + Any, - X: Any -{ - fn register_fn(&mut self, name: &str, fun: A) { - let wrapped: Box, &mut Box, &mut Box, &mut Box) - -> Result, EvalAltResult>> = - Box::new(move |arg1: &mut Box, - arg2: &mut Box, - arg3: &mut Box, - arg4: &mut Box| { - let inside1 = (*arg1).downcast_mut() as Option<&mut T>; - let inside2 = (*arg2).downcast_mut() as Option<&mut U>; - let inside3 = (*arg3).downcast_mut() as Option<&mut V>; - let inside4 = (*arg4).downcast_mut() as Option<&mut W>; - - match (inside1, inside2, inside3, inside4) { - (Some(b), Some(c), Some(d), Some(e)) => { - Ok(Box::new(fun(b.clone(), c.clone(), d.clone(), e.clone())) as Box) - } - _ => Err(EvalAltResult::ErrorFunctionArgMismatch), - } - }); - - let ent = self.fns.entry(name.to_string()).or_insert_with(Vec::new); - (*ent).push(FnType::ExternalFn4(wrapped)); - } -} - -impl<'a, A, T, U, V, W> FnRegister for Engine - where A: 'static + Fn(&mut T, U, V) -> W, - T: Any, - U: Clone + Any, - V: Clone + Any, - W: Any -{ - fn register_fn(&mut self, name: &str, fun: A) { - let wrapped: Box, &mut Box, &mut Box) - -> Result, EvalAltResult>> = - Box::new(move |arg1: &mut Box, arg2: &mut Box, arg3: &mut Box| { - let inside1 = (*arg1).downcast_mut() as Option<&mut T>; - let inside2 = (*arg2).downcast_mut() as Option<&mut U>; - let inside3 = (*arg3).downcast_mut() as Option<&mut V>; - - match (inside1, inside2, inside3) { - (Some(b), Some(c), Some(d)) => { - Ok(Box::new(fun(b, c.clone(), d.clone())) as Box) - } - _ => Err(EvalAltResult::ErrorFunctionArgMismatch), - } - }); - - let ent = self.fns.entry(name.to_string()).or_insert_with(Vec::new); - (*ent).push(FnType::ExternalFn3(wrapped)); - } -} - -impl<'a, A, T, U, V, W> FnRegister for Engine - where A: 'static + Fn(T, U, V) -> W, - T: Clone + Any, - U: Clone + Any, - V: Clone + Any, - W: Any -{ - fn register_fn(&mut self, name: &str, fun: A) { - let wrapped: Box, &mut Box, &mut Box) - -> Result, EvalAltResult>> = - Box::new(move |arg1: &mut Box, arg2: &mut Box, arg3: &mut Box| { - let inside1 = (*arg1).downcast_mut() as Option<&mut T>; - let inside2 = (*arg2).downcast_mut() as Option<&mut U>; - let inside3 = (*arg3).downcast_mut() as Option<&mut V>; - - match (inside1, inside2, inside3) { - (Some(b), Some(c), Some(d)) => { - Ok(Box::new(fun(b.clone(), c.clone(), d.clone())) as Box) - } - _ => Err(EvalAltResult::ErrorFunctionArgMismatch), - } - }); - - let ent = self.fns.entry(name.to_string()).or_insert_with(Vec::new); - (*ent).push(FnType::ExternalFn3(wrapped)); - } -} - -impl<'a, A, T, U, V> FnRegister for Engine - where A: 'static + Fn(&mut T, U) -> V, - T: Any, - U: Clone + Any, - V: Any -{ - fn register_fn(&mut self, name: &str, fun: A) { - let wrapped: Box, &mut Box) -> Result, EvalAltResult>> = - Box::new(move |arg1: &mut Box, arg2: &mut Box| { - let inside1 = (*arg1).downcast_mut() as Option<&mut T>; - let inside2 = (*arg2).downcast_mut() as Option<&mut U>; - - match (inside1, inside2) { - (Some(b), Some(c)) => Ok(Box::new(fun(b, c.clone())) as Box), - _ => Err(EvalAltResult::ErrorFunctionArgMismatch), - } - }); - - let ent = self.fns.entry(name.to_string()).or_insert_with(Vec::new); - (*ent).push(FnType::ExternalFn2(wrapped)); - } -} - -impl<'a, A, T, U, V> FnRegister for Engine - where A: 'static + Fn(T, U) -> V, - T: Clone + Any, - U: Clone + Any, - V: Any -{ - fn register_fn(&mut self, name: &str, fun: A) { - let wrapped: Box, &mut Box) -> Result, EvalAltResult>> = - Box::new(move |arg1: &mut Box, arg2: &mut Box| { - let inside1 = (*arg1).downcast_mut() as Option<&mut T>; - let inside2 = (*arg2).downcast_mut() as Option<&mut U>; - - match (inside1, inside2) { - (Some(b), Some(c)) => Ok(Box::new(fun(b.clone(), c.clone())) as Box), - _ => Err(EvalAltResult::ErrorFunctionArgMismatch), - } - }); - - let ent = self.fns.entry(name.to_string()).or_insert_with(Vec::new); - (*ent).push(FnType::ExternalFn2(wrapped)); - } -} - -impl<'a, A, T, U> FnRegister for Engine - where A: 'static + Fn(&mut T) -> U, - T: Any, - U: Any -{ - fn register_fn(&mut self, name: &str, fun: A) { - let wrapped: Box) -> Result, EvalAltResult>> = - Box::new(move |arg: &mut Box| { - let inside = (*arg).downcast_mut() as Option<&mut T>; - - match inside { - Some(b) => Ok(Box::new(fun(b)) as Box), - None => Err(EvalAltResult::ErrorFunctionArgMismatch), - } - }); - - let ent = self.fns.entry(name.to_string()).or_insert_with(Vec::new); - (*ent).push(FnType::ExternalFn1(wrapped)); - } -} - - -impl<'a, A, T, U> FnRegister for Engine - where A: 'static + Fn(T) -> U, - T: Clone + Any, - U: Any -{ - fn register_fn(&mut self, name: &str, fun: A) { - let wrapped: Box) -> Result, EvalAltResult>> = - Box::new(move |arg: &mut Box| { - let inside = (*arg).downcast_mut() as Option<&mut T>; - match inside { - Some(b) => Ok(Box::new(fun(b.clone())) as Box), - None => Err(EvalAltResult::ErrorFunctionArgMismatch), - } - }); - - let ent = self.fns.entry(name.to_string()).or_insert_with(Vec::new); - (*ent).push(FnType::ExternalFn1(wrapped)); - } -} - -impl FnRegister for Engine - where A: 'static + Fn() -> T, - T: Any -{ - fn register_fn(&mut self, name: &str, fun: A) { - let wrapped: Box Result, EvalAltResult>> = Box::new(move || { - Ok(Box::new(fun()) as Box) - }); - - let ent = self.fns.entry(name.to_string()).or_insert_with(Vec::new); - (*ent).push(FnType::ExternalFn0(wrapped)); - } -} +#[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); diff --git a/src/lib.rs b/src/lib.rs index 03ba0945..0ffb0a62 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,10 +1,11 @@ //! # Rhai - embedded scripting for Rust +//! //! Rhai is a tiny, simple and very fast embedded scripting language for Rust //! that gives you a safe and easy way to add scripting to your applications. //! It provides a familiar syntax based on JS and Rust and a simple Rust interface. //! Here is a quick example. First, the contents of `my_script.rhai`: -//! -//! ```rust_todo_disable_testing_enable_highlighting +//! +//! ```rust,ignore //! fn factorial(x) { //! if x == 1 { return 1; } //! x * factorial(x - 1) @@ -12,36 +13,35 @@ //! //! compute_something(factorial(10)) //! ``` -//! +//! //! And the Rust part: -//! +//! //! ```rust -//! use rhai::{FnRegister, Engine}; -//! +//! use rhai::{Engine, RegisterFn}; +//! //! fn compute_something(x: i64) -> bool { //! (x % 40) == 0 //! } -//! +//! //! let mut engine = Engine::new(); //! engine.register_fn("compute_something", compute_something); -//! # // Very ugly hack incoming, TODO +//! # // Very ugly hack incoming, TODO (maybe mark as no_run?) //! # use std::fs::{File, remove_file}; //! # use std::io::Write; //! # let mut f = File::create("my_script.rhai").unwrap(); //! # let _ = write!(f, "{}", "fn f(x) { if x == 1 { return 1; } x * f(x-1) } compute_something(f(10))"); -//! assert!(engine.eval_file::("my_script.rhai").unwrap()); +//! assert_eq!(engine.eval_file::("my_script.rhai"), Ok(true)); //! # let _ = remove_file("my_script.rhai"); //! ``` //! -//! [Check out the README on github for more information!](https://github.com/jonathandturner/rhai) +//! [Check out the README on GitHub for more information!](https://github.com/jonathandturner/rhai) // lints required by Rhai -#![allow(unknown_lints, - type_complexity, - new_without_default_derive, - needless_pass_by_value, - too_many_arguments)] +#![allow(warnings, unknown_lints, type_complexity, new_without_default_derive, + needless_pass_by_value, too_many_arguments)] +mod any; +mod call; mod engine; mod fn_register; mod parser; @@ -49,6 +49,6 @@ mod parser; #[cfg(test)] mod tests; -pub use engine::{Engine, Scope, EvalAltResult}; -pub use fn_register::FnRegister; - +pub use any::Any; +pub use engine::{Engine, EvalAltResult, Scope}; +pub use fn_register::RegisterFn; diff --git a/src/tests/arrays.rs b/src/tests/arrays.rs index 4d87728b..07e2cd30 100644 --- a/src/tests/arrays.rs +++ b/src/tests/arrays.rs @@ -1,5 +1,5 @@ use engine::Engine; -use fn_register::FnRegister; +use fn_register::RegisterFn; #[test] fn test_arrays() { diff --git a/src/tests/float.rs b/src/tests/float.rs index 6030a5b2..573077ff 100644 --- a/src/tests/float.rs +++ b/src/tests/float.rs @@ -1,5 +1,5 @@ use engine::Engine; -use fn_register::FnRegister; +use fn_register::RegisterFn; #[test] fn test_float() { diff --git a/src/tests/get_set.rs b/src/tests/get_set.rs index 46790e81..6315ad2c 100644 --- a/src/tests/get_set.rs +++ b/src/tests/get_set.rs @@ -1,5 +1,5 @@ use engine::Engine; -use fn_register::FnRegister; +use fn_register::RegisterFn; #[test] fn test_get_set() { @@ -86,9 +86,5 @@ fn test_big_get_set() { engine.register_fn("new_tp", TestParent::new); - if let Ok(result) = engine.eval::("let a = new_tp(); a.child.x = 500; a.child.x") { - assert_eq!(result, 500); - } else { - assert!(false); - } + assert_eq!(engine.eval::("let a = new_tp(); a.child.x = 500; a.child.x"), Ok(500)); } diff --git a/src/tests/method_call.rs b/src/tests/method_call.rs index a2c36ed9..72ed3064 100644 --- a/src/tests/method_call.rs +++ b/src/tests/method_call.rs @@ -1,5 +1,5 @@ use engine::Engine; -use fn_register::FnRegister; +use fn_register::RegisterFn; #[test] fn test_method_call() { diff --git a/src/tests/mismatched_op.rs b/src/tests/mismatched_op.rs index 381e2b39..a3e04999 100644 --- a/src/tests/mismatched_op.rs +++ b/src/tests/mismatched_op.rs @@ -4,8 +4,8 @@ use engine::{Engine, EvalAltResult}; fn test_mismatched_op() { let mut engine = Engine::new(); - match engine.eval::("60 + \"hello\"") { - Err(EvalAltResult::ErrorFunctionArgMismatch) => (), - _ => assert!(false), - } + assert_eq!( + engine.eval::("60 + \"hello\""), + Err(EvalAltResult::ErrorFunctionNotFound) + ); }