1use 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 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 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); if eq(new_form.bind(cx), form.bind(cx)) {
328 Ok(form.bind(cx))
329 } else {
330 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 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 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 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 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);