reqlang_expr/
types.rs

1use std::fmt::{Debug, Display};
2
3use crate::value::Value;
4
5#[derive(Clone, PartialEq)]
6pub enum Type {
7    Value,
8    String,
9    Fn {
10        args: Vec<Type>,
11        variadic_arg: Option<Box<Type>>,
12        returns: Box<Type>,
13    },
14    Bool,
15    Unknown,
16}
17
18impl Type {
19    pub fn name(&self) -> String {
20        match self {
21            Type::Value => "Value".to_string(),
22            Type::String => "String".to_string(),
23            Type::Fn {
24                args,
25                variadic_arg,
26                returns,
27            } => {
28                let mut args: Vec<String> = args.iter().map(|arg| arg.name()).collect();
29
30                if let Some(varg) = variadic_arg {
31                    args.push(format!("...{}", varg.name()));
32                }
33
34                let args = args.join(", ");
35
36                let returns = returns.name();
37
38                format!("Fn({args}) -> {returns}")
39            }
40            Type::Bool => "Bool".to_string(),
41            Type::Unknown => "Unknown".to_string(),
42        }
43    }
44}
45
46impl Display for Type {
47    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
48        write!(f, "{}", self.name())
49    }
50}
51
52impl Debug for Type {
53    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
54        write!(f, "{}", self.name())
55    }
56}
57
58impl From<Value> for Type {
59    fn from(value: Value) -> Self {
60        match value {
61            Value::String(_) => Type::String,
62            Value::Fn(builtin_fn) => {
63                let mut args: Vec<Type> =
64                    builtin_fn.args.iter().map(|arg| arg.ty.clone()).collect();
65
66                let variadic_arg = builtin_fn
67                    .args
68                    .last()
69                    .filter(|arg| arg.variadic)
70                    .map(|arg| Box::new(arg.ty.clone()));
71
72                if variadic_arg.is_some() {
73                    args.pop();
74                }
75
76                Type::Fn {
77                    args,
78                    variadic_arg,
79                    returns: Box::new(builtin_fn.return_type.clone()),
80                }
81            }
82            Value::Bool(_) => Type::Bool,
83            Value::Type(ty) => *ty.clone(),
84        }
85    }
86}
87
88#[cfg(test)]
89mod from_tests {
90    use std::rc::Rc;
91
92    use crate::prelude::{BuiltinFn, FnArg};
93
94    use super::*;
95
96    #[test]
97    fn test_from_type_value() {
98        let type_value = Value::Type(Type::String.into());
99        let ty: Type = type_value.into();
100        assert_eq!(Type::String, ty);
101    }
102
103    #[test]
104    fn test_get_type_type_value() {
105        let string_value = Value::Type(Type::String.into());
106        let ty: Type = string_value.get_type();
107        assert_eq!(Type::String, ty);
108    }
109
110    #[test]
111    fn test_from_string_value() {
112        let string_value = Value::String("test".to_string());
113        let ty: Type = string_value.into();
114        assert_eq!(Type::String, ty);
115    }
116
117    #[test]
118    fn test_get_type_string_value() {
119        let string_value = Value::String("test".to_string());
120        let ty: Type = string_value.get_type();
121        assert_eq!(Type::String, ty);
122    }
123
124    #[test]
125    fn test_from_bool_value() {
126        let bool_value = Value::Bool(true);
127        let ty: Type = bool_value.into();
128        assert_eq!(Type::Bool, ty);
129    }
130
131    #[test]
132    fn test_get_type_bool_value() {
133        let bool_value = Value::Bool(true);
134        let ty: Type = bool_value.get_type();
135        assert_eq!(Type::Bool, ty);
136    }
137
138    #[test]
139    fn test_from_fn_value() {
140        let builtin_fn = Value::Fn(Rc::new(BuiltinFn {
141            name: "test".to_string(),
142            args: vec![FnArg::new("a", Type::Value)],
143            return_type: Type::String,
144            func: Rc::new(|_| Value::String("".to_string())),
145        }));
146
147        let ty: Type = builtin_fn.into();
148
149        assert_eq!(
150            Type::Fn {
151                args: vec![Type::Value],
152                variadic_arg: None,
153                returns: Box::new(Type::String),
154            },
155            ty
156        );
157    }
158
159    #[test]
160    fn test_get_type_fn_value() {
161        let builtin_fn = Value::Fn(Rc::new(BuiltinFn {
162            name: "test".to_string(),
163            args: vec![FnArg::new("a", Type::Value)],
164            return_type: Type::String,
165            func: Rc::new(|_| Value::String("".to_string())),
166        }));
167
168        let ty: Type = builtin_fn.get_type();
169
170        assert_eq!(
171            Type::Fn {
172                args: vec![Type::Value],
173                variadic_arg: None,
174                returns: Box::new(Type::String),
175            },
176            ty
177        );
178    }
179}
180
181#[cfg(test)]
182mod name_and_display_tests {
183    use super::*;
184
185    #[test]
186    fn test_name_value() {
187        assert_eq!("Value", Type::Value.name());
188    }
189
190    #[test]
191    fn test_name_string() {
192        assert_eq!("String", Type::String.name());
193    }
194
195    #[test]
196    fn test_name_fn_0_args() {
197        assert_eq!(
198            "Fn() -> String",
199            Type::Fn {
200                args: vec![],
201                variadic_arg: None,
202                returns: Type::String.into(),
203            }
204            .name()
205        );
206    }
207
208    #[test]
209    fn test_name_fn_0_args_and_varadic() {
210        assert_eq!(
211            "Fn(...Value) -> String",
212            Type::Fn {
213                args: vec![],
214                variadic_arg: Some(Type::Value.into()),
215                returns: Type::String.into(),
216            }
217            .name()
218        );
219    }
220
221    #[test]
222    fn test_name_fn_1_args() {
223        assert_eq!(
224            "Fn(Value) -> String",
225            Type::Fn {
226                args: vec![Type::Value],
227                variadic_arg: None,
228                returns: Type::String.into(),
229            }
230            .name()
231        );
232    }
233
234    #[test]
235    fn test_name_fn_2_args() {
236        assert_eq!(
237            "Fn(Value, String) -> String",
238            Type::Fn {
239                args: vec![Type::Value, Type::String],
240                variadic_arg: None,
241                returns: Type::String.into(),
242            }
243            .name()
244        );
245    }
246
247    #[test]
248    fn test_name_fn_2_args_and_varadic() {
249        assert_eq!(
250            "Fn(Value, String, ...Value) -> String",
251            Type::Fn {
252                args: vec![Type::Value, Type::String],
253                variadic_arg: Some(Type::Value.into()),
254                returns: Type::String.into(),
255            }
256            .name()
257        );
258    }
259
260    #[test]
261    fn test_name_bool() {
262        assert_eq!("Bool", Type::Bool.name());
263    }
264}