roan_engine/vm/
native_fn.rs1use 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}