Skip to main content

blisp/
runtime.rs

1use crate::r#macro;
2
3use super::{parser, semantics, LispErr, Pos};
4use alloc::{
5    boxed::Box,
6    collections::{btree_map::BTreeMap, linked_list::LinkedList, vec_deque::VecDeque},
7    format,
8    string::{String, ToString},
9    vec,
10    vec::Vec,
11};
12use core::{
13    cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd},
14    ops::{Shl, Shr},
15    pin::Pin,
16    ptr::{read_volatile, write_volatile},
17};
18use num_bigint::BigInt;
19use num_traits::{ToPrimitive, Zero};
20
21type Expr = semantics::LangExpr;
22type Pattern = semantics::Pattern;
23
24struct RuntimeErr {
25    msg: String,
26    pos: Pos,
27}
28
29#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
30pub struct Variables {
31    vars: VecDeque<BTreeMap<String, RTData>>,
32}
33
34impl Variables {
35    fn new() -> Variables {
36        let mut list = VecDeque::new();
37        list.push_back(BTreeMap::new());
38        Variables { vars: list }
39    }
40
41    fn push(&mut self) {
42        self.vars.push_back(BTreeMap::new());
43    }
44
45    fn pop(&mut self) {
46        self.vars.pop_back();
47    }
48
49    fn insert(&mut self, id: String, data: RTData) {
50        let m = self.vars.back_mut().unwrap();
51        m.insert(id, data);
52    }
53
54    fn get(&mut self, id: &str) -> Option<&RTData> {
55        for m in self.vars.iter().rev() {
56            if let Some(val) = m.get(id) {
57                return Some(val);
58            }
59        }
60        None
61    }
62}
63
64#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
65pub enum TCall {
66    Defun(String),
67    Lambda(u64),
68}
69
70#[derive(Eq, Debug, Clone)]
71pub struct IntType(*mut (BigInt, bool));
72
73impl IntType {
74    fn get_int(&self) -> &BigInt {
75        unsafe { &(*self.0).0 }
76    }
77
78    fn get_ref(&mut self) -> &mut bool {
79        unsafe { &mut (*self.0).1 }
80    }
81}
82
83impl Ord for IntType {
84    fn cmp(&self, other: &Self) -> Ordering {
85        let s1 = self.get_int();
86        let s2 = other.get_int();
87        s1.cmp(s2)
88    }
89}
90
91impl PartialOrd for IntType {
92    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
93        let s1 = self.get_int();
94        let s2 = other.get_int();
95        Some(s1.cmp(s2))
96    }
97}
98
99impl PartialEq for IntType {
100    fn eq(&self, other: &Self) -> bool {
101        let s1 = self.get_int();
102        let s2 = other.get_int();
103        s1 == s2
104    }
105}
106
107#[derive(Eq, Debug, Clone)]
108pub struct StrType(*mut (String, bool));
109
110impl StrType {
111    fn get_string(&self) -> &String {
112        unsafe { &(*self.0).0 }
113    }
114
115    fn get_ref(&mut self) -> &mut bool {
116        unsafe { &mut (*self.0).1 }
117    }
118}
119
120impl Ord for StrType {
121    fn cmp(&self, other: &Self) -> Ordering {
122        let s1 = self.get_string();
123        let s2 = other.get_string();
124        s1.cmp(s2)
125    }
126}
127
128impl PartialOrd for StrType {
129    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
130        let s1 = self.get_string();
131        let s2 = other.get_string();
132        Some(s1.cmp(s2))
133    }
134}
135
136impl PartialEq for StrType {
137    fn eq(&self, other: &Self) -> bool {
138        let s1 = self.get_string();
139        let s2 = other.get_string();
140        s1 == s2
141    }
142}
143
144#[derive(Eq, Debug, Clone)]
145pub struct ClojureType(*mut (Clojure, bool));
146
147impl ClojureType {
148    fn get_clojure(&self) -> &Clojure {
149        unsafe { &(*self.0).0 }
150    }
151
152    fn get_clojure_mut(&mut self) -> &mut Clojure {
153        unsafe { &mut (*self.0).0 }
154    }
155
156    fn get_ref(&mut self) -> &mut bool {
157        unsafe { &mut (*self.0).1 }
158    }
159}
160
161impl Ord for ClojureType {
162    fn cmp(&self, other: &Self) -> Ordering {
163        let s1 = self.get_clojure();
164        let s2 = other.get_clojure();
165        s1.cmp(s2)
166    }
167}
168
169impl PartialOrd for ClojureType {
170    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
171        let s1 = self.get_clojure();
172        let s2 = other.get_clojure();
173        Some(s1.cmp(s2))
174    }
175}
176
177impl PartialEq for ClojureType {
178    fn eq(&self, other: &Self) -> bool {
179        let s1 = self.get_clojure();
180        let s2 = other.get_clojure();
181        s1 == s2
182    }
183}
184
185#[derive(Eq, Debug, Clone)]
186pub struct LDataType(*mut (LabeledData, bool));
187
188impl LDataType {
189    fn get_ldata(&self) -> &LabeledData {
190        unsafe { &(*self.0).0 }
191    }
192
193    fn get_ldata_mut(&mut self) -> &mut LabeledData {
194        unsafe { &mut (*self.0).0 }
195    }
196
197    fn get_ref(&mut self) -> &mut bool {
198        unsafe { &mut (*self.0).1 }
199    }
200}
201
202impl Ord for LDataType {
203    fn cmp(&self, other: &Self) -> Ordering {
204        let s1 = self.get_ldata();
205        let s2 = other.get_ldata();
206        s1.cmp(s2)
207    }
208}
209
210impl PartialOrd for LDataType {
211    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
212        let s1 = self.get_ldata();
213        let s2 = other.get_ldata();
214        Some(s1.cmp(s2))
215    }
216}
217
218impl PartialEq for LDataType {
219    fn eq(&self, other: &Self) -> bool {
220        let s1 = self.get_ldata();
221        let s2 = other.get_ldata();
222        s1 == s2
223    }
224}
225
226#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq)]
227pub enum RTData {
228    Str(StrType),
229    Char(char),
230    Int(IntType),
231    Bool(bool),
232    Defun(String),
233    Lambda(ClojureType),
234    LData(LDataType),
235    TailCall(TCall, Variables),
236}
237
238fn escape_char(c: char) -> String {
239    match c {
240        '\n' => "\\n".to_string(),
241        '\r' => "\\r".to_string(),
242        '\t' => "\\t".to_string(),
243        '\0' => "\\0".to_string(),
244        _ => c.to_string(),
245    }
246}
247
248impl RTData {
249    fn get_in_lisp(&self, list_head: bool) -> String {
250        match self {
251            RTData::Str(n) => {
252                let mut str = "\"".to_string();
253                for s in n.get_string().chars() {
254                    if s == '"' {
255                        str.push_str("\\\"");
256                    } else {
257                        str.push_str(&escape_char(s));
258                    }
259                }
260                str.push('"');
261                str
262            }
263            RTData::Char(c) => {
264                if *c == '`' {
265                    "`\\``".to_string()
266                } else {
267                    let s = escape_char(*c);
268                    format!("`{}`", s)
269                }
270            }
271            RTData::Int(n) => {
272                format!("{}", n.get_int())
273            }
274            RTData::Bool(n) => n.to_string(),
275            RTData::Defun(n) => n.to_string(),
276            RTData::Lambda(n) => format!("(Lambda {})", n.get_clojure().ident),
277            RTData::LData(n) => {
278                let label = &n.get_ldata().label;
279                if label == "Cons" {
280                    let e1;
281                    let e2;
282                    match n.get_ldata().data.as_ref() {
283                        Some(ld) => {
284                            e1 = ld[0].get_in_lisp(true);
285                            e2 = ld[1].get_in_lisp(false);
286                        }
287                        None => panic!("invalid list"),
288                    }
289                    if list_head {
290                        if e2.is_empty() {
291                            format!("'({})", e1)
292                        } else {
293                            format!("'({} {})", e1, e2)
294                        }
295                    } else if e2.is_empty() {
296                        e1
297                    } else {
298                        format!("{} {}", e1, e2)
299                    }
300                } else if label == "Nil" {
301                    if list_head {
302                        "'()".to_string()
303                    } else {
304                        "".to_string()
305                    }
306                } else if label == "Tuple" {
307                    match n.get_ldata().data.as_ref() {
308                        Some(ld) => {
309                            let mut msg = "".to_string();
310                            let len = (*ld).len();
311                            let mut i = 1;
312                            for d in ld.iter() {
313                                if i == len {
314                                    msg = format!("{}{}", msg, d.get_in_lisp(true));
315                                } else {
316                                    msg = format!("{}{} ", msg, d.get_in_lisp(true));
317                                }
318                                i += 1;
319                            }
320                            format!("[{}]", msg)
321                        }
322                        None => "[]".to_string(),
323                    }
324                } else {
325                    match n.get_ldata().data.as_ref() {
326                        Some(ld) => {
327                            let mut msg = format!("({}", label);
328                            for d in ld.iter() {
329                                msg = format!("{} {}", msg, d.get_in_lisp(true));
330                            }
331                            format!("{})", msg)
332                        }
333                        None => label.to_string(),
334                    }
335                }
336            }
337            RTData::TailCall(TCall::Defun(f), _) => format!("(TailCall (Defun {}))", f),
338            RTData::TailCall(TCall::Lambda(f), _) => format!("(TailCall (Lambda {}))", f),
339        }
340    }
341}
342
343#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
344struct LabeledData {
345    label: String,
346    data: Option<Vec<RTData>>,
347}
348
349#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
350struct Clojure {
351    ident: u64,
352    data: Option<BTreeMap<String, RTData>>,
353}
354
355const MIN_GC_NUM: usize = 1024;
356
357#[derive(Debug)]
358pub(crate) struct RootObject {
359    objects: LinkedList<Pin<Box<(LabeledData, bool)>>>,
360    clojure: LinkedList<Pin<Box<(Clojure, bool)>>>,
361    integers: LinkedList<Pin<Box<(BigInt, bool)>>>,
362    strings: LinkedList<Pin<Box<(String, bool)>>>,
363    threshold: usize,
364}
365
366impl RootObject {
367    fn new() -> RootObject {
368        RootObject {
369            objects: LinkedList::new(),
370            clojure: LinkedList::new(),
371            integers: LinkedList::new(),
372            strings: LinkedList::new(),
373            threshold: MIN_GC_NUM,
374        }
375    }
376
377    fn len(&self) -> usize {
378        self.objects.len() + self.clojure.len() + self.integers.len() + self.strings.len()
379    }
380
381    fn make_int(&mut self, n: BigInt) -> IntType {
382        self.integers.push_back(Box::pin((n, false)));
383        let ptr = self.integers.back_mut().unwrap();
384        IntType(unsafe { ptr.as_mut().get_unchecked_mut() as *mut (BigInt, bool) })
385    }
386
387    fn make_str(&mut self, str: String) -> StrType {
388        self.strings.push_back(Box::pin((str, false)));
389        let ptr = self.strings.back_mut().unwrap();
390        StrType(unsafe { ptr.as_mut().get_unchecked_mut() as *mut (String, bool) })
391    }
392
393    fn make_obj(&mut self, label: String, data: Option<Vec<RTData>>) -> LDataType {
394        let obj = LabeledData { label, data };
395        self.objects.push_back(Box::pin((obj, false)));
396        let ptr = self.objects.back_mut().unwrap();
397        LDataType(unsafe { ptr.as_mut().get_unchecked_mut() as *mut (LabeledData, bool) })
398    }
399
400    fn make_clojure(&mut self, ident: u64, data: Option<BTreeMap<String, RTData>>) -> ClojureType {
401        let obj = Clojure { ident, data };
402        self.clojure.push_back(Box::pin((obj, false)));
403        let ptr = self.clojure.back_mut().unwrap();
404        ClojureType(unsafe { ptr.as_mut().get_unchecked_mut() as *mut (Clojure, bool) })
405    }
406}
407
408pub struct Environment<'a> {
409    pub(crate) ctx: &'a semantics::Context,
410    pub(crate) lambda: &'a BTreeMap<u64, semantics::Lambda>,
411    pub(crate) root: &'a mut RootObject,
412    pub(crate) vars: &'a mut VecDeque<Variables>,
413}
414
415pub(crate) fn eval(
416    code: &str,
417    ctx: &semantics::Context,
418) -> Result<LinkedList<Result<String, String>>, LispErr> {
419    let mut ps = parser::Parser::new(code, crate::FileType::Eval);
420    let mut exprs: LinkedList<parser::Expr> = match ps.parse() {
421        Ok(e) => e,
422        Err(e) => {
423            let msg = format!("Syntax Error: {}", e.msg);
424            return Err(LispErr { msg, pos: e.pos });
425        }
426    };
427
428    if let Err(e) = r#macro::process_macros(&mut exprs) {
429        let msg = format!("Macro Error: {}", e.msg);
430        return Err(LispErr::new(msg, e.pos));
431    }
432
433    for expr in exprs.iter_mut() {
434        if let Err(e) = r#macro::apply(expr, &ctx.macros) {
435            let msg: String = format!("Macro Error: {}", e.msg);
436            return Err(LispErr { msg, pos: e.pos });
437        }
438    }
439
440    let mut typed_exprs = LinkedList::new();
441    for expr in &exprs {
442        match semantics::typing_expr(expr, ctx) {
443            Ok(e) => {
444                typed_exprs.push_back(e);
445            }
446            Err(e) => {
447                let msg = format!("Typing Error: {}", e.msg);
448                return Err(LispErr { msg, pos: e.pos });
449            }
450        }
451    }
452
453    let mut root = RootObject::new();
454    let mut result = LinkedList::new();
455    for (expr, lambda) in &typed_exprs {
456        let mut vars = VecDeque::new();
457        vars.push_back(Variables::new());
458
459        let mut env = Environment {
460            ctx,
461            lambda,
462            root: &mut root,
463            vars: &mut vars,
464        };
465
466        match eval_expr(expr, &mut env) {
467            Ok(val) => {
468                result.push_back(Ok(val.get_in_lisp(true)));
469            }
470            Err(e) => {
471                let msg = format!(
472                    "(RuntimeErr [{} (Pos {} {})])",
473                    e.msg, e.pos.line, e.pos.column
474                );
475                result.push_back(Err(msg));
476                return Ok(result);
477            }
478        }
479    }
480
481    Ok(result)
482}
483
484fn get_data_of_id(id: &str, vars: &mut VecDeque<Variables>) -> RTData {
485    match vars.back_mut().unwrap().get(id) {
486        Some(data) => data.clone(),
487        None => RTData::Defun(id.to_string()),
488    }
489}
490
491fn eval_expr(expr: &Expr, env: &mut Environment<'_>) -> Result<RTData, RuntimeErr> {
492    match expr {
493        Expr::LitStr(e) => Ok(RTData::Str(env.root.make_str(e.str.clone()))),
494        Expr::LitNum(e) => Ok(RTData::Int(env.root.make_int(e.num.clone()))),
495        Expr::LitChar(e) => Ok(RTData::Char(e.c)),
496        Expr::LitBool(e) => Ok(RTData::Bool(e.val)),
497        Expr::IfExpr(e) => eval_if(e, env),
498        Expr::DataExpr(e) => eval_data(e, env),
499        Expr::ListExpr(e) => eval_list(e, env),
500        Expr::LetExpr(e) => eval_let(e, env),
501        Expr::MatchExpr(e) => eval_match(e, env),
502        Expr::IDExpr(e) => Ok(eval_id(e, env.vars)),
503        Expr::ApplyExpr(e) => eval_apply(e, env),
504        Expr::TupleExpr(e) => eval_tuple(e, env),
505        Expr::LambdaExpr(e) => Ok(eval_lambda(e, env)),
506    }
507}
508
509fn eval_lambda(expr: &semantics::Lambda, env: &mut Environment<'_>) -> RTData {
510    let data = if !expr.vars.is_empty() {
511        let mut m = BTreeMap::new();
512        for v in &expr.vars {
513            m.insert(v.to_string(), get_data_of_id(v, env.vars));
514        }
515        Some(m)
516    } else {
517        None
518    };
519
520    let ptr = env.root.make_clojure(expr.ident, data);
521    RTData::Lambda(ptr)
522}
523
524fn eval_tuple(expr: &semantics::Exprs, env: &mut Environment<'_>) -> Result<RTData, RuntimeErr> {
525    let mut v = Vec::new();
526    for e in expr.exprs.iter() {
527        v.push(eval_expr(e, env)?);
528    }
529
530    let ptr = env.root.make_obj("Tuple".to_string(), Some(v));
531
532    Ok(RTData::LData(ptr))
533}
534
535fn get_fun<'a>(
536    ctx: &'a semantics::Context,
537    fun_name: &str,
538    expr: &Expr,
539) -> Result<&'a semantics::Defun, RuntimeErr> {
540    let fun = match ctx.funs.get(fun_name) {
541        Some(f) => f,
542        None => {
543            let pos = expr.get_pos();
544            let msg = format!("{} is not defined", fun_name);
545            return Err(RuntimeErr { msg, pos });
546        }
547    };
548
549    Ok(fun)
550}
551
552fn get_lambda<'a>(
553    ctx: &'a semantics::Context,
554    lambda: &'a BTreeMap<u64, semantics::Lambda>,
555    id: u64,
556    expr: &Expr,
557) -> Result<&'a semantics::Lambda, RuntimeErr> {
558    let fun;
559    match ctx.lambda.get(&id) {
560        Some(f) => {
561            fun = f;
562        }
563        None => match lambda.get(&id) {
564            Some(f) => {
565                fun = f;
566            }
567            None => {
568                let pos = expr.get_pos();
569                let msg = format!("could not find (Lambda {})", id);
570                return Err(RuntimeErr { msg, pos });
571            }
572        },
573    }
574
575    Ok(fun)
576}
577
578fn call_lambda(
579    expr: &semantics::Apply,
580    env: &mut Environment<'_>,
581    cloj: &Clojure,
582    iter: core::slice::Iter<semantics::LangExpr>,
583    fun_expr: &semantics::LangExpr,
584) -> Result<RTData, RuntimeErr> {
585    // look up lambda
586    let ident = cloj.ident;
587    let fun = get_lambda(env.ctx, env.lambda, ident, fun_expr)?;
588
589    // set up arguments
590    let mut vars_fun = Variables::new();
591    for (e, arg) in iter.zip(fun.args.iter()) {
592        let data = eval_expr(e, env)?;
593        vars_fun.insert(arg.id.to_string(), data);
594    }
595
596    // set up free variables
597    match &cloj.data {
598        Some(d) => {
599            for (key, val) in d {
600                vars_fun.insert(key.to_string(), val.clone());
601            }
602        }
603        None => (),
604    }
605
606    // tail call optimization
607    if expr.is_tail {
608        Ok(RTData::TailCall(TCall::Lambda(ident), vars_fun))
609    } else {
610        env.vars.push_back(vars_fun);
611        let result = eval_tail_call(&fun.expr, env);
612        env.vars.pop_back();
613        result
614    }
615}
616
617fn eval_apply(expr: &semantics::Apply, env: &mut Environment<'_>) -> Result<RTData, RuntimeErr> {
618    let mut iter = expr.exprs.iter();
619    let fun_expr = match iter.next() {
620        Some(e) => e,
621        None => {
622            let pos = expr.pos;
623            return Err(RuntimeErr {
624                msg: "empty application".to_string(),
625                pos,
626            });
627        }
628    };
629
630    match eval_expr(fun_expr, env)? {
631        RTData::Defun(fun_name) => {
632            // call built-in function
633            if env.ctx.built_in.contains(&fun_name) {
634                let mut v = Vec::new();
635                for e in iter {
636                    let data = eval_expr(e, env)?;
637                    v.push(data);
638                }
639                return eval_built_in(fun_name, &v, expr.pos, env);
640            }
641
642            if let Some(ffi) = env.ctx.ext_ffi.get(fun_name.as_str()) {
643                let mut v = Vec::new();
644                for e in iter {
645                    let data = eval_expr(e, env)?;
646                    v.push(data);
647                }
648                return Ok(ffi(env, &v));
649            }
650
651            // look up defun
652            if let Ok(fun) = get_fun(env.ctx, &fun_name, fun_expr) {
653                // set up arguments
654                let mut vars_fun = Variables::new();
655                for (e, arg) in iter.zip(fun.args.iter()) {
656                    let data = eval_expr(e, env)?;
657                    vars_fun.insert(arg.id.to_string(), data);
658                }
659
660                // tail call optimization
661                if expr.is_tail {
662                    Ok(RTData::TailCall(TCall::Defun(fun_name), vars_fun))
663                } else {
664                    env.vars.push_back(vars_fun);
665                    let result = eval_tail_call(&fun.expr, env)?;
666                    env.vars.pop_back();
667                    Ok(result)
668                }
669            } else {
670                // call clojure
671                if let Some(RTData::Lambda(cloj)) = env.vars.back_mut().unwrap().get(&fun_name) {
672                    let c = cloj.clone();
673                    return call_lambda(expr, env, c.get_clojure(), iter, fun_expr);
674                }
675
676                // could not find such function
677                let pos = fun_expr.get_pos();
678                let msg = format!("{} is not defined", fun_name);
679                Err(RuntimeErr { msg, pos })
680            }
681        }
682        RTData::Lambda(f) => {
683            let f = f.get_clojure();
684            call_lambda(expr, env, f, iter, fun_expr)
685        }
686        _ => {
687            let pos = fun_expr.get_pos();
688            Err(RuntimeErr {
689                msg: "not function".to_string(),
690                pos,
691            })
692        }
693    }
694}
695
696fn eval_tail_call<'a>(
697    mut expr: &'a Expr,
698    env: &'a mut Environment<'_>,
699) -> Result<RTData, RuntimeErr> {
700    loop {
701        match eval_expr(expr, env)? {
702            RTData::TailCall(TCall::Defun(fun_name), vars_fun) => {
703                let fun = get_fun(env.ctx, &fun_name, expr)?;
704                expr = &fun.expr;
705                env.vars.pop_back();
706                env.vars.push_back(vars_fun);
707                collect_garbage(env.vars, env.root); // mark and sweep
708            }
709            RTData::TailCall(TCall::Lambda(id), vars_fun) => {
710                let fun = get_lambda(env.ctx, env.lambda, id, expr)?;
711                expr = &fun.expr;
712                env.vars.pop_back();
713                env.vars.push_back(vars_fun);
714                collect_garbage(env.vars, env.root); // mark and sweep
715            }
716            x => {
717                return Ok(x);
718            }
719        }
720    }
721}
722
723fn get_int(args: &[RTData], pos: Pos) -> Result<*const BigInt, RuntimeErr> {
724    match &args[0] {
725        RTData::Int(n) => Ok(n.get_int()),
726        _ => Err(RuntimeErr {
727            msg: "there must be exactly 2 integers".to_string(),
728            pos,
729        }),
730    }
731}
732
733fn get_int_int(args: &[RTData], pos: Pos) -> Result<(*const BigInt, *const BigInt), RuntimeErr> {
734    match (&args[0], &args[1]) {
735        (RTData::Int(n1), RTData::Int(n2)) => Ok((n1.get_int(), n2.get_int())),
736        _ => Err(RuntimeErr {
737            msg: "there must be exactly 2 integers".to_string(),
738            pos,
739        }),
740    }
741}
742
743fn get_int_int_int(
744    args: &[RTData],
745    pos: Pos,
746) -> Result<(*const BigInt, *const BigInt, *const BigInt), RuntimeErr> {
747    match (&args[0], &args[1], &args[2]) {
748        (RTData::Int(n1), RTData::Int(n2), RTData::Int(n3)) => {
749            Ok((n1.get_int(), n2.get_int(), n3.get_int()))
750        }
751        _ => Err(RuntimeErr {
752            msg: "there must be exactly 3 integers".to_string(),
753            pos,
754        }),
755    }
756}
757
758fn get_bool_bool(args: &[RTData], pos: Pos) -> Result<(bool, bool), RuntimeErr> {
759    match (args[0].clone(), args[1].clone()) {
760        (RTData::Bool(n1), RTData::Bool(n2)) => Ok((n1, n2)),
761        _ => Err(RuntimeErr {
762            msg: "there must be exactly 2 boolean values".to_string(),
763            pos,
764        }),
765    }
766}
767
768fn get_bool(args: &[RTData], pos: Pos) -> Result<bool, RuntimeErr> {
769    match args[0].clone() {
770        RTData::Bool(n) => Ok(n),
771        _ => Err(RuntimeErr {
772            msg: "there must be exactly 1 boolean value".to_string(),
773            pos,
774        }),
775    }
776}
777
778fn eval_built_in(
779    fun_name: String,
780    args: &[RTData],
781    pos: Pos,
782    env: &mut Environment<'_>,
783) -> Result<RTData, RuntimeErr> {
784    match fun_name.as_str() {
785        "+" => {
786            let (n1, n2) = get_int_int(args, pos)?;
787            let n = unsafe { &*n1 + &*n2 };
788            Ok(RTData::Int(env.root.make_int(n)))
789        }
790        "-" => {
791            let (n1, n2) = get_int_int(args, pos)?;
792            let n = unsafe { &*n1 - &*n2 };
793            Ok(RTData::Int(env.root.make_int(n)))
794        }
795        "*" => {
796            let (n1, n2) = get_int_int(args, pos)?;
797            let n = unsafe { &*n1 * &*n2 };
798            Ok(RTData::Int(env.root.make_int(n)))
799        }
800        "/" => {
801            let (n1, n2) = get_int_int(args, pos)?;
802            let n = unsafe { &*n1 / &*n2 };
803            Ok(RTData::Int(env.root.make_int(n)))
804        }
805        "%" => {
806            let (n1, n2) = get_int_int(args, pos)?;
807            let n = unsafe { &*n1 % &*n2 };
808            Ok(RTData::Int(env.root.make_int(n)))
809        }
810        "=" | "eq" => Ok(RTData::Bool(args[0] == args[1])),
811        "!=" | "neq" => Ok(RTData::Bool(args[0] != args[1])),
812        "<=" | "leq" => Ok(RTData::Bool(args[0] <= args[1])),
813        ">=" | "geq" => Ok(RTData::Bool(args[0] >= args[1])),
814        ">" | "gt" => Ok(RTData::Bool(args[0] > args[1])),
815        "<" | "lt" => Ok(RTData::Bool(args[0] < args[1])),
816        "and" => {
817            let (n1, n2) = get_bool_bool(args, pos)?;
818            Ok(RTData::Bool(n1 && n2))
819        }
820        "or" => {
821            let (n1, n2) = get_bool_bool(args, pos)?;
822            Ok(RTData::Bool(n1 || n2))
823        }
824        "xor" => {
825            let (n1, n2) = get_bool_bool(args, pos)?;
826            Ok(RTData::Bool(n1 ^ n2))
827        }
828        "not" => {
829            let n = get_bool(args, pos)?;
830            Ok(RTData::Bool(!n))
831        }
832        "band" => {
833            let (n1, n2) = get_int_int(args, pos)?;
834            let n = unsafe { &*n1 & &*n2 };
835            Ok(RTData::Int(env.root.make_int(n)))
836        }
837        "bor" => {
838            let (n1, n2) = get_int_int(args, pos)?;
839            let n = unsafe { &*n1 | &*n2 };
840            Ok(RTData::Int(env.root.make_int(n)))
841        }
842        "bxor" => {
843            let (n1, n2) = get_int_int(args, pos)?;
844            let n = unsafe { &*n1 ^ &*n2 };
845            Ok(RTData::Int(env.root.make_int(n)))
846        }
847        "sqrt" => {
848            let n = get_int(args, pos)?;
849            if unsafe { (*n) >= Zero::zero() } {
850                let n = unsafe { (*n).sqrt() };
851                let n = RTData::Int(env.root.make_int(n));
852                let ptr = env.root.make_obj("Some".to_string(), Some(vec![n]));
853                Ok(RTData::LData(ptr))
854            } else {
855                let ptr = env.root.make_obj("None".to_string(), None);
856                Ok(RTData::LData(ptr))
857            }
858        }
859        "pow" => {
860            let (n1, n2) = get_int_int(args, pos)?;
861            if let Some(e) = unsafe { (*n2).to_u32() } {
862                let n = unsafe { (*n1).pow(e) };
863                let n = RTData::Int(env.root.make_int(n));
864                let ptr = env.root.make_obj("Some".to_string(), Some(vec![n]));
865                Ok(RTData::LData(ptr))
866            } else {
867                let ptr = env.root.make_obj("None".to_string(), None);
868                Ok(RTData::LData(ptr))
869            }
870        }
871        ">>" => {
872            let (n1, n2) = get_int_int(args, pos)?;
873            if let Some(e) = unsafe { (*n2).to_u64() } {
874                let n = unsafe { (*n1).clone() };
875                let n = n.shr(e);
876                let n = RTData::Int(env.root.make_int(n));
877                let ptr = env.root.make_obj("Some".to_string(), Some(vec![n]));
878                Ok(RTData::LData(ptr))
879            } else {
880                let ptr = env.root.make_obj("None".to_string(), None);
881                Ok(RTData::LData(ptr))
882            }
883        }
884        "<<" => {
885            let (n1, n2) = get_int_int(args, pos)?;
886            if let Some(e) = unsafe { (*n2).to_u64() } {
887                let n = unsafe { (*n1).clone() };
888                let n = n.shl(e);
889                let n = RTData::Int(env.root.make_int(n));
890                let ptr = env.root.make_obj("Some".to_string(), Some(vec![n]));
891                Ok(RTData::LData(ptr))
892            } else {
893                let ptr = env.root.make_obj("None".to_string(), None);
894                Ok(RTData::LData(ptr))
895            }
896        }
897        "chars" => {
898            let mut tail = RTData::LData(env.root.make_obj("Nil".to_string(), None));
899            if let RTData::Str(st) = &args[0] {
900                let s = st.get_string();
901                for c in s.chars().rev() {
902                    let c = RTData::Char(c);
903                    let cons =
904                        RTData::LData(env.root.make_obj("Cons".to_string(), Some(vec![c, tail])));
905                    tail = cons;
906                }
907            }
908            Ok(tail)
909        }
910        "str" => {
911            let mut head = &args[0];
912            let mut s = "".to_string();
913            loop {
914                if let RTData::LData(data) = head {
915                    if data.get_ldata().label == "Cons" {
916                        if let Some(d) = &data.get_ldata().data {
917                            if let RTData::Char(c) = &d[0] {
918                                s.push(*c);
919                                head = &d[1];
920                            } else {
921                                return Err(RuntimeErr {
922                                    msg: "not char".to_string(),
923                                    pos,
924                                });
925                            }
926                        } else {
927                            return Err(RuntimeErr {
928                                msg: "invalid cons".to_string(),
929                                pos,
930                            });
931                        }
932                    } else if data.get_ldata().label == "Nil" {
933                        break;
934                    } else {
935                        return Err(RuntimeErr {
936                            msg: "not list".to_string(),
937                            pos,
938                        });
939                    }
940                }
941            }
942            let ptr = env.root.make_str(s);
943            Ok(RTData::Str(ptr))
944        }
945        "call-rust" => {
946            let (n1, n2, n3) = get_int_int_int(args, pos)?;
947            let n = unsafe { (env.ctx.callback)(&*n1, &*n2, &*n3) };
948            if let Some(n) = n {
949                let n = RTData::Int(env.root.make_int(n));
950                let ptr = env.root.make_obj("Some".to_string(), Some(vec![n]));
951                Ok(RTData::LData(ptr))
952            } else {
953                let ptr = env.root.make_obj("None".to_string(), None);
954                Ok(RTData::LData(ptr))
955            }
956        }
957        _ => Err(RuntimeErr {
958            msg: "unknown built-in function".to_string(),
959            pos,
960        }),
961    }
962}
963
964fn eval_match(
965    expr: &semantics::MatchNode,
966    env: &mut Environment<'_>,
967) -> Result<RTData, RuntimeErr> {
968    let data = eval_expr(&expr.expr, env)?;
969
970    for c in &expr.cases {
971        env.vars.back_mut().unwrap().push();
972        if eval_pat(&c.pattern, data.clone(), env.vars) {
973            let retval = eval_expr(&c.expr, env)?;
974            env.vars.back_mut().unwrap().pop();
975            return Ok(retval);
976        }
977        env.vars.back_mut().unwrap().pop();
978    }
979
980    let pos = expr.pos;
981    Err(RuntimeErr {
982        msg: "pattern-matching is not exhaustive".to_string(),
983        pos,
984    })
985}
986
987fn eval_id(expr: &semantics::IDNode, vars: &mut VecDeque<Variables>) -> RTData {
988    let id = expr.id.to_string();
989    get_data_of_id(&id, vars)
990}
991
992fn eval_list(expr: &semantics::Exprs, env: &mut Environment<'_>) -> Result<RTData, RuntimeErr> {
993    let mut elm = env.root.make_obj("Nil".to_string(), None);
994    for e in expr.exprs.iter().rev() {
995        let val = eval_expr(e, env)?;
996        elm = env
997            .root
998            .make_obj("Cons".to_string(), Some(vec![val, RTData::LData(elm)]));
999    }
1000
1001    Ok(RTData::LData(elm))
1002}
1003
1004fn eval_if(expr: &semantics::IfNode, env: &mut Environment<'_>) -> Result<RTData, RuntimeErr> {
1005    let cond = eval_expr(&expr.cond_expr, env)?;
1006    let flag = match cond {
1007        RTData::Bool(e) => e,
1008        _ => {
1009            let pos = expr.cond_expr.get_pos();
1010            return Err(RuntimeErr {
1011                msg: "type mismatched".to_string(),
1012                pos,
1013            });
1014        }
1015    };
1016
1017    if flag {
1018        eval_expr(&expr.then_expr, env)
1019    } else {
1020        eval_expr(&expr.else_expr, env)
1021    }
1022}
1023
1024fn eval_data(expr: &semantics::DataNode, env: &mut Environment<'_>) -> Result<RTData, RuntimeErr> {
1025    let data = if expr.exprs.is_empty() {
1026        None
1027    } else {
1028        let mut v = Vec::new();
1029        for e in &expr.exprs {
1030            v.push(eval_expr(e, env)?);
1031        }
1032        Some(v)
1033    };
1034
1035    let ptr = env.root.make_obj(expr.label.id.to_string(), data);
1036
1037    Ok(RTData::LData(ptr))
1038}
1039
1040fn eval_let(expr: &semantics::LetNode, env: &mut Environment<'_>) -> Result<RTData, RuntimeErr> {
1041    env.vars.back_mut().unwrap().push();
1042
1043    for def in &expr.def_vars {
1044        let data = eval_expr(&def.expr, env)?;
1045        if !eval_pat(&def.pattern, data, env.vars) {
1046            let pos = def.pattern.get_pos();
1047            return Err(RuntimeErr {
1048                msg: "failed pattern matching".to_string(),
1049                pos,
1050            });
1051        }
1052    }
1053
1054    let result = eval_expr(&expr.expr, env)?;
1055    env.vars.back_mut().unwrap().pop();
1056
1057    Ok(result)
1058}
1059
1060fn eval_pat(pat: &Pattern, data: RTData, vars: &mut VecDeque<Variables>) -> bool {
1061    match pat {
1062        Pattern::PatID(p) => {
1063            vars.back_mut().unwrap().insert(p.id.to_string(), data);
1064            true
1065        }
1066        Pattern::PatStr(p) => match data {
1067            RTData::Str(n) => n.get_string() == &p.str,
1068            _ => false,
1069        },
1070        Pattern::PatChar(p) => match data {
1071            RTData::Char(n) => n == p.c,
1072            _ => false,
1073        },
1074        Pattern::PatNum(p) => match data {
1075            RTData::Int(n) => n.get_int() == &p.num,
1076            _ => false,
1077        },
1078        Pattern::PatBool(p) => match data {
1079            RTData::Bool(n) => n == p.val,
1080            _ => false,
1081        },
1082        Pattern::PatNil(_) => match data {
1083            RTData::LData(ptr) => ptr.get_ldata().label == "Nil",
1084            _ => false,
1085        },
1086        Pattern::PatTuple(p) => match data {
1087            RTData::LData(ptr) => {
1088                if ptr.get_ldata().label != "Tuple" {
1089                    return false;
1090                }
1091
1092                match &ptr.get_ldata().data {
1093                    Some(rds) => {
1094                        for (pat2, rd) in p.pattern.iter().zip(rds.iter()) {
1095                            if !eval_pat(pat2, rd.clone(), vars) {
1096                                return false;
1097                            }
1098                        }
1099                        true
1100                    }
1101                    None => true,
1102                }
1103            }
1104            _ => false,
1105        },
1106        Pattern::PatData(p) => match data {
1107            RTData::LData(ptr) => {
1108                if ptr.get_ldata().label != p.label.id {
1109                    return false;
1110                }
1111
1112                match &ptr.get_ldata().data {
1113                    Some(rds) => {
1114                        for (pat2, rd) in p.pattern.iter().zip(rds.iter()) {
1115                            if !eval_pat(pat2, rd.clone(), vars) {
1116                                return false;
1117                            }
1118                        }
1119                        true
1120                    }
1121                    None => true,
1122                }
1123            }
1124            _ => false,
1125        },
1126    }
1127}
1128
1129/// do garbage collection
1130fn collect_garbage(vars: &mut VecDeque<Variables>, root: &mut RootObject) {
1131    let n = root.len();
1132    if n < root.threshold {
1133        return;
1134    }
1135
1136    mark(vars);
1137    sweep(&mut root.clojure);
1138    sweep(&mut root.objects);
1139    sweep(&mut root.integers);
1140    sweep(&mut root.strings);
1141
1142    let n = root.len();
1143    root.threshold = n * 2;
1144    if root.threshold < (MIN_GC_NUM >> 1) {
1145        root.threshold = MIN_GC_NUM;
1146    }
1147}
1148
1149/// mark reachable objects
1150fn mark(vars: &mut VecDeque<Variables>) {
1151    for v in vars.iter_mut() {
1152        for var in v.vars.iter_mut() {
1153            for (_, v) in var.iter_mut() {
1154                mark_obj(v);
1155            }
1156        }
1157    }
1158}
1159
1160/// mark reachable objects recursively
1161fn mark_obj(data: &mut RTData) {
1162    match data {
1163        RTData::Str(ptr) => unsafe {
1164            write_volatile(ptr.get_ref(), true);
1165        },
1166        RTData::Int(ptr) => unsafe {
1167            write_volatile(ptr.get_ref(), true);
1168        },
1169        RTData::Lambda(ptr) => unsafe {
1170            if !read_volatile(ptr.get_ref()) {
1171                write_volatile(ptr.get_ref(), true);
1172                if let Some(data) = &mut ptr.get_clojure_mut().data {
1173                    for (_, v) in data.iter_mut() {
1174                        mark_obj(v);
1175                    }
1176                }
1177            }
1178        },
1179        RTData::LData(ptr) => unsafe {
1180            if !read_volatile(ptr.get_ref()) {
1181                write_volatile(ptr.get_ref(), true);
1182                if let Some(data) = &mut ptr.get_ldata_mut().data {
1183                    for v in data.iter_mut() {
1184                        mark_obj(v);
1185                    }
1186                }
1187            }
1188        },
1189        _ => (),
1190    }
1191}
1192
1193/// remove unreachable objects
1194fn sweep<T>(root: &mut LinkedList<Pin<Box<(T, bool)>>>) {
1195    let mut tail = root.split_off(0);
1196    loop {
1197        if tail.is_empty() {
1198            break;
1199        }
1200
1201        // take head
1202        let mut head;
1203        if tail.len() == 1 {
1204            head = tail.split_off(0);
1205        } else {
1206            let tmp = tail.split_off(1);
1207            head = tail;
1208            tail = tmp;
1209        };
1210
1211        // check the head is reachable or not
1212        let h = head.front_mut().unwrap();
1213        let marked = unsafe { read_volatile(&h.as_ref().1) };
1214        let flag = if marked {
1215            // the head is reachable
1216            let h = h.as_mut();
1217            unsafe {
1218                h.get_unchecked_mut().1 = false;
1219            }
1220            true
1221        } else {
1222            // the head unreachable
1223            false
1224        };
1225
1226        // if reachable, append the head
1227        if flag {
1228            root.append(&mut head);
1229        }
1230    }
1231}
1232
1233pub trait RTDataToRust<T> {
1234    fn into(&self) -> T;
1235}
1236
1237/// Get a BigInt value.
1238impl RTDataToRust<BigInt> for RTData {
1239    fn into(&self) -> BigInt {
1240        if let RTData::Int(data) = self {
1241            data.get_int().clone()
1242        } else {
1243            panic!("data is not BigInt");
1244        }
1245    }
1246}
1247
1248/// Get a char value.
1249impl RTDataToRust<char> for RTData {
1250    fn into(&self) -> char {
1251        if let RTData::Char(data) = self {
1252            *data
1253        } else {
1254            panic!("data is not Char");
1255        }
1256    }
1257}
1258
1259/// Get a String value.
1260impl RTDataToRust<String> for RTData {
1261    fn into(&self) -> String {
1262        if let RTData::Str(data) = self {
1263            data.get_string().clone()
1264        } else {
1265            panic!("data is not String");
1266        }
1267    }
1268}
1269
1270/// Get a boolean value.
1271impl RTDataToRust<bool> for RTData {
1272    fn into(&self) -> bool {
1273        if let RTData::Bool(data) = self {
1274            *data
1275        } else {
1276            panic!("data is not Bool");
1277        }
1278    }
1279}
1280
1281/// Convert a BLisp's List to a Rust's Vec.
1282impl<T> RTDataToRust<Vec<T>> for RTData
1283where
1284    RTData: RTDataToRust<T>,
1285{
1286    fn into(&self) -> Vec<T> {
1287        if let RTData::LData(data) = self {
1288            let ldata = data.get_ldata();
1289            let mut result = Vec::new();
1290            list_to_vec(ldata, &mut result);
1291
1292            return result;
1293        }
1294
1295        panic!("data is not List");
1296    }
1297}
1298
1299/// Convert a BLisp's Option to a Rust's Option.
1300impl<T> RTDataToRust<Option<T>> for RTData
1301where
1302    RTData: RTDataToRust<T>,
1303{
1304    fn into(&self) -> Option<T> {
1305        if let RTData::LData(data) = self {
1306            let ldata = data.get_ldata();
1307            match ldata.label.as_str() {
1308                "Some" => {
1309                    if let Some(v) = &ldata.data {
1310                        let e: T = RTDataToRust::into(&v[0]);
1311                        Some(e)
1312                    } else {
1313                        panic!("invalid Some")
1314                    }
1315                }
1316                "None" => None,
1317                _ => panic!("label is neither Some nor None"),
1318            }
1319        } else {
1320            panic!("data is not Option");
1321        }
1322    }
1323}
1324
1325/// Convert a BLisp's list to a Rust's Vec.
1326fn list_to_vec<T>(mut ldata: &LabeledData, result: &mut Vec<T>)
1327where
1328    RTData: RTDataToRust<T>,
1329{
1330    loop {
1331        match ldata.label.as_str() {
1332            "Cons" => {
1333                if let Some(v) = &ldata.data {
1334                    let e: T = RTDataToRust::into(&v[0]);
1335                    result.push(e);
1336
1337                    if let RTData::LData(data) = &v[1] {
1338                        ldata = data.get_ldata();
1339                    } else {
1340                        panic!("no next in Cons")
1341                    }
1342                } else {
1343                    panic!("invalid Cons");
1344                }
1345            }
1346            "Nil" => break,
1347            _ => panic!("label is neither Cons nor Nil"),
1348        }
1349    }
1350}
1351
1352/// Convert a BLisp's Result to a Rust's Result.
1353impl<T, E> RTDataToRust<Result<T, E>> for RTData
1354where
1355    RTData: RTDataToRust<T> + RTDataToRust<E>,
1356{
1357    fn into(&self) -> Result<T, E> {
1358        if let RTData::LData(data) = self {
1359            let ldata = data.get_ldata();
1360            match ldata.label.as_str() {
1361                "Ok" => {
1362                    if let Some(v) = &ldata.data {
1363                        let e: T = RTDataToRust::into(&v[0]);
1364                        Ok(e)
1365                    } else {
1366                        panic!("invalid Ok")
1367                    }
1368                }
1369                "Err" => {
1370                    if let Some(v) = &ldata.data {
1371                        let e: E = RTDataToRust::into(&v[0]);
1372                        Err(e)
1373                    } else {
1374                        panic!("invalid Err")
1375                    }
1376                }
1377                _ => panic!("label is neither Ok nor Err"),
1378            }
1379        } else {
1380            panic!("data is not Result");
1381        }
1382    }
1383}
1384
1385macro_rules! impl_rt_data_to_rust_tuple {
1386    ($($(#[$impl_attrs:meta])*
1387    [ $(($index:literal, $name_snake:ident, $name_pascal:ident)),+ $(,)? ]),+ $(,)?) => {
1388        $($(#[$impl_attrs])*
1389        impl<$($name_pascal),*> RTDataToRust<($($name_pascal),*)> for RTData
1390        where $(RTData: RTDataToRust<$name_pascal>),* {
1391            fn into(&self) -> ($($name_pascal),*) {
1392                if let RTData::LData(data) = self {
1393                    let ldata = data.get_ldata();
1394                    if ldata.label.as_str() == "Tuple" {
1395                        if let Some(v) = &ldata.data {
1396                            $(let $name_snake: $name_pascal = RTDataToRust::into(&v[$index]);)*
1397
1398                            ($($name_snake),*)
1399                        } else {
1400                            panic!("invalid Tuple")
1401                        }
1402                    } else {
1403                        panic!("label is not Tuple")
1404                    }
1405                } else {
1406                    panic!("data is not a Tuple")
1407                }
1408            }
1409        })*
1410    }
1411}
1412impl_rt_data_to_rust_tuple![
1413    /// Convert a BLisp's Tuple to a Rust's Tuple
1414    /// where the length is 2.
1415    [
1416        (0, v0, T0),
1417        (1, v1, T1),
1418    ],
1419    /// Convert a BLisp's Tuple to a Rust's Tuple
1420    /// where the length is 3.
1421    [
1422        (0, v0, T0),
1423        (1, v1, T1),
1424        (2, v2, T2),
1425    ],
1426    /// Convert a BLisp's Tuple to a Rust's Tuple
1427    /// where the length is 4.
1428    [
1429        (0, v0, T0),
1430        (1, v1, T1),
1431        (2, v2, T2),
1432        (3, v3, T3),
1433    ],
1434    /// Convert a BLisp's Tuple to a Rust's Tuple
1435    /// where the length is 5.
1436    [
1437        (0, v0, T0),
1438        (1, v1, T1),
1439        (2, v2, T2),
1440        (3, v3, T3),
1441        (4, v4, T4),
1442    ],
1443    /// Convert a BLisp's Tuple to a Rust's Tuple
1444    /// where the length is 6.
1445    [
1446        (0, v0, T0),
1447        (1, v1, T1),
1448        (2, v2, T2),
1449        (3, v3, T3),
1450        (4, v4, T4),
1451        (5, v5, T5),
1452    ],
1453    /// Convert a BLisp's Tuple to a Rust's Tuple
1454    /// where the length is 7.
1455    [
1456        (0, v0, T0),
1457        (1, v1, T1),
1458        (2, v2, T2),
1459        (3, v3, T3),
1460        (4, v4, T4),
1461        (5, v5, T5),
1462        (6, v6, T6),
1463    ],
1464    /// Convert a BLisp's Tuple to a Rust's Tuple
1465    /// where the length is 8.
1466    [
1467        (0, v0, T0),
1468        (1, v1, T1),
1469        (2, v2, T2),
1470        (3, v3, T3),
1471        (4, v4, T4),
1472        (5, v5, T5),
1473        (6, v6, T6),
1474        (7, v7, T7),
1475    ],
1476    /// Convert a BLisp's Tuple to a Rust's Tuple
1477    /// where the length is 9.
1478    [
1479        (0, v0, T0),
1480        (1, v1, T1),
1481        (2, v2, T2),
1482        (3, v3, T3),
1483        (4, v4, T4),
1484        (5, v5, T5),
1485        (6, v6, T6),
1486        (7, v7, T7),
1487        (8, v8, T8),
1488    ],
1489    /// Convert a BLisp's Tuple to a Rust's Tuple
1490    /// where the length is 10.
1491    [
1492        (0, v0, T0),
1493        (1, v1, T1),
1494        (2, v2, T2),
1495        (3, v3, T3),
1496        (4, v4, T4),
1497        (5, v5, T5),
1498        (6, v6, T6),
1499        (7, v7, T7),
1500        (8, v8, T8),
1501        (9, v9, T9),
1502    ],
1503    /// Convert a BLisp's Tuple to a Rust's Tuple
1504    /// where the length is 11.
1505    [
1506        (0, v0, T0),
1507        (1, v1, T1),
1508        (2, v2, T2),
1509        (3, v3, T3),
1510        (4, v4, T4),
1511        (5, v5, T5),
1512        (6, v6, T6),
1513        (7, v7, T7),
1514        (8, v8, T8),
1515        (9, v9, T9),
1516        (10, v10, T10),
1517    ],
1518    /// Convert a BLisp's Tuple to a Rust's Tuple
1519    /// where the length is 12.
1520    [
1521        (0, v0, T0),
1522        (1, v1, T1),
1523        (2, v2, T2),
1524        (3, v3, T3),
1525        (4, v4, T4),
1526        (5, v5, T5),
1527        (6, v6, T6),
1528        (7, v7, T7),
1529        (8, v8, T8),
1530        (9, v9, T9),
1531        (10, v10, T10),
1532        (11, v11, T11),
1533    ],
1534];
1535
1536pub trait RustToRTData<T> {
1537    fn from(env: &mut Environment<'_>, value: T) -> Self;
1538}
1539
1540impl RustToRTData<BigInt> for RTData {
1541    fn from(env: &mut Environment<'_>, value: BigInt) -> Self {
1542        RTData::Int(env.root.make_int(value))
1543    }
1544}
1545
1546impl RustToRTData<char> for RTData {
1547    fn from(_env: &mut Environment<'_>, value: char) -> Self {
1548        RTData::Char(value)
1549    }
1550}
1551
1552impl RustToRTData<bool> for RTData {
1553    fn from(_env: &mut Environment<'_>, value: bool) -> Self {
1554        RTData::Bool(value)
1555    }
1556}
1557
1558impl RustToRTData<String> for RTData {
1559    fn from(env: &mut Environment<'_>, value: String) -> Self {
1560        RTData::Str(env.root.make_str(value))
1561    }
1562}
1563
1564impl<T> RustToRTData<Option<T>> for RTData
1565where
1566    RTData: RustToRTData<T>,
1567{
1568    fn from(env: &mut Environment<'_>, value: Option<T>) -> Self {
1569        if let Some(value) = value {
1570            let value = RustToRTData::from(env, value);
1571            RTData::LData(env.root.make_obj("Some".to_string(), Some(vec![value])))
1572        } else {
1573            RTData::LData(env.root.make_obj("None".to_string(), None))
1574        }
1575    }
1576}
1577
1578impl<T, E> RustToRTData<Result<T, E>> for RTData
1579where
1580    RTData: RustToRTData<T> + RustToRTData<E>,
1581{
1582    fn from(env: &mut Environment<'_>, value: Result<T, E>) -> Self {
1583        match value {
1584            Ok(value) => {
1585                let value = RustToRTData::from(env, value);
1586                RTData::LData(env.root.make_obj("Ok".to_string(), Some(vec![value])))
1587            }
1588            Err(value) => {
1589                let value = RustToRTData::from(env, value);
1590                RTData::LData(env.root.make_obj("Err".to_string(), Some(vec![value])))
1591            }
1592        }
1593    }
1594}
1595
1596impl RustToRTData<()> for RTData {
1597    fn from(env: &mut Environment<'_>, _: ()) -> Self {
1598        RTData::LData(env.root.make_obj("Tuple".to_string(), Some(vec![])))
1599    }
1600}
1601
1602macro_rules! impl_rust_to_rt_data_tuple {
1603    ($([ $(($name_snake:ident, $name_pascal:ident)),+ $(,)? ]),+ $(,)?) => {
1604        $(impl<$($name_pascal),*> RustToRTData<($($name_pascal),*)> for RTData
1605        where $(RTData: RustToRTData<$name_pascal>),* {
1606            fn from(env: &mut Environment<'_>, ($($name_snake),*): ($($name_pascal),*)) -> Self {
1607                $(let $name_snake = <RTData as RustToRTData<$name_pascal>>::from(env, $name_snake);)*
1608                RTData::LData(env.root.make_obj("Tuple".to_string(), Some(vec![$($name_snake),*])))
1609            }
1610        })*
1611    }
1612}
1613impl_rust_to_rt_data_tuple![
1614    [(v0, V0), (v1, V1),],
1615    [(v0, V0), (v1, V1), (v2, V2),],
1616    [(v0, V0), (v1, V1), (v2, V2), (v3, V3),],
1617    [(v0, V0), (v1, V1), (v2, V2), (v3, V3), (v4, V4),],
1618    [(v0, V0), (v1, V1), (v2, V2), (v3, V3), (v4, V4), (v5, V5),],
1619    [
1620        (v0, V0),
1621        (v1, V1),
1622        (v2, V2),
1623        (v3, V3),
1624        (v4, V4),
1625        (v5, V5),
1626        (v6, V6),
1627    ],
1628    [
1629        (v0, V0),
1630        (v1, V1),
1631        (v2, V2),
1632        (v3, V3),
1633        (v4, V4),
1634        (v5, V5),
1635        (v6, V6),
1636        (v7, V7),
1637    ],
1638    [
1639        (v0, V0),
1640        (v1, V1),
1641        (v2, V2),
1642        (v3, V3),
1643        (v4, V4),
1644        (v5, V5),
1645        (v6, V6),
1646        (v7, V7),
1647        (v8, V8),
1648    ],
1649    [
1650        (v0, V0),
1651        (v1, V1),
1652        (v2, V2),
1653        (v3, V3),
1654        (v4, V4),
1655        (v5, V5),
1656        (v6, V6),
1657        (v7, V7),
1658        (v8, V8),
1659        (v9, V9),
1660    ],
1661    [
1662        (v0, V0),
1663        (v1, V1),
1664        (v2, V2),
1665        (v3, V3),
1666        (v4, V4),
1667        (v5, V5),
1668        (v6, V6),
1669        (v7, V7),
1670        (v8, V8),
1671        (v9, V9),
1672        (v10, V10),
1673    ],
1674    [
1675        (v0, V0),
1676        (v1, V1),
1677        (v2, V2),
1678        (v3, V3),
1679        (v4, V4),
1680        (v5, V5),
1681        (v6, V6),
1682        (v7, V7),
1683        (v8, V8),
1684        (v9, V9),
1685        (v10, V10),
1686        (v11, V11),
1687    ],
1688];
1689
1690impl<T> RustToRTData<Vec<T>> for RTData
1691where
1692    RTData: RustToRTData<T>,
1693{
1694    fn from(env: &mut Environment<'_>, vec: Vec<T>) -> Self {
1695        Self::LData(collection_to_list(env, vec.into_iter()))
1696    }
1697}
1698impl<T, const N: usize> RustToRTData<[T; N]> for RTData
1699where
1700    RTData: RustToRTData<T>,
1701{
1702    fn from(env: &mut Environment<'_>, slice: [T; N]) -> Self {
1703        Self::LData(collection_to_list(env, slice.into_iter()))
1704    }
1705}
1706
1707/// Convert a collection into a cons list.
1708fn collection_to_list<I, T>(env: &mut Environment<'_>, iter: I) -> LDataType
1709where
1710    I: DoubleEndedIterator<Item = T>,
1711    RTData: RustToRTData<T>,
1712{
1713    let mut iter = iter
1714        .map(|item| {
1715            (
1716                "Cons".to_string(),
1717                Some(vec![<RTData as RustToRTData<T>>::from(env, item)]),
1718            )
1719        })
1720        .chain([("Nil".to_string(), None)].into_iter())
1721        .collect::<Vec<_>>()
1722        .into_iter()
1723        .map(|(label, data)| env.root.make_obj(label, data))
1724        .rev()
1725        .peekable();
1726
1727    let mut root_cons = None;
1728    while let Some(item) = iter.next() {
1729        match iter.peek_mut() {
1730            Some(next) => {
1731                next.get_ldata_mut()
1732                    .data
1733                    .as_mut()
1734                    .expect("all items after a nil should contain a value")
1735                    .push(RTData::LData(item));
1736            }
1737            None => {
1738                root_cons = Some(item);
1739            }
1740        }
1741    }
1742
1743    root_cons.expect("chaining a nil should ensure that the iterator always has a value")
1744}
1745
1746pub trait FFI {
1747    /// Extern expression of BLisp
1748    fn blisp_extern(&self) -> &'static str;
1749
1750    /// Return the corresponding FFI.
1751    fn ffi(&self) -> fn(env: &mut Environment<'_>, args: &[RTData]) -> RTData;
1752
1753    /// The function name.
1754    fn name(&self) -> &'static str;
1755}