roan_engine/vm/
native_fn.rs

1use crate::value::Value;
2use anyhow::Result;
3use std::{
4    fmt,
5    fmt::{Display, Formatter},
6};
7use tracing::debug;
8
9#[derive(Debug, Clone)]
10pub struct NativeFunctionParam {
11    pub name: String,
12    pub ty: String,
13    pub is_rest: bool,
14}
15
16#[derive(Debug, Clone)]
17pub struct NativeFunction {
18    pub name: String,
19    pub func: fn(args: Vec<Value>) -> Value,
20    pub params: Vec<NativeFunctionParam>,
21}
22
23impl NativeFunction {
24    pub fn new(
25        name: impl Into<String>,
26        params: Vec<NativeFunctionParam>,
27        func: fn(args: Vec<Value>) -> Value,
28    ) -> Self {
29        Self {
30            name: name.into(),
31            func,
32            params,
33        }
34    }
35
36    pub fn call(&mut self, args: Vec<Value>) -> Result<Value> {
37        debug!(
38            "Executing native function: {} with {:?} args",
39            self.name,
40            args.len()
41        );
42
43        let mut params = vec![];
44        for (param, val) in self.params.iter().zip(args.clone()) {
45            if param.is_rest {
46                let rest: Vec<Value> = args.iter().skip(self.params.len() - 1).cloned().collect();
47
48                params.extend(rest);
49            } else {
50                params.push(val);
51            }
52        }
53
54        Ok((self.func)(params))
55    }
56}
57
58#[cfg(test)]
59mod tests {
60    use super::*;
61    use crate::{as_cast, native_function, value::Value};
62
63    native_function!(fn __add_str(str1, str2) {
64        let str1 = as_cast!(str1, String);
65        let str2 = as_cast!(str2, String);
66
67        Value::String(format!("{}{}", str1, str2))
68    });
69
70    #[test]
71    fn test_native_function() {
72        assert_eq!(
73            __add_str()
74                .call(vec![
75                    Value::String("Hello".to_string()),
76                    Value::String("World".to_string())
77                ])
78                .unwrap(),
79            Value::String("HelloWorld".to_string())
80        );
81    }
82
83    native_function!(fn __test1(a, b) {
84        assert_eq!(a, Value::Int(1));
85        assert_eq!(b, Value::Int(2));
86        Value::Null
87    });
88
89    #[test]
90    fn test_native_function_with_params() {
91        assert_eq!(
92            __test1().call(vec![Value::Int(1), Value::Int(2)]).unwrap(),
93            Value::Null
94        );
95    }
96
97    native_function!(fn __test(a, b, ...rest) {
98        assert_eq!(a, Value::Int(1));
99        assert_eq!(b, Value::Int(2));
100        assert_eq!(rest[0], Value::Int(3));
101        Value::Null
102    });
103
104    #[test]
105    fn test_native_function_with_rest_param() {
106        assert_eq!(
107            __test()
108                .call(vec![
109                    Value::Int(1),
110                    Value::Int(2),
111                    Value::Int(3),
112                    Value::Int(4)
113                ])
114                .unwrap(),
115            Value::Null
116        );
117    }
118}
119
120impl Display for NativeFunction {
121    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
122        write!(f, "<native fn {}>", self.name)
123    }
124}