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, WithLifetime, 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
134impl<'new> WithLifetime<'new> for EvalResult<'_> {
135    type Out = EvalResult<'new>;
136
137    unsafe fn with_lifetime(self) -> Self::Out {
138        self.map(|x| x.with_lifetime())
139    }
140}
141
142#[defun]
143pub(crate) fn apply<'ob>(
144    function: &Rto<Function>,
145    arguments: ArgSlice,
146    env: &mut Rt<Env>,
147    cx: &'ob mut Context,
148) -> Result<Object<'ob>> {
149    let arg_slice = env.stack.arg_slice(arguments);
150    if !arg_slice.is_empty() {
151        let last = arg_slice.last().unwrap().bind(cx);
152        let len = env.stack.len();
153        let beg = len - arg_slice.len();
154        let end = len - 1;
155        env.stack.extend_as_vec_from_within(beg..end);
156        for element in last.as_list()? {
157            let e = cx.bind(element?);
158            env.stack.push(e);
159        }
160        let args = env.stack.len() - len;
161        let frame = &mut CallFrame::new_with_args(env, args);
162        function.call(frame, None, cx).map_err(Into::into)
163    } else {
164        function.call(&mut CallFrame::new(env), None, cx).map_err(Into::into)
165    }
166}
167
168#[defun]
169pub(crate) fn funcall<'ob>(
170    function: &Rto<Function>,
171    arguments: ArgSlice,
172    env: &mut Rt<Env>,
173    cx: &'ob mut Context,
174) -> Result<Object<'ob>> {
175    let beg = env.stack.len() - arguments.len();
176    env.stack.extend_as_vec_from_within(beg..);
177    let frame = &mut CallFrame::new_with_args(env, arguments.len());
178    function.call(frame, None, cx).map_err(Into::into)
179}
180
181#[defun]
182fn run_hooks<'ob>(hooks: ArgSlice, env: &mut Rt<Env>, cx: &'ob mut Context) -> Result<Object<'ob>> {
183    let hook_count = hooks.len();
184    for i in 0..hook_count {
185        let hook = env.stack[hook_count - i - 1].bind(cx);
186        match hook.untag() {
187            ObjectType::Symbol(sym) => {
188                if let Some(val) = env.vars.get(sym) {
189                    let val = val.bind(cx);
190                    match val.untag() {
191                        ObjectType::Cons(hook_list) => {
192                            rooted_iter!(hooks, hook_list, cx);
193                            while let Some(hook) = hooks.next()? {
194                                let func = hook.try_as()?;
195                                call!(func; env, cx)?;
196                            }
197                        }
198                        ObjectType::NIL => {}
199                        _ => {
200                            let func: Function = val.try_into()?;
201                            root!(func, cx);
202                            call!(func; env, cx)?;
203                        }
204                    }
205                }
206            }
207            x => bail!(TypeError::new(Type::Symbol, x)),
208        }
209    }
210    Ok(NIL)
211}
212
213#[defun]
214fn run_hook_with_args<'ob>(
215    hook: &Rto<Object>,
216    args: ArgSlice,
217    env: &mut Rt<Env>,
218    cx: &'ob mut Context,
219) -> Result<Object<'ob>> {
220    match hook.untag(cx) {
221        ObjectType::Symbol(sym) => {
222            if let Some(val) = env.vars.get(sym) {
223                let val = val.bind(cx);
224                match val.untag() {
225                    ObjectType::Cons(hook_list) => {
226                        rooted_iter!(hooks, hook_list, cx);
227                        while let Some(hook) = hooks.next()? {
228                            let func: &Rto<Function> = hook.try_as()?;
229                            let beg = env.stack.len() - args.len();
230                            env.stack.extend_as_vec_from_within(beg..);
231                            let frame = &mut CallFrame::new_with_args(env, args.len());
232                            func.call(frame, None, cx)?;
233                        }
234                    }
235                    ObjectType::NIL => {}
236                    _ => {
237                        let func: Function = val.try_into()?;
238                        root!(func, cx);
239                        call!(func; env, cx)?;
240                    }
241                }
242            }
243        }
244        x => bail!(TypeError::new(Type::Symbol, x)),
245    }
246    Ok(NIL)
247}
248
249#[defun]
250pub(crate) fn autoload_do_load<'ob>(
251    fundef: &Rto<Object>,
252    funname: Option<&Rto<Gc<Symbol>>>,
253    macro_only: Option<&Rto<Object>>,
254    env: &mut Rt<Env>,
255    cx: &'ob mut Context,
256) -> Result<Object<'ob>> {
257    // TODO: want to handle the case where the file is already loaded.
258    let Ok((sym::AUTOLOAD, ObjectType::Cons(body))) = fundef.bind(cx).as_cons_pair() else {
259        return Ok(fundef.bind(cx));
260    };
261    ensure!(macro_only.is_none(), "autoload-do-load macro-only is not yet implemented");
262    let mut iter = body.elements();
263    let file: Gc<&LispString> = match iter.next() {
264        Some(x) => x?.try_into()?,
265        None => bail!("Malformed autoload"),
266    };
267    ensure!(
268        iter.fallible().all(|x| Ok(x.is_nil()))?,
269        "autoload arguments are not yet implemented"
270    );
271    root!(file, cx);
272    crate::lread::load(file, None, None, cx, env)?;
273    match funname {
274        Some(func) => match func.untag(cx).func(cx) {
275            Some(x) => Ok(x.into()),
276            None => Err(anyhow!("autoload of {func} did not provide a definition")),
277        },
278        _ => Ok(NIL),
279    }
280}
281
282#[defun]
283fn autoload<'ob>(
284    function: Symbol<'ob>,
285    file: &str,
286    docstring: Option<Object>,
287    interactive: Option<Object>,
288    load_type: Option<Object>,
289    cx: &'ob Context,
290) -> Result<Symbol<'ob>> {
291    if function.has_func() {
292        Ok(sym::NIL)
293    } else {
294        let autoload = list![sym::AUTOLOAD, file, docstring, interactive, load_type; cx];
295        crate::data::fset(function, autoload)
296    }
297}
298
299#[defun]
300pub(crate) fn macroexpand<'ob>(
301    form: &Rto<Object>,
302    environment: Option<&Rto<Object>>,
303    cx: &'ob mut Context,
304    env: &mut Rt<Env>,
305) -> Result<Object<'ob>> {
306    let ObjectType::Cons(cons) = form.untag(cx) else { return Ok(form.bind(cx)) };
307    let ObjectType::Symbol(sym) = cons.car().untag() else { return Ok(form.bind(cx)) };
308    // shadow the macro based on ENVIRONMENT
309    let func = match environment {
310        Some(env) => match assq(sym.into(), env.bind(cx).try_into()?)?.untag() {
311            ObjectType::Cons(cons) => Some(cons.cdr().try_into()?),
312            _ => get_macro_func(sym, cx),
313        },
314        _ => get_macro_func(sym, cx),
315    };
316    let Some(macro_func) = func else { return Ok(form.bind(cx)) };
317    let mut iter = cons.cdr().as_list()?.fallible();
318    let mut frame = CallFrame::new(env);
319    while let Some(arg) = iter.next()? {
320        frame.push_arg(arg);
321    }
322    root!(macro_func, cx);
323    let name = sym.name().to_owned();
324    let new_form = macro_func.call(&mut frame, Some(&name), cx)?;
325    drop(frame);
326    root!(new_form, cx); // polonius
327    if eq(new_form.bind(cx), form.bind(cx)) {
328        Ok(form.bind(cx))
329    } else {
330        // recursively expand the macro's
331        macroexpand(new_form, environment, cx, env)
332    }
333}
334
335fn get_macro_func<'ob>(name: Symbol, cx: &'ob Context) -> Option<Function<'ob>> {
336    if let Some(callable) = name.follow_indirect(cx)
337        && let Ok((sym::MACRO, cdr)) = callable.as_cons_pair()
338    {
339        return Some(cdr.tag());
340    }
341    None
342}
343
344#[defun]
345fn func_arity<'ob>(function: Function, cx: &'ob Context) -> Result<&'ob Cons> {
346    let from_args = |args: FnArgs| {
347        let min = args.required;
348        if args.rest {
349            // TODO: Handle unevalled
350            Cons::new(min, sym::MANY, cx)
351        } else {
352            Cons::new(min, args.optional + min, cx)
353        }
354    };
355    match function.untag() {
356        FunctionType::ByteFn(func) => Ok(from_args(func.args)),
357        FunctionType::SubrFn(func) => Ok(from_args(func.args)),
358        FunctionType::Cons(func) => {
359            let arg_pos = match func.car().untag() {
360                ObjectType::Symbol(sym::CLOSURE) => 2,
361                ObjectType::Symbol(sym::LAMBDA) => 1,
362                other => bail!(TypeError::new(Type::Func, other)),
363            };
364            let Some(args) = func.elements().fallible().nth(arg_pos)? else {
365                bail!("Invalid function: {func}")
366            };
367            let (req, opt, rest) = crate::interpreter::parse_arg_list(args)?;
368            let args = FnArgs {
369                required: req.len() as u16,
370                optional: opt.len() as u16,
371                rest: rest.is_some(),
372                ..FnArgs::default()
373            };
374            Ok(from_args(args))
375        }
376        FunctionType::Symbol(sym) => {
377            let Some(func) = sym.follow_indirect(cx) else { bail!("Void Function: {sym}") };
378            func_arity(func, cx)
379        }
380    }
381}
382
383#[defun]
384#[expect(non_snake_case)]
385fn internal__define_uninitialized_variable<'ob>(
386    _symbol: Symbol<'ob>,
387    _doc: Option<Object>,
388) -> Object<'ob> {
389    // TODO: implement doc strings
390    NIL
391}
392
393#[defun]
394fn signal(mut error_symbol: Object, data: Object, env: &mut Rt<Env>) -> Result<bool> {
395    if error_symbol.is_nil() && data.is_nil() {
396        error_symbol = sym::ERROR.into();
397    }
398    Err(EvalError::signal(error_symbol, data, env).into())
399}
400
401#[defun]
402fn special_variable_p(symbol: Symbol) -> bool {
403    symbol.is_special()
404}
405
406#[defun]
407fn set_default_toplevel_value<'ob>(
408    symbol: Symbol,
409    value: Object,
410    env: &'ob mut Rt<Env>,
411) -> Result<Object<'ob>> {
412    env.set_var(symbol, value)?;
413    Ok(NIL)
414}
415
416#[defun]
417fn set_default<'ob>(
418    symbol: Symbol,
419    value: Object<'ob>,
420    env: &'ob mut Rt<Env>,
421) -> Result<Object<'ob>> {
422    // TODO: implement buffer local variables
423    env.set_var(symbol, value)?;
424    Ok(value)
425}
426
427impl Rto<Function<'_>> {
428    pub(crate) fn call<'ob>(
429        &self,
430        frame: &mut CallFrame<'_, '_>,
431        name: Option<&str>,
432        cx: &'ob mut Context,
433    ) -> EvalResult<'ob> {
434        debug!("calling: {self}");
435        let name = name.unwrap_or("lambda");
436        frame.finalize_arguments();
437        let arg_cnt = frame.arg_count();
438        cx.garbage_collect(false);
439        match self.untag(cx) {
440            FunctionType::ByteFn(f) => {
441                root!(f, cx);
442                crate::bytecode::call(f, arg_cnt, name, frame, cx)
443                    .map_err(|e| e.add_trace(name, frame.arg_slice()))
444            }
445            FunctionType::SubrFn(f) => {
446                (*f).call(arg_cnt, frame, cx).map_err(|e| add_trace(e, name, frame.arg_slice()))
447            }
448            FunctionType::Cons(_) => {
449                crate::interpreter::call_closure(self.try_as().unwrap(), arg_cnt, name, frame, cx)
450                    .map_err(|e| e.add_trace(name, frame.arg_slice()))
451            }
452            FunctionType::Symbol(sym) => {
453                let Some(func) = sym.follow_indirect(cx) else { bail_err!("Void Function: {sym}") };
454                if let Ok((sym::AUTOLOAD, _)) = func.as_cons_pair() {
455                    // TODO: inifinite loop if autoload does not resolve
456                    root!(sym, cx);
457                    crate::eval::autoload_do_load(self.cast(), None, None, frame, cx)
458                        .map_err(|e| add_trace(e, name, frame.arg_slice()))?;
459                    let Some(func) = sym.bind(cx).follow_indirect(cx) else {
460                        bail_err!("autoload for {sym} failed to define function")
461                    };
462                    root!(func, cx);
463                    let name = sym.bind(cx).name().to_owned();
464                    func.call(frame, Some(&name), cx)
465                } else {
466                    root!(func, cx);
467                    let name = sym.name().to_owned();
468                    func.call(frame, Some(&name), cx)
469                }
470            }
471        }
472    }
473}
474
475pub(crate) fn add_trace(err: anyhow::Error, name: &str, args: &[Rto<Object>]) -> EvalError {
476    match err.downcast::<EvalError>() {
477        Ok(err) => err.add_trace(name, args),
478        Err(e) => EvalError::with_trace(e, name, args),
479    }
480}
481
482defsym!(FUNCTION);
483defsym!(QUOTE);
484defsym!(MACRO);
485defsym!(UNQUOTE, ",");
486defsym!(SPLICE, ",@");
487defsym!(BACKQUOTE, "`");
488defsym!(AND_OPTIONAL, "&optional");
489defsym!(AND_REST, "&rest");
490defsym!(LAMBDA);
491defsym!(CLOSURE);
492defsym!(CONDITION_CASE);
493defsym!(UNWIND_PROTECT);
494defsym!(SAVE_EXCURSION);
495defsym!(SAVE_CURRENT_BUFFER);
496defsym!(WHILE);
497defsym!(INLINE);
498defsym!(PROGN);
499defsym!(PROG1);
500defsym!(PROG2);
501defsym!(SETQ);
502defsym!(DEFCONST);
503defsym!(COND);
504defsym!(LET);
505defsym!(LET_STAR, "let*");
506defsym!(IF);
507defsym!(AND);
508defsym!(OR);
509defsym!(INTERACTIVE);
510defsym!(CATCH);
511defsym!(THROW);
512defsym!(ERROR);
513defsym!(DEBUG);
514defsym!(VOID_VARIABLE);
515
516defvar!(DEBUG_ON_ERROR, false);
517defvar!(INTERNAL_MAKE_INTERPRETED_CLOSURE_FUNCTION);