rune/
eval.rs

1//! Lisp evaluation primitives.
2use crate::core::cons::{Cons, ConsError};
3use crate::core::env::{ArgSlice, CallFrame, Env, sym};
4use crate::core::error::{Type, TypeError};
5use crate::core::gc::{Rt, Rto};
6use crate::core::object::{
7    FnArgs, Function, LispString, NIL, ObjectType, Symbol, TagType, display_slice,
8};
9use crate::core::{
10    gc::Context,
11    object::{FunctionType, Gc, Object},
12};
13use crate::data::LispError;
14use crate::fns::{assq, eq};
15use crate::rooted_iter;
16use anyhow::{Result, anyhow, bail, ensure};
17use fallible_iterator::FallibleIterator;
18use fallible_streaming_iterator::FallibleStreamingIterator;
19use rune_core::macros::{bail_err, call, list, root};
20use rune_macros::defun;
21use std::fmt::{Display, Formatter};
22
23#[derive(Debug)]
24pub(crate) struct EvalError {
25    backtrace: Vec<Box<str>>,
26    pub(crate) error: ErrorType,
27}
28
29#[derive(Debug)]
30pub(crate) enum ErrorType {
31    Throw(u32),
32    Signal(u32),
33    Err(anyhow::Error),
34}
35
36impl std::error::Error for EvalError {}
37
38impl Display for EvalError {
39    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
40        match &self.error {
41            ErrorType::Err(e) => writeln!(f, "{e}")?,
42            ErrorType::Throw(_) => writeln!(f, "No catch for throw")?,
43            ErrorType::Signal(_) => writeln!(f, "Signal")?,
44        }
45        Ok(())
46    }
47}
48
49impl EvalError {
50    pub(crate) fn new_error(error: anyhow::Error) -> Self {
51        Self { backtrace: Vec::new(), error: ErrorType::Err(error) }
52    }
53
54    pub(crate) fn signal(error_symbol: Object, data: Object, env: &mut Rt<Env>) -> Self {
55        Self {
56            backtrace: Vec::new(),
57            error: ErrorType::Signal(env.set_exception(error_symbol, data)),
58        }
59    }
60
61    pub(crate) fn throw(tag: Object, data: Object, env: &mut Rt<Env>) -> Self {
62        Self { backtrace: Vec::new(), error: ErrorType::Throw(env.set_exception(tag, data)) }
63    }
64
65    pub(crate) fn new(error: impl Into<Self>) -> Self {
66        error.into()
67    }
68
69    pub(crate) fn with_trace(error: anyhow::Error, name: &str, args: &[Rto<Object>]) -> Self {
70        let display = display_slice(args);
71        let trace = format!("{name} {display}").into_boxed_str();
72        Self { backtrace: vec![trace], error: ErrorType::Err(error) }
73    }
74
75    pub(crate) fn add_trace(mut self, name: &str, args: &[Rto<Object>]) -> Self {
76        let display = display_slice(args);
77        self.backtrace.push(format!("{name} {display}").into_boxed_str());
78        self
79    }
80
81    pub(crate) fn print_backtrace(&self) {
82        println!("BEGIN_BACKTRACE");
83        for (i, x) in self.backtrace.iter().enumerate() {
84            println!("{i}: {x}");
85        }
86        println!("END_BACKTRACE");
87    }
88}
89
90impl From<anyhow::Error> for EvalError {
91    fn from(e: anyhow::Error) -> Self {
92        Self::new_error(e)
93    }
94}
95
96impl From<ConsError> for EvalError {
97    fn from(e: ConsError) -> Self {
98        Self::new_error(anyhow::anyhow!(e))
99    }
100}
101
102impl From<String> for EvalError {
103    fn from(e: String) -> Self {
104        Self::new_error(anyhow::anyhow!(e))
105    }
106}
107
108impl From<&'static str> for EvalError {
109    fn from(e: &'static str) -> Self {
110        Self::new_error(anyhow::anyhow!(e))
111    }
112}
113
114impl From<TypeError> for EvalError {
115    fn from(e: TypeError) -> Self {
116        Self::new_error(e.into())
117    }
118}
119
120impl From<LispError> for EvalError {
121    fn from(e: LispError) -> Self {
122        Self::new_error(e.into())
123    }
124}
125
126impl From<std::convert::Infallible> for EvalError {
127    fn from(e: std::convert::Infallible) -> Self {
128        Self::new_error(e.into())
129    }
130}
131
132pub(crate) type EvalResult<'ob> = Result<Object<'ob>, EvalError>;
133
134#[defun]
135pub(crate) fn apply<'ob>(
136    function: &Rto<Function>,
137    arguments: ArgSlice,
138    env: &mut Rt<Env>,
139    cx: &'ob mut Context,
140) -> Result<Object<'ob>> {
141    let arg_slice = env.stack.arg_slice(arguments);
142    if !arg_slice.is_empty() {
143        let last = arg_slice.last().unwrap().bind(cx);
144        let len = env.stack.len();
145        let beg = len - arg_slice.len();
146        let end = len - 1;
147        env.stack.extend_as_vec_from_within(beg..end);
148        for element in last.as_list()? {
149            let e = cx.bind(element?);
150            env.stack.push(e);
151        }
152        let args = env.stack.len() - len;
153        let frame = &mut CallFrame::new_with_args(env, args);
154        function.call(frame, None, cx).map_err(Into::into)
155    } else {
156        function.call(&mut CallFrame::new(env), None, cx).map_err(Into::into)
157    }
158}
159
160#[defun]
161pub(crate) fn funcall<'ob>(
162    function: &Rto<Function>,
163    arguments: ArgSlice,
164    env: &mut Rt<Env>,
165    cx: &'ob mut Context,
166) -> Result<Object<'ob>> {
167    let beg = env.stack.len() - arguments.len();
168    env.stack.extend_as_vec_from_within(beg..);
169    let frame = &mut CallFrame::new_with_args(env, arguments.len());
170    function.call(frame, None, cx).map_err(Into::into)
171}
172
173#[defun]
174fn run_hooks<'ob>(hooks: ArgSlice, env: &mut Rt<Env>, cx: &'ob mut Context) -> Result<Object<'ob>> {
175    let hook_count = hooks.len();
176    for i in 0..hook_count {
177        let hook = env.stack[hook_count - i - 1].bind(cx);
178        match hook.untag() {
179            ObjectType::Symbol(sym) => {
180                if let Some(val) = env.vars.get(sym) {
181                    let val = val.bind(cx);
182                    match val.untag() {
183                        ObjectType::Cons(hook_list) => {
184                            rooted_iter!(hooks, hook_list, cx);
185                            while let Some(hook) = hooks.next()? {
186                                let func = hook.try_as()?;
187                                call!(func; env, cx)?;
188                            }
189                        }
190                        ObjectType::NIL => {}
191                        _ => {
192                            let func: Function = val.try_into()?;
193                            root!(func, cx);
194                            call!(func; env, cx)?;
195                        }
196                    }
197                }
198            }
199            x => bail!(TypeError::new(Type::Symbol, x)),
200        }
201    }
202    Ok(NIL)
203}
204
205#[defun]
206fn run_hook_with_args<'ob>(
207    hook: &Rto<Object>,
208    args: ArgSlice,
209    env: &mut Rt<Env>,
210    cx: &'ob mut Context,
211) -> Result<Object<'ob>> {
212    match hook.untag(cx) {
213        ObjectType::Symbol(sym) => {
214            if let Some(val) = env.vars.get(sym) {
215                let val = val.bind(cx);
216                match val.untag() {
217                    ObjectType::Cons(hook_list) => {
218                        rooted_iter!(hooks, hook_list, cx);
219                        while let Some(hook) = hooks.next()? {
220                            let func: &Rto<Function> = hook.try_as()?;
221                            let beg = env.stack.len() - args.len();
222                            env.stack.extend_as_vec_from_within(beg..);
223                            let frame = &mut CallFrame::new_with_args(env, args.len());
224                            func.call(frame, None, cx)?;
225                        }
226                    }
227                    ObjectType::NIL => {}
228                    _ => {
229                        let func: Function = val.try_into()?;
230                        root!(func, cx);
231                        call!(func; env, cx)?;
232                    }
233                }
234            }
235        }
236        x => bail!(TypeError::new(Type::Symbol, x)),
237    }
238    Ok(NIL)
239}
240
241#[defun]
242pub(crate) fn autoload_do_load<'ob>(
243    fundef: &Rto<Object>,
244    funname: Option<&Rto<Gc<Symbol>>>,
245    macro_only: Option<&Rto<Object>>,
246    env: &mut Rt<Env>,
247    cx: &'ob mut Context,
248) -> Result<Object<'ob>> {
249    // TODO: want to handle the case where the file is already loaded.
250    let Ok((sym::AUTOLOAD, ObjectType::Cons(body))) = fundef.bind(cx).as_cons_pair() else {
251        return Ok(fundef.bind(cx));
252    };
253    ensure!(macro_only.is_none(), "autoload-do-load macro-only is not yet implemented");
254    let mut iter = body.elements();
255    let file: Gc<&LispString> = match iter.next() {
256        Some(x) => x?.try_into()?,
257        None => bail!("Malformed autoload"),
258    };
259    ensure!(
260        iter.fallible().all(|x| Ok(x.is_nil()))?,
261        "autoload arguments are not yet implemented"
262    );
263    root!(file, cx);
264    crate::lread::load(file, None, None, cx, env)?;
265    match funname {
266        Some(func) => match func.untag(cx).func(cx) {
267            Some(x) => Ok(x.into()),
268            None => Err(anyhow!("autoload of {func} did not provide a definition")),
269        },
270        _ => Ok(NIL),
271    }
272}
273
274#[defun]
275fn autoload<'ob>(
276    function: Symbol<'ob>,
277    file: &str,
278    docstring: Option<Object>,
279    interactive: Option<Object>,
280    load_type: Option<Object>,
281    cx: &'ob Context,
282) -> Result<Symbol<'ob>> {
283    if function.has_func() {
284        Ok(sym::NIL)
285    } else {
286        let autoload = list![sym::AUTOLOAD, file, docstring, interactive, load_type; cx];
287        crate::data::fset(function, autoload)
288    }
289}
290
291#[defun]
292pub(crate) fn macroexpand<'ob>(
293    form: &Rto<Object>,
294    environment: Option<&Rto<Object>>,
295    cx: &'ob mut Context,
296    env: &mut Rt<Env>,
297) -> Result<Object<'ob>> {
298    let ObjectType::Cons(cons) = form.untag(cx) else { return Ok(form.bind(cx)) };
299    let ObjectType::Symbol(sym) = cons.car().untag() else { return Ok(form.bind(cx)) };
300    // shadow the macro based on ENVIRONMENT
301    let func = match environment {
302        Some(env) => match assq(sym.into(), env.bind(cx).try_into()?)?.untag() {
303            ObjectType::Cons(cons) => Some(cons.cdr().try_into()?),
304            _ => get_macro_func(sym, cx),
305        },
306        _ => get_macro_func(sym, cx),
307    };
308    let Some(macro_func) = func else { return Ok(form.bind(cx)) };
309    let mut iter = cons.cdr().as_list()?.fallible();
310    let mut frame = CallFrame::new(env);
311    while let Some(arg) = iter.next()? {
312        frame.push_arg(arg);
313    }
314    root!(macro_func, cx);
315    let name = sym.name().to_owned();
316    let new_form = macro_func.call(&mut frame, Some(&name), cx)?;
317    drop(frame);
318    root!(new_form, cx); // polonius
319    if eq(new_form.bind(cx), form.bind(cx)) {
320        Ok(form.bind(cx))
321    } else {
322        // recursively expand the macro's
323        macroexpand(new_form, environment, cx, env)
324    }
325}
326
327fn get_macro_func<'ob>(name: Symbol, cx: &'ob Context) -> Option<Function<'ob>> {
328    if let Some(callable) = name.follow_indirect(cx)
329        && let Ok((sym::MACRO, cdr)) = callable.as_cons_pair()
330    {
331        return Some(cdr.tag());
332    }
333    None
334}
335
336#[defun]
337fn func_arity<'ob>(function: Function, cx: &'ob Context) -> Result<&'ob Cons> {
338    let from_args = |args: FnArgs| {
339        let min = args.required;
340        if args.rest {
341            // TODO: Handle unevalled
342            Cons::new(min, sym::MANY, cx)
343        } else {
344            Cons::new(min, args.optional + min, cx)
345        }
346    };
347    match function.untag() {
348        FunctionType::ByteFn(func) => Ok(from_args(func.args)),
349        FunctionType::SubrFn(func) => Ok(from_args(func.args)),
350        FunctionType::Cons(func) => {
351            let arg_pos = match func.car().untag() {
352                ObjectType::Symbol(sym::CLOSURE) => 2,
353                ObjectType::Symbol(sym::LAMBDA) => 1,
354                other => bail!(TypeError::new(Type::Func, other)),
355            };
356            let Some(args) = func.elements().fallible().nth(arg_pos)? else {
357                bail!("Invalid function: {func}")
358            };
359            let (req, opt, rest) = crate::interpreter::parse_arg_list(args)?;
360            let args = FnArgs {
361                required: req.len() as u16,
362                optional: opt.len() as u16,
363                rest: rest.is_some(),
364                ..FnArgs::default()
365            };
366            Ok(from_args(args))
367        }
368        FunctionType::Symbol(sym) => {
369            let Some(func) = sym.follow_indirect(cx) else { bail!("Void Function: {sym}") };
370            func_arity(func, cx)
371        }
372    }
373}
374
375#[defun]
376#[expect(non_snake_case)]
377fn internal__define_uninitialized_variable<'ob>(
378    _symbol: Symbol<'ob>,
379    _doc: Option<Object>,
380) -> Object<'ob> {
381    // TODO: implement doc strings
382    NIL
383}
384
385#[defun]
386fn signal(mut error_symbol: Object, data: Object, env: &mut Rt<Env>) -> Result<bool> {
387    if error_symbol.is_nil() && data.is_nil() {
388        error_symbol = sym::ERROR.into();
389    }
390    Err(EvalError::signal(error_symbol, data, env).into())
391}
392
393#[defun]
394fn special_variable_p(symbol: Symbol) -> bool {
395    symbol.is_special()
396}
397
398#[defun]
399fn set_default_toplevel_value<'ob>(
400    symbol: Symbol,
401    value: Object,
402    env: &'ob mut Rt<Env>,
403) -> Result<Object<'ob>> {
404    env.set_var(symbol, value)?;
405    Ok(NIL)
406}
407
408#[defun]
409fn set_default<'ob>(
410    symbol: Symbol,
411    value: Object<'ob>,
412    env: &'ob mut Rt<Env>,
413) -> Result<Object<'ob>> {
414    // TODO: implement buffer local variables
415    env.set_var(symbol, value)?;
416    Ok(value)
417}
418
419impl Rto<Function<'_>> {
420    pub(crate) fn call<'ob>(
421        &self,
422        frame: &mut CallFrame<'_, '_>,
423        name: Option<&str>,
424        cx: &'ob mut Context,
425    ) -> EvalResult<'ob> {
426        debug!("calling: {self}");
427        let name = name.unwrap_or("lambda");
428        frame.finalize_arguments();
429        let arg_cnt = frame.arg_count();
430        cx.garbage_collect(false);
431        match self.untag(cx) {
432            FunctionType::ByteFn(f) => {
433                root!(f, cx);
434                crate::bytecode::call(f, arg_cnt, name, frame, cx)
435                    .map_err(|e| e.add_trace(name, frame.arg_slice()))
436            }
437            FunctionType::SubrFn(f) => {
438                (*f).call(arg_cnt, frame, cx).map_err(|e| add_trace(e, name, frame.arg_slice()))
439            }
440            FunctionType::Cons(_) => {
441                crate::interpreter::call_closure(self.try_as().unwrap(), arg_cnt, name, frame, cx)
442                    .map_err(|e| e.add_trace(name, frame.arg_slice()))
443            }
444            FunctionType::Symbol(sym) => {
445                let Some(func) = sym.follow_indirect(cx) else { bail_err!("Void Function: {sym}") };
446                if let Ok((sym::AUTOLOAD, _)) = func.as_cons_pair() {
447                    // TODO: inifinite loop if autoload does not resolve
448                    root!(sym, cx);
449                    crate::eval::autoload_do_load(self.cast(), None, None, frame, cx)
450                        .map_err(|e| add_trace(e, name, frame.arg_slice()))?;
451                    let Some(func) = sym.bind(cx).follow_indirect(cx) else {
452                        bail_err!("autoload for {sym} failed to define function")
453                    };
454                    root!(func, cx);
455                    let name = sym.bind(cx).name().to_owned();
456                    func.call(frame, Some(&name), cx)
457                } else {
458                    root!(func, cx);
459                    let name = sym.name().to_owned();
460                    func.call(frame, Some(&name), cx)
461                }
462            }
463        }
464    }
465}
466
467pub(crate) fn add_trace(err: anyhow::Error, name: &str, args: &[Rto<Object>]) -> EvalError {
468    match err.downcast::<EvalError>() {
469        Ok(err) => err.add_trace(name, args),
470        Err(e) => EvalError::with_trace(e, name, args),
471    }
472}
473
474defsym!(FUNCTION);
475defsym!(QUOTE);
476defsym!(MACRO);
477defsym!(UNQUOTE, ",");
478defsym!(SPLICE, ",@");
479defsym!(BACKQUOTE, "`");
480defsym!(AND_OPTIONAL, "&optional");
481defsym!(AND_REST, "&rest");
482defsym!(LAMBDA);
483defsym!(CLOSURE);
484defsym!(CONDITION_CASE);
485defsym!(UNWIND_PROTECT);
486defsym!(SAVE_EXCURSION);
487defsym!(SAVE_CURRENT_BUFFER);
488defsym!(WHILE);
489defsym!(INLINE);
490defsym!(PROGN);
491defsym!(PROG1);
492defsym!(PROG2);
493defsym!(SETQ);
494defsym!(DEFCONST);
495defsym!(COND);
496defsym!(LET);
497defsym!(LET_STAR, "let*");
498defsym!(IF);
499defsym!(AND);
500defsym!(OR);
501defsym!(INTERACTIVE);
502defsym!(CATCH);
503defsym!(THROW);
504defsym!(ERROR);
505defsym!(DEBUG);
506defsym!(VOID_VARIABLE);
507
508defvar!(DEBUG_ON_ERROR, false);
509defvar!(INTERNAL_MAKE_INTERPRETED_CLOSURE_FUNCTION);