bebop_lang/lisp/
builtin.rs

1use std::time::{SystemTime, UNIX_EPOCH, Duration};
2use crate::lisp::{
3    add_builtin, eval, to_num, to_qexpr, to_str, to_sym, Lenv, Lerr, LerrType, Llambda, Lval,
4};
5
6pub fn init_builtins(env: &mut Lenv) {
7    add_builtin(env, "!", builtin_not);
8    add_builtin(env, "+", builtin_add);
9    add_builtin(env, "-", builtin_sub);
10    add_builtin(env, "*", builtin_mul);
11    add_builtin(env, "/", builtin_div);
12    add_builtin(env, "%", builtin_mod);
13
14    add_builtin(env, "head", builtin_head);
15    add_builtin(env, "tail", builtin_tail);
16    add_builtin(env, "list", builtin_list);
17    add_builtin(env, "eval", builtin_eval);
18    add_builtin(env, "join", builtin_join);
19    add_builtin(env, "concat", builtin_concat);
20
21    add_builtin(env, "\\", builtin_lambda);
22    add_builtin(env, "def", builtin_def);
23    add_builtin(env, "=", builtin_var);
24
25    add_builtin(env, "if", builtin_if);
26    add_builtin(env, "echo", builtin_echo);
27    add_builtin(env, "rand", builtin_rand);
28
29    add_builtin(env, "die", builtin_err);
30
31    add_builtin(env, "<", builtin_lt);
32    add_builtin(env, ">", builtin_gt);
33    add_builtin(env, ">=", builtin_gte);
34    add_builtin(env, "<=", builtin_lte);
35    add_builtin(env, "==", builtin_eq);
36    add_builtin(env, "!=", builtin_ne);
37    add_builtin(env, "&&", builtin_and);
38    add_builtin(env, "||", builtin_or);
39}
40
41fn builtin_op(sym: &str, operands: Vec<Lval>) -> Result<Lval, Lerr> {
42    // cast everything into a number
43    let numbers = operands
44        .into_iter()
45        .map(to_num)
46        .collect::<Option<Vec<f64>>>()
47        .ok_or(Lerr::new(
48            LerrType::BadNum,
49            format!("Function {} can operate only on numbers", sym),
50        ))?;
51
52    // handle unary functions
53    if numbers.len() == 1 {
54        if "-" == sym {
55            return Ok(Lval::Num(-numbers[0]));
56        } else if "!" == sym {
57            let n = if numbers[0] == 0_f64 { 1_f64 } else { 0_f64 };
58            return Ok(Lval::Num(n));
59        } else {
60            return Ok(Lval::Num(numbers[0]));
61        }
62    }
63
64    let mut x = numbers[0];
65    let mut i = 1;
66
67    // apply the symbol over each operand
68    while i < numbers.len() {
69        let y = numbers[i];
70        match sym {
71            "-" => x -= y,
72            "*" => x *= y,
73            "%" => x %= y,
74            "/" => {
75                if y == 0_f64 {
76                    return Err(Lerr::new(
77                        LerrType::DivZero,
78                        format!("You cannot divide {}, or any number, by 0", x),
79                    ));
80                } else {
81                    x /= y;
82                }
83            }
84            _ => x += y,
85        }
86        i += 1;
87    }
88
89    Ok(Lval::Num(x))
90}
91
92fn builtin_ord(sym: &str, operands: Vec<Lval>) -> Result<Lval, Lerr> {
93    // need exactly two operands
94    if operands.len() != 2 {
95        return Err(Lerr::new(
96            LerrType::IncorrectParamCount,
97            format!(
98                "Function {} needed 2 args but was given {}",
99                sym,
100                operands.len()
101            ),
102        ));
103    }
104
105    // cast everything into a number
106    let numbers = operands
107        .into_iter()
108        .map(to_num)
109        .collect::<Option<Vec<f64>>>()
110        .ok_or(Lerr::new(
111            LerrType::BadNum,
112            format!("Function {} can operate only on numbers", sym),
113        ))?;
114
115    let x = numbers[0];
116    let y = numbers[1];
117
118    // these are for booleans
119    let a = if x == 0_f64 { false } else { true };
120    let b = if y == 0_f64 { false } else { true };
121
122    let r = match sym {
123        ">" => x > y,
124        "<" => x < y,
125        ">=" => x >= y,
126        "<=" => x <= y,
127        "&&" => a && b,
128        "||" => a || b,
129        _ => false,
130    };
131
132    if r {
133        Ok(Lval::Num(1_f64))
134    } else {
135        Ok(Lval::Num(0_f64))
136    }
137}
138
139fn builtin_eq(_env: &mut Lenv, operands: Vec<Lval>) -> Result<Lval, Lerr> {
140    // need exactly two operands
141    if operands.len() != 2 {
142        return Err(Lerr::new(
143            LerrType::IncorrectParamCount,
144            format!("Function eq needed 2 arg but was given {}", operands.len()),
145        ));
146    }
147
148    if operands[0] == operands[1] {
149        Ok(Lval::Num(1_f64))
150    } else {
151        Ok(Lval::Num(0_f64))
152    }
153}
154
155fn builtin_ne(_env: &mut Lenv, operands: Vec<Lval>) -> Result<Lval, Lerr> {
156    // need exactly two operands
157    if operands.len() != 2 {
158        return Err(Lerr::new(
159            LerrType::IncorrectParamCount,
160            format!("Function eq needed 2 arg but was given {}", operands.len()),
161        ));
162    }
163
164    if operands[0] == operands[1] {
165        Ok(Lval::Num(0_f64))
166    } else {
167        Ok(Lval::Num(1_f64))
168    }
169}
170
171fn builtin_gt(_env: &mut Lenv, operands: Vec<Lval>) -> Result<Lval, Lerr> {
172    builtin_ord(">", operands)
173}
174
175fn builtin_lt(_env: &mut Lenv, operands: Vec<Lval>) -> Result<Lval, Lerr> {
176    builtin_ord("<", operands)
177}
178
179fn builtin_gte(_env: &mut Lenv, operands: Vec<Lval>) -> Result<Lval, Lerr> {
180    builtin_ord(">=", operands)
181}
182
183fn builtin_lte(_env: &mut Lenv, operands: Vec<Lval>) -> Result<Lval, Lerr> {
184    builtin_ord("<=", operands)
185}
186
187fn builtin_and(_env: &mut Lenv, operands: Vec<Lval>) -> Result<Lval, Lerr> {
188    builtin_ord("&&", operands)
189}
190
191fn builtin_or(_env: &mut Lenv, operands: Vec<Lval>) -> Result<Lval, Lerr> {
192    builtin_ord("||", operands)
193}
194
195fn builtin_not(_env: &mut Lenv, operands: Vec<Lval>) -> Result<Lval, Lerr> {
196    builtin_op("!", operands)
197}
198
199fn builtin_add(_env: &mut Lenv, operands: Vec<Lval>) -> Result<Lval, Lerr> {
200    builtin_op("+", operands)
201}
202
203fn builtin_sub(_env: &mut Lenv, operands: Vec<Lval>) -> Result<Lval, Lerr> {
204    builtin_op("-", operands)
205}
206
207fn builtin_mul(_env: &mut Lenv, operands: Vec<Lval>) -> Result<Lval, Lerr> {
208    builtin_op("*", operands)
209}
210
211fn builtin_mod(_env: &mut Lenv, operands: Vec<Lval>) -> Result<Lval, Lerr> {
212    builtin_op("%", operands)
213}
214
215fn builtin_div(_env: &mut Lenv, operands: Vec<Lval>) -> Result<Lval, Lerr> {
216    builtin_op("/", operands)
217}
218
219fn builtin_rand(_env: &mut Lenv, operands: Vec<Lval>) -> Result<Lval, Lerr> {
220    if operands.len() != 0 {
221        return Err(Lerr::new(
222            LerrType::IncorrectParamCount,
223            format!("Function if needed 0 arg but was given {}", operands.len()),
224        ));
225    }
226
227    let nanos = SystemTime::now().duration_since(UNIX_EPOCH).unwrap_or(Duration::from_nanos(12345)).subsec_nanos();
228    Ok(Lval::Num(nanos as f64))
229}
230
231fn builtin_if(env: &mut Lenv, operands: Vec<Lval>) -> Result<Lval, Lerr> {
232    if operands.len() != 3 {
233        return Err(Lerr::new(
234            LerrType::IncorrectParamCount,
235            format!("Function if needed 3 arg but was given {}", operands.len()),
236        ));
237    }
238
239    let conditional = to_num(operands[0].clone()).ok_or(Lerr::new(
240        LerrType::WrongType,
241        format!(
242            "Function if needed conditional but was given {:?}",
243            operands[0]
244        ),
245    ))?;
246
247    let then = to_qexpr(operands[1].clone()).ok_or(Lerr::new(
248        LerrType::WrongType,
249        format!(
250            "Function if needed qexpr for Then but was given {:?}",
251            operands[1]
252        ),
253    ))?;
254
255    let els = to_qexpr(operands[2].clone()).ok_or(Lerr::new(
256        LerrType::WrongType,
257        format!(
258            "Function if needed qexpr for Else but was given {:?}",
259            operands[2]
260        ),
261    ))?;
262
263    if conditional == 0_f64 {
264        eval::eval(env, Lval::Sexpr(els))
265    } else {
266        eval::eval(env, Lval::Sexpr(then))
267    }
268}
269
270fn builtin_err(_env: &mut Lenv, operands: Vec<Lval>) -> Result<Lval, Lerr> {
271    let err = to_str(operands[0].clone()).ok_or(Lerr::new(
272        LerrType::WrongType,
273        format!(
274            "Function die needed qexpr for Else but was given {:?}",
275            operands[0]
276        ),
277    ))?;
278
279    Err(Lerr::new(LerrType::Interrupt, err))
280}
281
282fn builtin_head(_env: &mut Lenv, operands: Vec<Lval>) -> Result<Lval, Lerr> {
283    // we want only one arguement
284    if operands.len() != 1 {
285        return Err(Lerr::new(
286            LerrType::IncorrectParamCount,
287            format!(
288                "Function head needed 1 arg but was given {}",
289                operands.len()
290            ),
291        ));
292    }
293
294    let arg = &operands[0];
295    // need a list/qexpr to work with
296    match arg {
297        Lval::Qexpr(qexpr) => {
298            if qexpr.len() == 0 {
299                Err(Lerr::new(
300                    LerrType::EmptyList,
301                    format!("Function head was given empty list"),
302                ))
303            } else {
304                Ok(qexpr[0].clone())
305            }
306        }
307        _ => Err(Lerr::new(
308            LerrType::WrongType,
309            format!("Function head needed Qexpr but was given {:?}", arg),
310        )),
311    }
312}
313
314fn builtin_tail(_env: &mut Lenv, operands: Vec<Lval>) -> Result<Lval, Lerr> {
315    // we want only one arguement
316    if operands.len() != 1 {
317        return Err(Lerr::new(
318            LerrType::IncorrectParamCount,
319            format!(
320                "Function tail needed 1 arg but was given {}",
321                operands.len()
322            ),
323        ));
324    }
325
326    let arg = &operands[0];
327    // need a list/qexpr to work with
328    match arg {
329        Lval::Qexpr(qexpr) => {
330            if qexpr.len() == 0 {
331                Err(Lerr::new(
332                    LerrType::EmptyList,
333                    format!("Function tail was given empty list"),
334                ))
335            } else {
336                Ok(Lval::Qexpr(qexpr[1..].to_vec()))
337            }
338        }
339        _ => Err(Lerr::new(
340            LerrType::WrongType,
341            format!("Function tail needed Qexpr but was given {:?}", arg),
342        )),
343    }
344}
345
346fn builtin_list(_env: &mut Lenv, operands: Vec<Lval>) -> Result<Lval, Lerr> {
347    Ok(Lval::Qexpr(operands))
348}
349
350fn builtin_eval(env: &mut Lenv, operands: Vec<Lval>) -> Result<Lval, Lerr> {
351    // we only want to evaluate one arguement
352    if operands.len() != 1 {
353        return Err(Lerr::new(
354            LerrType::IncorrectParamCount,
355            format!(
356                "Function eval needed 1 arg but was given {}",
357                operands.len()
358            ),
359        ));
360    }
361
362    let arg = &operands[0];
363    match arg {
364        Lval::Qexpr(qexpr) => eval::eval(env, Lval::Sexpr(qexpr[..].to_vec())),
365        _ => eval::eval(env, arg.clone()),
366    }
367}
368
369fn builtin_echo(env: &mut Lenv, operands: Vec<Lval>) -> Result<Lval, Lerr> {
370    // we only want to evaluate one arguement
371    if operands.len() != 1 {
372        return Err(Lerr::new(
373            LerrType::IncorrectParamCount,
374            format!(
375                "Function echo needed 1 arg but was given {}",
376                operands.len()
377            ),
378        ));
379    }
380
381    let arg = &operands[0];
382    Ok(Lval::Str(format!("\"{:?}\"", arg)))
383}
384
385fn builtin_join(_env: &mut Lenv, operands: Vec<Lval>) -> Result<Lval, Lerr> {
386    // need at least 2 arguements
387    if operands.len() < 2 {
388        return Err(Lerr::new(
389            LerrType::IncorrectParamCount,
390            format!(
391                "Function join needed 2 arg but was given {}",
392                operands.len()
393            ),
394        ));
395    }
396
397    // cast everything into a qexppr
398    let qexprs = operands
399        .into_iter()
400        .map(to_qexpr)
401        .collect::<Option<Vec<_>>>()
402        .ok_or(Lerr::new(
403            LerrType::WrongType,
404            format!("Function join needed Qexpr but was given"),
405        ))?;
406
407    // push each elements from each arguements into one qexpr
408    let mut joined = vec![];
409    for qexp in qexprs {
410        for item in qexp {
411            joined.push(item);
412        }
413    }
414
415    Ok(Lval::Qexpr(joined))
416}
417
418fn builtin_concat(_env: &mut Lenv, operands: Vec<Lval>) -> Result<Lval, Lerr> {
419    // need at least 1 arguements
420    if operands.len() < 1 {
421        return Err(Lerr::new(
422            LerrType::IncorrectParamCount,
423            format!(
424                "Function concat needed >= 1 arg but was given {}",
425                operands.len()
426            ),
427        ));
428    }
429
430    // cast everything into a qexppr
431    let strings = operands
432        .into_iter()
433        .map(to_str)
434        .collect::<Option<Vec<_>>>()
435        .ok_or(Lerr::new(
436            LerrType::WrongType,
437            format!("Function concat needed Strings but was given"),
438        ))?;
439
440    // push each elements from each arguements into one string
441    let mut concatted = String::from("");
442    for string in strings {
443        concatted = format!("{}{}", concatted, string);
444    }
445
446    Ok(Lval::Str(concatted))
447}
448
449fn builtin_def(env: &mut Lenv, operands: Vec<Lval>) -> Result<Lval, Lerr> {
450    builtin_assign("def", env, operands)
451}
452
453fn builtin_var(env: &mut Lenv, operands: Vec<Lval>) -> Result<Lval, Lerr> {
454    builtin_assign("=", env, operands)
455}
456
457fn builtin_assign(sym: &str, env: &mut Lenv, operands: Vec<Lval>) -> Result<Lval, Lerr> {
458    // need at least an arguement list and a value
459    if operands.len() < 2 {
460        return Err(Lerr::new(
461            LerrType::IncorrectParamCount,
462            format!(
463                "Function def needed 2 args but was given {}",
464                operands.len()
465            ),
466        ));
467    }
468
469    let args = operands[0].clone();
470
471    // need each argument to be a symbol
472    let args = to_qexpr(args)
473        .ok_or(Lerr::new(
474            LerrType::WrongType,
475            format!("Function def needed Qexpr but was given {:?}", operands[0]),
476        ))?
477        .into_iter()
478        .map(to_sym)
479        .collect::<Option<Vec<String>>>()
480        .ok_or(Lerr::new(
481            LerrType::WrongType,
482            format!("Function def needed a param list of all Symbols"),
483        ))?;
484
485    // need to have the same number of args and values to assign
486    if args.len() != operands.len() - 1 {
487        return Err(Lerr::new(
488            LerrType::IncorrectParamCount,
489            format!(
490                "Function def needed to assign {} values but was passed {}",
491                args.len(),
492                operands.len() - 1
493            ),
494        ));
495    }
496
497    // assign each arg to a corresponding value
498    for (i, arg) in args.into_iter().enumerate() {
499        if sym == "def" {
500            env.insert_last(&arg, operands[i + 1].clone());
501        } else {
502            env.insert(&arg, operands[i + 1].clone());
503        }
504    }
505
506    Ok(Lval::Str(String::from("")))
507}
508
509fn builtin_lambda(env: &mut Lenv, operands: Vec<Lval>) -> Result<Lval, Lerr> {
510    if operands.len() != 2 {
511        return Err(Lerr::new(
512            LerrType::IncorrectParamCount,
513            format!("Function \\ needed 2 arg but was given {}", operands.len()),
514        ));
515    }
516
517    // needs all arguements to be qexpr
518    let results = operands
519        .into_iter()
520        .map(to_qexpr)
521        .collect::<Option<Vec<_>>>()
522        .ok_or(Lerr::new(
523            LerrType::WrongType,
524            format!("Function \\ needed a Qexpr for arguments and a Qexpr for body"),
525        ))?;
526
527    let args = results[0].clone();
528    // need each argument to be a symbol
529    let args = args
530        .into_iter()
531        .map(to_sym)
532        .collect::<Option<Vec<String>>>()
533        .ok_or(Lerr::new(
534            LerrType::WrongType,
535            format!("Function \\ needed a param list of all Symbols"),
536        ))?;
537
538    let body = results[1].clone();
539    let new_env = env.peek().unwrap().clone();
540    let lambda = Llambda::new(args, body, new_env);
541
542    Ok(Lval::Lambda(lambda))
543}
544
545#[cfg(test)]
546mod tests {
547    use super::*;
548    use crate::lisp::{env::init_env, to_lambda};
549
550    fn empty_fun(_env: &mut Lenv, _operands: Vec<Lval>) -> Result<Lval, Lerr> {
551        Ok(Lval::Sexpr(vec![]))
552    }
553
554    #[test]
555    fn it_correctly_uses_head() {
556        let env = &mut init_env();
557        let expr = Lval::Qexpr(vec![
558            Lval::Sym(String::from("+")),
559            Lval::Num(1_f64),
560            Lval::Sexpr(vec![
561                Lval::Sym(String::from("+")),
562                Lval::Num(1_f64),
563                Lval::Num(1_f64),
564            ]),
565        ]);
566        assert_eq!(
567            builtin_head(env, vec![expr.clone()]).unwrap(),
568            Lval::Sym(String::from("+"))
569        );
570
571        let _ = builtin_head(env, vec![])
572            .map_err(|err| assert_eq!(err.etype, LerrType::IncorrectParamCount));
573
574        let _ = builtin_head(env, vec![Lval::Sym(String::from("+"))])
575            .map_err(|err| assert_eq!(err.etype, LerrType::WrongType));
576
577        let _ = builtin_head(env, vec![Lval::Qexpr(vec![])])
578            .map_err(|err| assert_eq!(err.etype, LerrType::EmptyList));
579    }
580
581    #[test]
582    fn it_correctly_uses_tail() {
583        let env = &mut init_env();
584        let expr = Lval::Qexpr(vec![
585            Lval::Sym(String::from("+")),
586            Lval::Num(1_f64),
587            Lval::Sexpr(vec![
588                Lval::Sym(String::from("+")),
589                Lval::Num(1_f64),
590                Lval::Num(1_f64),
591            ]),
592        ]);
593        assert_eq!(
594            builtin_tail(env, vec![expr.clone()]).unwrap(),
595            Lval::Qexpr(vec![
596                Lval::Num(1_f64),
597                Lval::Sexpr(vec![
598                    Lval::Sym(String::from("+")),
599                    Lval::Num(1_f64),
600                    Lval::Num(1_f64),
601                ])
602            ])
603        );
604        let _ = builtin_tail(env, vec![])
605            .map_err(|err| assert_eq!(err.etype, LerrType::IncorrectParamCount));
606
607        let _ = builtin_tail(env, vec![Lval::Sym(String::from("+"))])
608            .map_err(|err| assert_eq!(err.etype, LerrType::WrongType));
609
610        let _ = builtin_tail(env, vec![Lval::Qexpr(vec![])])
611            .map_err(|err| assert_eq!(err.etype, LerrType::EmptyList));
612    }
613
614    #[test]
615    fn it_correctly_uses_list() {
616        let env = &mut init_env();
617        let expr = vec![
618            Lval::Sym(String::from("+")),
619            Lval::Num(1_f64),
620            Lval::Sexpr(vec![
621                Lval::Sym(String::from("+")),
622                Lval::Num(1_f64),
623                Lval::Num(1_f64),
624            ]),
625        ];
626        assert_eq!(
627            builtin_list(env, expr.clone()).unwrap(),
628            Lval::Qexpr(vec![
629                Lval::Sym(String::from("+")),
630                Lval::Num(1_f64),
631                Lval::Sexpr(vec![
632                    Lval::Sym(String::from("+")),
633                    Lval::Num(1_f64),
634                    Lval::Num(1_f64),
635                ])
636            ])
637        );
638        assert_eq!(
639            builtin_list(
640                env,
641                vec![
642                    Lval::Sym(String::from("+")),
643                    Lval::Num(1_f64),
644                    Lval::Num(1_f64),
645                ]
646            )
647            .unwrap(),
648            Lval::Qexpr(vec![
649                Lval::Sym(String::from("+")),
650                Lval::Num(1_f64),
651                Lval::Num(1_f64),
652            ])
653        );
654        assert_eq!(builtin_list(env, vec![]).unwrap(), Lval::Qexpr(vec![]));
655        assert_eq!(
656            builtin_list(env, vec![Lval::Sym(String::from("+"))]).unwrap(),
657            Lval::Qexpr(vec![Lval::Sym(String::from("+")),])
658        );
659        assert_eq!(
660            builtin_list(env, vec![Lval::Sexpr(vec![])]).unwrap(),
661            Lval::Qexpr(vec![Lval::Sexpr(vec![]),])
662        );
663    }
664
665    #[test]
666    fn it_correctly_uses_eval() {
667        let env = &mut init_env();
668        let expr = Lval::Qexpr(vec![
669            Lval::Sym(String::from("+")),
670            Lval::Num(1_f64),
671            Lval::Sexpr(vec![
672                Lval::Sym(String::from("+")),
673                Lval::Num(1_f64),
674                Lval::Num(1_f64),
675            ]),
676        ]);
677        assert_eq!(
678            builtin_eval(env, vec![expr.clone()]).unwrap(),
679            Lval::Num(3_f64)
680        );
681
682        let _ = builtin_eval(env, vec![expr.clone(), expr.clone()])
683            .map_err(|err| assert_eq!(err.etype, LerrType::IncorrectParamCount));
684
685        let _ = builtin_eval(env, vec![])
686            .map_err(|err| assert_eq!(err.etype, LerrType::IncorrectParamCount));
687
688        assert_eq!(
689            builtin_eval(env, vec![Lval::Sym(String::from("-"))]).unwrap(),
690            Lval::Fun(empty_fun)
691        );
692        assert_eq!(
693            builtin_eval(env, vec![Lval::Sexpr(vec![Lval::Sym(String::from("-"))])]).unwrap(),
694            Lval::Fun(empty_fun)
695        );
696        assert_eq!(
697            builtin_eval(env, vec![Lval::Qexpr(vec![])]).unwrap(),
698            Lval::Sexpr(vec![])
699        );
700    }
701
702    #[test]
703    fn it_correctly_uses_join() {
704        let env = &mut init_env();
705        let expr = Lval::Qexpr(vec![
706            Lval::Sym(String::from("+")),
707            Lval::Num(1_f64),
708            Lval::Sexpr(vec![
709                Lval::Sym(String::from("+")),
710                Lval::Num(1_f64),
711                Lval::Num(1_f64),
712            ]),
713        ]);
714        assert_eq!(
715            builtin_join(env, vec![expr.clone(), expr.clone()]).unwrap(),
716            Lval::Qexpr(vec![
717                Lval::Sym(String::from("+")),
718                Lval::Num(1_f64),
719                Lval::Sexpr(vec![
720                    Lval::Sym(String::from("+")),
721                    Lval::Num(1_f64),
722                    Lval::Num(1_f64),
723                ]),
724                Lval::Sym(String::from("+")),
725                Lval::Num(1_f64),
726                Lval::Sexpr(vec![
727                    Lval::Sym(String::from("+")),
728                    Lval::Num(1_f64),
729                    Lval::Num(1_f64),
730                ]),
731            ])
732        );
733
734        let _ = builtin_join(env, vec![expr.clone()])
735            .map_err(|err| assert_eq!(err.etype, LerrType::IncorrectParamCount));
736
737        let _ = builtin_join(env, vec![])
738            .map_err(|err| assert_eq!(err.etype, LerrType::IncorrectParamCount));
739
740        let _ = builtin_join(env, vec![expr.clone(), Lval::Sym(String::from("+"))])
741            .map_err(|err| assert_eq!(err.etype, LerrType::WrongType));
742
743        assert_eq!(
744            builtin_join(env, vec![expr.clone(), Lval::Qexpr(vec![])]).unwrap(),
745            Lval::Qexpr(vec![
746                Lval::Sym(String::from("+")),
747                Lval::Num(1_f64),
748                Lval::Sexpr(vec![
749                    Lval::Sym(String::from("+")),
750                    Lval::Num(1_f64),
751                    Lval::Num(1_f64),
752                ]),
753            ])
754        );
755    }
756
757    #[test]
758    fn it_correctly_uses_concat() {
759        let env = &mut init_env();
760        assert_eq!(
761            builtin_concat(
762                env,
763                vec![
764                    Lval::Str(String::from("ceci")),
765                    Lval::Str(String::from(" n'est")),
766                    Lval::Str(String::from(" pas")),
767                    Lval::Str(String::from(" une")),
768                    Lval::Str(String::from(" pipe"))
769                ]
770            )
771            .unwrap(),
772            Lval::Str(String::from("ceci n'est pas une pipe"))
773        );
774    }
775
776    #[test]
777    fn it_correctly_uses_define() {
778        let env = &mut init_env();
779        assert_eq!(
780            builtin_def(
781                env,
782                vec![
783                    Lval::Qexpr(vec![
784                        Lval::Sym(String::from("a")),
785                        Lval::Sym(String::from("b")),
786                        Lval::Sym(String::from("c"))
787                    ]),
788                    Lval::Num(1_f64),
789                    Lval::Sym(String::from("+")),
790                    Lval::Sexpr(vec![]),
791                ]
792            )
793            .unwrap(),
794            Lval::Sexpr(vec![])
795        );
796        assert_eq!(
797            crate::lisp::eval::eval(env, Lval::Sym(String::from("a"))).unwrap(),
798            Lval::Num(1_f64)
799        );
800        assert_eq!(
801            crate::lisp::eval::eval(env, Lval::Sym(String::from("b"))).unwrap(),
802            Lval::Sym(String::from("+"))
803        );
804        assert_eq!(
805            crate::lisp::eval::eval(env, Lval::Sym(String::from("c"))).unwrap(),
806            Lval::Sexpr(vec![])
807        );
808        let _ = builtin_def(
809            env,
810            vec![Lval::Qexpr(vec![
811                Lval::Sym(String::from("a")),
812                Lval::Sym(String::from("b")),
813                Lval::Sym(String::from("c")),
814            ])],
815        )
816        .map_err(|err| assert_eq!(err.etype, LerrType::IncorrectParamCount));
817
818        let _ = builtin_def(
819            env,
820            vec![
821                Lval::Qexpr(vec![
822                    Lval::Sym(String::from("a")),
823                    Lval::Sym(String::from("b")),
824                ]),
825                Lval::Num(1_f64),
826                Lval::Sym(String::from("+")),
827                Lval::Sym(String::from("+")),
828            ],
829        )
830        .map_err(|err| assert_eq!(err.etype, LerrType::IncorrectParamCount));
831        let _ = builtin_def(
832            env,
833            vec![Lval::Qexpr(vec![Lval::Num(1_f64)]), Lval::Num(1_f64)],
834        )
835        .map_err(|err| assert_eq!(err.etype, LerrType::WrongType));
836    }
837
838    //(\ {a b} {* a b}) 1 2
839    #[test]
840    fn it_correctly_uses_lambda() {
841        let env = &mut init_env();
842        assert!(to_lambda(
843            &builtin_lambda(
844                env,
845                vec![
846                    Lval::Qexpr(vec![
847                        Lval::Sym(String::from("a")),
848                        Lval::Sym(String::from("b")),
849                    ]),
850                    Lval::Qexpr(vec![
851                        Lval::Sym(String::from("+")),
852                        Lval::Sym(String::from("a")),
853                        Lval::Sym(String::from("b")),
854                    ]),
855                ]
856            )
857            .unwrap()
858        )
859        .is_some());
860
861        let expr = Lval::Sexpr(vec![
862            Lval::Sexpr(vec![
863                Lval::Sym(String::from("\\")),
864                Lval::Qexpr(vec![
865                    Lval::Sym(String::from("a")),
866                    Lval::Sym(String::from("b")),
867                ]),
868                Lval::Qexpr(vec![
869                    Lval::Sym(String::from("+")),
870                    Lval::Sym(String::from("a")),
871                    Lval::Sym(String::from("b")),
872                ]),
873            ]),
874            Lval::Num(2_f64),
875            Lval::Num(2_f64),
876        ]);
877        assert_eq!(eval::eval(env, expr).unwrap(), Lval::Num(4_f64));
878    }
879
880    #[test]
881    fn it_correctly_uses_ord() {
882        let env = &mut init_env();
883        assert_eq!(
884            builtin_lt(env, vec![Lval::Num(1_f64), Lval::Num(2_f64)]).unwrap(),
885            Lval::Num(1_f64)
886        );
887        assert_eq!(
888            builtin_lt(env, vec![Lval::Num(2_f64), Lval::Num(1_f64)]).unwrap(),
889            Lval::Num(0_f64)
890        );
891
892        assert_eq!(
893            builtin_gt(env, vec![Lval::Num(1_f64), Lval::Num(2_f64)]).unwrap(),
894            Lval::Num(0_f64)
895        );
896        assert_eq!(
897            builtin_gt(env, vec![Lval::Num(2_f64), Lval::Num(1_f64)]).unwrap(),
898            Lval::Num(1_f64)
899        );
900
901        assert_eq!(
902            builtin_gte(env, vec![Lval::Num(1_f64), Lval::Num(2_f64)]).unwrap(),
903            Lval::Num(0_f64)
904        );
905        assert_eq!(
906            builtin_gte(env, vec![Lval::Num(2_f64), Lval::Num(1_f64)]).unwrap(),
907            Lval::Num(1_f64)
908        );
909        assert_eq!(
910            builtin_gte(env, vec![Lval::Num(2_f64), Lval::Num(2_f64)]).unwrap(),
911            Lval::Num(1_f64)
912        );
913
914        assert_eq!(
915            builtin_lte(env, vec![Lval::Num(1_f64), Lval::Num(2_f64)]).unwrap(),
916            Lval::Num(1_f64)
917        );
918        assert_eq!(
919            builtin_lte(env, vec![Lval::Num(2_f64), Lval::Num(1_f64)]).unwrap(),
920            Lval::Num(0_f64)
921        );
922        assert_eq!(
923            builtin_lte(env, vec![Lval::Num(2_f64), Lval::Num(2_f64)]).unwrap(),
924            Lval::Num(1_f64)
925        );
926    }
927
928    #[test]
929    fn it_correctly_uses_if() {
930        let env = &mut init_env();
931        assert_eq!(
932            builtin_if(
933                env,
934                vec![
935                    Lval::Num(1_f64),
936                    Lval::Qexpr(vec![Lval::Num(6_f64)]),
937                    Lval::Qexpr(vec![Lval::Num(9_f64)])
938                ]
939            )
940            .unwrap(),
941            Lval::Num(6_f64)
942        );
943        assert_eq!(
944            builtin_if(
945                env,
946                vec![
947                    Lval::Num(0_f64),
948                    Lval::Qexpr(vec![Lval::Num(6_f64)]),
949                    Lval::Qexpr(vec![Lval::Num(9_f64)])
950                ]
951            )
952            .unwrap(),
953            Lval::Num(9_f64)
954        );
955    }
956}