1use core::fmt;
2use std::fmt::Display;
3
4use crate::{types::Type, value::Value};
5
6#[derive(Clone)]
7pub struct FnArg {
8 pub name: String,
9 pub ty: Type,
10 pub variadic: bool,
11}
12
13impl FnArg {
14 pub fn new(name: &str, ty: Type) -> Self {
15 Self {
16 name: String::from(name),
17 ty,
18 variadic: false,
19 }
20 }
21
22 pub fn new_varadic(name: &str, ty: Type) -> Self {
23 Self {
24 name: String::from(name),
25 ty,
26 variadic: true,
27 }
28 }
29}
30
31pub struct BuiltinFn {
33 pub name: String,
35 pub args: Vec<FnArg>,
37 pub return_type: Type,
38 pub func: std::rc::Rc<dyn Fn(Vec<Value>) -> Value>,
40}
41
42impl BuiltinFn {
43 pub fn arity(&self) -> u8 {
44 let len = self.args.len() as u8;
45
46 if self.is_variadic() { len - 1 } else { len }
47 }
48
49 pub fn is_variadic(&self) -> bool {
50 self.args.last().map(|arg| arg.variadic).unwrap_or(false)
51 }
52
53 pub fn arity_matches(&self, arity: u8) -> bool {
54 if self.is_variadic() {
55 self.arity() <= arity
56 } else {
57 self.arity() == arity
58 }
59 }
60}
61
62impl PartialEq for BuiltinFn {
63 fn eq(&self, other: &Self) -> bool {
64 self.name == other.name
65 }
66}
67
68impl Display for BuiltinFn {
69 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
70 let name = &self.name;
71 let args: Vec<String> = self
72 .args
73 .iter()
74 .map(|arg| {
75 let prefix: &str = if arg.variadic { "..." } else { "" };
76
77 format!("{prefix}{}: {}", arg.name.clone(), arg.ty.name())
78 })
79 .collect();
80
81 let args: String = args.join(", ");
82
83 let return_type: String = self.return_type.name().to_string();
84
85 write!(f, "{name}({args}) -> {return_type}")
86 }
87}
88
89impl fmt::Debug for BuiltinFn {
90 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
91 let name = &self.name;
92 let args: Vec<String> = self
93 .args
94 .iter()
95 .map(|arg| {
96 let prefix: &str = if arg.variadic { "..." } else { "" };
97
98 format!("{prefix}{}: {}", arg.name.clone(), arg.ty.name())
99 })
100 .collect();
101
102 let args: String = args.join(", ");
103
104 let return_type: String = self.return_type.name().to_string();
105
106 write!(f, "{name}({args}) -> {return_type}")
107 }
108}
109
110#[derive(Debug, PartialEq)]
111pub enum FnArity {
112 N(u8),
113 Variadic { n: u8 },
114}
115
116impl Display for FnArity {
117 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
118 let string = match self {
119 FnArity::N(n) => n.to_string(),
120 FnArity::Variadic { n } => {
121 if *n == 0 {
122 "...".to_string()
123 } else {
124 format!("{n}, ...")
125 }
126 }
127 };
128
129 write!(f, "{}", string)
130 }
131}
132
133pub struct BuiltinFns;
134
135impl BuiltinFns {
136 pub fn id(args: Vec<Value>) -> Value {
137 let arg = args.first().unwrap();
138
139 arg.clone()
140 }
141
142 pub fn noop(_: Vec<Value>) -> Value {
143 Value::String(String::from("noop"))
144 }
145
146 pub fn is_empty(args: Vec<Value>) -> Value {
147 let string_arg = args
148 .first()
149 .expect("should have string expression passed")
150 .get_string();
151
152 Value::Bool(string_arg.is_empty())
153 }
154
155 pub fn not(args: Vec<Value>) -> Value {
156 let bool_arg = args
157 .first()
158 .expect("should have boolean expression passed")
159 .get_bool();
160
161 Value::Bool(!bool_arg)
162 }
163
164 pub fn and(args: Vec<Value>) -> Value {
165 let a_arg = args
166 .first()
167 .expect("should have first expression passed")
168 .get_bool();
169 let b_arg = args
170 .get(1)
171 .expect("should have second expression passed")
172 .get_bool();
173
174 Value::Bool(a_arg && b_arg)
175 }
176
177 pub fn or(args: Vec<Value>) -> Value {
178 let a_arg = args
179 .first()
180 .expect("should have first expression passed")
181 .get_bool();
182 let b_arg = args
183 .get(1)
184 .expect("should have second expression passed")
185 .get_bool();
186
187 Value::Bool(a_arg || b_arg)
188 }
189
190 pub fn cond(args: Vec<Value>) -> Value {
191 let cond_arg = args
192 .first()
193 .expect("should have cond expression passed")
194 .get_bool();
195 let then_arg = args
196 .get(1)
197 .cloned()
198 .expect("should have then expression passed");
199 let else_arg = args
200 .get(2)
201 .cloned()
202 .expect("should have else expression passed");
203
204 if cond_arg { then_arg } else { else_arg }
205 }
206
207 pub fn to_str(args: Vec<Value>) -> Value {
208 let value_arg = args.first().expect("should have string expression passed");
209
210 match value_arg {
211 Value::String(_) => value_arg.clone(),
212 _ => Value::String(value_arg.to_string()),
213 }
214 }
215
216 pub fn concat(args: Vec<Value>) -> Value {
217 let mut result = String::new();
218
219 for arg in args {
220 let value = match arg {
221 Value::String(string) => string,
222 _ => arg.to_string(),
223 };
224
225 result.push_str(value.as_str());
226 }
227
228 Value::String(result)
229 }
230
231 pub fn contains(args: Vec<Value>) -> Value {
232 let needle_arg = args
233 .first()
234 .expect("should have first expression passed")
235 .get_string();
236 let haystack_arg = args
237 .get(1)
238 .expect("should have second expression passed")
239 .get_string();
240
241 Value::Bool(haystack_arg.contains(needle_arg))
242 }
243
244 pub fn trim(args: Vec<Value>) -> Value {
245 let string_arg = args
246 .first()
247 .expect("should have string expression passed")
248 .get_string();
249
250 Value::String(string_arg.trim().to_string())
251 }
252
253 pub fn trim_start(args: Vec<Value>) -> Value {
254 let string_arg = args
255 .first()
256 .expect("should have string expression passed")
257 .get_string();
258
259 Value::String(string_arg.trim_start().to_string())
260 }
261
262 pub fn trim_end(args: Vec<Value>) -> Value {
263 let string_arg = args
264 .first()
265 .expect("should have string expression passed")
266 .get_string();
267
268 Value::String(string_arg.trim_end().to_string())
269 }
270
271 pub fn lowercase(args: Vec<Value>) -> Value {
272 let string_arg = args
273 .first()
274 .expect("should have string expression passed")
275 .get_string();
276
277 Value::String(string_arg.to_lowercase().to_string())
278 }
279
280 pub fn uppercase(args: Vec<Value>) -> Value {
281 let string_arg = args
282 .first()
283 .expect("should have string expression passed")
284 .get_string();
285
286 Value::String(string_arg.to_uppercase().to_string())
287 }
288
289 pub fn eq(args: Vec<Value>) -> Value {
290 let a_arg = args.first().expect("should have first expression passed");
291 let b_arg = args.get(1).expect("should have second expression passed");
292
293 Value::Bool(a_arg == b_arg)
294 }
295
296 pub fn get_type(args: Vec<Value>) -> Value {
297 let value_arg = args.first().expect("should have first expression passed");
298
299 Value::String(value_arg.get_type().name())
300 }
301}
302
303#[cfg(test)]
304mod value_tests {
305 use std::rc::Rc;
306
307 use super::*;
308
309 #[test]
310 fn test_builtins_display_0_arity() {
311 assert_eq!(
312 "test_builtin() -> String",
313 format!(
314 "{}",
315 BuiltinFn {
316 name: "test_builtin".to_string(),
317 args: vec![],
318 return_type: Type::String,
319 func: Rc::new(|_| { Value::String("test_builtin".to_string()) })
320 }
321 )
322 )
323 }
324
325 #[test]
326 fn test_builtins_debug_0_arity() {
327 assert_eq!(
328 "test_builtin() -> String",
329 format!(
330 "{:#?}",
331 BuiltinFn {
332 name: "test_builtin".to_string(),
333 args: vec![],
334 return_type: Type::String,
335 func: Rc::new(|_| { Value::String("test_builtin".to_string()) })
336 }
337 )
338 )
339 }
340
341 #[test]
342 fn test_builtins_display_1_arity() {
343 assert_eq!(
344 "test_builtin(value: String) -> String",
345 format!(
346 "{}",
347 BuiltinFn {
348 name: "test_builtin".to_string(),
349 args: vec![FnArg::new("value", Type::String)],
350 return_type: Type::String,
351 func: Rc::new(|_| { Value::String("test_builtin".to_string()) })
352 }
353 )
354 )
355 }
356
357 #[test]
358 fn test_builtins_debug_1_arity() {
359 assert_eq!(
360 "test_builtin(value: String) -> String",
361 format!(
362 "{:#?}",
363 BuiltinFn {
364 name: "test_builtin".to_string(),
365 args: vec![FnArg::new("value", Type::String)],
366 return_type: Type::String,
367 func: Rc::new(|_| { Value::String("test_builtin".to_string()) })
368 }
369 )
370 )
371 }
372
373 #[test]
374 fn test_builtins_display_2_arity() {
375 assert_eq!(
376 "test_builtin(a: String, b: String) -> String",
377 format!(
378 "{}",
379 BuiltinFn {
380 name: "test_builtin".to_string(),
381 args: vec![FnArg::new("a", Type::String), FnArg::new("b", Type::String)],
382 return_type: Type::String,
383 func: Rc::new(|_| { Value::String("test_builtin".to_string()) })
384 }
385 )
386 )
387 }
388
389 #[test]
390 fn test_builtins_debug_2_arity() {
391 assert_eq!(
392 "test_builtin(a: String, b: String) -> String",
393 format!(
394 "{:#?}",
395 BuiltinFn {
396 name: "test_builtin".to_string(),
397 args: vec![FnArg::new("a", Type::String), FnArg::new("b", Type::String)],
398 return_type: Type::String,
399 func: Rc::new(|_| { Value::String("test_builtin".to_string()) })
400 }
401 )
402 )
403 }
404}