1use std::sync::Arc;
10
11use tatara_lisp::{
12 Atom, MacroDef, MacroParams, Span, Spanned, SpannedExpander, SpannedForm,
13};
14
15use crate::code::{spanned_to_value, value_to_spanned};
16use crate::env::Env;
17use crate::error::{EvalError, Result};
18use crate::ffi::{
19 Arity, Caller, FnEntry, FnImpl, FnRegistry, FromValue, HigherOrderCallable, IntoValue,
20 NativeCallable,
21};
22use crate::module::{Loader, Module, ModuleError, ModuleRegistry, NoLoader};
23use crate::special::SpecialForm;
24use crate::value::{Closure, ErrorObj, NativeFn, Value};
25
26pub struct Interpreter<H> {
29 pub(crate) registry: FnRegistry<H>,
30 pub(crate) globals: Env,
31 pub(crate) expander: SpannedExpander,
36 pub(crate) modules: ModuleRegistry,
40 pub(crate) loader: Arc<dyn Loader>,
43 pub(crate) current_module: Option<Arc<str>>,
48}
49
50impl<H: 'static> Interpreter<H> {
51 pub fn new() -> Self {
52 Self {
53 registry: FnRegistry::new(),
54 globals: Env::new(),
55 expander: SpannedExpander::new(),
56 modules: ModuleRegistry::new(),
57 loader: Arc::new(NoLoader),
58 current_module: None,
59 }
60 }
61
62 pub fn set_loader(&mut self, loader: Arc<dyn Loader>) {
65 self.loader = loader;
66 }
67
68 pub fn modules(&self) -> &ModuleRegistry {
70 &self.modules
71 }
72
73 pub fn register_fn<F>(&mut self, name: impl Into<Arc<str>>, arity: Arity, callable: F)
77 where
78 F: NativeCallable<H>,
79 {
80 let name = name.into();
81 self.registry.insert(FnEntry {
82 name: name.clone(),
83 arity,
84 callable: FnImpl::Native(Arc::new(callable)),
85 });
86 self.globals.define(
87 name.clone(),
88 Value::NativeFn(Arc::new(NativeFn { name, arity })),
89 );
90 }
91
92 pub fn register_higher_order_fn<F>(
97 &mut self,
98 name: impl Into<Arc<str>>,
99 arity: Arity,
100 callable: F,
101 ) where
102 F: HigherOrderCallable<H>,
103 {
104 let name = name.into();
105 self.registry.insert(FnEntry {
106 name: name.clone(),
107 arity,
108 callable: FnImpl::Higher(Arc::new(callable)),
109 });
110 self.globals.define(
111 name.clone(),
112 Value::NativeFn(Arc::new(NativeFn { name, arity })),
113 );
114 }
115
116 pub fn eval_spanned(&mut self, form: &Spanned, host: &mut H) -> Result<Value> {
121 let expanded = self.fully_expand(form, host)?;
122 eval_in(
123 &mut self.globals,
124 &self.registry,
125 &self.expander,
126 &expanded,
127 host,
128 )
129 }
130
131 pub fn eval_program(&mut self, forms: &[Spanned], host: &mut H) -> Result<Value> {
143 let mut last = Value::Nil;
144 for form in forms {
145 last = self.eval_top_form(form, host)?;
146 }
147 Ok(last)
148 }
149
150 pub fn eval_top_form(&mut self, form: &Spanned, host: &mut H) -> Result<Value> {
156 if self.expander.try_register_macro(form)? {
157 return Ok(Value::Nil);
158 }
159 if let Some(head) = head_symbol(form) {
163 match head {
164 "provide" => return self.eval_provide(form, host),
165 "require" => return self.eval_require(form, host),
166 _ => {}
167 }
168 }
169 let expanded = self.fully_expand(form, host)?;
170 eval_in(
171 &mut self.globals,
172 &self.registry,
173 &self.expander,
174 &expanded,
175 host,
176 )
177 }
178
179 fn eval_provide(&mut self, form: &Spanned, _host: &mut H) -> Result<Value> {
183 let items = form.as_list().unwrap_or(&[]);
184 let span = form.span;
185 let Some(current) = self.current_module.clone() else {
186 return Err(EvalError::bad_form(
187 "provide",
188 "`provide` only valid at module top level — embedder evaluating top-level code has no current module",
189 span,
190 ));
191 };
192 let mut names: Vec<Arc<str>> = Vec::with_capacity(items.len().saturating_sub(1));
194 for item in &items[1..] {
195 let name = item.as_symbol().ok_or_else(|| {
196 EvalError::bad_form(
197 "provide",
198 "expected symbol — every arg must name a binding to export",
199 item.span,
200 )
201 })?;
202 names.push(Arc::<str>::from(name));
203 }
204 {
209 let mut g = self.modules.inner_lock();
210 g.exports_staging
214 .entry(current.to_string())
215 .or_default()
216 .extend(names.iter().cloned());
217 }
218 Ok(Value::Nil)
219 }
220
221 fn eval_require(&mut self, form: &Spanned, host: &mut H) -> Result<Value> {
230 let items = form.as_list().unwrap_or(&[]);
231 let span = form.span;
232 if items.len() < 2 {
233 return Err(EvalError::bad_form(
234 "require",
235 "expected (require \"path\" [:as alias] [:refer (...)])",
236 span,
237 ));
238 }
239 let path: Arc<str> = match items[1].as_string() {
240 Some(s) => Arc::from(s),
241 None => {
242 return Err(EvalError::bad_form(
243 "require",
244 "first arg must be a string path",
245 items[1].span,
246 ))
247 }
248 };
249
250 let mut alias: Option<Arc<str>> = None;
252 let mut refer: Option<Vec<Arc<str>>> = None;
253 let mut i = 2usize;
254 while i < items.len() {
255 let kw = items[i].as_keyword().ok_or_else(|| {
256 EvalError::bad_form(
257 "require",
258 "expected keyword (:as / :refer) after path",
259 items[i].span,
260 )
261 })?;
262 let val = items.get(i + 1).ok_or_else(|| {
263 EvalError::bad_form("require", "keyword without value", items[i].span)
264 })?;
265 match kw {
266 "as" => {
267 alias = Some(Arc::from(val.as_symbol().ok_or_else(|| {
268 EvalError::bad_form("require", ":as needs a symbol alias", val.span)
269 })?));
270 }
271 "refer" => {
272 let names_list = val.as_list().ok_or_else(|| {
273 EvalError::bad_form(
274 "require",
275 ":refer needs a parenthesized list of symbols",
276 val.span,
277 )
278 })?;
279 let mut names = Vec::with_capacity(names_list.len());
280 for n in names_list {
281 names.push(Arc::<str>::from(n.as_symbol().ok_or_else(|| {
282 EvalError::bad_form(
283 "require",
284 ":refer list must contain symbols only",
285 n.span,
286 )
287 })?));
288 }
289 refer = Some(names);
290 }
291 other => {
292 return Err(EvalError::bad_form(
293 "require",
294 format!("unknown require option :{other}"),
295 items[i].span,
296 ));
297 }
298 }
299 i += 2;
300 }
301
302 if !self.modules.has(&path) {
304 self.load_module(&path, span, host)?;
305 }
306 let module = self
307 .modules
308 .get(&path)
309 .ok_or_else(|| EvalError::native_fn("require", "module disappeared after load", span))?;
310
311 let chosen_alias = alias.unwrap_or_else(|| path.clone());
313 for name in &module.exports {
314 let value = module
315 .bindings
316 .get(name)
317 .cloned()
318 .unwrap_or(Value::Nil);
319 let qualified: Arc<str> = Arc::from(format!("{chosen_alias}/{name}"));
320 self.globals.define(qualified, value);
321 }
322 if let Some(names) = refer {
323 for name in names {
324 if let Some(value) = module.bindings.get(&name) {
325 if module.exports.contains(&name) {
326 self.globals.define(name.clone(), value.clone());
327 } else {
328 return Err(EvalError::User {
329 value: error_value("not-exported", &format!(
330 "{path} does not export {name}"
331 )),
332 at: span,
333 });
334 }
335 } else {
336 return Err(EvalError::User {
337 value: error_value("not-defined", &format!(
338 "{path} does not define {name}"
339 )),
340 at: span,
341 });
342 }
343 }
344 }
345 Ok(Value::Nil)
346 }
347
348 fn load_module(&mut self, path: &str, span: Span, host: &mut H) -> Result<()> {
354 self.modules
356 .begin_load(path)
357 .map_err(|e| module_error_to_eval(e, span))?;
358
359 let source = match self.loader.load(path) {
361 Ok(s) => s,
362 Err(e) => {
363 self.modules.abort_load(path);
364 return Err(module_error_to_eval(e, span));
365 }
366 };
367
368 let forms = match tatara_lisp::read_spanned(&source) {
370 Ok(f) => f,
371 Err(e) => {
372 self.modules.abort_load(path);
373 return Err(EvalError::Reader(e));
374 }
375 };
376
377 let saved_globals = std::mem::replace(&mut self.globals, Env::new());
381 for (name, value) in saved_globals.iter_top_level() {
385 if matches!(value, Value::NativeFn(_) | Value::Closure(_)) {
389 self.globals.define(name.clone(), value.clone());
390 }
391 }
392 let saved_current = self.current_module.replace(Arc::from(path));
393
394 let mut eval_err: Option<EvalError> = None;
396 for f in &forms {
397 if let Err(e) = self.eval_top_form(f, host) {
401 eval_err = Some(e);
402 break;
403 }
404 }
405
406 let module_globals = std::mem::replace(&mut self.globals, saved_globals);
408 self.current_module = saved_current;
409
410 if let Some(e) = eval_err {
411 self.modules.abort_load(path);
412 return Err(e);
413 }
414
415 let mut module = Module::new(path);
418 for (name, value) in module_globals.iter_top_level() {
419 if !matches!(value, Value::NativeFn(_)) {
422 module.define(name.clone(), value.clone());
423 }
424 }
425 let staged = {
427 let mut g = self.modules.inner_lock();
428 g.exports_staging
429 .remove(path)
430 .unwrap_or_default()
431 };
432 for n in staged {
433 module.add_export(n);
434 }
435 self.modules.finish_load(module);
436 Ok(())
437 }
438
439 pub fn fully_expand(&mut self, form: &Spanned, host: &mut H) -> Result<Spanned> {
450 if self.expander.is_empty() {
452 return Ok(form.clone());
453 }
454 self.expand_recursive(form, host)
455 }
456
457 fn expand_recursive(&mut self, form: &Spanned, host: &mut H) -> Result<Spanned> {
458 match &form.form {
459 SpannedForm::List(items) if !items.is_empty() => {
460 if let Some(head) = items[0].as_symbol() {
461 if self.expander.has(head) {
462 let expanded =
466 self.expand_macro_call(head, &items[1..], form.span, host)?;
467 return self.expand_recursive(&expanded, host);
468 }
469 }
470 let mut out = Vec::with_capacity(items.len());
473 for child in items {
474 out.push(self.expand_recursive(child, host)?);
475 }
476 Ok(Spanned::new(form.span, SpannedForm::List(out)))
477 }
478 SpannedForm::Quote(_) => {
479 Ok(form.clone())
481 }
482 SpannedForm::Quasiquote(inner) => {
483 Ok(Spanned::new(
485 form.span,
486 SpannedForm::Quasiquote(Box::new(self.expand_inside_quasiquote(inner, host)?)),
487 ))
488 }
489 _ => Ok(form.clone()),
491 }
492 }
493
494 fn expand_inside_quasiquote(&mut self, form: &Spanned, host: &mut H) -> Result<Spanned> {
495 match &form.form {
496 SpannedForm::Unquote(inner) => Ok(Spanned::new(
497 form.span,
498 SpannedForm::Unquote(Box::new(self.expand_recursive(inner, host)?)),
499 )),
500 SpannedForm::UnquoteSplice(inner) => Ok(Spanned::new(
501 form.span,
502 SpannedForm::UnquoteSplice(Box::new(self.expand_recursive(inner, host)?)),
503 )),
504 SpannedForm::List(items) => {
505 let mut out = Vec::with_capacity(items.len());
506 for item in items {
507 out.push(self.expand_inside_quasiquote(item, host)?);
508 }
509 Ok(Spanned::new(form.span, SpannedForm::List(out)))
510 }
511 _ => Ok(form.clone()),
512 }
513 }
514
515 fn expand_macro_call(
519 &mut self,
520 macro_name: &str,
521 args: &[Spanned],
522 call_span: Span,
523 host: &mut H,
524 ) -> Result<Spanned> {
525 let def: MacroDef = self
528 .expander
529 .get_macro(macro_name)
530 .cloned()
531 .ok_or_else(|| {
532 EvalError::native_fn(
533 Arc::<str>::from(macro_name),
534 "macro disappeared during expansion",
535 call_span,
536 )
537 })?;
538
539 let body_spanned = Spanned::from_sexp_at(&def.body, call_span);
544
545 let body_expanded = self.fully_expand(&body_spanned, host)?;
551
552 let mut macro_env = self.globals.clone();
555 macro_env.push();
556 bind_macro_args(&mut macro_env, &def.name, &def.params, args, call_span)?;
557
558 let result = eval_in(
561 &mut macro_env,
562 &self.registry,
563 &self.expander,
564 &body_expanded,
565 host,
566 )?;
567
568 value_to_spanned(&result, call_span).map_err(|reason| {
572 EvalError::native_fn(
573 Arc::<str>::from(format!("macro {macro_name}")),
574 reason,
575 call_span,
576 )
577 })
578 }
579
580 pub fn expander(&self) -> &SpannedExpander {
583 &self.expander
584 }
585
586 pub fn expander_mut(&mut self) -> &mut SpannedExpander {
590 &mut self.expander
591 }
592
593 pub fn lookup_global(&self, name: &str) -> Option<Value> {
595 self.globals.lookup(name)
596 }
597
598 pub fn define_global(&mut self, name: impl Into<Arc<str>>, value: Value) {
600 self.globals.define(name, value);
601 }
602
603 pub fn globals_snapshot(&self) -> &Env {
606 &self.globals
607 }
608
609 pub fn apply_external_value(
613 &mut self,
614 callee: &Value,
615 args: Vec<Value>,
616 host: &mut H,
617 call_span: Span,
618 ) -> Result<Value> {
619 apply_external(callee, args, call_span, &self.registry, &self.expander, host)
620 }
621
622 pub fn eval_program_vm(&mut self, forms: &[Spanned], host: &mut H) -> Result<Value> {
629 let mut expanded: Vec<Spanned> = Vec::with_capacity(forms.len());
630 for form in forms {
631 if self.expander.try_register_macro(form)? {
632 continue;
633 }
634 expanded.push(self.fully_expand(form, host)?);
635 }
636 let chunk = crate::vm::compile_program(&expanded).map_err(|e| match e {
637 crate::vm::CompileError::Bad { at, message } => {
638 EvalError::bad_form(Arc::<str>::from("vm:compile"), message, at)
639 }
640 })?;
641 let mut vm = crate::vm::Vm::new();
642 vm.run(&chunk, self, host).map_err(|e| match e {
643 crate::vm::VmError::Eval(inner) => inner,
644 other => EvalError::native_fn(Arc::<str>::from("vm"), format!("{other}"), Span::synthetic()),
645 })
646 }
647
648 pub fn register_typed0<R, F>(&mut self, name: impl Into<Arc<str>>, f: F)
652 where
653 R: IntoValue + 'static,
654 F: Fn(&mut H) -> Result<R> + Send + Sync + 'static,
655 {
656 self.register_fn(
657 name,
658 Arity::Exact(0),
659 move |_args: &[Value], host: &mut H, _sp| f(host).map(IntoValue::into_value),
660 );
661 }
662
663 pub fn register_typed1<A, R, F>(&mut self, name: impl Into<Arc<str>>, f: F)
665 where
666 A: FromValue + 'static,
667 R: IntoValue + 'static,
668 F: Fn(&mut H, A) -> Result<R> + Send + Sync + 'static,
669 {
670 self.register_fn(
671 name,
672 Arity::Exact(1),
673 move |args: &[Value], host: &mut H, sp| {
674 let a = A::from_value(&args[0], sp)?;
675 f(host, a).map(IntoValue::into_value)
676 },
677 );
678 }
679
680 pub fn register_typed2<A, B, R, F>(&mut self, name: impl Into<Arc<str>>, f: F)
682 where
683 A: FromValue + 'static,
684 B: FromValue + 'static,
685 R: IntoValue + 'static,
686 F: Fn(&mut H, A, B) -> Result<R> + Send + Sync + 'static,
687 {
688 self.register_fn(
689 name,
690 Arity::Exact(2),
691 move |args: &[Value], host: &mut H, sp| {
692 let a = A::from_value(&args[0], sp)?;
693 let b = B::from_value(&args[1], sp)?;
694 f(host, a, b).map(IntoValue::into_value)
695 },
696 );
697 }
698
699 pub fn register_typed3<A, B, C, R, F>(&mut self, name: impl Into<Arc<str>>, f: F)
701 where
702 A: FromValue + 'static,
703 B: FromValue + 'static,
704 C: FromValue + 'static,
705 R: IntoValue + 'static,
706 F: Fn(&mut H, A, B, C) -> Result<R> + Send + Sync + 'static,
707 {
708 self.register_fn(
709 name,
710 Arity::Exact(3),
711 move |args: &[Value], host: &mut H, sp| {
712 let a = A::from_value(&args[0], sp)?;
713 let b = B::from_value(&args[1], sp)?;
714 let c = C::from_value(&args[2], sp)?;
715 f(host, a, b, c).map(IntoValue::into_value)
716 },
717 );
718 }
719
720 pub fn register_typed4<A, B, C, D, R, F>(&mut self, name: impl Into<Arc<str>>, f: F)
722 where
723 A: FromValue + 'static,
724 B: FromValue + 'static,
725 C: FromValue + 'static,
726 D: FromValue + 'static,
727 R: IntoValue + 'static,
728 F: Fn(&mut H, A, B, C, D) -> Result<R> + Send + Sync + 'static,
729 {
730 self.register_fn(
731 name,
732 Arity::Exact(4),
733 move |args: &[Value], host: &mut H, sp| {
734 let a = A::from_value(&args[0], sp)?;
735 let b = B::from_value(&args[1], sp)?;
736 let c = C::from_value(&args[2], sp)?;
737 let d = D::from_value(&args[3], sp)?;
738 f(host, a, b, c, d).map(IntoValue::into_value)
739 },
740 );
741 }
742}
743
744impl<H: 'static> Default for Interpreter<H> {
745 fn default() -> Self {
746 Self::new()
747 }
748}
749
750pub(crate) fn eval_in<H: 'static>(
755 env: &mut Env,
756 registry: &FnRegistry<H>,
757 expander: &SpannedExpander,
758 form: &Spanned,
759 host: &mut H,
760) -> Result<Value> {
761 match &form.form {
762 SpannedForm::Nil => Ok(Value::Nil),
763 SpannedForm::Atom(a) => eval_atom(a, form.span, env),
764 SpannedForm::Quote(inner) => Ok(quoted_value(inner)),
765 SpannedForm::Quasiquote(inner) => quasiquote_eval(inner, env, registry, expander, host),
766 SpannedForm::Unquote(_) | SpannedForm::UnquoteSplice(_) => Err(EvalError::bad_form(
767 "unquote",
768 "unquote outside of quasiquote",
769 form.span,
770 )),
771 SpannedForm::List(items) => {
772 if items.is_empty() {
773 return Ok(Value::Nil);
774 }
775 if let Some(head_sym) = items[0].as_symbol() {
779 if let Some(sf) = SpecialForm::from_symbol(head_sym) {
780 return eval_special(sf, items, form.span, env, registry, expander, host);
781 }
782 }
783 eval_application(items, form.span, env, registry, expander, host)
784 }
785 }
786}
787
788fn eval_atom(a: &Atom, span: Span, env: &Env) -> Result<Value> {
789 match a {
790 Atom::Symbol(name) => env
791 .lookup(name)
792 .ok_or_else(|| EvalError::unbound(name.as_str(), span)),
793 Atom::Keyword(s) => Ok(Value::Keyword(crate::interner::intern(s.as_str()))),
794 Atom::Str(s) => Ok(Value::Str(Arc::from(s.as_str()))),
795 Atom::Int(n) => Ok(Value::Int(*n)),
796 Atom::Float(n) => Ok(Value::Float(*n)),
797 Atom::Bool(b) => Ok(Value::Bool(*b)),
798 }
799}
800
801fn quoted_value(inner: &Spanned) -> Value {
805 crate::code::spanned_to_value(inner)
806}
807
808fn quasiquote_eval<H: 'static>(
814 form: &Spanned,
815 env: &mut Env,
816 registry: &FnRegistry<H>,
817 expander: &SpannedExpander,
818 host: &mut H,
819) -> Result<Value> {
820 match &form.form {
821 SpannedForm::Unquote(inner) => eval_in(env, registry, expander, inner, host),
822 SpannedForm::UnquoteSplice(_) => Err(EvalError::bad_form(
823 "unquote-splice",
824 "`,@` only valid directly inside a list",
825 form.span,
826 )),
827 SpannedForm::List(items) => {
828 let mut out: Vec<Value> = Vec::with_capacity(items.len());
829 for item in items {
830 if let SpannedForm::UnquoteSplice(inner) = &item.form {
831 let v = eval_in(env, registry, expander, inner, host)?;
832 match v {
833 Value::List(xs) => out.extend(xs.iter().cloned()),
834 Value::Nil => {}
835 other => {
836 return Err(EvalError::type_mismatch(
837 "list",
838 other.type_name(),
839 item.span,
840 ))
841 }
842 }
843 } else {
844 out.push(quasiquote_eval(item, env, registry, expander, host)?);
845 }
846 }
847 if out.is_empty() {
848 Ok(Value::Nil)
849 } else {
850 Ok(Value::list(out))
851 }
852 }
853 SpannedForm::Nil => Ok(Value::Nil),
854 SpannedForm::Atom(a) => Ok(match a {
855 Atom::Symbol(s) => Value::Symbol(crate::interner::intern(s.as_str())),
856 Atom::Keyword(s) => Value::Keyword(crate::interner::intern(s.as_str())),
857 Atom::Str(s) => Value::Str(Arc::from(s.as_str())),
858 Atom::Int(n) => Value::Int(*n),
859 Atom::Float(n) => Value::Float(*n),
860 Atom::Bool(b) => Value::Bool(*b),
861 }),
862 SpannedForm::Quote(_) | SpannedForm::Quasiquote(_) => {
866 Ok(Value::Sexp(form.to_sexp(), form.span))
867 }
868 }
869}
870
871fn eval_application<H: 'static>(
874 items: &[Spanned],
875 call_span: Span,
876 env: &mut Env,
877 registry: &FnRegistry<H>,
878 expander: &SpannedExpander,
879 host: &mut H,
880) -> Result<Value> {
881 let head_val = eval_in(env, registry, expander, &items[0], host)?;
882 let mut args: Vec<Value> = Vec::with_capacity(items.len().saturating_sub(1));
883 for arg_form in &items[1..] {
884 args.push(eval_in(env, registry, expander, arg_form, host)?);
885 }
886 apply(&head_val, args, call_span, registry, expander, host)
887}
888
889fn apply<H: 'static>(
890 callee: &Value,
891 args: Vec<Value>,
892 call_span: Span,
893 registry: &FnRegistry<H>,
894 expander: &SpannedExpander,
895 host: &mut H,
896) -> Result<Value> {
897 match callee {
898 Value::NativeFn(nfn) => {
899 if nfn.arity.check(args.len()).is_err() {
900 return Err(EvalError::ArityMismatch {
901 fn_name: nfn.name.clone(),
902 expected: nfn.arity,
903 got: args.len(),
904 at: call_span,
905 });
906 }
907 let entry = registry.lookup(&nfn.name).ok_or_else(|| {
908 EvalError::native_fn(
909 nfn.name.clone(),
910 format!("native fn {} is not registered", nfn.name),
911 call_span,
912 )
913 })?;
914 match &entry.callable {
915 FnImpl::Native(f) => f.call(&args, host, call_span),
916 FnImpl::Higher(f) => {
917 let caller = Caller { registry, expander };
918 f.call(&args, host, &caller, call_span)
919 }
920 }
921 }
922 Value::Closure(c) => call_closure(c.clone(), args, call_span, registry, expander, host),
923 Value::Foreign(any) => {
928 if let Some(cc) = any
929 .clone()
930 .downcast::<crate::vm::run::CompiledClosure>()
931 .ok()
932 {
933 let lifted = cc.lift_to_closure();
934 return call_closure(lifted, args, call_span, registry, expander, host);
935 }
936 Err(EvalError::NotCallable {
937 value_kind: callee.type_name(),
938 at: call_span,
939 })
940 }
941 other => Err(EvalError::NotCallable {
942 value_kind: other.type_name(),
943 at: call_span,
944 }),
945 }
946}
947
948enum TailResult {
971 Done(Value),
973 Resume(Arc<Closure>, Vec<Value>, Span),
978}
979
980fn eval_in_tail<H: 'static>(
984 env: &mut Env,
985 registry: &FnRegistry<H>,
986 expander: &SpannedExpander,
987 form: &Spanned,
988 host: &mut H,
989) -> Result<TailResult> {
990 match &form.form {
991 SpannedForm::List(items) if !items.is_empty() => {
992 if let Some(head_sym) = items[0].as_symbol() {
994 if let Some(sf) = SpecialForm::from_symbol(head_sym) {
995 return eval_special_tail(sf, items, form.span, env, registry, expander, host);
996 }
997 }
998 let head_val = eval_in(env, registry, expander, &items[0], host)?;
1001 let mut args: Vec<Value> = Vec::with_capacity(items.len().saturating_sub(1));
1002 for arg_form in &items[1..] {
1003 args.push(eval_in(env, registry, expander, arg_form, host)?);
1004 }
1005 match head_val {
1006 Value::Closure(c) => Ok(TailResult::Resume(c, args, form.span)),
1007 _ => apply(&head_val, args, form.span, registry, expander, host)
1008 .map(TailResult::Done),
1009 }
1010 }
1011 _ => eval_in(env, registry, expander, form, host).map(TailResult::Done),
1013 }
1014}
1015
1016fn eval_special_tail<H: 'static>(
1017 sf: SpecialForm,
1018 items: &[Spanned],
1019 call_span: Span,
1020 env: &mut Env,
1021 registry: &FnRegistry<H>,
1022 expander: &SpannedExpander,
1023 host: &mut H,
1024) -> Result<TailResult> {
1025 match sf {
1026 SpecialForm::If => {
1027 if items.len() < 3 || items.len() > 4 {
1028 return eval_special(sf, items, call_span, env, registry, expander, host)
1029 .map(TailResult::Done);
1030 }
1031 let c = eval_in(env, registry, expander, &items[1], host)?;
1032 if c.is_truthy() {
1033 eval_in_tail(env, registry, expander, &items[2], host)
1034 } else if items.len() == 4 {
1035 eval_in_tail(env, registry, expander, &items[3], host)
1036 } else {
1037 Ok(TailResult::Done(Value::Nil))
1038 }
1039 }
1040 SpecialForm::Begin => {
1041 let body = &items[1..];
1042 if body.is_empty() {
1043 return Ok(TailResult::Done(Value::Nil));
1044 }
1045 for form in &body[..body.len() - 1] {
1046 eval_in(env, registry, expander, form, host)?;
1047 }
1048 eval_in_tail(env, registry, expander, body.last().unwrap(), host)
1049 }
1050 SpecialForm::When | SpecialForm::Unless => {
1051 if items.len() < 2 {
1052 return eval_special(sf, items, call_span, env, registry, expander, host)
1053 .map(TailResult::Done);
1054 }
1055 let invert = matches!(sf, SpecialForm::Unless);
1056 let cond = eval_in(env, registry, expander, &items[1], host)?;
1057 let run = cond.is_truthy() ^ invert;
1058 if !run {
1059 return Ok(TailResult::Done(Value::Nil));
1060 }
1061 let body = &items[2..];
1062 if body.is_empty() {
1063 return Ok(TailResult::Done(Value::Nil));
1064 }
1065 for form in &body[..body.len() - 1] {
1066 eval_in(env, registry, expander, form, host)?;
1067 }
1068 eval_in_tail(env, registry, expander, body.last().unwrap(), host)
1069 }
1070 SpecialForm::Cond => {
1071 for clause in &items[1..] {
1072 let Some(clause_list) = clause.as_list() else {
1073 return eval_special(sf, items, call_span, env, registry, expander, host)
1074 .map(TailResult::Done);
1075 };
1076 if clause_list.is_empty() {
1077 return eval_special(sf, items, call_span, env, registry, expander, host)
1078 .map(TailResult::Done);
1079 }
1080 let is_else = clause_list[0].as_symbol() == Some("else");
1081 let cond_matches = if is_else {
1082 true
1083 } else {
1084 eval_in(env, registry, expander, &clause_list[0], host)?.is_truthy()
1085 };
1086 if cond_matches {
1087 let body = &clause_list[1..];
1088 if body.is_empty() {
1089 return Ok(TailResult::Done(Value::Nil));
1090 }
1091 for form in &body[..body.len() - 1] {
1092 eval_in(env, registry, expander, form, host)?;
1093 }
1094 return eval_in_tail(env, registry, expander, body.last().unwrap(), host);
1095 }
1096 }
1097 Ok(TailResult::Done(Value::Nil))
1098 }
1099 SpecialForm::Let | SpecialForm::LetStar | SpecialForm::LetRec => {
1100 eval_let_family_tail(sf, items, call_span, env, registry, expander, host)
1101 }
1102 SpecialForm::And => {
1103 let exprs = &items[1..];
1104 if exprs.is_empty() {
1105 return Ok(TailResult::Done(Value::Bool(true)));
1106 }
1107 for e in &exprs[..exprs.len() - 1] {
1109 let v = eval_in(env, registry, expander, e, host)?;
1110 if !v.is_truthy() {
1111 return Ok(TailResult::Done(v));
1112 }
1113 }
1114 eval_in_tail(env, registry, expander, exprs.last().unwrap(), host)
1116 }
1117 SpecialForm::Or => {
1118 let exprs = &items[1..];
1119 if exprs.is_empty() {
1120 return Ok(TailResult::Done(Value::Bool(false)));
1121 }
1122 for e in &exprs[..exprs.len() - 1] {
1123 let v = eval_in(env, registry, expander, e, host)?;
1124 if v.is_truthy() {
1125 return Ok(TailResult::Done(v));
1126 }
1127 }
1128 eval_in_tail(env, registry, expander, exprs.last().unwrap(), host)
1129 }
1130 SpecialForm::Try => {
1131 sf_try(items, call_span, env, registry, expander, host).map(TailResult::Done)
1137 }
1138 SpecialForm::MacroexpandOne => {
1139 sf_macroexpand(items, call_span, env, registry, expander, host, false)
1140 .map(TailResult::Done)
1141 }
1142 SpecialForm::MacroexpandAll => {
1143 sf_macroexpand(items, call_span, env, registry, expander, host, true)
1144 .map(TailResult::Done)
1145 }
1146 SpecialForm::Delay => sf_delay(items, call_span, env).map(TailResult::Done),
1147 SpecialForm::Eval => {
1148 sf_eval(items, call_span, env, registry, expander, host).map(TailResult::Done)
1149 }
1150 _ => {
1152 eval_special(sf, items, call_span, env, registry, expander, host).map(TailResult::Done)
1153 }
1154 }
1155}
1156
1157fn eval_let_family_tail<H: 'static>(
1161 sf: SpecialForm,
1162 items: &[Spanned],
1163 call_span: Span,
1164 env: &mut Env,
1165 registry: &FnRegistry<H>,
1166 expander: &SpannedExpander,
1167 host: &mut H,
1168) -> Result<TailResult> {
1169 if items.len() < 3 {
1170 return Err(EvalError::bad_form(
1171 match sf {
1172 SpecialForm::Let => "let",
1173 SpecialForm::LetStar => "let*",
1174 SpecialForm::LetRec => "letrec",
1175 _ => "let-family",
1176 },
1177 "expected ((name expr)...) body...",
1178 call_span,
1179 ));
1180 }
1181 let bindings = parse_binding_list(
1182 &items[1],
1183 match sf {
1184 SpecialForm::Let => "let",
1185 SpecialForm::LetStar => "let*",
1186 SpecialForm::LetRec => "letrec",
1187 _ => "let-family",
1188 },
1189 )?;
1190
1191 match sf {
1192 SpecialForm::Let => {
1193 let mut values = Vec::with_capacity(bindings.len());
1194 for (_, expr) in &bindings {
1195 values.push(eval_in(env, registry, expander, expr, host)?);
1196 }
1197 env.push();
1198 for ((name, _), val) in bindings.into_iter().zip(values) {
1199 env.define(name, val);
1200 }
1201 }
1202 SpecialForm::LetStar => {
1203 env.push();
1204 for (name, expr) in bindings {
1205 let v = eval_in(env, registry, expander, expr, host)?;
1206 env.define(name, v);
1207 }
1208 }
1209 SpecialForm::LetRec => {
1210 env.push();
1211 for (name, _) in &bindings {
1212 env.define(name.clone(), Value::Nil);
1213 }
1214 for (name, expr) in &bindings {
1215 let v = eval_in(env, registry, expander, expr, host)?;
1216 env.define(name.clone(), v);
1217 }
1218 }
1219 _ => unreachable!(),
1220 }
1221
1222 let body = &items[2..];
1223 let result = if body.is_empty() {
1224 Ok(TailResult::Done(Value::Nil))
1225 } else {
1226 for form in &body[..body.len() - 1] {
1227 if let Err(e) = eval_in(env, registry, expander, form, host) {
1228 env.pop();
1229 return Err(e);
1230 }
1231 }
1232 eval_in_tail(env, registry, expander, body.last().unwrap(), host)
1233 };
1234 env.pop();
1235 result
1236}
1237
1238pub(crate) fn apply_external<H: 'static>(
1244 callee: &Value,
1245 args: Vec<Value>,
1246 call_span: Span,
1247 registry: &FnRegistry<H>,
1248 expander: &SpannedExpander,
1249 host: &mut H,
1250) -> Result<Value> {
1251 apply(callee, args, call_span, registry, expander, host)
1252}
1253
1254fn bind_macro_args(
1263 env: &mut Env,
1264 macro_name: &str,
1265 params: &MacroParams,
1266 args: &[Spanned],
1267 call_span: Span,
1268) -> Result<()> {
1269 let bound = params
1270 .bind_carrier(macro_name, args, call_span)
1271 .map_err(|e| {
1272 EvalError::native_fn(
1273 Arc::<str>::from(format!("macro {macro_name}")),
1274 e.to_string(),
1275 call_span,
1276 )
1277 })?;
1278 for (name, value) in params.names().into_iter().zip(bound.iter()) {
1279 env.define(Arc::<str>::from(name), spanned_to_value(value));
1280 }
1281 Ok(())
1282}
1283
1284fn call_closure<H: 'static>(
1289 closure: Arc<Closure>,
1290 args: Vec<Value>,
1291 call_span: Span,
1292 registry: &FnRegistry<H>,
1293 expander: &SpannedExpander,
1294 host: &mut H,
1295) -> Result<Value> {
1296 let mut current = closure;
1297 let mut current_args = args;
1298 let mut current_span = call_span;
1299 loop {
1300 let required = current.params.len();
1302 let has_rest = current.rest.is_some();
1303 if !has_rest && current_args.len() != required {
1304 return Err(EvalError::ArityMismatch {
1305 fn_name: Arc::from("<closure>"),
1306 expected: Arity::Exact(required),
1307 got: current_args.len(),
1308 at: current_span,
1309 });
1310 }
1311 if has_rest && current_args.len() < required {
1312 return Err(EvalError::ArityMismatch {
1313 fn_name: Arc::from("<closure>"),
1314 expected: Arity::AtLeast(required),
1315 got: current_args.len(),
1316 at: current_span,
1317 });
1318 }
1319
1320 let mut env = current.captured_env.clone();
1323 env.push();
1324 for (param, arg) in current.params.iter().zip(current_args.iter()) {
1325 env.define(param.clone(), arg.clone());
1326 }
1327 if let Some(rest_name) = ¤t.rest {
1328 let rest_args: Vec<Value> = current_args.iter().skip(required).cloned().collect();
1329 env.define(rest_name.clone(), Value::list(rest_args));
1330 }
1331
1332 let body = ¤t.body;
1335 if body.is_empty() {
1336 return Ok(Value::Nil);
1337 }
1338 for body_form in &body[..body.len() - 1] {
1339 eval_in(&mut env, registry, expander, body_form, host)?;
1340 }
1341 match eval_in_tail(&mut env, registry, expander, body.last().unwrap(), host)? {
1342 TailResult::Done(v) => return Ok(v),
1343 TailResult::Resume(next, next_args, next_span) => {
1344 current = next;
1347 current_args = next_args;
1348 current_span = next_span;
1349 }
1350 }
1351 }
1352}
1353
1354fn eval_special<H: 'static>(
1357 sf: SpecialForm,
1358 items: &[Spanned],
1359 call_span: Span,
1360 env: &mut Env,
1361 registry: &FnRegistry<H>,
1362 expander: &SpannedExpander,
1363 host: &mut H,
1364) -> Result<Value> {
1365 match sf {
1366 SpecialForm::Quote => sf_quote(items, call_span),
1367 SpecialForm::Quasiquote => {
1368 if items.len() != 2 {
1369 return Err(EvalError::bad_form(
1370 "quasiquote",
1371 format!("expected 1 arg, got {}", items.len() - 1),
1372 call_span,
1373 ));
1374 }
1375 quasiquote_eval(&items[1], env, registry, expander, host)
1376 }
1377 SpecialForm::If => sf_if(items, call_span, env, registry, expander, host),
1378 SpecialForm::Cond => sf_cond(items, call_span, env, registry, expander, host),
1379 SpecialForm::When => sf_when_unless(items, call_span, env, registry, expander, host, false),
1380 SpecialForm::Unless => {
1381 sf_when_unless(items, call_span, env, registry, expander, host, true)
1382 }
1383 SpecialForm::Let => sf_let(items, call_span, env, registry, expander, host),
1384 SpecialForm::LetStar => sf_let_star(items, call_span, env, registry, expander, host),
1385 SpecialForm::LetRec => sf_letrec(items, call_span, env, registry, expander, host),
1386 SpecialForm::Lambda => sf_lambda(items, call_span, env),
1387 SpecialForm::Define => sf_define(items, call_span, env, registry, expander, host),
1388 SpecialForm::Set => sf_set(items, call_span, env, registry, expander, host),
1389 SpecialForm::Begin => sf_begin(&items[1..], env, registry, expander, host),
1390 SpecialForm::And => sf_and(&items[1..], env, registry, expander, host),
1391 SpecialForm::Or => sf_or(&items[1..], env, registry, expander, host),
1392 SpecialForm::Not => sf_not(items, call_span, env, registry, expander, host),
1393 SpecialForm::Try => sf_try(items, call_span, env, registry, expander, host),
1394 SpecialForm::MacroexpandOne => {
1395 sf_macroexpand(items, call_span, env, registry, expander, host, false)
1396 }
1397 SpecialForm::MacroexpandAll => {
1398 sf_macroexpand(items, call_span, env, registry, expander, host, true)
1399 }
1400 SpecialForm::Delay => sf_delay(items, call_span, env),
1401 SpecialForm::Eval => sf_eval(items, call_span, env, registry, expander, host),
1402 SpecialForm::Provide | SpecialForm::Require => Err(EvalError::bad_form(
1403 if matches!(sf, SpecialForm::Provide) { "provide" } else { "require" },
1404 "module-system forms are only valid at top level — wrap your call in (eval (quote ...)) if you really need it dynamic",
1405 call_span,
1406 )),
1407 }
1408}
1409
1410fn head_symbol(form: &Spanned) -> Option<&str> {
1414 let SpannedForm::List(items) = &form.form else {
1415 return None;
1416 };
1417 items.first().and_then(Spanned::as_symbol)
1418}
1419
1420fn error_value(tag: &str, message: &str) -> Value {
1422 Value::Error(Arc::new(ErrorObj {
1423 tag: Arc::from(tag),
1424 message: Arc::from(message),
1425 data: Vec::new(),
1426 }))
1427}
1428
1429fn module_error_to_eval(e: ModuleError, span: Span) -> EvalError {
1433 let (tag, message) = match &e {
1434 ModuleError::NotFound(_) => ("module-not-found", e.to_string()),
1435 ModuleError::Circular { .. } => ("circular-require", e.to_string()),
1436 ModuleError::NotExported(_, _) => ("not-exported", e.to_string()),
1437 };
1438 EvalError::User {
1439 value: error_value(tag, &message),
1440 at: span,
1441 }
1442}
1443
1444fn sf_quote(items: &[Spanned], span: Span) -> Result<Value> {
1445 if items.len() != 2 {
1446 return Err(EvalError::bad_form(
1447 "quote",
1448 format!("expected 1 arg, got {}", items.len() - 1),
1449 span,
1450 ));
1451 }
1452 Ok(crate::code::spanned_to_value(&items[1]))
1458}
1459
1460fn sf_if<H: 'static>(
1461 items: &[Spanned],
1462 span: Span,
1463 env: &mut Env,
1464 registry: &FnRegistry<H>,
1465 expander: &SpannedExpander,
1466 host: &mut H,
1467) -> Result<Value> {
1468 if items.len() < 3 || items.len() > 4 {
1469 return Err(EvalError::bad_form(
1470 "if",
1471 format!("expected (if c t [e]), got {} subforms", items.len()),
1472 span,
1473 ));
1474 }
1475 let c = eval_in(env, registry, expander, &items[1], host)?;
1476 if c.is_truthy() {
1477 eval_in(env, registry, expander, &items[2], host)
1478 } else if items.len() == 4 {
1479 eval_in(env, registry, expander, &items[3], host)
1480 } else {
1481 Ok(Value::Nil)
1482 }
1483}
1484
1485fn sf_cond<H: 'static>(
1486 items: &[Spanned],
1487 span: Span,
1488 env: &mut Env,
1489 registry: &FnRegistry<H>,
1490 expander: &SpannedExpander,
1491 host: &mut H,
1492) -> Result<Value> {
1493 for clause in &items[1..] {
1494 let Some(clause_list) = clause.as_list() else {
1495 return Err(EvalError::bad_form(
1496 "cond",
1497 "clause must be a list",
1498 clause.span,
1499 ));
1500 };
1501 if clause_list.is_empty() {
1502 return Err(EvalError::bad_form("cond", "empty clause", clause.span));
1503 }
1504 let is_else = clause_list[0].as_symbol() == Some("else");
1505 let cond_matches = if is_else {
1506 true
1507 } else {
1508 let v = eval_in(env, registry, expander, &clause_list[0], host)?;
1509 v.is_truthy()
1510 };
1511 if cond_matches {
1512 let mut last = Value::Nil;
1513 for expr in &clause_list[1..] {
1514 last = eval_in(env, registry, expander, expr, host)?;
1515 }
1516 return Ok(last);
1517 }
1518 }
1519 let _ = span;
1521 Ok(Value::Nil)
1522}
1523
1524fn sf_when_unless<H: 'static>(
1525 items: &[Spanned],
1526 span: Span,
1527 env: &mut Env,
1528 registry: &FnRegistry<H>,
1529 expander: &SpannedExpander,
1530 host: &mut H,
1531 invert: bool,
1532) -> Result<Value> {
1533 if items.len() < 2 {
1534 return Err(EvalError::bad_form(
1535 if invert { "unless" } else { "when" },
1536 "need a test",
1537 span,
1538 ));
1539 }
1540 let cond = eval_in(env, registry, expander, &items[1], host)?;
1541 let run = cond.is_truthy() ^ invert;
1542 if run {
1543 let mut last = Value::Nil;
1544 for expr in &items[2..] {
1545 last = eval_in(env, registry, expander, expr, host)?;
1546 }
1547 Ok(last)
1548 } else {
1549 Ok(Value::Nil)
1550 }
1551}
1552
1553fn parse_binding_list<'a>(
1555 list: &'a Spanned,
1556 form_name: &'static str,
1557) -> Result<Vec<(Arc<str>, &'a Spanned)>> {
1558 let bindings = list
1559 .as_list()
1560 .ok_or_else(|| EvalError::bad_form(form_name, "bindings must be a list", list.span))?;
1561 let mut out = Vec::with_capacity(bindings.len());
1562 for binding in bindings {
1563 let pair = binding.as_list().ok_or_else(|| {
1564 EvalError::bad_form(form_name, "each binding must be (name expr)", binding.span)
1565 })?;
1566 if pair.len() != 2 {
1567 return Err(EvalError::bad_form(
1568 form_name,
1569 "binding must be exactly (name expr)",
1570 binding.span,
1571 ));
1572 }
1573 let name = pair[0].as_symbol().ok_or_else(|| {
1574 EvalError::bad_form(form_name, "binding name must be a symbol", pair[0].span)
1575 })?;
1576 out.push((Arc::<str>::from(name), &pair[1]));
1577 }
1578 Ok(out)
1579}
1580
1581fn sf_let<H: 'static>(
1582 items: &[Spanned],
1583 span: Span,
1584 env: &mut Env,
1585 registry: &FnRegistry<H>,
1586 expander: &SpannedExpander,
1587 host: &mut H,
1588) -> Result<Value> {
1589 if items.len() < 3 {
1590 return Err(EvalError::bad_form(
1591 "let",
1592 "expected (let ((name expr)...) body...)",
1593 span,
1594 ));
1595 }
1596 let bindings = parse_binding_list(&items[1], "let")?;
1597 let mut values = Vec::with_capacity(bindings.len());
1600 for (_, expr) in &bindings {
1601 values.push(eval_in(env, registry, expander, expr, host)?);
1602 }
1603 env.push();
1604 for ((name, _), val) in bindings.into_iter().zip(values) {
1605 env.define(name, val);
1606 }
1607 let result = eval_body(&items[2..], env, registry, expander, host);
1608 env.pop();
1609 result
1610}
1611
1612fn sf_let_star<H: 'static>(
1613 items: &[Spanned],
1614 span: Span,
1615 env: &mut Env,
1616 registry: &FnRegistry<H>,
1617 expander: &SpannedExpander,
1618 host: &mut H,
1619) -> Result<Value> {
1620 if items.len() < 3 {
1621 return Err(EvalError::bad_form(
1622 "let*",
1623 "expected (let* ((name expr)...) body...)",
1624 span,
1625 ));
1626 }
1627 let bindings = parse_binding_list(&items[1], "let*")?;
1628 env.push();
1629 for (name, expr) in bindings {
1630 let v = eval_in(env, registry, expander, expr, host)?;
1631 env.define(name, v);
1632 }
1633 let result = eval_body(&items[2..], env, registry, expander, host);
1634 env.pop();
1635 result
1636}
1637
1638fn sf_letrec<H: 'static>(
1639 items: &[Spanned],
1640 span: Span,
1641 env: &mut Env,
1642 registry: &FnRegistry<H>,
1643 expander: &SpannedExpander,
1644 host: &mut H,
1645) -> Result<Value> {
1646 if items.len() < 3 {
1647 return Err(EvalError::bad_form(
1648 "letrec",
1649 "expected (letrec ((name expr)...) body...)",
1650 span,
1651 ));
1652 }
1653 let bindings = parse_binding_list(&items[1], "letrec")?;
1654 env.push();
1655 for (name, _) in &bindings {
1658 env.define(name.clone(), Value::Nil);
1659 }
1660 for (name, expr) in &bindings {
1661 let v = eval_in(env, registry, expander, expr, host)?;
1662 env.define(name.clone(), v);
1663 }
1664 let result = eval_body(&items[2..], env, registry, expander, host);
1665 env.pop();
1666 result
1667}
1668
1669fn eval_body<H: 'static>(
1670 body: &[Spanned],
1671 env: &mut Env,
1672 registry: &FnRegistry<H>,
1673 expander: &SpannedExpander,
1674 host: &mut H,
1675) -> Result<Value> {
1676 let mut last = Value::Nil;
1677 for form in body {
1678 last = eval_in(env, registry, expander, form, host)?;
1679 }
1680 Ok(last)
1681}
1682
1683fn sf_lambda(items: &[Spanned], span: Span, env: &Env) -> Result<Value> {
1684 if items.len() < 3 {
1685 return Err(EvalError::bad_form(
1686 "lambda",
1687 "expected (lambda (params...) body...)",
1688 span,
1689 ));
1690 }
1691 let param_list: &[Spanned] = match &items[1].form {
1694 SpannedForm::Nil => &[],
1695 SpannedForm::List(xs) => xs.as_slice(),
1696 _ => {
1697 return Err(EvalError::bad_form(
1698 "lambda",
1699 "params must be a list",
1700 items[1].span,
1701 ))
1702 }
1703 };
1704 let (params, rest) = parse_lambda_params(param_list, items[1].span)?;
1705 let body = items[2..].to_vec();
1706 Ok(Value::Closure(Arc::new(Closure {
1707 params,
1708 rest,
1709 body,
1710 captured_env: env.clone(),
1711 source: span,
1712 })))
1713}
1714
1715fn parse_lambda_params(list: &[Spanned], span: Span) -> Result<(Vec<Arc<str>>, Option<Arc<str>>)> {
1716 let mut params = Vec::new();
1717 let mut rest = None;
1718 let mut i = 0;
1719 while i < list.len() {
1720 let s = list[i]
1721 .as_symbol()
1722 .ok_or_else(|| EvalError::bad_form("lambda", "param must be a symbol", list[i].span))?;
1723 if s == "&rest" {
1724 let name = list
1725 .get(i + 1)
1726 .and_then(Spanned::as_symbol)
1727 .ok_or_else(|| EvalError::bad_form("lambda", "&rest needs a name", span))?;
1728 rest = Some(Arc::<str>::from(name));
1729 if i + 2 != list.len() {
1730 return Err(EvalError::bad_form(
1731 "lambda",
1732 "&rest must be the last param",
1733 span,
1734 ));
1735 }
1736 break;
1737 }
1738 params.push(Arc::<str>::from(s));
1739 i += 1;
1740 }
1741 Ok((params, rest))
1742}
1743
1744fn sf_define<H: 'static>(
1746 items: &[Spanned],
1747 span: Span,
1748 env: &mut Env,
1749 registry: &FnRegistry<H>,
1750 expander: &SpannedExpander,
1751 host: &mut H,
1752) -> Result<Value> {
1753 if items.len() < 3 {
1754 return Err(EvalError::bad_form(
1755 "define",
1756 "expected (define name expr) or (define (name args) body)",
1757 span,
1758 ));
1759 }
1760 match &items[1].form {
1761 SpannedForm::Atom(Atom::Symbol(name)) => {
1762 let v = eval_in(env, registry, expander, &items[2], host)?;
1763 env.define(Arc::<str>::from(name.as_str()), v);
1764 Ok(Value::Nil)
1765 }
1766 SpannedForm::List(head_list) => {
1767 if head_list.is_empty() {
1768 return Err(EvalError::bad_form(
1769 "define",
1770 "empty (name args) list",
1771 items[1].span,
1772 ));
1773 }
1774 let name = head_list[0].as_symbol().ok_or_else(|| {
1775 EvalError::bad_form(
1776 "define",
1777 "first item in (name args) must be a symbol",
1778 head_list[0].span,
1779 )
1780 })?;
1781 let (params, rest) = parse_lambda_params(&head_list[1..], items[1].span)?;
1782 let body = items[2..].to_vec();
1783 let closure = Arc::new(Closure {
1784 params,
1785 rest,
1786 body,
1787 captured_env: env.clone(),
1788 source: span,
1789 });
1790 env.define(Arc::<str>::from(name), Value::Closure(closure));
1791 Ok(Value::Nil)
1792 }
1793 _ => Err(EvalError::bad_form(
1794 "define",
1795 "second form must be a symbol or (name args) list",
1796 items[1].span,
1797 )),
1798 }
1799}
1800
1801fn sf_set<H: 'static>(
1802 items: &[Spanned],
1803 span: Span,
1804 env: &mut Env,
1805 registry: &FnRegistry<H>,
1806 expander: &SpannedExpander,
1807 host: &mut H,
1808) -> Result<Value> {
1809 if items.len() != 3 {
1810 return Err(EvalError::bad_form(
1811 "set!",
1812 "expected (set! name expr)",
1813 span,
1814 ));
1815 }
1816 let name = items[1]
1817 .as_symbol()
1818 .ok_or_else(|| EvalError::bad_form("set!", "first arg must be a symbol", items[1].span))?;
1819 let v = eval_in(env, registry, expander, &items[2], host)?;
1820 if env.set(name, v) {
1821 Ok(Value::Nil)
1822 } else {
1823 Err(EvalError::unbound(name, items[1].span))
1824 }
1825}
1826
1827fn sf_begin<H: 'static>(
1828 body: &[Spanned],
1829 env: &mut Env,
1830 registry: &FnRegistry<H>,
1831 expander: &SpannedExpander,
1832 host: &mut H,
1833) -> Result<Value> {
1834 eval_body(body, env, registry, expander, host)
1835}
1836
1837fn sf_and<H: 'static>(
1838 exprs: &[Spanned],
1839 env: &mut Env,
1840 registry: &FnRegistry<H>,
1841 expander: &SpannedExpander,
1842 host: &mut H,
1843) -> Result<Value> {
1844 let mut last = Value::Bool(true);
1845 for e in exprs {
1846 last = eval_in(env, registry, expander, e, host)?;
1847 if !last.is_truthy() {
1848 return Ok(last);
1849 }
1850 }
1851 Ok(last)
1852}
1853
1854fn sf_or<H: 'static>(
1855 exprs: &[Spanned],
1856 env: &mut Env,
1857 registry: &FnRegistry<H>,
1858 expander: &SpannedExpander,
1859 host: &mut H,
1860) -> Result<Value> {
1861 let mut last = Value::Bool(false);
1862 for e in exprs {
1863 last = eval_in(env, registry, expander, e, host)?;
1864 if last.is_truthy() {
1865 return Ok(last);
1866 }
1867 }
1868 Ok(last)
1869}
1870
1871fn sf_not<H: 'static>(
1872 items: &[Spanned],
1873 span: Span,
1874 env: &mut Env,
1875 registry: &FnRegistry<H>,
1876 expander: &SpannedExpander,
1877 host: &mut H,
1878) -> Result<Value> {
1879 if items.len() != 2 {
1880 return Err(EvalError::bad_form("not", "expected (not x)", span));
1881 }
1882 let v = eval_in(env, registry, expander, &items[1], host)?;
1883 Ok(Value::Bool(!v.is_truthy()))
1884}
1885
1886fn sf_try<H: 'static>(
1905 items: &[Spanned],
1906 span: Span,
1907 env: &mut Env,
1908 registry: &FnRegistry<H>,
1909 expander: &SpannedExpander,
1910 host: &mut H,
1911) -> Result<Value> {
1912 if items.len() < 3 {
1913 return Err(EvalError::bad_form(
1914 "try",
1915 "expected (try body... (catch (e) handler...))",
1916 span,
1917 ));
1918 }
1919 let catch_form = items.last().unwrap();
1921 let catch_list = catch_form.as_list().ok_or_else(|| {
1922 EvalError::bad_form(
1923 "try",
1924 "last form must be (catch (binding) handler...)",
1925 catch_form.span,
1926 )
1927 })?;
1928 if catch_list.is_empty() || catch_list[0].as_symbol() != Some("catch") {
1929 return Err(EvalError::bad_form(
1930 "try",
1931 "last form must be a (catch ...) clause",
1932 catch_form.span,
1933 ));
1934 }
1935 if catch_list.len() < 3 {
1936 return Err(EvalError::bad_form(
1937 "catch",
1938 "expected (catch (binding) handler...)",
1939 catch_form.span,
1940 ));
1941 }
1942 let binding_list = catch_list[1].as_list().ok_or_else(|| {
1943 EvalError::bad_form(
1944 "catch",
1945 "binding must be a 1-element list (e)",
1946 catch_list[1].span,
1947 )
1948 })?;
1949 if binding_list.len() != 1 {
1950 return Err(EvalError::bad_form(
1951 "catch",
1952 "binding must bind exactly one symbol",
1953 catch_list[1].span,
1954 ));
1955 }
1956 let binding_name = binding_list[0].as_symbol().ok_or_else(|| {
1957 EvalError::bad_form("catch", "binding must be a symbol", binding_list[0].span)
1958 })?;
1959
1960 let body = &items[1..items.len() - 1];
1961 let mut last = Value::Nil;
1962 for form in body {
1963 match eval_in(env, registry, expander, form, host) {
1964 Ok(v) => {
1965 last = v;
1966 }
1967 Err(EvalError::User { value, .. }) => {
1968 return run_catch_handler(
1969 binding_name,
1970 value,
1971 &catch_list[2..],
1972 env,
1973 registry,
1974 expander,
1975 host,
1976 );
1977 }
1978 Err(other) => {
1979 let value = rust_err_to_value_error(&other);
1983 return run_catch_handler(
1984 binding_name,
1985 value,
1986 &catch_list[2..],
1987 env,
1988 registry,
1989 expander,
1990 host,
1991 );
1992 }
1993 }
1994 }
1995 Ok(last)
1996}
1997
1998fn run_catch_handler<H: 'static>(
1999 binding_name: &str,
2000 error_value: Value,
2001 handler_body: &[Spanned],
2002 env: &mut Env,
2003 registry: &FnRegistry<H>,
2004 expander: &SpannedExpander,
2005 host: &mut H,
2006) -> Result<Value> {
2007 env.push();
2008 env.define(Arc::<str>::from(binding_name), error_value);
2009 let mut last = Value::Nil;
2010 for form in handler_body {
2011 match eval_in(env, registry, expander, form, host) {
2012 Ok(v) => last = v,
2013 Err(e) => {
2014 env.pop();
2015 return Err(e);
2016 }
2017 }
2018 }
2019 env.pop();
2020 Ok(last)
2021}
2022
2023fn sf_eval<H: 'static>(
2032 items: &[Spanned],
2033 call_span: Span,
2034 env: &mut Env,
2035 registry: &FnRegistry<H>,
2036 expander: &SpannedExpander,
2037 host: &mut H,
2038) -> Result<Value> {
2039 if items.len() != 2 {
2040 return Err(EvalError::bad_form(
2041 "eval",
2042 "expected (eval form)",
2043 call_span,
2044 ));
2045 }
2046 let form_value = eval_in(env, registry, expander, &items[1], host)?;
2047 let form_spanned = crate::code::value_to_spanned(&form_value, call_span)
2048 .map_err(|reason| EvalError::native_fn(Arc::<str>::from("eval"), reason, call_span))?;
2049 let expanded = fully_expand_with(&form_spanned, registry, expander, env, host)?;
2050 eval_in(env, registry, expander, &expanded, host)
2051}
2052
2053fn sf_delay(items: &[Spanned], call_span: Span, env: &Env) -> Result<Value> {
2058 if items.len() != 2 {
2059 return Err(EvalError::bad_form(
2060 "delay",
2061 "expected (delay expr)",
2062 call_span,
2063 ));
2064 }
2065 let body = vec![items[1].clone()];
2066 let thunk = Arc::new(Closure {
2067 params: Vec::new(),
2068 rest: None,
2069 body,
2070 captured_env: env.clone(),
2071 source: call_span,
2072 });
2073 Ok(Value::Promise(Arc::new(std::sync::Mutex::new(
2074 crate::value::PromiseState::Pending(thunk),
2075 ))))
2076}
2077
2078fn sf_macroexpand<H: 'static>(
2087 items: &[Spanned],
2088 call_span: Span,
2089 env: &mut Env,
2090 registry: &FnRegistry<H>,
2091 expander: &SpannedExpander,
2092 host: &mut H,
2093 fully: bool,
2094) -> Result<Value> {
2095 if items.len() != 2 {
2096 return Err(EvalError::bad_form(
2097 if fully {
2098 "macroexpand"
2099 } else {
2100 "macroexpand-1"
2101 },
2102 "expected (macroexpand[-1] form)",
2103 call_span,
2104 ));
2105 }
2106 let form_value = eval_in(env, registry, expander, &items[1], host)?;
2108 let form_spanned = crate::code::value_to_spanned(&form_value, call_span).map_err(|reason| {
2110 EvalError::native_fn(
2111 Arc::<str>::from(if fully {
2112 "macroexpand"
2113 } else {
2114 "macroexpand-1"
2115 }),
2116 reason,
2117 call_span,
2118 )
2119 })?;
2120
2121 let expanded = if fully {
2127 fully_expand_with(&form_spanned, registry, expander, env, host)?
2128 } else {
2129 macroexpand_one(&form_spanned, registry, expander, env, host)?
2130 };
2131
2132 Ok(crate::code::spanned_to_value(&expanded))
2133}
2134
2135fn expand_one_macro_call<H: 'static>(
2139 macro_name: &str,
2140 args: &[Spanned],
2141 call_span: Span,
2142 registry: &FnRegistry<H>,
2143 expander: &SpannedExpander,
2144 parent_env: &Env,
2145 host: &mut H,
2146) -> Result<Spanned> {
2147 let def: MacroDef = expander.get_macro(macro_name).cloned().ok_or_else(|| {
2148 EvalError::native_fn(
2149 Arc::<str>::from(macro_name),
2150 "macro disappeared during expansion",
2151 call_span,
2152 )
2153 })?;
2154 let body_spanned = Spanned::from_sexp_at(&def.body, call_span);
2155 let body_expanded = fully_expand_with(&body_spanned, registry, expander, parent_env, host)?;
2157
2158 let mut macro_env = parent_env.clone();
2159 macro_env.push();
2160 bind_macro_args(&mut macro_env, &def.name, &def.params, args, call_span)?;
2161 let result = eval_in(&mut macro_env, registry, expander, &body_expanded, host)?;
2162
2163 crate::code::value_to_spanned(&result, call_span).map_err(|reason| {
2164 EvalError::native_fn(
2165 Arc::<str>::from(format!("macro {macro_name}")),
2166 reason,
2167 call_span,
2168 )
2169 })
2170}
2171
2172fn fully_expand_with<H: 'static>(
2176 form: &Spanned,
2177 registry: &FnRegistry<H>,
2178 expander: &SpannedExpander,
2179 parent_env: &Env,
2180 host: &mut H,
2181) -> Result<Spanned> {
2182 if expander.is_empty() {
2183 return Ok(form.clone());
2184 }
2185 expand_recursive_with(form, registry, expander, parent_env, host)
2186}
2187
2188fn expand_recursive_with<H: 'static>(
2189 form: &Spanned,
2190 registry: &FnRegistry<H>,
2191 expander: &SpannedExpander,
2192 parent_env: &Env,
2193 host: &mut H,
2194) -> Result<Spanned> {
2195 match &form.form {
2196 SpannedForm::List(items) if !items.is_empty() => {
2197 if let Some(head) = items[0].as_symbol() {
2198 if expander.has(head) {
2199 let expanded = expand_one_macro_call(
2200 head,
2201 &items[1..],
2202 form.span,
2203 registry,
2204 expander,
2205 parent_env,
2206 host,
2207 )?;
2208 return expand_recursive_with(&expanded, registry, expander, parent_env, host);
2209 }
2210 }
2211 let mut out = Vec::with_capacity(items.len());
2212 for child in items {
2213 out.push(expand_recursive_with(
2214 child, registry, expander, parent_env, host,
2215 )?);
2216 }
2217 Ok(Spanned::new(form.span, SpannedForm::List(out)))
2218 }
2219 SpannedForm::Quote(_) => Ok(form.clone()),
2220 SpannedForm::Quasiquote(inner) => Ok(Spanned::new(
2221 form.span,
2222 SpannedForm::Quasiquote(Box::new(expand_inside_quasiquote_with(
2223 inner, registry, expander, parent_env, host,
2224 )?)),
2225 )),
2226 _ => Ok(form.clone()),
2227 }
2228}
2229
2230fn expand_inside_quasiquote_with<H: 'static>(
2231 form: &Spanned,
2232 registry: &FnRegistry<H>,
2233 expander: &SpannedExpander,
2234 parent_env: &Env,
2235 host: &mut H,
2236) -> Result<Spanned> {
2237 match &form.form {
2238 SpannedForm::Unquote(inner) => Ok(Spanned::new(
2239 form.span,
2240 SpannedForm::Unquote(Box::new(expand_recursive_with(
2241 inner, registry, expander, parent_env, host,
2242 )?)),
2243 )),
2244 SpannedForm::UnquoteSplice(inner) => Ok(Spanned::new(
2245 form.span,
2246 SpannedForm::UnquoteSplice(Box::new(expand_recursive_with(
2247 inner, registry, expander, parent_env, host,
2248 )?)),
2249 )),
2250 SpannedForm::List(items) => {
2251 let mut out = Vec::with_capacity(items.len());
2252 for item in items {
2253 out.push(expand_inside_quasiquote_with(
2254 item, registry, expander, parent_env, host,
2255 )?);
2256 }
2257 Ok(Spanned::new(form.span, SpannedForm::List(out)))
2258 }
2259 _ => Ok(form.clone()),
2260 }
2261}
2262
2263fn macroexpand_one<H: 'static>(
2266 form: &Spanned,
2267 registry: &FnRegistry<H>,
2268 expander: &SpannedExpander,
2269 parent_env: &Env,
2270 host: &mut H,
2271) -> Result<Spanned> {
2272 if let SpannedForm::List(items) = &form.form {
2273 if let Some(head) = items.first().and_then(Spanned::as_symbol) {
2274 if expander.has(head) {
2275 return expand_one_macro_call(
2276 head,
2277 &items[1..],
2278 form.span,
2279 registry,
2280 expander,
2281 parent_env,
2282 host,
2283 );
2284 }
2285 }
2286 }
2287 Ok(form.clone())
2288}
2289
2290fn rust_err_to_value_error(err: &EvalError) -> Value {
2293 use crate::value::ErrorObj;
2294 let tag: Arc<str> = match err {
2295 EvalError::UnboundSymbol { .. } => Arc::from("unbound-symbol"),
2296 EvalError::ArityMismatch { .. } => Arc::from("arity-mismatch"),
2297 EvalError::TypeMismatch { .. } => Arc::from("type-mismatch"),
2298 EvalError::DivisionByZero { .. } => Arc::from("division-by-zero"),
2299 EvalError::NotCallable { .. } => Arc::from("not-callable"),
2300 EvalError::BadSpecialForm { .. } => Arc::from("bad-special-form"),
2301 EvalError::NativeFn { .. } => Arc::from("native-fn"),
2302 EvalError::Reader(_) => Arc::from("reader"),
2303 EvalError::Halted => Arc::from("halted"),
2304 EvalError::NotImplemented(_) => Arc::from("not-implemented"),
2305 EvalError::User { .. } => Arc::from("user"),
2306 };
2307 let message: Arc<str> = Arc::from(err.short_message());
2308 Value::Error(Arc::new(ErrorObj {
2309 tag,
2310 message,
2311 data: Vec::new(),
2312 }))
2313}
2314
2315#[cfg(test)]
2316mod tests {
2317 use super::*;
2318 use crate::primitive::install_primitives;
2319 use tatara_lisp::read_spanned;
2320
2321 struct NoHost;
2322
2323 fn eval_ok(src: &str) -> Value {
2324 let forms = read_spanned(src).unwrap();
2325 let mut i: Interpreter<NoHost> = Interpreter::new();
2326 install_primitives(&mut i);
2327 let mut host = NoHost;
2328 i.eval_program(&forms, &mut host).unwrap()
2329 }
2330
2331 fn eval_err(src: &str) -> EvalError {
2332 let forms = read_spanned(src).unwrap();
2333 let mut i: Interpreter<NoHost> = Interpreter::new();
2334 install_primitives(&mut i);
2335 let mut host = NoHost;
2336 i.eval_program(&forms, &mut host).unwrap_err()
2337 }
2338
2339 #[test]
2342 fn literal_int() {
2343 assert!(matches!(eval_ok("42"), Value::Int(42)));
2344 }
2345
2346 #[test]
2347 fn unbound_symbol_errors() {
2348 let e = eval_err("no-such-var");
2349 assert!(matches!(e, EvalError::UnboundSymbol { .. }));
2350 }
2351
2352 #[test]
2353 fn quote_returns_runtime_list_of_symbols() {
2354 let v = eval_ok("'(a b c)");
2357 match v {
2358 Value::List(xs) => {
2359 assert_eq!(xs.len(), 3);
2360 assert!(matches!(&xs[0], Value::Symbol(s) if s.as_ref() == "a"));
2361 assert!(matches!(&xs[1], Value::Symbol(s) if s.as_ref() == "b"));
2362 assert!(matches!(&xs[2], Value::Symbol(s) if s.as_ref() == "c"));
2363 }
2364 other => panic!("{other:?}"),
2365 }
2366 }
2367
2368 #[test]
2371 fn add_ints() {
2372 assert!(matches!(eval_ok("(+ 1 2 3)"), Value::Int(6)));
2373 }
2374
2375 #[test]
2376 fn sub_divides_float() {
2377 match eval_ok("(- 10 3)") {
2378 Value::Int(7) => {}
2379 other => panic!("{other:?}"),
2380 }
2381 }
2382
2383 #[test]
2384 fn division_by_zero_errors() {
2385 assert!(matches!(
2386 eval_err("(/ 1 0)"),
2387 EvalError::DivisionByZero { .. }
2388 ));
2389 }
2390
2391 #[test]
2394 fn if_truthy_branch() {
2395 assert!(matches!(eval_ok("(if #t 1 2)"), Value::Int(1)));
2396 }
2397
2398 #[test]
2399 fn if_falsy_branch() {
2400 assert!(matches!(eval_ok("(if #f 1 2)"), Value::Int(2)));
2401 }
2402
2403 #[test]
2404 fn if_no_else_returns_nil() {
2405 assert!(matches!(eval_ok("(if #f 1)"), Value::Nil));
2406 }
2407
2408 #[test]
2409 fn cond_picks_first_match() {
2410 assert!(matches!(
2411 eval_ok("(cond (#f 1) (#t 2) (else 3))"),
2412 Value::Int(2)
2413 ));
2414 }
2415
2416 #[test]
2417 fn cond_falls_through_to_else() {
2418 assert!(matches!(
2419 eval_ok("(cond (#f 1) (#f 2) (else 3))"),
2420 Value::Int(3)
2421 ));
2422 }
2423
2424 #[test]
2425 fn when_runs_body_if_true() {
2426 assert!(matches!(eval_ok("(when #t 99)"), Value::Int(99)));
2427 assert!(matches!(eval_ok("(when #f 99)"), Value::Nil));
2428 }
2429
2430 #[test]
2433 fn let_binds_and_evaluates_body() {
2434 assert!(matches!(
2435 eval_ok("(let ((x 10) (y 20)) (+ x y))"),
2436 Value::Int(30)
2437 ));
2438 }
2439
2440 #[test]
2441 fn let_star_sequential_bindings() {
2442 assert!(matches!(
2443 eval_ok("(let* ((x 5) (y (+ x 1))) (+ x y))"),
2444 Value::Int(11)
2445 ));
2446 }
2447
2448 #[test]
2449 fn letrec_mutual_recursion() {
2450 let v = eval_ok(
2451 "(letrec ((even? (lambda (n) (if (= n 0) #t (odd? (- n 1)))))
2452 (odd? (lambda (n) (if (= n 0) #f (even? (- n 1))))))
2453 (even? 10))",
2454 );
2455 assert!(matches!(v, Value::Bool(true)));
2456 }
2457
2458 #[test]
2461 fn lambda_applies() {
2462 assert!(matches!(
2463 eval_ok("((lambda (x y) (+ x y)) 3 4)"),
2464 Value::Int(7)
2465 ));
2466 }
2467
2468 #[test]
2469 fn lambda_closes_over_env() {
2470 assert!(matches!(
2471 eval_ok("(let ((n 10)) ((lambda (x) (+ x n)) 5))"),
2472 Value::Int(15)
2473 ));
2474 }
2475
2476 #[test]
2477 fn closure_captures_by_value_at_creation() {
2478 let v = eval_ok(
2481 "(define make-adder (lambda (n) (lambda (x) (+ x n))))
2482 (define add5 (make-adder 5))
2483 (add5 10)",
2484 );
2485 assert!(matches!(v, Value::Int(15)));
2486 }
2487
2488 #[test]
2489 fn rest_args_collect_into_list() {
2490 let v = eval_ok("((lambda (x &rest rs) (length rs)) 1 2 3 4 5)");
2491 assert!(matches!(v, Value::Int(4)));
2492 }
2493
2494 #[test]
2495 fn closure_arity_mismatch() {
2496 let e = eval_err("((lambda (x y) (+ x y)) 1)");
2497 assert!(matches!(e, EvalError::ArityMismatch { .. }));
2498 }
2499
2500 #[test]
2503 fn define_then_use() {
2504 assert!(matches!(eval_ok("(define x 42) x"), Value::Int(42)));
2505 }
2506
2507 #[test]
2508 fn define_function_shorthand() {
2509 assert!(matches!(
2510 eval_ok("(define (sq x) (* x x)) (sq 6)"),
2511 Value::Int(36)
2512 ));
2513 }
2514
2515 #[test]
2516 fn set_mutates_existing() {
2517 assert!(matches!(
2518 eval_ok("(define x 1) (set! x 99) x"),
2519 Value::Int(99)
2520 ));
2521 }
2522
2523 #[test]
2524 fn set_unbound_errors() {
2525 let e = eval_err("(set! nope 1)");
2526 assert!(matches!(e, EvalError::UnboundSymbol { .. }));
2527 }
2528
2529 #[test]
2532 fn begin_returns_last() {
2533 assert!(matches!(eval_ok("(begin 1 2 3)"), Value::Int(3)));
2534 }
2535
2536 #[test]
2537 fn and_short_circuits() {
2538 assert!(matches!(eval_ok("(and 1 #f 2)"), Value::Bool(false)));
2539 assert!(matches!(eval_ok("(and 1 2 3)"), Value::Int(3)));
2540 assert!(matches!(eval_ok("(and)"), Value::Bool(true)));
2541 }
2542
2543 #[test]
2544 fn or_short_circuits() {
2545 assert!(matches!(eval_ok("(or #f #f 7)"), Value::Int(7)));
2546 assert!(matches!(eval_ok("(or #f #f)"), Value::Bool(false)));
2547 assert!(matches!(eval_ok("(or)"), Value::Bool(false)));
2548 }
2549
2550 #[test]
2551 fn not_inverts() {
2552 assert!(matches!(eval_ok("(not #t)"), Value::Bool(false)));
2553 assert!(matches!(eval_ok("(not #f)"), Value::Bool(true)));
2554 assert!(matches!(eval_ok("(not 42)"), Value::Bool(false)));
2555 }
2556
2557 #[test]
2560 fn recursive_factorial() {
2561 let v = eval_ok(
2562 "(define (fact n)
2563 (if (= n 0) 1 (* n (fact (- n 1)))))
2564 (fact 6)",
2565 );
2566 assert!(matches!(v, Value::Int(720)));
2567 }
2568
2569 #[test]
2570 fn recursive_length() {
2571 let v = eval_ok(
2572 "(define (len xs)
2573 (if (null? xs) 0 (+ 1 (len (cdr xs)))))
2574 (len (list 1 2 3 4 5))",
2575 );
2576 assert!(matches!(v, Value::Int(5)));
2577 }
2578
2579 #[test]
2584 fn quasiquote_plain_list_is_runtime_list() {
2585 let v = eval_ok("`(a b c)");
2586 match v {
2587 Value::List(xs) => {
2588 assert_eq!(xs.len(), 3);
2589 assert!(matches!(&xs[0], Value::Symbol(s) if s.as_ref() == "a"));
2590 assert!(matches!(&xs[1], Value::Symbol(s) if s.as_ref() == "b"));
2591 assert!(matches!(&xs[2], Value::Symbol(s) if s.as_ref() == "c"));
2592 }
2593 other => panic!("{other:?}"),
2594 }
2595 }
2596
2597 #[test]
2598 fn quasiquote_unquote_substitutes_evaluated_value() {
2599 let v = eval_ok("(let ((x 42)) `(a ,x c))");
2600 match v {
2601 Value::List(xs) => {
2602 assert_eq!(xs.len(), 3);
2603 assert!(matches!(&xs[1], Value::Int(42)));
2604 }
2605 other => panic!("{other:?}"),
2606 }
2607 }
2608
2609 #[test]
2610 fn quasiquote_unquote_arbitrary_expr() {
2611 let v = eval_ok("`(x ,(+ 1 2 3) y)");
2612 match v {
2613 Value::List(xs) => {
2614 assert!(matches!(&xs[1], Value::Int(6)));
2615 }
2616 other => panic!("{other:?}"),
2617 }
2618 }
2619
2620 #[test]
2621 fn quasiquote_splice_inlines_list() {
2622 let v = eval_ok("`(a ,@(list 1 2 3) b)");
2623 match v {
2624 Value::List(xs) => {
2625 assert_eq!(xs.len(), 5);
2626 assert!(matches!(&xs[0], Value::Symbol(s) if s.as_ref() == "a"));
2627 assert!(matches!(&xs[1], Value::Int(1)));
2628 assert!(matches!(&xs[2], Value::Int(2)));
2629 assert!(matches!(&xs[3], Value::Int(3)));
2630 assert!(matches!(&xs[4], Value::Symbol(s) if s.as_ref() == "b"));
2631 }
2632 other => panic!("{other:?}"),
2633 }
2634 }
2635
2636 #[test]
2637 fn quasiquote_splice_empty_list_splices_nothing() {
2638 let v = eval_ok("`(a ,@(list) b)");
2639 match v {
2640 Value::List(xs) => {
2641 assert_eq!(xs.len(), 2);
2642 assert!(matches!(&xs[0], Value::Symbol(s) if s.as_ref() == "a"));
2643 assert!(matches!(&xs[1], Value::Symbol(s) if s.as_ref() == "b"));
2644 }
2645 other => panic!("{other:?}"),
2646 }
2647 }
2648
2649 #[test]
2650 fn quasiquote_splice_non_list_errors() {
2651 let e = eval_err("`(a ,@42)");
2652 assert!(matches!(e, EvalError::TypeMismatch { .. }));
2653 }
2654
2655 #[test]
2656 fn quasiquote_atom_yields_atom_value() {
2657 assert!(matches!(eval_ok("`foo"), Value::Symbol(s) if s.as_ref() == "foo"));
2658 assert!(matches!(eval_ok("`42"), Value::Int(42)));
2659 }
2660
2661 #[test]
2662 fn quasiquote_with_nested_list_and_unquote() {
2663 let v = eval_ok("(let ((x 99)) `(foo (bar ,x) baz))");
2665 match v {
2666 Value::List(xs) => {
2667 assert_eq!(xs.len(), 3);
2668 match &xs[1] {
2669 Value::List(inner) => {
2670 assert!(matches!(&inner[1], Value::Int(99)));
2671 }
2672 other => panic!("{other:?}"),
2673 }
2674 }
2675 other => panic!("{other:?}"),
2676 }
2677 }
2678
2679 #[test]
2680 fn quasiquote_symbol_keyword_distinction_preserved() {
2681 let v = eval_ok("`(:key val)");
2682 match v {
2683 Value::List(xs) => {
2684 assert!(matches!(&xs[0], Value::Keyword(s) if s.as_ref() == "key"));
2685 assert!(matches!(&xs[1], Value::Symbol(s) if s.as_ref() == "val"));
2686 }
2687 other => panic!("{other:?}"),
2688 }
2689 }
2690
2691 #[test]
2692 fn bare_unquote_outside_quasiquote_errors() {
2693 let e = eval_err(",x");
2694 assert!(matches!(e, EvalError::BadSpecialForm { .. }));
2695 }
2696
2697 #[test]
2700 fn native_fn_reads_host_state() {
2701 struct Counter {
2702 n: i64,
2703 }
2704 let forms = read_spanned("(bump) (bump) (bump) (cur)").unwrap();
2705 let mut i: Interpreter<Counter> = Interpreter::new();
2706 install_primitives(&mut i);
2707 i.register_fn(
2708 "bump",
2709 Arity::Exact(0),
2710 |_args: &[Value], host: &mut Counter, _span| {
2711 host.n += 1;
2712 Ok(Value::Int(host.n))
2713 },
2714 );
2715 i.register_fn(
2716 "cur",
2717 Arity::Exact(0),
2718 |_args: &[Value], host: &mut Counter, _span| Ok(Value::Int(host.n)),
2719 );
2720 let mut host = Counter { n: 0 };
2721 let v = i.eval_program(&forms, &mut host).unwrap();
2722 assert!(matches!(v, Value::Int(3)));
2723 }
2724
2725 struct Ctx {
2728 records: Vec<(String, i64)>,
2729 }
2730
2731 #[test]
2732 fn register_typed1_marshals_string_arg() {
2733 let mut i: Interpreter<Ctx> = Interpreter::new();
2734 install_primitives(&mut i);
2735 i.register_typed1("greet", |_h: &mut Ctx, name: String| -> Result<String> {
2736 Ok(format!("hello {name}"))
2737 });
2738 let forms = read_spanned(r#"(greet "luis")"#).unwrap();
2739 let mut h = Ctx { records: vec![] };
2740 let v = i.eval_program(&forms, &mut h).unwrap();
2741 match v {
2742 Value::Str(s) => assert_eq!(&*s, "hello luis"),
2743 other => panic!("{other:?}"),
2744 }
2745 }
2746
2747 #[test]
2748 fn register_typed2_marshals_host_state_mutation() {
2749 let mut i: Interpreter<Ctx> = Interpreter::new();
2750 install_primitives(&mut i);
2751 i.register_typed2(
2752 "record",
2753 |h: &mut Ctx, name: String, n: i64| -> Result<()> {
2754 h.records.push((name, n));
2755 Ok(())
2756 },
2757 );
2758 let forms = read_spanned(r#"(record "a" 1) (record "b" 2)"#).unwrap();
2759 let mut h = Ctx { records: vec![] };
2760 let _ = i.eval_program(&forms, &mut h).unwrap();
2761 assert_eq!(h.records.len(), 2);
2762 assert_eq!(h.records[0], ("a".to_string(), 1));
2763 assert_eq!(h.records[1], ("b".to_string(), 2));
2764 }
2765
2766 #[test]
2767 fn register_typed_arg_type_mismatch_surfaces_at_call_site() {
2768 let mut i: Interpreter<Ctx> = Interpreter::new();
2769 install_primitives(&mut i);
2770 i.register_typed1("needs-int", |_h: &mut Ctx, n: i64| -> Result<i64> {
2771 Ok(n + 1)
2772 });
2773 let forms = read_spanned(r#"(needs-int "not-a-number")"#).unwrap();
2774 let mut h = Ctx { records: vec![] };
2775 let err = i.eval_program(&forms, &mut h).unwrap_err();
2776 assert!(matches!(
2777 err,
2778 EvalError::TypeMismatch {
2779 expected: "integer",
2780 ..
2781 }
2782 ));
2783 }
2784
2785 #[test]
2786 fn register_typed3_three_args() {
2787 let mut i: Interpreter<Ctx> = Interpreter::new();
2788 install_primitives(&mut i);
2789 i.register_typed3(
2790 "triple-sum",
2791 |_h: &mut Ctx, a: i64, b: i64, c: i64| -> Result<i64> { Ok(a + b + c) },
2792 );
2793 let forms = read_spanned("(triple-sum 10 20 30)").unwrap();
2794 let mut h = Ctx { records: vec![] };
2795 let v = i.eval_program(&forms, &mut h).unwrap();
2796 assert!(matches!(v, Value::Int(60)));
2797 }
2798
2799 #[test]
2802 fn user_macro_expands_and_evaluates() {
2803 let v = eval_ok(
2804 "(defmacro twice (x) `(* ,x 2))
2805 (twice 21)",
2806 );
2807 assert!(matches!(v, Value::Int(42)));
2808 }
2809
2810 #[test]
2811 fn user_macro_definition_returns_nil() {
2812 let v = eval_ok("(defmacro inc (x) `(+ ,x 1))");
2813 assert!(matches!(v, Value::Nil));
2814 }
2815
2816 #[test]
2817 fn user_macro_inside_define_body_expands() {
2818 let v = eval_ok(
2821 "(defmacro inc (x) `(+ ,x 1))
2822 (define (f n) (inc n))
2823 (f 41)",
2824 );
2825 assert!(matches!(v, Value::Int(42)));
2826 }
2827
2828 #[test]
2829 fn user_macro_with_rest_args_splices() {
2830 let v = eval_ok(
2831 "(defmacro sum-all (&rest xs) `(+ ,@xs))
2832 (sum-all 1 2 3 4 5)",
2833 );
2834 assert!(matches!(v, Value::Int(15)));
2835 }
2836
2837 #[test]
2838 fn nested_user_macros_compose() {
2839 let v = eval_ok(
2840 "(defmacro twice (x) `(* ,x 2))
2841 (defmacro quad (x) `(twice (twice ,x)))
2842 (quad 5)",
2843 );
2844 assert!(matches!(v, Value::Int(20)));
2845 }
2846
2847 #[test]
2848 fn user_macro_can_expand_to_special_form() {
2849 let v = eval_ok(
2852 "(defmacro guard (test then) `(if ,test ,then 0))
2853 (guard #t 99)",
2854 );
2855 assert!(matches!(v, Value::Int(99)));
2856 }
2857
2858 #[test]
2859 fn user_macro_redefined_replaces_prior_template() {
2860 let v = eval_ok(
2861 "(defmacro k () `1)
2862 (defmacro k () `2)
2863 (k)",
2864 );
2865 assert!(matches!(v, Value::Int(2)));
2866 }
2867
2868 #[test]
2869 fn user_macro_unbound_template_var_errors() {
2870 let mut i: Interpreter<NoHost> = Interpreter::new();
2876 install_primitives(&mut i);
2877 let forms = read_spanned("(defmacro bad (x) `(list ,y)) (bad 1)").unwrap();
2878 let err = i.eval_program(&forms, &mut NoHost).unwrap_err();
2879 match err {
2880 EvalError::UnboundSymbol { name, .. } => assert_eq!(&*name, "y"),
2881 other => panic!("expected UnboundSymbol, got {other:?}"),
2882 }
2883 }
2884
2885 #[test]
2886 fn defpoint_template_keyword_registers_as_macro() {
2887 let v = eval_ok(
2890 "(defpoint-template double (x) `(* ,x 2))
2891 (double 7)",
2892 );
2893 assert!(matches!(v, Value::Int(14)));
2894 }
2895
2896 #[test]
2897 fn defcheck_keyword_registers_as_macro() {
2898 let v = eval_ok(
2899 "(defcheck always-7 () `7)
2900 (always-7)",
2901 );
2902 assert!(matches!(v, Value::Int(7)));
2903 }
2904
2905 #[test]
2906 fn macro_call_evaluated_with_runtime_arg() {
2907 let v = eval_ok(
2911 "(defmacro double (x) `(+ ,x ,x))
2912 (define n 13)
2913 (double n)",
2914 );
2915 assert!(matches!(v, Value::Int(26)));
2916 }
2917
2918 #[test]
2919 fn macro_persists_across_eval_program_calls() {
2920 let mut i: Interpreter<NoHost> = Interpreter::new();
2923 install_primitives(&mut i);
2924 let mut host = NoHost;
2925 let defs = read_spanned("(defmacro inc (x) `(+ ,x 1))").unwrap();
2926 i.eval_program(&defs, &mut host).unwrap();
2927 assert_eq!(i.expander().len(), 1);
2928
2929 let call = read_spanned("(inc 41)").unwrap();
2930 let v = i.eval_program(&call, &mut host).unwrap();
2931 assert!(matches!(v, Value::Int(42)));
2932 }
2933
2934 #[test]
2935 fn macro_expansion_inside_lambda_body() {
2936 let v = eval_ok(
2937 "(defmacro sq (x) `(* ,x ,x))
2938 ((lambda (n) (sq n)) 9)",
2939 );
2940 assert!(matches!(v, Value::Int(81)));
2941 }
2942
2943 #[test]
2944 fn no_macros_registered_keeps_eval_program_a_passthrough() {
2945 let v = eval_ok("(+ 1 2 3)");
2951 assert!(matches!(v, Value::Int(6)));
2952 }
2953
2954 #[test]
2955 fn eval_top_form_drives_one_form_at_a_time() {
2956 let mut i: Interpreter<NoHost> = Interpreter::new();
2957 install_primitives(&mut i);
2958 let mut host = NoHost;
2959 let forms = read_spanned("(defmacro id (x) `,x) (id 42)").unwrap();
2960
2961 let r0 = i.eval_top_form(&forms[0], &mut host).unwrap();
2963 assert!(matches!(r0, Value::Nil));
2964
2965 let r1 = i.eval_top_form(&forms[1], &mut host).unwrap();
2967 assert!(matches!(r1, Value::Int(42)));
2968 }
2969
2970 use crate::install_full_stdlib_with;
2977
2978 fn run_full(src: &str) -> Value {
2979 let mut i: Interpreter<NoHost> = Interpreter::new();
2980 install_full_stdlib_with(&mut i, &mut NoHost);
2981 let forms = read_spanned(src).unwrap();
2982 i.eval_program(&forms, &mut NoHost).unwrap()
2983 }
2984
2985 #[test]
2986 fn macro_can_use_map_at_expansion_time() {
2987 let v = run_full(
2991 "(defmacro double-each (&rest xs)
2992 `(list ,@(map (lambda (x) (* x 2)) xs)))
2993 (double-each 1 2 3 4 5)",
2994 );
2995 assert_eq!(format!("{v}"), "(2 4 6 8 10)");
2996 }
2997
2998 #[test]
2999 fn macro_can_use_foldl_at_expansion_time() {
3000 let v = run_full(
3004 "(defmacro static-sum (&rest xs)
3005 (foldl + 0 xs))
3006 (static-sum 1 2 3 4 5)",
3007 );
3008 assert!(matches!(v, Value::Int(15)));
3009 }
3010
3011 #[test]
3012 fn macro_can_use_filter_at_expansion_time() {
3013 let v = run_full(
3017 "(defmacro sum-positives (&rest xs)
3018 `(+ ,@(filter positive? xs)))
3019 (sum-positives 1 -2 3 -4 5)",
3020 );
3021 assert!(matches!(v, Value::Int(9)));
3023 }
3024
3025 #[test]
3026 fn macro_can_recursively_emit_let_chain() {
3027 let v = run_full(
3030 "(defmacro chain-let (binding &rest more)
3031 (if (null? more)
3032 `(let (,binding) #t)
3033 `(let (,binding) (chain-let ,@more))))
3034 (chain-let (a 1) (b 2) (c 3))",
3035 );
3036 assert!(matches!(v, Value::Bool(true)));
3037 }
3038
3039 #[test]
3040 fn macro_can_use_gensym_for_hygiene() {
3041 let v = run_full(
3044 "(defmacro swap-bind (init body)
3045 (let ((tmp (gensym \"tmp\")))
3046 `(let ((,tmp ,init))
3047 (+ ,tmp ,tmp))))
3048 (swap-bind 21 #t)",
3049 );
3050 assert!(matches!(v, Value::Int(42)));
3051 }
3052
3053 #[test]
3054 fn macro_can_inspect_arg_shape() {
3055 let v = run_full(
3057 "(defmacro shape-aware (x)
3058 (if (list? x)
3059 `(+ ,@x) ;; sum the children
3060 `,x)) ;; pass through scalars
3061 (+ (shape-aware (1 2 3)) (shape-aware 100))",
3062 );
3063 assert!(matches!(v, Value::Int(106)));
3065 }
3066
3067 #[test]
3068 fn macro_can_call_user_helper_fn() {
3069 let v = run_full(
3071 "(define (square x) (* x x))
3072 (defmacro static-square (n) (square n))
3073 (static-square 7)",
3074 );
3075 assert!(matches!(v, Value::Int(49)));
3076 }
3077
3078 #[test]
3079 fn macro_emitting_quoted_form_round_trips() {
3080 let v = run_full(
3083 "(defmacro literal-list (&rest xs)
3084 `(quote ,xs))
3085 (literal-list a b c)",
3086 );
3087 let s = format!("{v}");
3088 assert!(s.contains('a') && s.contains('b') && s.contains('c'));
3089 }
3090
3091 #[test]
3092 fn quasiquote_inside_quasiquote_in_macro_output_is_preserved() {
3093 let v = run_full(
3096 "(defmacro emit-qq (x) `(quasiquote (a (unquote ,x) c)))
3097 (let ((q (emit-qq 99))) q)",
3098 );
3099 assert_eq!(format!("{v}"), "(a 99 c)");
3101 }
3102
3103 #[test]
3104 fn macro_body_can_define_locals_and_dispatch() {
3105 let v = run_full(
3107 "(defmacro classify-args (&rest xs)
3108 (let ((evens (filter even? xs))
3109 (odds (filter odd? xs)))
3110 `(list (list :evens ,@evens)
3111 (list :odds ,@odds))))
3112 (classify-args 1 2 3 4 5 6)",
3113 );
3114 let s = format!("{v}");
3115 assert!(s.contains(":evens 2 4 6"));
3116 assert!(s.contains(":odds 1 3 5"));
3117 }
3118
3119 #[test]
3128 fn tco_self_recursion_via_if() {
3129 let v = run_full(
3133 "(define (sum n acc)
3134 (if (= n 0)
3135 acc
3136 (sum (- n 1) (+ acc n))))
3137 (sum 100000 0)",
3138 );
3139 assert!(matches!(v, Value::Int(5_000_050_000)));
3141 }
3142
3143 #[test]
3144 fn tco_mutual_recursion() {
3145 let v = run_full(
3148 "(define (even-r? n) (if (= n 0) #t (odd-r? (- n 1))))
3149 (define (odd-r? n) (if (= n 0) #f (even-r? (- n 1))))
3150 (even-r? 50000)",
3151 );
3152 assert!(matches!(v, Value::Bool(true)));
3153 }
3154
3155 #[test]
3156 fn tco_via_cond_branch() {
3157 let v = run_full(
3158 "(define (countdown n)
3159 (cond
3160 ((<= n 0) :done)
3161 (else (countdown (- n 1)))))
3162 (countdown 50000)",
3163 );
3164 assert!(matches!(v, Value::Keyword(s) if &*s == "done"));
3165 }
3166
3167 #[test]
3168 fn tco_via_let_body() {
3169 let v = run_full(
3172 "(define (loop-let n)
3173 (let ((m (- n 1)))
3174 (if (<= n 0) :done (loop-let m))))
3175 (loop-let 50000)",
3176 );
3177 assert!(matches!(v, Value::Keyword(s) if &*s == "done"));
3178 }
3179
3180 #[test]
3181 fn tco_via_begin_last_form() {
3182 let v = run_full(
3183 "(define (counter n)
3184 (begin
3185 (+ 1 1)
3186 (+ 2 2)
3187 (if (<= n 0) :done (counter (- n 1)))))
3188 (counter 50000)",
3189 );
3190 assert!(matches!(v, Value::Keyword(s) if &*s == "done"));
3191 }
3192
3193 #[test]
3194 fn tco_via_when_unless() {
3195 let v = run_full(
3196 "(define (drain n)
3197 (when (> n 0)
3198 (drain (- n 1))))
3199 (drain 50000)",
3200 );
3201 assert!(matches!(v, Value::Nil));
3203 }
3204
3205 #[test]
3206 fn tco_through_and_or_short_circuit_last() {
3207 let v = run_full(
3210 "(define (loop-and n)
3211 (and #t #t (if (<= n 0) :done (loop-and (- n 1)))))
3212 (loop-and 30000)",
3213 );
3214 assert!(matches!(v, Value::Keyword(s) if &*s == "done"));
3215 }
3216
3217 #[test]
3218 fn non_tail_recursion_still_works_for_small_n() {
3219 let v = run_full(
3223 "(define (fact n)
3224 (if (= n 0) 1 (* n (fact (- n 1)))))
3225 (fact 12)",
3226 );
3227 assert!(matches!(v, Value::Int(479_001_600)));
3229 }
3230
3231 #[test]
3234 fn error_constructor_returns_error_value() {
3235 let v = run_full("(error :validation \"bad input\")");
3236 match v {
3237 Value::Error(e) => {
3238 assert_eq!(&*e.tag, "validation");
3239 assert_eq!(&*e.message, "bad input");
3240 assert!(e.data.is_empty());
3241 }
3242 other => panic!("{other:?}"),
3243 }
3244 }
3245
3246 #[test]
3247 fn ex_info_uses_default_tag() {
3248 let v = run_full("(ex-info \"validation failed\" (list :field \"email\" :code 42))");
3249 match v {
3250 Value::Error(e) => {
3251 assert_eq!(&*e.tag, "ex-info");
3252 assert_eq!(&*e.message, "validation failed");
3253 assert_eq!(e.data.len(), 2);
3254 }
3255 other => panic!("{other:?}"),
3256 }
3257 }
3258
3259 #[test]
3260 fn error_predicate() {
3261 let v = run_full("(error? (error :x \"y\"))");
3262 assert!(matches!(v, Value::Bool(true)));
3263 let v = run_full("(error? 42)");
3264 assert!(matches!(v, Value::Bool(false)));
3265 }
3266
3267 #[test]
3268 fn error_accessors() {
3269 let v = run_full(
3270 "(let ((e (ex-info \"oops\" (list :user-id 42))))
3271 (list (error-tag e) (error-message e) (error-data-get e :user-id)))",
3272 );
3273 assert_eq!(format!("{v}"), "(:ex-info \"oops\" 42)");
3274 }
3275
3276 #[test]
3277 fn try_catches_thrown_error() {
3278 let v = run_full(
3279 "(try
3280 (throw (ex-info \"boom\" (list :code 500)))
3281 (catch (e)
3282 (error-message e)))",
3283 );
3284 assert_eq!(format!("{v}"), "\"boom\"");
3285 }
3286
3287 #[test]
3288 fn try_returns_body_value_when_no_throw() {
3289 let v = run_full(
3290 "(try
3291 (+ 1 2 3)
3292 (catch (e) :unreachable))",
3293 );
3294 assert!(matches!(v, Value::Int(6)));
3295 }
3296
3297 #[test]
3298 fn try_catches_runtime_errors_too() {
3299 let v = run_full(
3303 "(try
3304 (/ 1 0)
3305 (catch (e) (error-tag e)))",
3306 );
3307 assert!(matches!(v, Value::Keyword(s) if &*s == "division-by-zero"));
3308 }
3309
3310 #[test]
3311 fn try_catches_unbound_symbol_error() {
3312 let v = run_full(
3313 "(try
3314 undefined-var
3315 (catch (e) (error-tag e)))",
3316 );
3317 assert!(matches!(v, Value::Keyword(s) if &*s == "unbound-symbol"));
3318 }
3319
3320 #[test]
3321 fn try_catches_arity_mismatch() {
3322 let v = run_full(
3323 "(try
3324 ((lambda (x y) (+ x y)) 1)
3325 (catch (e) (error-tag e)))",
3326 );
3327 assert!(matches!(v, Value::Keyword(s) if &*s == "arity-mismatch"));
3328 }
3329
3330 #[test]
3331 fn nested_try_inner_handler_takes_precedence() {
3332 let v = run_full(
3333 "(try
3334 (try
3335 (throw (ex-info \"inner\" ()))
3336 (catch (e) :inner-caught))
3337 (catch (e) :outer-caught))",
3338 );
3339 assert!(matches!(v, Value::Keyword(s) if &*s == "inner-caught"));
3340 }
3341
3342 #[test]
3343 fn outer_try_catches_when_handler_rethrows() {
3344 let v = run_full(
3345 "(try
3346 (try
3347 (throw (ex-info \"first\" ()))
3348 (catch (e) (throw (ex-info \"rethrown\" ()))))
3349 (catch (e) (error-message e)))",
3350 );
3351 assert_eq!(format!("{v}"), "\"rethrown\"");
3352 }
3353
3354 #[test]
3355 fn throw_propagates_when_no_try() {
3356 let mut i: Interpreter<NoHost> = Interpreter::new();
3358 install_full_stdlib_with(&mut i, &mut NoHost);
3359 let forms = read_spanned("(throw (ex-info \"unhandled\" (list :code 99)))").unwrap();
3360 let err = i.eval_program(&forms, &mut NoHost).unwrap_err();
3361 match err {
3362 EvalError::User { value, .. } => match value {
3363 Value::Error(e) => {
3364 assert_eq!(&*e.message, "unhandled");
3365 }
3366 other => panic!("{other:?}"),
3367 },
3368 other => panic!("{other:?}"),
3369 }
3370 }
3371
3372 #[test]
3375 fn macroexpand_one_step() {
3376 let v = run_full(
3377 "(defmacro twice (x) `(* ,x 2))
3378 (macroexpand-1 '(twice 7))",
3379 );
3380 assert_eq!(format!("{v}"), "(* 7 2)");
3382 }
3383
3384 #[test]
3385 fn macroexpand_full_until_fixed_point() {
3386 let v = run_full(
3387 "(defmacro twice (x) `(* ,x 2))
3388 (defmacro quad (x) `(twice (twice ,x)))
3389 (macroexpand '(quad 5))",
3390 );
3391 assert_eq!(format!("{v}"), "(* (* 5 2) 2)");
3393 }
3394
3395 #[test]
3396 fn macroexpand_returns_unchanged_for_non_macro() {
3397 let v = run_full("(macroexpand-1 '(+ 1 2 3))");
3398 assert_eq!(format!("{v}"), "(+ 1 2 3)");
3400 }
3401
3402 #[test]
3403 fn macroexpand_one_does_not_recurse_into_children() {
3404 let v = run_full(
3406 "(defmacro twice (x) `(* ,x 2))
3407 (defmacro outer (x) `(list ,x))
3408 (macroexpand-1 '(outer (twice 3)))",
3409 );
3410 assert_eq!(format!("{v}"), "(list (twice 3))");
3412 }
3413
3414 #[test]
3415 fn macroexpand_recurses_into_children() {
3416 let v = run_full(
3417 "(defmacro twice (x) `(* ,x 2))
3418 (defmacro outer (x) `(list ,x))
3419 (macroexpand '(outer (twice 3)))",
3420 );
3421 assert_eq!(format!("{v}"), "(list (* 3 2))");
3423 }
3424
3425 fn run_with_modules(modules: &[(&str, &str)], src: &str) -> Value {
3428 use crate::module::MapLoader;
3429 let mut i: Interpreter<NoHost> = Interpreter::new();
3430 install_full_stdlib_with(&mut i, &mut NoHost);
3431 let mut loader = MapLoader::new();
3432 for (path, source) in modules {
3433 loader.insert(*path, *source);
3434 }
3435 i.set_loader(Arc::new(loader));
3436 let forms = read_spanned(src).unwrap();
3437 i.eval_program(&forms, &mut NoHost).unwrap()
3438 }
3439
3440 fn run_with_modules_err(modules: &[(&str, &str)], src: &str) -> EvalError {
3441 use crate::module::MapLoader;
3442 let mut i: Interpreter<NoHost> = Interpreter::new();
3443 install_full_stdlib_with(&mut i, &mut NoHost);
3444 let mut loader = MapLoader::new();
3445 for (path, source) in modules {
3446 loader.insert(*path, *source);
3447 }
3448 i.set_loader(Arc::new(loader));
3449 let forms = read_spanned(src).unwrap();
3450 i.eval_program(&forms, &mut NoHost).unwrap_err()
3451 }
3452
3453 #[test]
3454 fn require_with_explicit_alias_imports_qualified_names() {
3455 let v = run_with_modules(
3456 &[(
3457 "lib/math",
3458 "(define square (lambda (x) (* x x)))
3459 (define cube (lambda (x) (* x x x)))
3460 (provide square cube)",
3461 )],
3462 "(require \"lib/math\" :as math)
3463 (math/square 7)",
3464 );
3465 assert!(matches!(v, Value::Int(49)));
3466 }
3467
3468 #[test]
3469 fn require_uses_path_as_default_alias() {
3470 let v = run_with_modules(
3471 &[("lib/math", "(define double (lambda (x) (* x 2))) (provide double)")],
3472 "(require \"lib/math\")
3473 (lib/math/double 21)",
3474 );
3475 assert!(matches!(v, Value::Int(42)));
3478 }
3479
3480 #[test]
3481 fn require_refer_imports_unqualified_names() {
3482 let v = run_with_modules(
3483 &[(
3484 "lib/math",
3485 "(define square (lambda (x) (* x x)))
3486 (define cube (lambda (x) (* x x x)))
3487 (provide square cube)",
3488 )],
3489 "(require \"lib/math\" :refer (square))
3490 (square 6)",
3491 );
3492 assert!(matches!(v, Value::Int(36)));
3493 }
3494
3495 #[test]
3496 fn require_does_not_import_non_provided() {
3497 let err = run_with_modules_err(
3500 &[(
3501 "lib/secret",
3502 "(define public 1)
3503 (define private 2)
3504 (provide public)",
3505 )],
3506 "(require \"lib/secret\" :as s)
3507 s/private",
3508 );
3509 match err {
3510 EvalError::UnboundSymbol { name, .. } => assert_eq!(&*name, "s/private"),
3511 other => panic!("{other:?}"),
3512 }
3513 }
3514
3515 #[test]
3516 fn require_chain_a_imports_b() {
3517 let v = run_with_modules(
3518 &[
3519 (
3520 "lib/util",
3521 "(define inc1 (lambda (n) (+ n 1)))
3522 (provide inc1)",
3523 ),
3524 (
3525 "lib/wrapper",
3526 "(require \"lib/util\" :as u)
3527 (define inc2 (lambda (n) (u/inc1 (u/inc1 n))))
3528 (provide inc2)",
3529 ),
3530 ],
3531 "(require \"lib/wrapper\" :as w)
3532 (w/inc2 10)",
3533 );
3534 assert!(matches!(v, Value::Int(12)));
3535 }
3536
3537 #[test]
3538 fn require_module_not_found() {
3539 let err = run_with_modules_err(&[], "(require \"missing/module\")");
3540 match err {
3542 EvalError::User { value, .. } => match value {
3543 Value::Error(e) => {
3544 assert_eq!(&*e.tag, "module-not-found");
3545 assert!(e.message.contains("missing/module"));
3546 }
3547 other => panic!("{other:?}"),
3548 },
3549 other => panic!("{other:?}"),
3550 }
3551 }
3552
3553 #[test]
3554 fn circular_require_detected() {
3555 let err = run_with_modules_err(
3556 &[
3557 ("a", "(require \"b\") (provide x) (define x 1)"),
3558 ("b", "(require \"a\") (provide y) (define y 2)"),
3559 ],
3560 "(require \"a\")",
3561 );
3562 match err {
3563 EvalError::User { value, .. } => match value {
3564 Value::Error(e) => assert_eq!(&*e.tag, "circular-require"),
3565 other => panic!("{other:?}"),
3566 },
3567 other => panic!("{other:?}"),
3568 }
3569 }
3570
3571 #[test]
3572 fn provide_at_top_level_errors() {
3573 let mut i: Interpreter<NoHost> = Interpreter::new();
3575 install_full_stdlib_with(&mut i, &mut NoHost);
3576 let forms = read_spanned("(provide x)").unwrap();
3577 let err = i.eval_program(&forms, &mut NoHost).unwrap_err();
3578 assert!(matches!(err, EvalError::BadSpecialForm { form, .. } if &*form == "provide"));
3579 }
3580
3581 #[test]
3582 fn require_refer_unknown_name_errors() {
3583 let err = run_with_modules_err(
3584 &[(
3585 "lib/math",
3586 "(define square (lambda (x) (* x x))) (provide square)",
3587 )],
3588 "(require \"lib/math\" :refer (square cube))",
3589 );
3590 match err {
3591 EvalError::User { value, .. } => match value {
3592 Value::Error(e) => {
3593 assert!(matches!(&*e.tag, "not-defined" | "not-exported"));
3594 }
3595 other => panic!("{other:?}"),
3596 },
3597 other => panic!("{other:?}"),
3598 }
3599 }
3600
3601 #[test]
3602 fn require_caches_module_load_once() {
3603 let v = run_with_modules(
3604 &[(
3605 "lib/foo",
3606 "(define x 42) (provide x)",
3607 )],
3608 "(require \"lib/foo\" :as a)
3609 (require \"lib/foo\" :as b)
3610 (+ a/x b/x)",
3611 );
3612 assert!(matches!(v, Value::Int(84)));
3614 }
3615}