diff --git a/src/expression.rs b/src/expression.rs index 3e3aef7..dd0b7a7 100644 --- a/src/expression.rs +++ b/src/expression.rs @@ -52,13 +52,15 @@ impl Expression { match self { Expression::Constant(v) => v.clone(), Expression::Variable(name) => e.get(name).unwrap_or_default(), - Expression::Call(name, args) => f - .call( - name, - e, - &args.iter().map(|ex| ex.eval(e, f)).collect::>(), - ) - .unwrap(), + Expression::Call(name, args) => { + let args = args.iter().map(|ex| ex.eval(e, f)).collect::>(); + let res = f.call(name, e, &args); + if let Ok(res) = res { + res + } else { + args[0].call_method(name, e, f, &args) + } + } Expression::CallMethod(target, name, args) => { let target = target.eval(e, f); let v = vec![target.clone()]; diff --git a/src/function/function_impl.rs b/src/function/function_impl.rs index 2ebcfbc..94e0624 100644 --- a/src/function/function_impl.rs +++ b/src/function/function_impl.rs @@ -3,9 +3,9 @@ use super::{Env, FromValue, NativeFunction, Value}; macro_rules! impl_function { ( $($ty:ident),* $(,)? ) => { #[allow(non_snake_case, unused_variables, unused_mut, unused_assignments)] - impl NativeFunction<($($ty,)*)> for F + impl NativeFunction<((),(),$($ty,)*)> for F where - F: Fn($(&$ty,)*) -> R, + F: Fn($($ty,)*) -> R, R: Into, $($ty: FromValue,)* { @@ -33,9 +33,9 @@ macro_rules! impl_function { #[allow(non_snake_case, unused_variables, unused_mut, unused_assignments)] - impl NativeFunction<((), $($ty,)*)> for F + impl NativeFunction<((),(),(), $($ty,)*)> for F where - F: Fn(&Env, $(&$ty,)*) -> R, + F: Fn(&Env, $($ty,)*) -> R, R: Into, $($ty: FromValue,)* { @@ -64,4 +64,81 @@ macro_rules! impl_function { }; } +macro_rules! impl_ref_function { + ( $($ty:ident),* $(,)? ) => { + #[allow(non_snake_case, unused_variables, unused_mut, unused_assignments)] + impl NativeFunction<(Z,$($ty,)*)> for F + where + F: Fn(&Z, $(&$ty,)*) -> R, + R: Into, + Z: FromValue, + $($ty: FromValue,)* + { + fn native_execute(&self, _: &Env, args: &[Value]) -> Result { + let mut args = args.iter(); + let total_count = { + let mut count = 1; + $( + let _: Option<$ty> = None; + count += 1; + )* + count + }; + let mut count = 0; + let z = args.next() + .ok_or_else(|| format!("method expected {} parameters, but parameter {} was missing", total_count, count))?; + let z = Z::from_value(z) + .ok_or_else(|| format!("Parameter {} was not of type {}, it was {}", count, std::any::type_name::(), z.value_kind()))?; + $( + let arg = args.next() + .ok_or_else(|| format!("method expected {} parameters, but parameter {} was missing", total_count, count))?; + let $ty = $ty::from_value(arg) + .ok_or_else(|| format!("Parameter {} was not of type {}, it was {}", count, std::any::type_name::<$ty>(), arg.value_kind()))?; + count += 1; + )* + Ok(self(&z, $(&$ty,)*).into()) + } + } + + + #[allow(non_snake_case, unused_variables, unused_mut, unused_assignments)] + impl NativeFunction<((), Z, $($ty,)*)> for F + where + F: Fn(&Env, &Z, $(&$ty,)*) -> R, + R: Into, + Z: FromValue, + $($ty: FromValue,)* + { + fn native_execute(&self, env: &Env, args: &[Value]) -> Result { + let mut args = args.iter(); + let total_count = { + let mut count = 1; + $( + let _: Option<$ty> = None; + count += 1; + )* + count + }; + let mut count = 0; + let z = args.next() + .ok_or_else(|| format!("method expected {} parameters, but parameter {} was missing", total_count, count))?; + let z = Z::from_value(z) + .ok_or_else(|| format!("Parameter {} was not of type {}, it was {}", count, std::any::type_name::(), z.value_kind()))?; + $( + let arg = args.next() + .ok_or_else(|| format!("method expected {} parameters, but parameter {} was missing", total_count, count))?; + let $ty = $ty::from_value(arg) + .ok_or_else(|| format!("Parameter {} was not of type {}, it was {}", count, std::any::type_name::<$ty>(), arg.value_kind()))?; + count += 1; + )* + Ok(self(env, &z, $(&$ty,)*).into()) + } + } + + + + }; +} + crate::macros::for_each_tuple!(impl_function); +crate::macros::for_each_tuple!(impl_ref_function); diff --git a/src/main.rs b/src/main.rs index eada698..8a596f7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,6 +25,14 @@ struct Foo { x: i32, } +impl Foo { + fn edit(&self) -> Self { + let mut f = self.clone(); + f.x += 1; + f + } +} + impl CustomValue for Foo { fn as_any(&self) -> &dyn Any { self @@ -41,6 +49,12 @@ impl CustomValue for Foo { false } } + +fn functions(&self) -> Option { + let mut map = FunctionMap::new(); + map.insert_native("edit_foo", Foo::edit); + Some(map) +} } fn main() { @@ -53,10 +67,6 @@ fn main() { }); m.insert_native("waluigi", || "Waluigi"); m.insert_native("native_test", || Foo { x: 41 }); - m.insert_native("edit_foo", |f: &Foo| { - let mut f = f.clone(); - f.x += 1; - f - }); + run(m, res); } diff --git a/src/value.rs b/src/value.rs index 1277f94..ca947ab 100644 --- a/src/value.rs +++ b/src/value.rs @@ -85,7 +85,7 @@ impl Value { map } - pub fn inner_functions(&self) -> Option<&FunctionMap> { + pub fn inner_functions(&self) -> Option { if let Self::Custom(c) = self { c.functions() } else { @@ -165,7 +165,9 @@ impl From<()> for Value { } pub trait FromValue { - fn from_value(v: &Value) -> Option<&Self>; + fn from_value(v: &Value) -> Option + where + Self: Sized; } macro_rules! from_impl { @@ -178,9 +180,9 @@ macro_rules! from_impl { } impl FromValue for $type{ - fn from_value(v: &Value) -> Option<&Self> { + fn from_value(v: &Value) -> Option { match v { - Value::$variant(v) => Some(v), + Value::$variant(v) => Some(v.clone()), _ => None, } } @@ -190,15 +192,15 @@ macro_rules! from_impl { } impl FromValue for Value { - fn from_value(v: &Value) -> Option<&Self> { - Some(v) + fn from_value(v: &Value) -> Option { + Some(v.clone()) } } -impl FromValue for T { - fn from_value(v: &Value) -> Option<&Self> { +impl FromValue for T { + fn from_value(v: &Value) -> Option { match v { - Value::Custom(v) => v.as_any().downcast_ref(), + Value::Custom(v) => v.as_any().downcast_ref().cloned(), _ => None, } } @@ -218,15 +220,6 @@ impl From<&'_ str> for Value { } } -impl FromValue for str { - fn from_value(v: &Value) -> Option<&Self> { - match v { - Value::String(v) => Some(v.as_str()), - _ => None, - } - } -} - impl PartialEq for Value { fn eq(&self, other: &Self) -> bool { match (self, other) { diff --git a/src/value/custom.rs b/src/value/custom.rs index 2a0b704..2f5829f 100644 --- a/src/value/custom.rs +++ b/src/value/custom.rs @@ -31,7 +31,7 @@ pub trait CustomValue: std::fmt::Debug + BoxClone { None } - fn functions(&self) -> Option<&FunctionMap> { + fn functions(&self) -> Option { None } } diff --git a/test.foo b/test.foo index a612bba..285353f 100644 --- a/test.foo +++ b/test.foo @@ -16,4 +16,5 @@ print( edit_foo(native_test()) ); // edit_foo("hello"); // this doesnt work yet :(((( -// print(10.eq(20)); \ No newline at end of file +// print(10.eq(20)); +print(eq(10, 10)); \ No newline at end of file