sexprs_vm/
function.rs

1use std::fmt::{Debug, Display, Formatter};
2use std::iter::Zip;
3
4use sexprs_data_structures::{
5    AsSymbol, Symbol, Value, ValueIterator,
6};
7use sexprs_util::{try_result, with_caller, admonition, warn};
8use unique_pointer::UniquePointer;
9
10use crate::{runtime_error, BuiltinFunction, Context, Result, Sym};
11
12#[derive(Clone)]
13pub enum Function<'c> {
14    Builtin {
15        name: Symbol<'c>,
16        function: BuiltinFunction,
17    },
18    Defun {
19        name: Symbol<'c>,
20        args: Value<'c>,
21        body: Value<'c>,
22    },
23}
24impl<'c> Function<'c> {
25    pub fn is_builtin(&self) -> bool {
26        match self {
27            Function::Builtin {..} => true,
28            _ => false
29        }
30    }
31    pub fn is_defun(&self) -> bool {
32        match self {
33            Function::Defun {..} => true,
34            _ => false
35        }
36    }
37    pub fn validate_args(
38        &self,
39        name: &Symbol<'c>,
40        expected: &Value<'c>,
41        received: &Value<'c>,
42    ) -> Result<Zip<ValueIterator<'c>, ValueIterator<'c>>> {
43        let expected_length = expected.len();
44        let received_length = received.len();
45        if expected_length != received_length {
46            Err(with_caller!(runtime_error(
47                format!(
48                    "{} expected {} args [{:#?}] but received {}: {:#?}",
49                    name, expected_length, expected, received_length, received
50                ),
51                None
52            )))
53        } else {
54            Ok(expected
55                .clone()
56                .into_iter()
57                .zip(received))
58        }
59    }
60
61    pub fn bind_args_to_local_context(
62        &self,
63        mut vm: UniquePointer<Context<'c>>,
64        name: &Symbol<'c>,
65        expected: &Value<'c>,
66        received: &Value<'c>,
67    ) -> Result<Vec<(Symbol<'c>, Value<'c>)>> {
68        let mut args = Vec::<(Symbol<'c>, Value<'c>)>::new();
69        for (symbol, value) in try_result!(self.validate_args(name, expected, received))
70        {
71            args.push((symbol.as_symbol(), value.clone()));
72            try_result!(vm
73                .inner_mut()
74                .set_function_local(&symbol.as_symbol(), &Sym::Value(value.clone())));
75        }
76        Ok(args)
77    }
78
79    pub fn call(
80        &self,
81        mut vm: UniquePointer<Context<'c>>,
82        list: Value<'c>,
83    ) -> Result<Value<'c>> {
84        match self {
85            Function::Defun { name, args, body } => {
86                // warn!(82, "calling {}", name);
87                // dbg!(&list);
88                try_result!(self.bind_args_to_local_context(
89                    vm.clone(),
90                    name,
91                    args,
92                    &list
93                ));
94
95                let mut value = Value::nil();
96                for (_, val) in body.into_iter().enumerate() {
97                    value = try_result!(vm.inner_mut().eval(val));
98                }
99                Ok(value)
100            },
101            Function::Builtin { name, function, .. } => {
102                // warn!(74, "calling {}", name);
103                // dbg!(&list);
104
105                Ok(try_result!(function(vm, list)))
106            },
107        }
108    }
109}
110
111impl<'c> Display for Function<'c> {
112    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
113        write!(
114            f,
115            "{}",
116            match self {
117                Function::Defun { name, args, body } =>
118                    format!("(defun {} {} {})", name, args, body),
119                Function::Builtin { name, function } =>
120                    format!("builtin-function {} {:#?}", name, function),
121            }
122        )
123    }
124}
125
126impl<'c> Debug for Function<'c> {
127    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
128        write!(
129            f,
130            "{}",
131            match self {
132                Function::Defun { name, args, body } =>
133                    format!("(defun {} {} {})", name, args, body),
134                Function::Builtin { name, function } =>
135                    format!("builtin-function {} {:#?}", name, function),
136            }
137        )
138    }
139}