From f09545921f350db037e3e9e2e9a4ac5de2e4c324 Mon Sep 17 00:00:00 2001 From: torkleyy Date: Wed, 20 Dec 2017 12:16:14 +0100 Subject: [PATCH] Rewrite Rhai function dispatching --- examples/arrays_and_structs.rs | 7 +- examples/custom_types_and_methods.rs | 2 +- examples/hello.rs | 4 +- examples/repl.rs | 48 +- examples/reuse_scope.rs | 10 +- examples/rhai_runner.rs | 19 +- examples/simple_fn.rs | 19 +- src/any.rs | 102 +++ src/engine.rs | 1248 ++++++++------------------ src/fn_register.rs | 469 ++-------- src/lib.rs | 33 +- 11 files changed, 610 insertions(+), 1351 deletions(-) create mode 100644 src/any.rs diff --git a/examples/arrays_and_structs.rs b/examples/arrays_and_structs.rs index 4cd22b31..424676bd 100644 --- a/examples/arrays_and_structs.rs +++ b/examples/arrays_and_structs.rs @@ -3,7 +3,7 @@ use rhai::{Engine, FnRegister}; #[derive(Clone, Debug)] struct TestStruct { - x: i64 + x: i64, } impl TestStruct { @@ -24,5 +24,8 @@ 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[0].update(); x[0]") + ); } diff --git a/examples/custom_types_and_methods.rs b/examples/custom_types_and_methods.rs index 7b70914f..66a9b2ea 100644 --- a/examples/custom_types_and_methods.rs +++ b/examples/custom_types_and_methods.rs @@ -3,7 +3,7 @@ use rhai::{Engine, FnRegister}; #[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..cfc56596 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, FnRegister, 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..e4c4063d 100644 --- a/examples/rhai_runner.rs +++ b/examples/rhai_runner.rs @@ -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..b74a45db 100644 --- a/examples/simple_fn.rs +++ b/examples/simple_fn.rs @@ -1,7 +1,9 @@ extern crate rhai; -use rhai::{Engine, FnRegister}; +use rhai::{Any, Engine, RegisterFn}; fn add(x: i64, y: i64) -> i64 { + println!("Adding: {}", x + y); + x + y } @@ -9,8 +11,17 @@ fn main() { let mut engine = Engine::new(); engine.register_fn("add", add); + engine + .call_fn_raw( + "add".to_owned(), + vec![ + &mut (Box::new(3i64) as Box), + &mut (Box::new(5i64) as Box), + ], + ) + .expect("FAIL"); - if let Ok(result) = engine.eval::("add(40, 2)") { - println!("Answer: {}", result); // prints 42 - } + //if let Ok(result) = engine.eval::("add(40, 2)") { + // 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/engine.rs b/src/engine.rs index 18aa0ce6..8be07cc8 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -1,14 +1,14 @@ +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}; #[derive(Debug)] pub enum EvalAltResult { @@ -27,7 +27,6 @@ pub enum EvalAltResult { Return(Box), } - impl Error for EvalAltResult { fn description(&self) -> &str { match *self { @@ -66,29 +65,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 +87,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 Box>) -> Result, EvalAltResult>; + /// A type containing information about current scope. /// Useful for keeping state between `Engine` runs /// @@ -129,752 +116,270 @@ pub type Scope = Vec<(String, Box)>; impl Engine { /// 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 Box>, + ) -> Result, EvalAltResult> { + let spec = FnSpec { + ident, + args: Some( + args.iter() + .map(|a| ::type_id(a.as_ref())) + .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); - } + self.fns + .get(&spec) + .ok_or(EvalAltResult::ErrorFunctionNotFound) + .and_then(move |f| match *f { + FnIntExt::Ext(ref f) => f(args), + FnIntExt::Int(_) => unimplemented!(), + }) + } - 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); + pub fn register_fn_raw(&mut self, ident: String, args: Vec, f: Box) { + let spec = FnSpec { + ident, + args: Some(args), + }; - 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) - } - } - } - None => Err(EvalAltResult::ErrorFunctionNotFound), - } + 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 Box, + 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()).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].box_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, &mut v, 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 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; + scope + .iter_mut() + .rev() + .find(|&&mut (ref name, _)| *id == *name) + .map(|&mut (_, ref mut val)| val.as_ref().box_clone()) + .ok_or_else(|| EvalAltResult::ErrorVariableNotFound(id.clone())) + .and_then(|mut target| self.get_dot_val_helper(scope, &mut target, 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); - - 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())) + // let mut target: Option> = None; + // + // for &mut (ref name, ref mut val) in &mut scope.iter_mut().rev() { + // if *id == *name { + // target = val.as_ref().box_clone(); + // break; + // } + // } + // + // 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())) } 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 mut target: Option> = None; + scope + .iter_mut() + .rev() + .find(|&&mut (ref name, _)| *id == *name) + .ok_or_else(|| EvalAltResult::ErrorVariableNotFound(id.clone())) + .and_then(|&mut (_, ref mut val)| { + ((*val).downcast_mut() as Option<&mut Vec>>) + .and_then(|arr| { + idx_boxed + .downcast_ref::() + .map(|idx| arr[*idx as usize].box_clone()) + }) + .ok_or(EvalAltResult::ErrorIndexMismatch) + }) + .and_then(|mut target| self.get_dot_val_helper(scope, &mut target, 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>> { - 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())) + // let mut target: Option> = None; + // + // 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())) } _ => 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 Box, + 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, &mut source_val]) } - 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(&mut v, inner_rhs, source_val)) + .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, &mut v]) + }) } - } + _ => 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; 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())); - } + target = Some(val.clone()) } } @@ -894,8 +399,8 @@ impl Engine { } 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 + let idx = if let Some(i) = idx_boxed.downcast_ref::() { + *i as usize } else { return Err(EvalAltResult::ErrorIndexMismatch); }; @@ -904,15 +409,9 @@ impl Engine { 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 Some(arr_typed) = (*val).downcast_mut() as Option<&mut Vec>> + { + let result = Ok(arr_typed[idx].clone()); if let Ok(clone) = result { target = Some(clone); @@ -931,8 +430,9 @@ impl Engine { 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; + (*val).downcast_mut() as Option<&mut Vec>> + { + arr_typed[idx] = t; break; } } @@ -955,7 +455,7 @@ 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.box_clone()); } } Err(EvalAltResult::ErrorVariableNotFound(id.clone())) @@ -965,16 +465,11 @@ 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>> { - return self.call_fn("clone", - Some(&mut arr_typed[*i as usize]), - None, - None, - None, - None, - None); + (*val).downcast_mut() as Option<&mut Vec>> + { + return Ok(arr_typed[*i as usize].box_clone()); } else { return Err(EvalAltResult::ErrorIndexMismatch); } @@ -993,7 +488,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 +500,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 +534,14 @@ 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() + .collect(), + ), Expr::True => Ok(Box::new(true)), Expr::False => Ok(Box::new(false)), } @@ -1167,42 +594,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 +673,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(); @@ -1269,8 +693,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 { @@ -1281,12 +710,10 @@ impl Engine { } match x { - Ok(v) => { - match v.downcast::() { - Ok(out) => Ok(*out), - Err(_) => Err(EvalAltResult::ErrorMismatchOutputType), - } - } + Ok(v) => match v.downcast::() { + Ok(out) => Ok(*out), + Err(_) => Err(EvalAltResult::ErrorMismatchOutputType), + }, Err(e) => Err(e), } } @@ -1307,7 +734,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 +759,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 +777,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 +793,7 @@ impl Engine { } Ok(()) - }, + } Err(_) => Err(EvalAltResult::ErrorFunctionArgMismatch), } } @@ -1397,30 +835,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,9 +947,15 @@ 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); + // TODO + // TODO + // TODO + // TODO + //Engine::register_default_lib(&mut engine); engine } diff --git a/src/fn_register.rs b/src/fn_register.rs index d6d062f8..3e9aab6c 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 Box>| { + // 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(), 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, T, U, V, W, X, Y, Z); diff --git a/src/lib.rs b/src/lib.rs index 03ba0945..10ac21f6 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,34 @@ //! //! compute_something(factorial(10)) //! ``` -//! +//! //! And the Rust part: -//! +//! //! ```rust //! use rhai::{FnRegister, Engine}; -//! +//! //! 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 engine; mod fn_register; mod parser; @@ -49,6 +48,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;