Allow functions to take both ref and value params
This commit is contained in:
parent
25a9a772e6
commit
4700af0e54
|
@ -52,13 +52,15 @@ impl Expression {
|
||||||
match self {
|
match self {
|
||||||
Expression::Constant(v) => v.clone(),
|
Expression::Constant(v) => v.clone(),
|
||||||
Expression::Variable(name) => e.get(name).unwrap_or_default(),
|
Expression::Variable(name) => e.get(name).unwrap_or_default(),
|
||||||
Expression::Call(name, args) => f
|
Expression::Call(name, args) => {
|
||||||
.call(
|
let args = args.iter().map(|ex| ex.eval(e, f)).collect::<Vec<_>>();
|
||||||
name,
|
let res = f.call(name, e, &args);
|
||||||
e,
|
if let Ok(res) = res {
|
||||||
&args.iter().map(|ex| ex.eval(e, f)).collect::<Vec<_>>(),
|
res
|
||||||
)
|
} else {
|
||||||
.unwrap(),
|
args[0].call_method(name, e, f, &args)
|
||||||
|
}
|
||||||
|
}
|
||||||
Expression::CallMethod(target, name, args) => {
|
Expression::CallMethod(target, name, args) => {
|
||||||
let target = target.eval(e, f);
|
let target = target.eval(e, f);
|
||||||
let v = vec![target.clone()];
|
let v = vec![target.clone()];
|
||||||
|
|
|
@ -3,9 +3,9 @@ use super::{Env, FromValue, NativeFunction, Value};
|
||||||
macro_rules! impl_function {
|
macro_rules! impl_function {
|
||||||
( $($ty:ident),* $(,)? ) => {
|
( $($ty:ident),* $(,)? ) => {
|
||||||
#[allow(non_snake_case, unused_variables, unused_mut, unused_assignments)]
|
#[allow(non_snake_case, unused_variables, unused_mut, unused_assignments)]
|
||||||
impl<F,R,$($ty,)*> NativeFunction<($($ty,)*)> for F
|
impl<F,R,$($ty,)*> NativeFunction<((),(),$($ty,)*)> for F
|
||||||
where
|
where
|
||||||
F: Fn($(&$ty,)*) -> R,
|
F: Fn($($ty,)*) -> R,
|
||||||
R: Into<Value>,
|
R: Into<Value>,
|
||||||
$($ty: FromValue,)*
|
$($ty: FromValue,)*
|
||||||
{
|
{
|
||||||
|
@ -33,9 +33,9 @@ macro_rules! impl_function {
|
||||||
|
|
||||||
|
|
||||||
#[allow(non_snake_case, unused_variables, unused_mut, unused_assignments)]
|
#[allow(non_snake_case, unused_variables, unused_mut, unused_assignments)]
|
||||||
impl<F,R,$($ty,)*> NativeFunction<((), $($ty,)*)> for F
|
impl<F,R,$($ty,)*> NativeFunction<((),(),(), $($ty,)*)> for F
|
||||||
where
|
where
|
||||||
F: Fn(&Env, $(&$ty,)*) -> R,
|
F: Fn(&Env, $($ty,)*) -> R,
|
||||||
R: Into<Value>,
|
R: Into<Value>,
|
||||||
$($ty: FromValue,)*
|
$($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<F,R, Z, $($ty,)*> NativeFunction<(Z,$($ty,)*)> for F
|
||||||
|
where
|
||||||
|
F: Fn(&Z, $(&$ty,)*) -> R,
|
||||||
|
R: Into<Value>,
|
||||||
|
Z: FromValue,
|
||||||
|
$($ty: FromValue,)*
|
||||||
|
{
|
||||||
|
fn native_execute(&self, _: &Env, args: &[Value]) -> Result<Value, String> {
|
||||||
|
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>(), 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<F,R,Z,$($ty,)*> NativeFunction<((), Z, $($ty,)*)> for F
|
||||||
|
where
|
||||||
|
F: Fn(&Env, &Z, $(&$ty,)*) -> R,
|
||||||
|
R: Into<Value>,
|
||||||
|
Z: FromValue,
|
||||||
|
$($ty: FromValue,)*
|
||||||
|
{
|
||||||
|
fn native_execute(&self, env: &Env, args: &[Value]) -> Result<Value, String> {
|
||||||
|
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>(), 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_function);
|
||||||
|
crate::macros::for_each_tuple!(impl_ref_function);
|
||||||
|
|
20
src/main.rs
20
src/main.rs
|
@ -25,6 +25,14 @@ struct Foo {
|
||||||
x: i32,
|
x: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Foo {
|
||||||
|
fn edit(&self) -> Self {
|
||||||
|
let mut f = self.clone();
|
||||||
|
f.x += 1;
|
||||||
|
f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl CustomValue for Foo {
|
impl CustomValue for Foo {
|
||||||
fn as_any(&self) -> &dyn Any {
|
fn as_any(&self) -> &dyn Any {
|
||||||
self
|
self
|
||||||
|
@ -41,6 +49,12 @@ impl CustomValue for Foo {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn functions(&self) -> Option<FunctionMap> {
|
||||||
|
let mut map = FunctionMap::new();
|
||||||
|
map.insert_native("edit_foo", Foo::edit);
|
||||||
|
Some(map)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -53,10 +67,6 @@ fn main() {
|
||||||
});
|
});
|
||||||
m.insert_native("waluigi", || "Waluigi");
|
m.insert_native("waluigi", || "Waluigi");
|
||||||
m.insert_native("native_test", || Foo { x: 41 });
|
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);
|
run(m, res);
|
||||||
}
|
}
|
||||||
|
|
29
src/value.rs
29
src/value.rs
|
@ -85,7 +85,7 @@ impl Value {
|
||||||
map
|
map
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn inner_functions(&self) -> Option<&FunctionMap> {
|
pub fn inner_functions(&self) -> Option<FunctionMap> {
|
||||||
if let Self::Custom(c) = self {
|
if let Self::Custom(c) = self {
|
||||||
c.functions()
|
c.functions()
|
||||||
} else {
|
} else {
|
||||||
|
@ -165,7 +165,9 @@ impl From<()> for Value {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait FromValue {
|
pub trait FromValue {
|
||||||
fn from_value(v: &Value) -> Option<&Self>;
|
fn from_value(v: &Value) -> Option<Self>
|
||||||
|
where
|
||||||
|
Self: Sized;
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! from_impl {
|
macro_rules! from_impl {
|
||||||
|
@ -178,9 +180,9 @@ macro_rules! from_impl {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromValue for $type{
|
impl FromValue for $type{
|
||||||
fn from_value(v: &Value) -> Option<&Self> {
|
fn from_value(v: &Value) -> Option<Self> {
|
||||||
match v {
|
match v {
|
||||||
Value::$variant(v) => Some(v),
|
Value::$variant(v) => Some(v.clone()),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -190,15 +192,15 @@ macro_rules! from_impl {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromValue for Value {
|
impl FromValue for Value {
|
||||||
fn from_value(v: &Value) -> Option<&Self> {
|
fn from_value(v: &Value) -> Option<Self> {
|
||||||
Some(v)
|
Some(v.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: 'static + CustomValue> FromValue for T {
|
impl<T: 'static + CustomValue + Clone> FromValue for T {
|
||||||
fn from_value(v: &Value) -> Option<&Self> {
|
fn from_value(v: &Value) -> Option<Self> {
|
||||||
match v {
|
match v {
|
||||||
Value::Custom(v) => v.as_any().downcast_ref(),
|
Value::Custom(v) => v.as_any().downcast_ref().cloned(),
|
||||||
_ => None,
|
_ => 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 {
|
impl PartialEq for Value {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
|
|
|
@ -31,7 +31,7 @@ pub trait CustomValue: std::fmt::Debug + BoxClone {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn functions(&self) -> Option<&FunctionMap> {
|
fn functions(&self) -> Option<FunctionMap> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue