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 register_awaitable_fn<R, C>(
166 &mut self,
167 name: impl Into<Arc<str>>,
168 arity: Arity,
169 ready: R,
170 call: C,
171 ) where
172 R: Fn(&[Value], &H) -> bool + Send + Sync + 'static,
173 C: Fn(&[Value], &mut H, Span) -> Result<Value> + Send + Sync + 'static,
174 {
175 let name = name.into();
176 self.registry.insert(FnEntry {
177 name: name.clone(),
178 arity,
179 callable: FnImpl::Awaitable(Arc::new(crate::ffi::Awaitable { ready, call })),
180 });
181 self.globals.define(
182 name.clone(),
183 Value::NativeFn(Arc::new(NativeFn { name, arity })),
184 );
185 }
186
187 pub fn eval_spanned(&mut self, form: &Spanned, host: &mut H) -> Result<Value> {
192 let expanded = self.fully_expand(form, host)?;
193 eval_in(
194 &mut self.globals,
195 &self.registry,
196 &self.expander,
197 &expanded,
198 host,
199 )
200 }
201
202 pub fn eval_program(&mut self, forms: &[Spanned], host: &mut H) -> Result<Value> {
214 let mut last = Value::Nil;
215 for form in forms {
216 last = self.eval_top_form(form, host)?;
217 }
218 Ok(last)
219 }
220
221 pub fn eval_top_form(&mut self, form: &Spanned, host: &mut H) -> Result<Value> {
227 if self.expander.try_register_macro(form)? {
228 return Ok(Value::Nil);
229 }
230 if let Some(head) = head_symbol(form) {
234 match head {
235 "provide" => return self.eval_provide(form, host),
236 "require" => return self.eval_require(form, host),
237 _ => {}
238 }
239 }
240 let expanded = self.fully_expand(form, host)?;
241 eval_in(
242 &mut self.globals,
243 &self.registry,
244 &self.expander,
245 &expanded,
246 host,
247 )
248 }
249
250 fn eval_provide(&mut self, form: &Spanned, _host: &mut H) -> Result<Value> {
254 let items = form.as_list().unwrap_or(&[]);
255 let span = form.span;
256 let Some(current) = self.current_module.clone() else {
257 return Err(EvalError::bad_form(
258 "provide",
259 "`provide` only valid at module top level — embedder evaluating top-level code has no current module",
260 span,
261 ));
262 };
263 let mut names: Vec<Arc<str>> = Vec::with_capacity(items.len().saturating_sub(1));
265 for item in &items[1..] {
266 let name = item.as_symbol().ok_or_else(|| {
267 EvalError::bad_form(
268 "provide",
269 "expected symbol — every arg must name a binding to export",
270 item.span,
271 )
272 })?;
273 names.push(Arc::<str>::from(name));
274 }
275 {
280 let mut g = self.modules.inner_lock();
281 g.exports_staging
285 .entry(current.to_string())
286 .or_default()
287 .extend(names.iter().cloned());
288 }
289 Ok(Value::Nil)
290 }
291
292 fn eval_require(&mut self, form: &Spanned, host: &mut H) -> Result<Value> {
301 let items = form.as_list().unwrap_or(&[]);
302 let span = form.span;
303 if items.len() < 2 {
304 return Err(EvalError::bad_form(
305 "require",
306 "expected (require \"path\" [:as alias] [:refer (...)])",
307 span,
308 ));
309 }
310 let path: Arc<str> = match items[1].as_string() {
311 Some(s) => Arc::from(s),
312 None => {
313 return Err(EvalError::bad_form(
314 "require",
315 "first arg must be a string path",
316 items[1].span,
317 ))
318 }
319 };
320
321 let mut alias: Option<Arc<str>> = None;
323 let mut refer: Option<Vec<Arc<str>>> = None;
324 let mut i = 2usize;
325 while i < items.len() {
326 let kw = items[i].as_keyword().ok_or_else(|| {
327 EvalError::bad_form(
328 "require",
329 "expected keyword (:as / :refer) after path",
330 items[i].span,
331 )
332 })?;
333 let val = items.get(i + 1).ok_or_else(|| {
334 EvalError::bad_form("require", "keyword without value", items[i].span)
335 })?;
336 match kw {
337 "as" => {
338 alias = Some(Arc::from(val.as_symbol().ok_or_else(|| {
339 EvalError::bad_form("require", ":as needs a symbol alias", val.span)
340 })?));
341 }
342 "refer" => {
343 let names_list = val.as_list().ok_or_else(|| {
344 EvalError::bad_form(
345 "require",
346 ":refer needs a parenthesized list of symbols",
347 val.span,
348 )
349 })?;
350 let mut names = Vec::with_capacity(names_list.len());
351 for n in names_list {
352 names.push(Arc::<str>::from(n.as_symbol().ok_or_else(|| {
353 EvalError::bad_form(
354 "require",
355 ":refer list must contain symbols only",
356 n.span,
357 )
358 })?));
359 }
360 refer = Some(names);
361 }
362 other => {
363 return Err(EvalError::bad_form(
364 "require",
365 format!("unknown require option :{other}"),
366 items[i].span,
367 ));
368 }
369 }
370 i += 2;
371 }
372
373 if !self.modules.has(&path) {
375 self.load_module(&path, span, host)?;
376 }
377 let module = self
378 .modules
379 .get(&path)
380 .ok_or_else(|| EvalError::native_fn("require", "module disappeared after load", span))?;
381
382 let chosen_alias = alias.unwrap_or_else(|| path.clone());
384 for name in &module.exports {
385 let value = module
386 .bindings
387 .get(name)
388 .cloned()
389 .unwrap_or(Value::Nil);
390 let qualified: Arc<str> = Arc::from(format!("{chosen_alias}/{name}"));
391 self.globals.define(qualified, value);
392 }
393 if let Some(names) = refer {
394 for name in names {
395 if let Some(value) = module.bindings.get(&name) {
396 if module.exports.contains(&name) {
397 self.globals.define(name.clone(), value.clone());
398 } else {
399 return Err(EvalError::User {
400 value: error_value("not-exported", &format!(
401 "{path} does not export {name}"
402 )),
403 at: span,
404 });
405 }
406 } else {
407 return Err(EvalError::User {
408 value: error_value("not-defined", &format!(
409 "{path} does not define {name}"
410 )),
411 at: span,
412 });
413 }
414 }
415 }
416 Ok(Value::Nil)
417 }
418
419 fn load_module(&mut self, path: &str, span: Span, host: &mut H) -> Result<()> {
425 self.modules
427 .begin_load(path)
428 .map_err(|e| module_error_to_eval(e, span))?;
429
430 let source = match self.loader.load(path) {
432 Ok(s) => s,
433 Err(e) => {
434 self.modules.abort_load(path);
435 return Err(module_error_to_eval(e, span));
436 }
437 };
438
439 let forms = match tatara_lisp::read_spanned(&source) {
441 Ok(f) => f,
442 Err(e) => {
443 self.modules.abort_load(path);
444 return Err(EvalError::Reader(e));
445 }
446 };
447
448 let saved_globals = std::mem::replace(&mut self.globals, Env::new());
452 for (name, value) in saved_globals.iter_top_level() {
456 if matches!(value, Value::NativeFn(_) | Value::Closure(_)) {
460 self.globals.define(name.clone(), value.clone());
461 }
462 }
463 let saved_current = self.current_module.replace(Arc::from(path));
464
465 let mut eval_err: Option<EvalError> = None;
467 for f in &forms {
468 if let Err(e) = self.eval_top_form(f, host) {
472 eval_err = Some(e);
473 break;
474 }
475 }
476
477 let module_globals = std::mem::replace(&mut self.globals, saved_globals);
479 self.current_module = saved_current;
480
481 if let Some(e) = eval_err {
482 self.modules.abort_load(path);
483 return Err(e);
484 }
485
486 let mut module = Module::new(path);
489 for (name, value) in module_globals.iter_top_level() {
490 if !matches!(value, Value::NativeFn(_)) {
493 module.define(name.clone(), value.clone());
494 }
495 }
496 let staged = {
498 let mut g = self.modules.inner_lock();
499 g.exports_staging
500 .remove(path)
501 .unwrap_or_default()
502 };
503 for n in staged {
504 module.add_export(n);
505 }
506 self.modules.finish_load(module);
507 Ok(())
508 }
509
510 pub fn fully_expand(&mut self, form: &Spanned, host: &mut H) -> Result<Spanned> {
521 if self.expander.is_empty() {
523 return Ok(form.clone());
524 }
525 self.expand_recursive(form, host)
526 }
527
528 fn expand_recursive(&mut self, form: &Spanned, host: &mut H) -> Result<Spanned> {
529 match &form.form {
530 SpannedForm::List(items) if !items.is_empty() => {
531 if let Some(head) = items[0].as_symbol() {
532 if self.expander.has(head) {
533 let expanded =
537 self.expand_macro_call(head, &items[1..], form.span, host)?;
538 return self.expand_recursive(&expanded, host);
539 }
540 }
541 let mut out = Vec::with_capacity(items.len());
544 for child in items {
545 out.push(self.expand_recursive(child, host)?);
546 }
547 Ok(Spanned::new(form.span, SpannedForm::List(out)))
548 }
549 SpannedForm::Quote(_) => {
550 Ok(form.clone())
552 }
553 SpannedForm::Quasiquote(inner) => {
554 Ok(Spanned::new(
556 form.span,
557 SpannedForm::Quasiquote(Box::new(self.expand_inside_quasiquote(inner, host)?)),
558 ))
559 }
560 _ => Ok(form.clone()),
562 }
563 }
564
565 fn expand_inside_quasiquote(&mut self, form: &Spanned, host: &mut H) -> Result<Spanned> {
566 match &form.form {
567 SpannedForm::Unquote(inner) => Ok(Spanned::new(
568 form.span,
569 SpannedForm::Unquote(Box::new(self.expand_recursive(inner, host)?)),
570 )),
571 SpannedForm::UnquoteSplice(inner) => Ok(Spanned::new(
572 form.span,
573 SpannedForm::UnquoteSplice(Box::new(self.expand_recursive(inner, host)?)),
574 )),
575 SpannedForm::List(items) => {
576 let mut out = Vec::with_capacity(items.len());
577 for item in items {
578 out.push(self.expand_inside_quasiquote(item, host)?);
579 }
580 Ok(Spanned::new(form.span, SpannedForm::List(out)))
581 }
582 _ => Ok(form.clone()),
583 }
584 }
585
586 fn expand_macro_call(
590 &mut self,
591 macro_name: &str,
592 args: &[Spanned],
593 call_span: Span,
594 host: &mut H,
595 ) -> Result<Spanned> {
596 let def: MacroDef = self
599 .expander
600 .get_macro(macro_name)
601 .cloned()
602 .ok_or_else(|| {
603 EvalError::native_fn(
604 Arc::<str>::from(macro_name),
605 "macro disappeared during expansion",
606 call_span,
607 )
608 })?;
609
610 let body_spanned = Spanned::from_sexp_at(&def.body, call_span);
615
616 let body_expanded = self.fully_expand(&body_spanned, host)?;
622
623 let mut macro_env = self.globals.sealed_below_top();
631 bind_macro_args(&mut macro_env, &def.name, &def.params, args, call_span)?;
632
633 let result = eval_in(
636 &mut macro_env,
637 &self.registry,
638 &self.expander,
639 &body_expanded,
640 host,
641 )?;
642
643 value_to_spanned(&result, call_span).map_err(|reason| {
647 EvalError::native_fn(
648 Arc::<str>::from(format!("macro {macro_name}")),
649 reason,
650 call_span,
651 )
652 })
653 }
654
655 pub fn expander(&self) -> &SpannedExpander {
658 &self.expander
659 }
660
661 pub fn expander_mut(&mut self) -> &mut SpannedExpander {
665 &mut self.expander
666 }
667
668 pub fn lookup_global(&self, name: &str) -> Option<Value> {
670 self.globals.lookup(name)
671 }
672
673 pub fn define_global(&mut self, name: impl Into<Arc<str>>, value: Value) {
675 self.globals.define(name, value);
676 }
677
678 pub fn globals_snapshot(&self) -> &Env {
681 &self.globals
682 }
683
684 pub fn apply_external_value(
688 &mut self,
689 callee: &Value,
690 args: Vec<Value>,
691 host: &mut H,
692 call_span: Span,
693 ) -> Result<Value> {
694 apply_external(callee, args, call_span, &self.registry, &self.expander, host)
695 }
696
697 pub fn eval_program_vm(&mut self, forms: &[Spanned], host: &mut H) -> Result<Value> {
704 let mut expanded: Vec<Spanned> = Vec::with_capacity(forms.len());
705 for form in forms {
706 if self.expander.try_register_macro(form)? {
707 continue;
708 }
709 expanded.push(self.fully_expand(form, host)?);
710 }
711 let chunk = crate::vm::compile_program(&expanded).map_err(|e| match e {
712 crate::vm::CompileError::Bad { at, message } => {
713 EvalError::bad_form(Arc::<str>::from("vm:compile"), message, at)
714 }
715 })?;
716 let mut vm = crate::vm::Vm::new();
717 vm.run(&chunk, self, host).map_err(|e| match e {
718 crate::vm::VmError::Eval(inner) => inner,
719 other => EvalError::native_fn(Arc::<str>::from("vm"), format!("{other}"), Span::synthetic()),
720 })
721 }
722
723 pub fn register_typed0<R, F>(&mut self, name: impl Into<Arc<str>>, f: F)
727 where
728 R: IntoValue + 'static,
729 F: Fn(&mut H) -> Result<R> + Send + Sync + 'static,
730 {
731 self.register_fn(
732 name,
733 Arity::Exact(0),
734 move |_args: &[Value], host: &mut H, _sp| f(host).map(IntoValue::into_value),
735 );
736 }
737
738 pub fn register_typed1<A, R, F>(&mut self, name: impl Into<Arc<str>>, f: F)
740 where
741 A: FromValue + 'static,
742 R: IntoValue + 'static,
743 F: Fn(&mut H, A) -> Result<R> + Send + Sync + 'static,
744 {
745 self.register_fn(
746 name,
747 Arity::Exact(1),
748 move |args: &[Value], host: &mut H, sp| {
749 let a = A::from_value(&args[0], sp)?;
750 f(host, a).map(IntoValue::into_value)
751 },
752 );
753 }
754
755 pub fn register_typed2<A, B, R, F>(&mut self, name: impl Into<Arc<str>>, f: F)
757 where
758 A: FromValue + 'static,
759 B: FromValue + 'static,
760 R: IntoValue + 'static,
761 F: Fn(&mut H, A, B) -> Result<R> + Send + Sync + 'static,
762 {
763 self.register_fn(
764 name,
765 Arity::Exact(2),
766 move |args: &[Value], host: &mut H, sp| {
767 let a = A::from_value(&args[0], sp)?;
768 let b = B::from_value(&args[1], sp)?;
769 f(host, a, b).map(IntoValue::into_value)
770 },
771 );
772 }
773
774 pub fn register_typed3<A, B, C, R, F>(&mut self, name: impl Into<Arc<str>>, f: F)
776 where
777 A: FromValue + 'static,
778 B: FromValue + 'static,
779 C: FromValue + 'static,
780 R: IntoValue + 'static,
781 F: Fn(&mut H, A, B, C) -> Result<R> + Send + Sync + 'static,
782 {
783 self.register_fn(
784 name,
785 Arity::Exact(3),
786 move |args: &[Value], host: &mut H, sp| {
787 let a = A::from_value(&args[0], sp)?;
788 let b = B::from_value(&args[1], sp)?;
789 let c = C::from_value(&args[2], sp)?;
790 f(host, a, b, c).map(IntoValue::into_value)
791 },
792 );
793 }
794
795 pub fn register_typed4<A, B, C, D, R, F>(&mut self, name: impl Into<Arc<str>>, f: F)
797 where
798 A: FromValue + 'static,
799 B: FromValue + 'static,
800 C: FromValue + 'static,
801 D: FromValue + 'static,
802 R: IntoValue + 'static,
803 F: Fn(&mut H, A, B, C, D) -> Result<R> + Send + Sync + 'static,
804 {
805 self.register_fn(
806 name,
807 Arity::Exact(4),
808 move |args: &[Value], host: &mut H, sp| {
809 let a = A::from_value(&args[0], sp)?;
810 let b = B::from_value(&args[1], sp)?;
811 let c = C::from_value(&args[2], sp)?;
812 let d = D::from_value(&args[3], sp)?;
813 f(host, a, b, c, d).map(IntoValue::into_value)
814 },
815 );
816 }
817}
818
819impl<H: 'static> Default for Interpreter<H> {
820 fn default() -> Self {
821 Self::new()
822 }
823}
824
825pub(crate) fn eval_in<H: 'static>(
830 env: &mut Env,
831 registry: &FnRegistry<H>,
832 expander: &SpannedExpander,
833 form: &Spanned,
834 host: &mut H,
835) -> Result<Value> {
836 match &form.form {
837 SpannedForm::Nil => Ok(Value::Nil),
838 SpannedForm::Atom(a) => eval_atom(a, form.span, env),
839 SpannedForm::Quote(inner) => Ok(quoted_value(inner)),
840 SpannedForm::Quasiquote(inner) => quasiquote_eval(inner, env, registry, expander, host),
841 SpannedForm::Unquote(_) | SpannedForm::UnquoteSplice(_) => Err(EvalError::bad_form(
842 "unquote",
843 "unquote outside of quasiquote",
844 form.span,
845 )),
846 SpannedForm::List(items) => {
847 if items.is_empty() {
848 return Ok(Value::Nil);
849 }
850 if let Some(head_sym) = items[0].as_symbol() {
854 if let Some(sf) = SpecialForm::from_symbol(head_sym) {
855 return eval_special(sf, items, form.span, env, registry, expander, host);
856 }
857 }
858 eval_application(items, form.span, env, registry, expander, host)
859 }
860 }
861}
862
863fn eval_atom(a: &Atom, span: Span, env: &Env) -> Result<Value> {
864 match a {
865 Atom::Symbol(name) => env
866 .lookup(name)
867 .ok_or_else(|| EvalError::unbound(name.as_str(), span)),
868 Atom::Keyword(s) => Ok(Value::Keyword(crate::interner::intern(s.as_str()))),
869 Atom::Str(s) => Ok(Value::Str(Arc::from(s.as_str()))),
870 Atom::Int(n) => Ok(Value::Int(*n)),
871 Atom::Float(n) => Ok(Value::Float(*n)),
872 Atom::Bool(b) => Ok(Value::Bool(*b)),
873 }
874}
875
876fn quoted_value(inner: &Spanned) -> Value {
880 crate::code::spanned_to_value(inner)
881}
882
883fn quasiquote_eval<H: 'static>(
889 form: &Spanned,
890 env: &mut Env,
891 registry: &FnRegistry<H>,
892 expander: &SpannedExpander,
893 host: &mut H,
894) -> Result<Value> {
895 match &form.form {
896 SpannedForm::Unquote(inner) => eval_in(env, registry, expander, inner, host),
897 SpannedForm::UnquoteSplice(_) => Err(EvalError::bad_form(
898 "unquote-splice",
899 "`,@` only valid directly inside a list",
900 form.span,
901 )),
902 SpannedForm::List(items) => {
903 let mut out: Vec<Value> = Vec::with_capacity(items.len());
904 for item in items {
905 if let SpannedForm::UnquoteSplice(inner) = &item.form {
906 let v = eval_in(env, registry, expander, inner, host)?;
907 match v {
908 Value::List(xs) => out.extend(xs.iter().cloned()),
909 Value::Nil => {}
910 other => {
911 return Err(EvalError::type_mismatch(
912 "list",
913 other.type_name(),
914 item.span,
915 ))
916 }
917 }
918 } else {
919 out.push(quasiquote_eval(item, env, registry, expander, host)?);
920 }
921 }
922 if out.is_empty() {
923 Ok(Value::Nil)
924 } else {
925 Ok(Value::list(out))
926 }
927 }
928 SpannedForm::Nil => Ok(Value::Nil),
929 SpannedForm::Atom(a) => Ok(match a {
930 Atom::Symbol(s) => Value::Symbol(crate::interner::intern(s.as_str())),
931 Atom::Keyword(s) => Value::Keyword(crate::interner::intern(s.as_str())),
932 Atom::Str(s) => Value::Str(Arc::from(s.as_str())),
933 Atom::Int(n) => Value::Int(*n),
934 Atom::Float(n) => Value::Float(*n),
935 Atom::Bool(b) => Value::Bool(*b),
936 }),
937 SpannedForm::Quote(_) | SpannedForm::Quasiquote(_) => {
941 Ok(Value::Sexp(form.to_sexp(), form.span))
942 }
943 }
944}
945
946fn eval_application<H: 'static>(
949 items: &[Spanned],
950 call_span: Span,
951 env: &mut Env,
952 registry: &FnRegistry<H>,
953 expander: &SpannedExpander,
954 host: &mut H,
955) -> Result<Value> {
956 let head_val = eval_in(env, registry, expander, &items[0], host)?;
957 let mut args: Vec<Value> = Vec::with_capacity(items.len().saturating_sub(1));
958 for arg_form in &items[1..] {
959 args.push(eval_in(env, registry, expander, arg_form, host)?);
960 }
961 apply(&head_val, args, call_span, registry, expander, host)
962}
963
964fn apply<H: 'static>(
965 callee: &Value,
966 args: Vec<Value>,
967 call_span: Span,
968 registry: &FnRegistry<H>,
969 expander: &SpannedExpander,
970 host: &mut H,
971) -> Result<Value> {
972 match callee {
973 Value::NativeFn(nfn) => {
974 if nfn.arity.check(args.len()).is_err() {
975 return Err(EvalError::ArityMismatch {
976 fn_name: nfn.name.clone(),
977 expected: nfn.arity,
978 got: args.len(),
979 at: call_span,
980 });
981 }
982 let entry = registry.lookup(&nfn.name).ok_or_else(|| {
983 EvalError::native_fn(
984 nfn.name.clone(),
985 format!("native fn {} is not registered", nfn.name),
986 call_span,
987 )
988 })?;
989 match &entry.callable {
990 FnImpl::Native(f) => f.call(&args, host, call_span),
991 FnImpl::Higher(f) => {
992 let caller = Caller { registry, expander };
993 f.call(&args, host, &caller, call_span)
994 }
995 FnImpl::Awaitable(f) => {
1000 if f.ready(&args, host) {
1001 f.call(&args, host, call_span)
1002 } else {
1003 Ok(crate::vm::Vm::park())
1004 }
1005 }
1006 }
1007 }
1008 Value::Closure(c) => call_closure(c.clone(), args, call_span, registry, expander, host),
1009 Value::Foreign(any) => {
1014 if let Some(cc) = any
1015 .clone()
1016 .downcast::<crate::vm::run::CompiledClosure>()
1017 .ok()
1018 {
1019 let lifted = cc.lift_to_closure();
1020 return call_closure(lifted, args, call_span, registry, expander, host);
1021 }
1022 Err(EvalError::NotCallable {
1023 value_kind: callee.type_name(),
1024 at: call_span,
1025 })
1026 }
1027 other => Err(EvalError::NotCallable {
1028 value_kind: other.type_name(),
1029 at: call_span,
1030 }),
1031 }
1032}
1033
1034enum TailResult {
1057 Done(Value),
1059 Resume(Arc<Closure>, Vec<Value>, Span),
1064}
1065
1066fn eval_in_tail<H: 'static>(
1070 env: &mut Env,
1071 registry: &FnRegistry<H>,
1072 expander: &SpannedExpander,
1073 form: &Spanned,
1074 host: &mut H,
1075) -> Result<TailResult> {
1076 match &form.form {
1077 SpannedForm::List(items) if !items.is_empty() => {
1078 if let Some(head_sym) = items[0].as_symbol() {
1080 if let Some(sf) = SpecialForm::from_symbol(head_sym) {
1081 return eval_special_tail(sf, items, form.span, env, registry, expander, host);
1082 }
1083 }
1084 let head_val = eval_in(env, registry, expander, &items[0], host)?;
1087 let mut args: Vec<Value> = Vec::with_capacity(items.len().saturating_sub(1));
1088 for arg_form in &items[1..] {
1089 args.push(eval_in(env, registry, expander, arg_form, host)?);
1090 }
1091 match head_val {
1092 Value::Closure(c) => Ok(TailResult::Resume(c, args, form.span)),
1093 _ => apply(&head_val, args, form.span, registry, expander, host)
1094 .map(TailResult::Done),
1095 }
1096 }
1097 _ => eval_in(env, registry, expander, form, host).map(TailResult::Done),
1099 }
1100}
1101
1102fn eval_special_tail<H: 'static>(
1103 sf: SpecialForm,
1104 items: &[Spanned],
1105 call_span: Span,
1106 env: &mut Env,
1107 registry: &FnRegistry<H>,
1108 expander: &SpannedExpander,
1109 host: &mut H,
1110) -> Result<TailResult> {
1111 match sf {
1112 SpecialForm::If => {
1113 if items.len() < 3 || items.len() > 4 {
1114 return eval_special(sf, items, call_span, env, registry, expander, host)
1115 .map(TailResult::Done);
1116 }
1117 let c = eval_in(env, registry, expander, &items[1], host)?;
1118 if c.is_truthy() {
1119 eval_in_tail(env, registry, expander, &items[2], host)
1120 } else if items.len() == 4 {
1121 eval_in_tail(env, registry, expander, &items[3], host)
1122 } else {
1123 Ok(TailResult::Done(Value::Nil))
1124 }
1125 }
1126 SpecialForm::Begin => {
1127 let body = &items[1..];
1128 if body.is_empty() {
1129 return Ok(TailResult::Done(Value::Nil));
1130 }
1131 for form in &body[..body.len() - 1] {
1132 eval_in(env, registry, expander, form, host)?;
1133 }
1134 eval_in_tail(env, registry, expander, body.last().unwrap(), host)
1135 }
1136 SpecialForm::When | SpecialForm::Unless => {
1137 if items.len() < 2 {
1138 return eval_special(sf, items, call_span, env, registry, expander, host)
1139 .map(TailResult::Done);
1140 }
1141 let invert = matches!(sf, SpecialForm::Unless);
1142 let cond = eval_in(env, registry, expander, &items[1], host)?;
1143 let run = cond.is_truthy() ^ invert;
1144 if !run {
1145 return Ok(TailResult::Done(Value::Nil));
1146 }
1147 let body = &items[2..];
1148 if body.is_empty() {
1149 return Ok(TailResult::Done(Value::Nil));
1150 }
1151 for form in &body[..body.len() - 1] {
1152 eval_in(env, registry, expander, form, host)?;
1153 }
1154 eval_in_tail(env, registry, expander, body.last().unwrap(), host)
1155 }
1156 SpecialForm::Cond => {
1157 for clause in &items[1..] {
1158 let Some(clause_list) = clause.as_list() else {
1159 return eval_special(sf, items, call_span, env, registry, expander, host)
1160 .map(TailResult::Done);
1161 };
1162 if clause_list.is_empty() {
1163 return eval_special(sf, items, call_span, env, registry, expander, host)
1164 .map(TailResult::Done);
1165 }
1166 let is_else = clause_list[0].as_symbol() == Some("else");
1167 let cond_matches = if is_else {
1168 true
1169 } else {
1170 eval_in(env, registry, expander, &clause_list[0], host)?.is_truthy()
1171 };
1172 if cond_matches {
1173 let body = &clause_list[1..];
1174 if body.is_empty() {
1175 return Ok(TailResult::Done(Value::Nil));
1176 }
1177 for form in &body[..body.len() - 1] {
1178 eval_in(env, registry, expander, form, host)?;
1179 }
1180 return eval_in_tail(env, registry, expander, body.last().unwrap(), host);
1181 }
1182 }
1183 Ok(TailResult::Done(Value::Nil))
1184 }
1185 SpecialForm::Let | SpecialForm::LetStar | SpecialForm::LetRec => {
1186 eval_let_family_tail(sf, items, call_span, env, registry, expander, host)
1187 }
1188 SpecialForm::And => {
1189 let exprs = &items[1..];
1190 if exprs.is_empty() {
1191 return Ok(TailResult::Done(Value::Bool(true)));
1192 }
1193 for e in &exprs[..exprs.len() - 1] {
1195 let v = eval_in(env, registry, expander, e, host)?;
1196 if !v.is_truthy() {
1197 return Ok(TailResult::Done(v));
1198 }
1199 }
1200 eval_in_tail(env, registry, expander, exprs.last().unwrap(), host)
1202 }
1203 SpecialForm::Or => {
1204 let exprs = &items[1..];
1205 if exprs.is_empty() {
1206 return Ok(TailResult::Done(Value::Bool(false)));
1207 }
1208 for e in &exprs[..exprs.len() - 1] {
1209 let v = eval_in(env, registry, expander, e, host)?;
1210 if v.is_truthy() {
1211 return Ok(TailResult::Done(v));
1212 }
1213 }
1214 eval_in_tail(env, registry, expander, exprs.last().unwrap(), host)
1215 }
1216 SpecialForm::Try => {
1217 sf_try(items, call_span, env, registry, expander, host).map(TailResult::Done)
1223 }
1224 SpecialForm::MacroexpandOne => {
1225 sf_macroexpand(items, call_span, env, registry, expander, host, false)
1226 .map(TailResult::Done)
1227 }
1228 SpecialForm::MacroexpandAll => {
1229 sf_macroexpand(items, call_span, env, registry, expander, host, true)
1230 .map(TailResult::Done)
1231 }
1232 SpecialForm::Delay => sf_delay(items, call_span, env).map(TailResult::Done),
1233 SpecialForm::Eval => {
1234 sf_eval(items, call_span, env, registry, expander, host).map(TailResult::Done)
1235 }
1236 _ => {
1238 eval_special(sf, items, call_span, env, registry, expander, host).map(TailResult::Done)
1239 }
1240 }
1241}
1242
1243fn eval_let_family_tail<H: 'static>(
1247 sf: SpecialForm,
1248 items: &[Spanned],
1249 call_span: Span,
1250 env: &mut Env,
1251 registry: &FnRegistry<H>,
1252 expander: &SpannedExpander,
1253 host: &mut H,
1254) -> Result<TailResult> {
1255 if items.len() < 3 {
1256 return Err(EvalError::bad_form(
1257 match sf {
1258 SpecialForm::Let => "let",
1259 SpecialForm::LetStar => "let*",
1260 SpecialForm::LetRec => "letrec",
1261 _ => "let-family",
1262 },
1263 "expected ((name expr)...) body...",
1264 call_span,
1265 ));
1266 }
1267 let bindings = parse_binding_list(
1268 &items[1],
1269 match sf {
1270 SpecialForm::Let => "let",
1271 SpecialForm::LetStar => "let*",
1272 SpecialForm::LetRec => "letrec",
1273 _ => "let-family",
1274 },
1275 )?;
1276
1277 match sf {
1278 SpecialForm::Let => {
1279 let mut values = Vec::with_capacity(bindings.len());
1280 for (_, expr) in &bindings {
1281 values.push(eval_in(env, registry, expander, expr, host)?);
1282 }
1283 env.push();
1284 for ((name, _), val) in bindings.into_iter().zip(values) {
1285 env.define(name, val);
1286 }
1287 }
1288 SpecialForm::LetStar => {
1289 env.push();
1290 for (name, expr) in bindings {
1291 let v = eval_in(env, registry, expander, expr, host)?;
1292 env.define(name, v);
1293 }
1294 }
1295 SpecialForm::LetRec => {
1296 env.push();
1297 for (name, _) in &bindings {
1298 env.define(name.clone(), Value::Nil);
1299 }
1300 for (name, expr) in &bindings {
1301 let v = eval_in(env, registry, expander, expr, host)?;
1302 env.define(name.clone(), v);
1303 }
1304 }
1305 _ => unreachable!(),
1306 }
1307
1308 let body = &items[2..];
1309 let result = if body.is_empty() {
1310 Ok(TailResult::Done(Value::Nil))
1311 } else {
1312 for form in &body[..body.len() - 1] {
1313 if let Err(e) = eval_in(env, registry, expander, form, host) {
1314 env.pop();
1315 return Err(e);
1316 }
1317 }
1318 eval_in_tail(env, registry, expander, body.last().unwrap(), host)
1319 };
1320 env.pop();
1321 result
1322}
1323
1324pub(crate) fn apply_external<H: 'static>(
1330 callee: &Value,
1331 args: Vec<Value>,
1332 call_span: Span,
1333 registry: &FnRegistry<H>,
1334 expander: &SpannedExpander,
1335 host: &mut H,
1336) -> Result<Value> {
1337 apply(callee, args, call_span, registry, expander, host)
1338}
1339
1340fn bind_macro_args(
1349 env: &mut Env,
1350 macro_name: &str,
1351 params: &MacroParams,
1352 args: &[Spanned],
1353 call_span: Span,
1354) -> Result<()> {
1355 let bound = params
1356 .bind_carrier(macro_name, args, call_span)
1357 .map_err(|e| {
1358 EvalError::native_fn(
1359 Arc::<str>::from(format!("macro {macro_name}")),
1360 e.to_string(),
1361 call_span,
1362 )
1363 })?;
1364 for (name, value) in params.names().into_iter().zip(bound.iter()) {
1365 env.define(Arc::<str>::from(name), spanned_to_value(value));
1366 }
1367 Ok(())
1368}
1369
1370fn call_closure<H: 'static>(
1375 closure: Arc<Closure>,
1376 args: Vec<Value>,
1377 call_span: Span,
1378 registry: &FnRegistry<H>,
1379 expander: &SpannedExpander,
1380 host: &mut H,
1381) -> Result<Value> {
1382 let mut current = closure;
1383 let mut current_args = args;
1384 let mut current_span = call_span;
1385 loop {
1386 let required = current.params.len();
1388 let has_rest = current.rest.is_some();
1389 if !has_rest && current_args.len() != required {
1390 return Err(EvalError::ArityMismatch {
1391 fn_name: Arc::from("<closure>"),
1392 expected: Arity::Exact(required),
1393 got: current_args.len(),
1394 at: current_span,
1395 });
1396 }
1397 if has_rest && current_args.len() < required {
1398 return Err(EvalError::ArityMismatch {
1399 fn_name: Arc::from("<closure>"),
1400 expected: Arity::AtLeast(required),
1401 got: current_args.len(),
1402 at: current_span,
1403 });
1404 }
1405
1406 let mut env = current.captured_env.clone();
1409 env.push();
1410 for (param, arg) in current.params.iter().zip(current_args.iter()) {
1411 env.define(param.clone(), arg.clone());
1412 }
1413 if let Some(rest_name) = ¤t.rest {
1414 let rest_args: Vec<Value> = current_args.iter().skip(required).cloned().collect();
1415 env.define(rest_name.clone(), Value::list(rest_args));
1416 }
1417
1418 let body = ¤t.body;
1421 if body.is_empty() {
1422 return Ok(Value::Nil);
1423 }
1424 for body_form in &body[..body.len() - 1] {
1425 eval_in(&mut env, registry, expander, body_form, host)?;
1426 }
1427 match eval_in_tail(&mut env, registry, expander, body.last().unwrap(), host)? {
1428 TailResult::Done(v) => return Ok(v),
1429 TailResult::Resume(next, next_args, next_span) => {
1430 current = next;
1433 current_args = next_args;
1434 current_span = next_span;
1435 }
1436 }
1437 }
1438}
1439
1440fn eval_special<H: 'static>(
1443 sf: SpecialForm,
1444 items: &[Spanned],
1445 call_span: Span,
1446 env: &mut Env,
1447 registry: &FnRegistry<H>,
1448 expander: &SpannedExpander,
1449 host: &mut H,
1450) -> Result<Value> {
1451 match sf {
1452 SpecialForm::Quote => sf_quote(items, call_span),
1453 SpecialForm::Quasiquote => {
1454 if items.len() != 2 {
1455 return Err(EvalError::bad_form(
1456 "quasiquote",
1457 format!("expected 1 arg, got {}", items.len() - 1),
1458 call_span,
1459 ));
1460 }
1461 quasiquote_eval(&items[1], env, registry, expander, host)
1462 }
1463 SpecialForm::If => sf_if(items, call_span, env, registry, expander, host),
1464 SpecialForm::Cond => sf_cond(items, call_span, env, registry, expander, host),
1465 SpecialForm::When => sf_when_unless(items, call_span, env, registry, expander, host, false),
1466 SpecialForm::Unless => {
1467 sf_when_unless(items, call_span, env, registry, expander, host, true)
1468 }
1469 SpecialForm::Let => sf_let(items, call_span, env, registry, expander, host),
1470 SpecialForm::LetStar => sf_let_star(items, call_span, env, registry, expander, host),
1471 SpecialForm::LetRec => sf_letrec(items, call_span, env, registry, expander, host),
1472 SpecialForm::Lambda => sf_lambda(items, call_span, env),
1473 SpecialForm::Define => sf_define(items, call_span, env, registry, expander, host),
1474 SpecialForm::Set => sf_set(items, call_span, env, registry, expander, host),
1475 SpecialForm::Begin => sf_begin(&items[1..], env, registry, expander, host),
1476 SpecialForm::And => sf_and(&items[1..], env, registry, expander, host),
1477 SpecialForm::Or => sf_or(&items[1..], env, registry, expander, host),
1478 SpecialForm::Not => sf_not(items, call_span, env, registry, expander, host),
1479 SpecialForm::Try => sf_try(items, call_span, env, registry, expander, host),
1480 SpecialForm::MacroexpandOne => {
1481 sf_macroexpand(items, call_span, env, registry, expander, host, false)
1482 }
1483 SpecialForm::MacroexpandAll => {
1484 sf_macroexpand(items, call_span, env, registry, expander, host, true)
1485 }
1486 SpecialForm::Delay => sf_delay(items, call_span, env),
1487 SpecialForm::Eval => sf_eval(items, call_span, env, registry, expander, host),
1488 SpecialForm::Provide | SpecialForm::Require => Err(EvalError::bad_form(
1489 if matches!(sf, SpecialForm::Provide) { "provide" } else { "require" },
1490 "module-system forms are only valid at top level — wrap your call in (eval (quote ...)) if you really need it dynamic",
1491 call_span,
1492 )),
1493 }
1494}
1495
1496fn head_symbol(form: &Spanned) -> Option<&str> {
1500 let SpannedForm::List(items) = &form.form else {
1501 return None;
1502 };
1503 items.first().and_then(Spanned::as_symbol)
1504}
1505
1506fn error_value(tag: &str, message: &str) -> Value {
1508 Value::Error(Arc::new(ErrorObj {
1509 tag: Arc::from(tag),
1510 message: Arc::from(message),
1511 data: Vec::new(),
1512 }))
1513}
1514
1515fn module_error_to_eval(e: ModuleError, span: Span) -> EvalError {
1519 let (tag, message) = match &e {
1520 ModuleError::NotFound(_) => ("module-not-found", e.to_string()),
1521 ModuleError::Circular { .. } => ("circular-require", e.to_string()),
1522 ModuleError::NotExported(_, _) => ("not-exported", e.to_string()),
1523 };
1524 EvalError::User {
1525 value: error_value(tag, &message),
1526 at: span,
1527 }
1528}
1529
1530fn sf_quote(items: &[Spanned], span: Span) -> Result<Value> {
1531 if items.len() != 2 {
1532 return Err(EvalError::bad_form(
1533 "quote",
1534 format!("expected 1 arg, got {}", items.len() - 1),
1535 span,
1536 ));
1537 }
1538 Ok(crate::code::spanned_to_value(&items[1]))
1544}
1545
1546fn sf_if<H: 'static>(
1547 items: &[Spanned],
1548 span: Span,
1549 env: &mut Env,
1550 registry: &FnRegistry<H>,
1551 expander: &SpannedExpander,
1552 host: &mut H,
1553) -> Result<Value> {
1554 if items.len() < 3 || items.len() > 4 {
1555 return Err(EvalError::bad_form(
1556 "if",
1557 format!("expected (if c t [e]), got {} subforms", items.len()),
1558 span,
1559 ));
1560 }
1561 let c = eval_in(env, registry, expander, &items[1], host)?;
1562 if c.is_truthy() {
1563 eval_in(env, registry, expander, &items[2], host)
1564 } else if items.len() == 4 {
1565 eval_in(env, registry, expander, &items[3], host)
1566 } else {
1567 Ok(Value::Nil)
1568 }
1569}
1570
1571fn sf_cond<H: 'static>(
1572 items: &[Spanned],
1573 span: Span,
1574 env: &mut Env,
1575 registry: &FnRegistry<H>,
1576 expander: &SpannedExpander,
1577 host: &mut H,
1578) -> Result<Value> {
1579 for clause in &items[1..] {
1580 let Some(clause_list) = clause.as_list() else {
1581 return Err(EvalError::bad_form(
1582 "cond",
1583 "clause must be a list",
1584 clause.span,
1585 ));
1586 };
1587 if clause_list.is_empty() {
1588 return Err(EvalError::bad_form("cond", "empty clause", clause.span));
1589 }
1590 let is_else = clause_list[0].as_symbol() == Some("else");
1591 let cond_matches = if is_else {
1592 true
1593 } else {
1594 let v = eval_in(env, registry, expander, &clause_list[0], host)?;
1595 v.is_truthy()
1596 };
1597 if cond_matches {
1598 let mut last = Value::Nil;
1599 for expr in &clause_list[1..] {
1600 last = eval_in(env, registry, expander, expr, host)?;
1601 }
1602 return Ok(last);
1603 }
1604 }
1605 let _ = span;
1607 Ok(Value::Nil)
1608}
1609
1610fn sf_when_unless<H: 'static>(
1611 items: &[Spanned],
1612 span: Span,
1613 env: &mut Env,
1614 registry: &FnRegistry<H>,
1615 expander: &SpannedExpander,
1616 host: &mut H,
1617 invert: bool,
1618) -> Result<Value> {
1619 if items.len() < 2 {
1620 return Err(EvalError::bad_form(
1621 if invert { "unless" } else { "when" },
1622 "need a test",
1623 span,
1624 ));
1625 }
1626 let cond = eval_in(env, registry, expander, &items[1], host)?;
1627 let run = cond.is_truthy() ^ invert;
1628 if run {
1629 let mut last = Value::Nil;
1630 for expr in &items[2..] {
1631 last = eval_in(env, registry, expander, expr, host)?;
1632 }
1633 Ok(last)
1634 } else {
1635 Ok(Value::Nil)
1636 }
1637}
1638
1639fn parse_binding_list<'a>(
1641 list: &'a Spanned,
1642 form_name: &'static str,
1643) -> Result<Vec<(Arc<str>, &'a Spanned)>> {
1644 let bindings = list
1645 .as_list()
1646 .ok_or_else(|| EvalError::bad_form(form_name, "bindings must be a list", list.span))?;
1647 let mut out = Vec::with_capacity(bindings.len());
1648 for binding in bindings {
1649 let pair = binding.as_list().ok_or_else(|| {
1650 EvalError::bad_form(form_name, "each binding must be (name expr)", binding.span)
1651 })?;
1652 if pair.len() != 2 {
1653 return Err(EvalError::bad_form(
1654 form_name,
1655 "binding must be exactly (name expr)",
1656 binding.span,
1657 ));
1658 }
1659 let name = pair[0].as_symbol().ok_or_else(|| {
1660 EvalError::bad_form(form_name, "binding name must be a symbol", pair[0].span)
1661 })?;
1662 out.push((Arc::<str>::from(name), &pair[1]));
1663 }
1664 Ok(out)
1665}
1666
1667fn sf_let<H: 'static>(
1668 items: &[Spanned],
1669 span: Span,
1670 env: &mut Env,
1671 registry: &FnRegistry<H>,
1672 expander: &SpannedExpander,
1673 host: &mut H,
1674) -> Result<Value> {
1675 if items.len() < 3 {
1676 return Err(EvalError::bad_form(
1677 "let",
1678 "expected (let ((name expr)...) body...)",
1679 span,
1680 ));
1681 }
1682 let bindings = parse_binding_list(&items[1], "let")?;
1683 let mut values = Vec::with_capacity(bindings.len());
1686 for (_, expr) in &bindings {
1687 values.push(eval_in(env, registry, expander, expr, host)?);
1688 }
1689 env.push();
1690 for ((name, _), val) in bindings.into_iter().zip(values) {
1691 env.define(name, val);
1692 }
1693 let result = eval_body(&items[2..], env, registry, expander, host);
1694 env.pop();
1695 result
1696}
1697
1698fn sf_let_star<H: 'static>(
1699 items: &[Spanned],
1700 span: Span,
1701 env: &mut Env,
1702 registry: &FnRegistry<H>,
1703 expander: &SpannedExpander,
1704 host: &mut H,
1705) -> Result<Value> {
1706 if items.len() < 3 {
1707 return Err(EvalError::bad_form(
1708 "let*",
1709 "expected (let* ((name expr)...) body...)",
1710 span,
1711 ));
1712 }
1713 let bindings = parse_binding_list(&items[1], "let*")?;
1714 env.push();
1715 for (name, expr) in bindings {
1716 let v = eval_in(env, registry, expander, expr, host)?;
1717 env.define(name, v);
1718 }
1719 let result = eval_body(&items[2..], env, registry, expander, host);
1720 env.pop();
1721 result
1722}
1723
1724fn sf_letrec<H: 'static>(
1725 items: &[Spanned],
1726 span: Span,
1727 env: &mut Env,
1728 registry: &FnRegistry<H>,
1729 expander: &SpannedExpander,
1730 host: &mut H,
1731) -> Result<Value> {
1732 if items.len() < 3 {
1733 return Err(EvalError::bad_form(
1734 "letrec",
1735 "expected (letrec ((name expr)...) body...)",
1736 span,
1737 ));
1738 }
1739 let bindings = parse_binding_list(&items[1], "letrec")?;
1740 env.push();
1741 for (name, _) in &bindings {
1744 env.define(name.clone(), Value::Nil);
1745 }
1746 for (name, expr) in &bindings {
1747 let v = eval_in(env, registry, expander, expr, host)?;
1748 env.define(name.clone(), v);
1749 }
1750 let result = eval_body(&items[2..], env, registry, expander, host);
1751 env.pop();
1752 result
1753}
1754
1755fn eval_body<H: 'static>(
1756 body: &[Spanned],
1757 env: &mut Env,
1758 registry: &FnRegistry<H>,
1759 expander: &SpannedExpander,
1760 host: &mut H,
1761) -> Result<Value> {
1762 let mut last = Value::Nil;
1763 for form in body {
1764 last = eval_in(env, registry, expander, form, host)?;
1765 }
1766 Ok(last)
1767}
1768
1769fn sf_lambda(items: &[Spanned], span: Span, env: &Env) -> Result<Value> {
1770 if items.len() < 3 {
1771 return Err(EvalError::bad_form(
1772 "lambda",
1773 "expected (lambda (params...) body...)",
1774 span,
1775 ));
1776 }
1777 let param_list: &[Spanned] = match &items[1].form {
1780 SpannedForm::Nil => &[],
1781 SpannedForm::List(xs) => xs.as_slice(),
1782 _ => {
1783 return Err(EvalError::bad_form(
1784 "lambda",
1785 "params must be a list",
1786 items[1].span,
1787 ))
1788 }
1789 };
1790 let (params, rest) = parse_lambda_params(param_list, items[1].span)?;
1791 let body = items[2..].to_vec();
1792 Ok(Value::Closure(Arc::new(Closure {
1793 params,
1794 rest,
1795 body,
1796 captured_env: env.clone(),
1797 source: span,
1798 })))
1799}
1800
1801fn parse_lambda_params(list: &[Spanned], span: Span) -> Result<(Vec<Arc<str>>, Option<Arc<str>>)> {
1802 let mut params = Vec::new();
1803 let mut rest = None;
1804 let mut i = 0;
1805 while i < list.len() {
1806 let s = list[i]
1807 .as_symbol()
1808 .ok_or_else(|| EvalError::bad_form("lambda", "param must be a symbol", list[i].span))?;
1809 if s == "&rest" {
1810 let name = list
1811 .get(i + 1)
1812 .and_then(Spanned::as_symbol)
1813 .ok_or_else(|| EvalError::bad_form("lambda", "&rest needs a name", span))?;
1814 rest = Some(Arc::<str>::from(name));
1815 if i + 2 != list.len() {
1816 return Err(EvalError::bad_form(
1817 "lambda",
1818 "&rest must be the last param",
1819 span,
1820 ));
1821 }
1822 break;
1823 }
1824 params.push(Arc::<str>::from(s));
1825 i += 1;
1826 }
1827 Ok((params, rest))
1828}
1829
1830fn sf_define<H: 'static>(
1832 items: &[Spanned],
1833 span: Span,
1834 env: &mut Env,
1835 registry: &FnRegistry<H>,
1836 expander: &SpannedExpander,
1837 host: &mut H,
1838) -> Result<Value> {
1839 if items.len() < 3 {
1840 return Err(EvalError::bad_form(
1841 "define",
1842 "expected (define name expr) or (define (name args) body)",
1843 span,
1844 ));
1845 }
1846 match &items[1].form {
1847 SpannedForm::Atom(Atom::Symbol(name)) => {
1848 let v = eval_in(env, registry, expander, &items[2], host)?;
1849 env.define(Arc::<str>::from(name.as_str()), v);
1850 Ok(Value::Nil)
1851 }
1852 SpannedForm::List(head_list) => {
1853 if head_list.is_empty() {
1854 return Err(EvalError::bad_form(
1855 "define",
1856 "empty (name args) list",
1857 items[1].span,
1858 ));
1859 }
1860 let name = head_list[0].as_symbol().ok_or_else(|| {
1861 EvalError::bad_form(
1862 "define",
1863 "first item in (name args) must be a symbol",
1864 head_list[0].span,
1865 )
1866 })?;
1867 let (params, rest) = parse_lambda_params(&head_list[1..], items[1].span)?;
1868 let body = items[2..].to_vec();
1869 let closure = Arc::new(Closure {
1870 params,
1871 rest,
1872 body,
1873 captured_env: env.clone(),
1874 source: span,
1875 });
1876 env.define(Arc::<str>::from(name), Value::Closure(closure));
1877 Ok(Value::Nil)
1878 }
1879 _ => Err(EvalError::bad_form(
1880 "define",
1881 "second form must be a symbol or (name args) list",
1882 items[1].span,
1883 )),
1884 }
1885}
1886
1887fn sf_set<H: 'static>(
1888 items: &[Spanned],
1889 span: Span,
1890 env: &mut Env,
1891 registry: &FnRegistry<H>,
1892 expander: &SpannedExpander,
1893 host: &mut H,
1894) -> Result<Value> {
1895 if items.len() != 3 {
1896 return Err(EvalError::bad_form(
1897 "set!",
1898 "expected (set! name expr)",
1899 span,
1900 ));
1901 }
1902 let name = items[1]
1903 .as_symbol()
1904 .ok_or_else(|| EvalError::bad_form("set!", "first arg must be a symbol", items[1].span))?;
1905 let v = eval_in(env, registry, expander, &items[2], host)?;
1906 if env.set(name, v) {
1907 Ok(Value::Nil)
1908 } else if env.is_sealed_binding(name) {
1909 Err(EvalError::bad_form(
1912 "set!",
1913 format!(
1914 "cannot `set!` {name:?} from a macro body — it is bound outside \
1915 the expansion and sealed. Macro expansion must be deterministic, \
1916 so compile-time state cannot outlive the expansion. Use a local \
1917 binding, or return the value in the expansion."
1918 ),
1919 items[1].span,
1920 ))
1921 } else {
1922 Err(EvalError::unbound(name, items[1].span))
1923 }
1924}
1925
1926fn sf_begin<H: 'static>(
1927 body: &[Spanned],
1928 env: &mut Env,
1929 registry: &FnRegistry<H>,
1930 expander: &SpannedExpander,
1931 host: &mut H,
1932) -> Result<Value> {
1933 eval_body(body, env, registry, expander, host)
1934}
1935
1936fn sf_and<H: 'static>(
1937 exprs: &[Spanned],
1938 env: &mut Env,
1939 registry: &FnRegistry<H>,
1940 expander: &SpannedExpander,
1941 host: &mut H,
1942) -> Result<Value> {
1943 let mut last = Value::Bool(true);
1944 for e in exprs {
1945 last = eval_in(env, registry, expander, e, host)?;
1946 if !last.is_truthy() {
1947 return Ok(last);
1948 }
1949 }
1950 Ok(last)
1951}
1952
1953fn sf_or<H: 'static>(
1954 exprs: &[Spanned],
1955 env: &mut Env,
1956 registry: &FnRegistry<H>,
1957 expander: &SpannedExpander,
1958 host: &mut H,
1959) -> Result<Value> {
1960 let mut last = Value::Bool(false);
1961 for e in exprs {
1962 last = eval_in(env, registry, expander, e, host)?;
1963 if last.is_truthy() {
1964 return Ok(last);
1965 }
1966 }
1967 Ok(last)
1968}
1969
1970fn sf_not<H: 'static>(
1971 items: &[Spanned],
1972 span: Span,
1973 env: &mut Env,
1974 registry: &FnRegistry<H>,
1975 expander: &SpannedExpander,
1976 host: &mut H,
1977) -> Result<Value> {
1978 if items.len() != 2 {
1979 return Err(EvalError::bad_form("not", "expected (not x)", span));
1980 }
1981 let v = eval_in(env, registry, expander, &items[1], host)?;
1982 Ok(Value::Bool(!v.is_truthy()))
1983}
1984
1985fn sf_try<H: 'static>(
2004 items: &[Spanned],
2005 span: Span,
2006 env: &mut Env,
2007 registry: &FnRegistry<H>,
2008 expander: &SpannedExpander,
2009 host: &mut H,
2010) -> Result<Value> {
2011 if items.len() < 3 {
2012 return Err(EvalError::bad_form(
2013 "try",
2014 "expected (try body... (catch (e) handler...))",
2015 span,
2016 ));
2017 }
2018 let catch_form = items.last().unwrap();
2020 let catch_list = catch_form.as_list().ok_or_else(|| {
2021 EvalError::bad_form(
2022 "try",
2023 "last form must be (catch (binding) handler...)",
2024 catch_form.span,
2025 )
2026 })?;
2027 if catch_list.is_empty() || catch_list[0].as_symbol() != Some("catch") {
2028 return Err(EvalError::bad_form(
2029 "try",
2030 "last form must be a (catch ...) clause",
2031 catch_form.span,
2032 ));
2033 }
2034 if catch_list.len() < 3 {
2035 return Err(EvalError::bad_form(
2036 "catch",
2037 "expected (catch (binding) handler...)",
2038 catch_form.span,
2039 ));
2040 }
2041 let binding_list = catch_list[1].as_list().ok_or_else(|| {
2042 EvalError::bad_form(
2043 "catch",
2044 "binding must be a 1-element list (e)",
2045 catch_list[1].span,
2046 )
2047 })?;
2048 if binding_list.len() != 1 {
2049 return Err(EvalError::bad_form(
2050 "catch",
2051 "binding must bind exactly one symbol",
2052 catch_list[1].span,
2053 ));
2054 }
2055 let binding_name = binding_list[0].as_symbol().ok_or_else(|| {
2056 EvalError::bad_form("catch", "binding must be a symbol", binding_list[0].span)
2057 })?;
2058
2059 let body = &items[1..items.len() - 1];
2060 let mut last = Value::Nil;
2061 for form in body {
2062 match eval_in(env, registry, expander, form, host) {
2063 Ok(v) => {
2064 last = v;
2065 }
2066 Err(EvalError::User { value, .. }) => {
2067 return run_catch_handler(
2068 binding_name,
2069 value,
2070 &catch_list[2..],
2071 env,
2072 registry,
2073 expander,
2074 host,
2075 );
2076 }
2077 Err(other) => {
2078 let value = rust_err_to_value_error(&other);
2082 return run_catch_handler(
2083 binding_name,
2084 value,
2085 &catch_list[2..],
2086 env,
2087 registry,
2088 expander,
2089 host,
2090 );
2091 }
2092 }
2093 }
2094 Ok(last)
2095}
2096
2097fn run_catch_handler<H: 'static>(
2098 binding_name: &str,
2099 error_value: Value,
2100 handler_body: &[Spanned],
2101 env: &mut Env,
2102 registry: &FnRegistry<H>,
2103 expander: &SpannedExpander,
2104 host: &mut H,
2105) -> Result<Value> {
2106 env.push();
2107 env.define(Arc::<str>::from(binding_name), error_value);
2108 let mut last = Value::Nil;
2109 for form in handler_body {
2110 match eval_in(env, registry, expander, form, host) {
2111 Ok(v) => last = v,
2112 Err(e) => {
2113 env.pop();
2114 return Err(e);
2115 }
2116 }
2117 }
2118 env.pop();
2119 Ok(last)
2120}
2121
2122fn sf_eval<H: 'static>(
2131 items: &[Spanned],
2132 call_span: Span,
2133 env: &mut Env,
2134 registry: &FnRegistry<H>,
2135 expander: &SpannedExpander,
2136 host: &mut H,
2137) -> Result<Value> {
2138 if items.len() != 2 {
2139 return Err(EvalError::bad_form(
2140 "eval",
2141 "expected (eval form)",
2142 call_span,
2143 ));
2144 }
2145 let form_value = eval_in(env, registry, expander, &items[1], host)?;
2146 let form_spanned = crate::code::value_to_spanned(&form_value, call_span)
2147 .map_err(|reason| EvalError::native_fn(Arc::<str>::from("eval"), reason, call_span))?;
2148 let expanded = fully_expand_with(&form_spanned, registry, expander, env, host)?;
2149 eval_in(env, registry, expander, &expanded, host)
2150}
2151
2152fn sf_delay(items: &[Spanned], call_span: Span, env: &Env) -> Result<Value> {
2157 if items.len() != 2 {
2158 return Err(EvalError::bad_form(
2159 "delay",
2160 "expected (delay expr)",
2161 call_span,
2162 ));
2163 }
2164 let body = vec![items[1].clone()];
2165 let thunk = Arc::new(Closure {
2166 params: Vec::new(),
2167 rest: None,
2168 body,
2169 captured_env: env.clone(),
2170 source: call_span,
2171 });
2172 Ok(Value::Promise(Arc::new(std::sync::Mutex::new(
2173 crate::value::PromiseState::Pending(thunk),
2174 ))))
2175}
2176
2177fn sf_macroexpand<H: 'static>(
2186 items: &[Spanned],
2187 call_span: Span,
2188 env: &mut Env,
2189 registry: &FnRegistry<H>,
2190 expander: &SpannedExpander,
2191 host: &mut H,
2192 fully: bool,
2193) -> Result<Value> {
2194 if items.len() != 2 {
2195 return Err(EvalError::bad_form(
2196 if fully {
2197 "macroexpand"
2198 } else {
2199 "macroexpand-1"
2200 },
2201 "expected (macroexpand[-1] form)",
2202 call_span,
2203 ));
2204 }
2205 let form_value = eval_in(env, registry, expander, &items[1], host)?;
2207 let form_spanned = crate::code::value_to_spanned(&form_value, call_span).map_err(|reason| {
2209 EvalError::native_fn(
2210 Arc::<str>::from(if fully {
2211 "macroexpand"
2212 } else {
2213 "macroexpand-1"
2214 }),
2215 reason,
2216 call_span,
2217 )
2218 })?;
2219
2220 let expanded = if fully {
2226 fully_expand_with(&form_spanned, registry, expander, env, host)?
2227 } else {
2228 macroexpand_one(&form_spanned, registry, expander, env, host)?
2229 };
2230
2231 Ok(crate::code::spanned_to_value(&expanded))
2232}
2233
2234fn expand_one_macro_call<H: 'static>(
2238 macro_name: &str,
2239 args: &[Spanned],
2240 call_span: Span,
2241 registry: &FnRegistry<H>,
2242 expander: &SpannedExpander,
2243 parent_env: &Env,
2244 host: &mut H,
2245) -> Result<Spanned> {
2246 let def: MacroDef = expander.get_macro(macro_name).cloned().ok_or_else(|| {
2247 EvalError::native_fn(
2248 Arc::<str>::from(macro_name),
2249 "macro disappeared during expansion",
2250 call_span,
2251 )
2252 })?;
2253 let body_spanned = Spanned::from_sexp_at(&def.body, call_span);
2254 let body_expanded = fully_expand_with(&body_spanned, registry, expander, parent_env, host)?;
2256
2257 let mut macro_env = parent_env.clone();
2258 macro_env.push();
2259 bind_macro_args(&mut macro_env, &def.name, &def.params, args, call_span)?;
2260 let result = eval_in(&mut macro_env, registry, expander, &body_expanded, host)?;
2261
2262 crate::code::value_to_spanned(&result, call_span).map_err(|reason| {
2263 EvalError::native_fn(
2264 Arc::<str>::from(format!("macro {macro_name}")),
2265 reason,
2266 call_span,
2267 )
2268 })
2269}
2270
2271fn fully_expand_with<H: 'static>(
2275 form: &Spanned,
2276 registry: &FnRegistry<H>,
2277 expander: &SpannedExpander,
2278 parent_env: &Env,
2279 host: &mut H,
2280) -> Result<Spanned> {
2281 if expander.is_empty() {
2282 return Ok(form.clone());
2283 }
2284 expand_recursive_with(form, registry, expander, parent_env, host)
2285}
2286
2287fn expand_recursive_with<H: 'static>(
2288 form: &Spanned,
2289 registry: &FnRegistry<H>,
2290 expander: &SpannedExpander,
2291 parent_env: &Env,
2292 host: &mut H,
2293) -> Result<Spanned> {
2294 match &form.form {
2295 SpannedForm::List(items) if !items.is_empty() => {
2296 if let Some(head) = items[0].as_symbol() {
2297 if expander.has(head) {
2298 let expanded = expand_one_macro_call(
2299 head,
2300 &items[1..],
2301 form.span,
2302 registry,
2303 expander,
2304 parent_env,
2305 host,
2306 )?;
2307 return expand_recursive_with(&expanded, registry, expander, parent_env, host);
2308 }
2309 }
2310 let mut out = Vec::with_capacity(items.len());
2311 for child in items {
2312 out.push(expand_recursive_with(
2313 child, registry, expander, parent_env, host,
2314 )?);
2315 }
2316 Ok(Spanned::new(form.span, SpannedForm::List(out)))
2317 }
2318 SpannedForm::Quote(_) => Ok(form.clone()),
2319 SpannedForm::Quasiquote(inner) => Ok(Spanned::new(
2320 form.span,
2321 SpannedForm::Quasiquote(Box::new(expand_inside_quasiquote_with(
2322 inner, registry, expander, parent_env, host,
2323 )?)),
2324 )),
2325 _ => Ok(form.clone()),
2326 }
2327}
2328
2329fn expand_inside_quasiquote_with<H: 'static>(
2330 form: &Spanned,
2331 registry: &FnRegistry<H>,
2332 expander: &SpannedExpander,
2333 parent_env: &Env,
2334 host: &mut H,
2335) -> Result<Spanned> {
2336 match &form.form {
2337 SpannedForm::Unquote(inner) => Ok(Spanned::new(
2338 form.span,
2339 SpannedForm::Unquote(Box::new(expand_recursive_with(
2340 inner, registry, expander, parent_env, host,
2341 )?)),
2342 )),
2343 SpannedForm::UnquoteSplice(inner) => Ok(Spanned::new(
2344 form.span,
2345 SpannedForm::UnquoteSplice(Box::new(expand_recursive_with(
2346 inner, registry, expander, parent_env, host,
2347 )?)),
2348 )),
2349 SpannedForm::List(items) => {
2350 let mut out = Vec::with_capacity(items.len());
2351 for item in items {
2352 out.push(expand_inside_quasiquote_with(
2353 item, registry, expander, parent_env, host,
2354 )?);
2355 }
2356 Ok(Spanned::new(form.span, SpannedForm::List(out)))
2357 }
2358 _ => Ok(form.clone()),
2359 }
2360}
2361
2362fn macroexpand_one<H: 'static>(
2365 form: &Spanned,
2366 registry: &FnRegistry<H>,
2367 expander: &SpannedExpander,
2368 parent_env: &Env,
2369 host: &mut H,
2370) -> Result<Spanned> {
2371 if let SpannedForm::List(items) = &form.form {
2372 if let Some(head) = items.first().and_then(Spanned::as_symbol) {
2373 if expander.has(head) {
2374 return expand_one_macro_call(
2375 head,
2376 &items[1..],
2377 form.span,
2378 registry,
2379 expander,
2380 parent_env,
2381 host,
2382 );
2383 }
2384 }
2385 }
2386 Ok(form.clone())
2387}
2388
2389fn rust_err_to_value_error(err: &EvalError) -> Value {
2392 use crate::value::ErrorObj;
2393 let tag: Arc<str> = match err {
2394 EvalError::UnboundSymbol { .. } => Arc::from("unbound-symbol"),
2395 EvalError::ArityMismatch { .. } => Arc::from("arity-mismatch"),
2396 EvalError::TypeMismatch { .. } => Arc::from("type-mismatch"),
2397 EvalError::DivisionByZero { .. } => Arc::from("division-by-zero"),
2398 EvalError::NotCallable { .. } => Arc::from("not-callable"),
2399 EvalError::BadSpecialForm { .. } => Arc::from("bad-special-form"),
2400 EvalError::NativeFn { .. } => Arc::from("native-fn"),
2401 EvalError::Reader(_) => Arc::from("reader"),
2402 EvalError::Halted => Arc::from("halted"),
2403 EvalError::NotImplemented(_) => Arc::from("not-implemented"),
2404 EvalError::User { .. } => Arc::from("user"),
2405 };
2406 let message: Arc<str> = Arc::from(err.short_message());
2407 Value::Error(Arc::new(ErrorObj {
2408 tag,
2409 message,
2410 data: Vec::new(),
2411 }))
2412}
2413
2414#[cfg(test)]
2415mod tests {
2416 use super::*;
2417 use crate::primitive::install_primitives;
2418 use tatara_lisp::read_spanned;
2419
2420 struct NoHost;
2421
2422 fn eval_ok(src: &str) -> Value {
2423 let forms = read_spanned(src).unwrap();
2424 let mut i: Interpreter<NoHost> = Interpreter::new();
2425 install_primitives(&mut i);
2426 let mut host = NoHost;
2427 i.eval_program(&forms, &mut host).unwrap()
2428 }
2429
2430 fn eval_err(src: &str) -> EvalError {
2431 let forms = read_spanned(src).unwrap();
2432 let mut i: Interpreter<NoHost> = Interpreter::new();
2433 install_primitives(&mut i);
2434 let mut host = NoHost;
2435 i.eval_program(&forms, &mut host).unwrap_err()
2436 }
2437
2438 #[test]
2441 fn literal_int() {
2442 assert!(matches!(eval_ok("42"), Value::Int(42)));
2443 }
2444
2445 #[test]
2446 fn unbound_symbol_errors() {
2447 let e = eval_err("no-such-var");
2448 assert!(matches!(e, EvalError::UnboundSymbol { .. }));
2449 }
2450
2451 #[test]
2452 fn quote_returns_runtime_list_of_symbols() {
2453 let v = eval_ok("'(a b c)");
2456 match v {
2457 Value::List(xs) => {
2458 assert_eq!(xs.len(), 3);
2459 assert!(matches!(&xs[0], Value::Symbol(s) if s.as_ref() == "a"));
2460 assert!(matches!(&xs[1], Value::Symbol(s) if s.as_ref() == "b"));
2461 assert!(matches!(&xs[2], Value::Symbol(s) if s.as_ref() == "c"));
2462 }
2463 other => panic!("{other:?}"),
2464 }
2465 }
2466
2467 #[test]
2470 fn add_ints() {
2471 assert!(matches!(eval_ok("(+ 1 2 3)"), Value::Int(6)));
2472 }
2473
2474 #[test]
2475 fn sub_divides_float() {
2476 match eval_ok("(- 10 3)") {
2477 Value::Int(7) => {}
2478 other => panic!("{other:?}"),
2479 }
2480 }
2481
2482 #[test]
2483 fn division_by_zero_errors() {
2484 assert!(matches!(
2485 eval_err("(/ 1 0)"),
2486 EvalError::DivisionByZero { .. }
2487 ));
2488 }
2489
2490 #[test]
2493 fn if_truthy_branch() {
2494 assert!(matches!(eval_ok("(if #t 1 2)"), Value::Int(1)));
2495 }
2496
2497 #[test]
2498 fn if_falsy_branch() {
2499 assert!(matches!(eval_ok("(if #f 1 2)"), Value::Int(2)));
2500 }
2501
2502 #[test]
2503 fn if_no_else_returns_nil() {
2504 assert!(matches!(eval_ok("(if #f 1)"), Value::Nil));
2505 }
2506
2507 #[test]
2508 fn cond_picks_first_match() {
2509 assert!(matches!(
2510 eval_ok("(cond (#f 1) (#t 2) (else 3))"),
2511 Value::Int(2)
2512 ));
2513 }
2514
2515 #[test]
2516 fn cond_falls_through_to_else() {
2517 assert!(matches!(
2518 eval_ok("(cond (#f 1) (#f 2) (else 3))"),
2519 Value::Int(3)
2520 ));
2521 }
2522
2523 #[test]
2524 fn when_runs_body_if_true() {
2525 assert!(matches!(eval_ok("(when #t 99)"), Value::Int(99)));
2526 assert!(matches!(eval_ok("(when #f 99)"), Value::Nil));
2527 }
2528
2529 #[test]
2532 fn let_binds_and_evaluates_body() {
2533 assert!(matches!(
2534 eval_ok("(let ((x 10) (y 20)) (+ x y))"),
2535 Value::Int(30)
2536 ));
2537 }
2538
2539 #[test]
2540 fn let_star_sequential_bindings() {
2541 assert!(matches!(
2542 eval_ok("(let* ((x 5) (y (+ x 1))) (+ x y))"),
2543 Value::Int(11)
2544 ));
2545 }
2546
2547 #[test]
2548 fn letrec_mutual_recursion() {
2549 let v = eval_ok(
2550 "(letrec ((even? (lambda (n) (if (= n 0) #t (odd? (- n 1)))))
2551 (odd? (lambda (n) (if (= n 0) #f (even? (- n 1))))))
2552 (even? 10))",
2553 );
2554 assert!(matches!(v, Value::Bool(true)));
2555 }
2556
2557 #[test]
2560 fn lambda_applies() {
2561 assert!(matches!(
2562 eval_ok("((lambda (x y) (+ x y)) 3 4)"),
2563 Value::Int(7)
2564 ));
2565 }
2566
2567 #[test]
2568 fn lambda_closes_over_env() {
2569 assert!(matches!(
2570 eval_ok("(let ((n 10)) ((lambda (x) (+ x n)) 5))"),
2571 Value::Int(15)
2572 ));
2573 }
2574
2575 #[test]
2576 fn closure_captures_by_value_at_creation() {
2577 let v = eval_ok(
2580 "(define make-adder (lambda (n) (lambda (x) (+ x n))))
2581 (define add5 (make-adder 5))
2582 (add5 10)",
2583 );
2584 assert!(matches!(v, Value::Int(15)));
2585 }
2586
2587 #[test]
2588 fn rest_args_collect_into_list() {
2589 let v = eval_ok("((lambda (x &rest rs) (length rs)) 1 2 3 4 5)");
2590 assert!(matches!(v, Value::Int(4)));
2591 }
2592
2593 #[test]
2594 fn closure_arity_mismatch() {
2595 let e = eval_err("((lambda (x y) (+ x y)) 1)");
2596 assert!(matches!(e, EvalError::ArityMismatch { .. }));
2597 }
2598
2599 #[test]
2602 fn define_then_use() {
2603 assert!(matches!(eval_ok("(define x 42) x"), Value::Int(42)));
2604 }
2605
2606 #[test]
2607 fn define_function_shorthand() {
2608 assert!(matches!(
2609 eval_ok("(define (sq x) (* x x)) (sq 6)"),
2610 Value::Int(36)
2611 ));
2612 }
2613
2614 #[test]
2615 fn set_mutates_existing() {
2616 assert!(matches!(
2617 eval_ok("(define x 1) (set! x 99) x"),
2618 Value::Int(99)
2619 ));
2620 }
2621
2622 #[test]
2623 fn set_unbound_errors() {
2624 let e = eval_err("(set! nope 1)");
2625 assert!(matches!(e, EvalError::UnboundSymbol { .. }));
2626 }
2627
2628 #[test]
2631 fn begin_returns_last() {
2632 assert!(matches!(eval_ok("(begin 1 2 3)"), Value::Int(3)));
2633 }
2634
2635 #[test]
2636 fn and_short_circuits() {
2637 assert!(matches!(eval_ok("(and 1 #f 2)"), Value::Bool(false)));
2638 assert!(matches!(eval_ok("(and 1 2 3)"), Value::Int(3)));
2639 assert!(matches!(eval_ok("(and)"), Value::Bool(true)));
2640 }
2641
2642 #[test]
2643 fn or_short_circuits() {
2644 assert!(matches!(eval_ok("(or #f #f 7)"), Value::Int(7)));
2645 assert!(matches!(eval_ok("(or #f #f)"), Value::Bool(false)));
2646 assert!(matches!(eval_ok("(or)"), Value::Bool(false)));
2647 }
2648
2649 #[test]
2650 fn not_inverts() {
2651 assert!(matches!(eval_ok("(not #t)"), Value::Bool(false)));
2652 assert!(matches!(eval_ok("(not #f)"), Value::Bool(true)));
2653 assert!(matches!(eval_ok("(not 42)"), Value::Bool(false)));
2654 }
2655
2656 #[test]
2659 fn recursive_factorial() {
2660 let v = eval_ok(
2661 "(define (fact n)
2662 (if (= n 0) 1 (* n (fact (- n 1)))))
2663 (fact 6)",
2664 );
2665 assert!(matches!(v, Value::Int(720)));
2666 }
2667
2668 #[test]
2669 fn recursive_length() {
2670 let v = eval_ok(
2671 "(define (len xs)
2672 (if (null? xs) 0 (+ 1 (len (cdr xs)))))
2673 (len (list 1 2 3 4 5))",
2674 );
2675 assert!(matches!(v, Value::Int(5)));
2676 }
2677
2678 #[test]
2683 fn quasiquote_plain_list_is_runtime_list() {
2684 let v = eval_ok("`(a b c)");
2685 match v {
2686 Value::List(xs) => {
2687 assert_eq!(xs.len(), 3);
2688 assert!(matches!(&xs[0], Value::Symbol(s) if s.as_ref() == "a"));
2689 assert!(matches!(&xs[1], Value::Symbol(s) if s.as_ref() == "b"));
2690 assert!(matches!(&xs[2], Value::Symbol(s) if s.as_ref() == "c"));
2691 }
2692 other => panic!("{other:?}"),
2693 }
2694 }
2695
2696 #[test]
2697 fn quasiquote_unquote_substitutes_evaluated_value() {
2698 let v = eval_ok("(let ((x 42)) `(a ,x c))");
2699 match v {
2700 Value::List(xs) => {
2701 assert_eq!(xs.len(), 3);
2702 assert!(matches!(&xs[1], Value::Int(42)));
2703 }
2704 other => panic!("{other:?}"),
2705 }
2706 }
2707
2708 #[test]
2709 fn quasiquote_unquote_arbitrary_expr() {
2710 let v = eval_ok("`(x ,(+ 1 2 3) y)");
2711 match v {
2712 Value::List(xs) => {
2713 assert!(matches!(&xs[1], Value::Int(6)));
2714 }
2715 other => panic!("{other:?}"),
2716 }
2717 }
2718
2719 #[test]
2720 fn quasiquote_splice_inlines_list() {
2721 let v = eval_ok("`(a ,@(list 1 2 3) b)");
2722 match v {
2723 Value::List(xs) => {
2724 assert_eq!(xs.len(), 5);
2725 assert!(matches!(&xs[0], Value::Symbol(s) if s.as_ref() == "a"));
2726 assert!(matches!(&xs[1], Value::Int(1)));
2727 assert!(matches!(&xs[2], Value::Int(2)));
2728 assert!(matches!(&xs[3], Value::Int(3)));
2729 assert!(matches!(&xs[4], Value::Symbol(s) if s.as_ref() == "b"));
2730 }
2731 other => panic!("{other:?}"),
2732 }
2733 }
2734
2735 #[test]
2736 fn quasiquote_splice_empty_list_splices_nothing() {
2737 let v = eval_ok("`(a ,@(list) b)");
2738 match v {
2739 Value::List(xs) => {
2740 assert_eq!(xs.len(), 2);
2741 assert!(matches!(&xs[0], Value::Symbol(s) if s.as_ref() == "a"));
2742 assert!(matches!(&xs[1], Value::Symbol(s) if s.as_ref() == "b"));
2743 }
2744 other => panic!("{other:?}"),
2745 }
2746 }
2747
2748 #[test]
2749 fn quasiquote_splice_non_list_errors() {
2750 let e = eval_err("`(a ,@42)");
2751 assert!(matches!(e, EvalError::TypeMismatch { .. }));
2752 }
2753
2754 #[test]
2755 fn quasiquote_atom_yields_atom_value() {
2756 assert!(matches!(eval_ok("`foo"), Value::Symbol(s) if s.as_ref() == "foo"));
2757 assert!(matches!(eval_ok("`42"), Value::Int(42)));
2758 }
2759
2760 #[test]
2761 fn quasiquote_with_nested_list_and_unquote() {
2762 let v = eval_ok("(let ((x 99)) `(foo (bar ,x) baz))");
2764 match v {
2765 Value::List(xs) => {
2766 assert_eq!(xs.len(), 3);
2767 match &xs[1] {
2768 Value::List(inner) => {
2769 assert!(matches!(&inner[1], Value::Int(99)));
2770 }
2771 other => panic!("{other:?}"),
2772 }
2773 }
2774 other => panic!("{other:?}"),
2775 }
2776 }
2777
2778 #[test]
2779 fn quasiquote_symbol_keyword_distinction_preserved() {
2780 let v = eval_ok("`(:key val)");
2781 match v {
2782 Value::List(xs) => {
2783 assert!(matches!(&xs[0], Value::Keyword(s) if s.as_ref() == "key"));
2784 assert!(matches!(&xs[1], Value::Symbol(s) if s.as_ref() == "val"));
2785 }
2786 other => panic!("{other:?}"),
2787 }
2788 }
2789
2790 #[test]
2791 fn bare_unquote_outside_quasiquote_errors() {
2792 let e = eval_err(",x");
2793 assert!(matches!(e, EvalError::BadSpecialForm { .. }));
2794 }
2795
2796 #[test]
2799 fn native_fn_reads_host_state() {
2800 struct Counter {
2801 n: i64,
2802 }
2803 let forms = read_spanned("(bump) (bump) (bump) (cur)").unwrap();
2804 let mut i: Interpreter<Counter> = Interpreter::new();
2805 install_primitives(&mut i);
2806 i.register_fn(
2807 "bump",
2808 Arity::Exact(0),
2809 |_args: &[Value], host: &mut Counter, _span| {
2810 host.n += 1;
2811 Ok(Value::Int(host.n))
2812 },
2813 );
2814 i.register_fn(
2815 "cur",
2816 Arity::Exact(0),
2817 |_args: &[Value], host: &mut Counter, _span| Ok(Value::Int(host.n)),
2818 );
2819 let mut host = Counter { n: 0 };
2820 let v = i.eval_program(&forms, &mut host).unwrap();
2821 assert!(matches!(v, Value::Int(3)));
2822 }
2823
2824 struct Ctx {
2827 records: Vec<(String, i64)>,
2828 }
2829
2830 #[test]
2831 fn register_typed1_marshals_string_arg() {
2832 let mut i: Interpreter<Ctx> = Interpreter::new();
2833 install_primitives(&mut i);
2834 i.register_typed1("greet", |_h: &mut Ctx, name: String| -> Result<String> {
2835 Ok(format!("hello {name}"))
2836 });
2837 let forms = read_spanned(r#"(greet "luis")"#).unwrap();
2838 let mut h = Ctx { records: vec![] };
2839 let v = i.eval_program(&forms, &mut h).unwrap();
2840 match v {
2841 Value::Str(s) => assert_eq!(&*s, "hello luis"),
2842 other => panic!("{other:?}"),
2843 }
2844 }
2845
2846 #[test]
2847 fn register_typed2_marshals_host_state_mutation() {
2848 let mut i: Interpreter<Ctx> = Interpreter::new();
2849 install_primitives(&mut i);
2850 i.register_typed2(
2851 "record",
2852 |h: &mut Ctx, name: String, n: i64| -> Result<()> {
2853 h.records.push((name, n));
2854 Ok(())
2855 },
2856 );
2857 let forms = read_spanned(r#"(record "a" 1) (record "b" 2)"#).unwrap();
2858 let mut h = Ctx { records: vec![] };
2859 let _ = i.eval_program(&forms, &mut h).unwrap();
2860 assert_eq!(h.records.len(), 2);
2861 assert_eq!(h.records[0], ("a".to_string(), 1));
2862 assert_eq!(h.records[1], ("b".to_string(), 2));
2863 }
2864
2865 #[test]
2866 fn register_typed_arg_type_mismatch_surfaces_at_call_site() {
2867 let mut i: Interpreter<Ctx> = Interpreter::new();
2868 install_primitives(&mut i);
2869 i.register_typed1("needs-int", |_h: &mut Ctx, n: i64| -> Result<i64> {
2870 Ok(n + 1)
2871 });
2872 let forms = read_spanned(r#"(needs-int "not-a-number")"#).unwrap();
2873 let mut h = Ctx { records: vec![] };
2874 let err = i.eval_program(&forms, &mut h).unwrap_err();
2875 assert!(matches!(
2876 err,
2877 EvalError::TypeMismatch {
2878 expected: "integer",
2879 ..
2880 }
2881 ));
2882 }
2883
2884 #[test]
2885 fn register_typed3_three_args() {
2886 let mut i: Interpreter<Ctx> = Interpreter::new();
2887 install_primitives(&mut i);
2888 i.register_typed3(
2889 "triple-sum",
2890 |_h: &mut Ctx, a: i64, b: i64, c: i64| -> Result<i64> { Ok(a + b + c) },
2891 );
2892 let forms = read_spanned("(triple-sum 10 20 30)").unwrap();
2893 let mut h = Ctx { records: vec![] };
2894 let v = i.eval_program(&forms, &mut h).unwrap();
2895 assert!(matches!(v, Value::Int(60)));
2896 }
2897
2898 #[test]
2901 fn user_macro_expands_and_evaluates() {
2902 let v = eval_ok(
2903 "(defmacro twice (x) `(* ,x 2))
2904 (twice 21)",
2905 );
2906 assert!(matches!(v, Value::Int(42)));
2907 }
2908
2909 #[test]
2910 fn user_macro_definition_returns_nil() {
2911 let v = eval_ok("(defmacro inc (x) `(+ ,x 1))");
2912 assert!(matches!(v, Value::Nil));
2913 }
2914
2915 #[test]
2916 fn user_macro_inside_define_body_expands() {
2917 let v = eval_ok(
2920 "(defmacro inc (x) `(+ ,x 1))
2921 (define (f n) (inc n))
2922 (f 41)",
2923 );
2924 assert!(matches!(v, Value::Int(42)));
2925 }
2926
2927 #[test]
2928 fn user_macro_with_rest_args_splices() {
2929 let v = eval_ok(
2930 "(defmacro sum-all (&rest xs) `(+ ,@xs))
2931 (sum-all 1 2 3 4 5)",
2932 );
2933 assert!(matches!(v, Value::Int(15)));
2934 }
2935
2936 #[test]
2937 fn nested_user_macros_compose() {
2938 let v = eval_ok(
2939 "(defmacro twice (x) `(* ,x 2))
2940 (defmacro quad (x) `(twice (twice ,x)))
2941 (quad 5)",
2942 );
2943 assert!(matches!(v, Value::Int(20)));
2944 }
2945
2946 #[test]
2947 fn user_macro_can_expand_to_special_form() {
2948 let v = eval_ok(
2951 "(defmacro guard (test then) `(if ,test ,then 0))
2952 (guard #t 99)",
2953 );
2954 assert!(matches!(v, Value::Int(99)));
2955 }
2956
2957 #[test]
2958 fn user_macro_redefined_replaces_prior_template() {
2959 let v = eval_ok(
2960 "(defmacro k () `1)
2961 (defmacro k () `2)
2962 (k)",
2963 );
2964 assert!(matches!(v, Value::Int(2)));
2965 }
2966
2967 #[test]
2968 fn user_macro_unbound_template_var_errors() {
2969 let mut i: Interpreter<NoHost> = Interpreter::new();
2975 install_primitives(&mut i);
2976 let forms = read_spanned("(defmacro bad (x) `(list ,y)) (bad 1)").unwrap();
2977 let err = i.eval_program(&forms, &mut NoHost).unwrap_err();
2978 match err {
2979 EvalError::UnboundSymbol { name, .. } => assert_eq!(&*name, "y"),
2980 other => panic!("expected UnboundSymbol, got {other:?}"),
2981 }
2982 }
2983
2984 #[test]
2985 fn defpoint_template_keyword_registers_as_macro() {
2986 let v = eval_ok(
2989 "(defpoint-template double (x) `(* ,x 2))
2990 (double 7)",
2991 );
2992 assert!(matches!(v, Value::Int(14)));
2993 }
2994
2995 #[test]
2996 fn defcheck_keyword_registers_as_macro() {
2997 let v = eval_ok(
2998 "(defcheck always-7 () `7)
2999 (always-7)",
3000 );
3001 assert!(matches!(v, Value::Int(7)));
3002 }
3003
3004 #[test]
3005 fn macro_call_evaluated_with_runtime_arg() {
3006 let v = eval_ok(
3010 "(defmacro double (x) `(+ ,x ,x))
3011 (define n 13)
3012 (double n)",
3013 );
3014 assert!(matches!(v, Value::Int(26)));
3015 }
3016
3017 #[test]
3018 fn macro_persists_across_eval_program_calls() {
3019 let mut i: Interpreter<NoHost> = Interpreter::new();
3022 install_primitives(&mut i);
3023 let mut host = NoHost;
3024 let defs = read_spanned("(defmacro inc (x) `(+ ,x 1))").unwrap();
3025 i.eval_program(&defs, &mut host).unwrap();
3026 assert_eq!(i.expander().len(), 1);
3027
3028 let call = read_spanned("(inc 41)").unwrap();
3029 let v = i.eval_program(&call, &mut host).unwrap();
3030 assert!(matches!(v, Value::Int(42)));
3031 }
3032
3033 #[test]
3034 fn macro_expansion_inside_lambda_body() {
3035 let v = eval_ok(
3036 "(defmacro sq (x) `(* ,x ,x))
3037 ((lambda (n) (sq n)) 9)",
3038 );
3039 assert!(matches!(v, Value::Int(81)));
3040 }
3041
3042 #[test]
3043 fn no_macros_registered_keeps_eval_program_a_passthrough() {
3044 let v = eval_ok("(+ 1 2 3)");
3050 assert!(matches!(v, Value::Int(6)));
3051 }
3052
3053 #[test]
3054 fn eval_top_form_drives_one_form_at_a_time() {
3055 let mut i: Interpreter<NoHost> = Interpreter::new();
3056 install_primitives(&mut i);
3057 let mut host = NoHost;
3058 let forms = read_spanned("(defmacro id (x) `,x) (id 42)").unwrap();
3059
3060 let r0 = i.eval_top_form(&forms[0], &mut host).unwrap();
3062 assert!(matches!(r0, Value::Nil));
3063
3064 let r1 = i.eval_top_form(&forms[1], &mut host).unwrap();
3066 assert!(matches!(r1, Value::Int(42)));
3067 }
3068
3069 use crate::install_full_stdlib_with;
3076
3077 fn run_full(src: &str) -> Value {
3078 let mut i: Interpreter<NoHost> = Interpreter::new();
3079 install_full_stdlib_with(&mut i, &mut NoHost);
3080 let forms = read_spanned(src).unwrap();
3081 i.eval_program(&forms, &mut NoHost).unwrap()
3082 }
3083
3084 #[test]
3085 fn macro_can_use_map_at_expansion_time() {
3086 let v = run_full(
3090 "(defmacro double-each (&rest xs)
3091 `(list ,@(map (lambda (x) (* x 2)) xs)))
3092 (double-each 1 2 3 4 5)",
3093 );
3094 assert_eq!(format!("{v}"), "(2 4 6 8 10)");
3095 }
3096
3097 #[test]
3098 fn macro_can_use_foldl_at_expansion_time() {
3099 let v = run_full(
3103 "(defmacro static-sum (&rest xs)
3104 (foldl + 0 xs))
3105 (static-sum 1 2 3 4 5)",
3106 );
3107 assert!(matches!(v, Value::Int(15)));
3108 }
3109
3110 #[test]
3111 fn macro_can_use_filter_at_expansion_time() {
3112 let v = run_full(
3116 "(defmacro sum-positives (&rest xs)
3117 `(+ ,@(filter positive? xs)))
3118 (sum-positives 1 -2 3 -4 5)",
3119 );
3120 assert!(matches!(v, Value::Int(9)));
3122 }
3123
3124 #[test]
3125 fn macro_can_recursively_emit_let_chain() {
3126 let v = run_full(
3129 "(defmacro chain-let (binding &rest more)
3130 (if (null? more)
3131 `(let (,binding) #t)
3132 `(let (,binding) (chain-let ,@more))))
3133 (chain-let (a 1) (b 2) (c 3))",
3134 );
3135 assert!(matches!(v, Value::Bool(true)));
3136 }
3137
3138 #[test]
3139 fn macro_can_use_gensym_for_hygiene() {
3140 let v = run_full(
3143 "(defmacro swap-bind (init body)
3144 (let ((tmp (gensym \"tmp\")))
3145 `(let ((,tmp ,init))
3146 (+ ,tmp ,tmp))))
3147 (swap-bind 21 #t)",
3148 );
3149 assert!(matches!(v, Value::Int(42)));
3150 }
3151
3152 #[test]
3153 fn macro_can_inspect_arg_shape() {
3154 let v = run_full(
3156 "(defmacro shape-aware (x)
3157 (if (list? x)
3158 `(+ ,@x) ;; sum the children
3159 `,x)) ;; pass through scalars
3160 (+ (shape-aware (1 2 3)) (shape-aware 100))",
3161 );
3162 assert!(matches!(v, Value::Int(106)));
3164 }
3165
3166 #[test]
3167 fn macro_can_call_user_helper_fn() {
3168 let v = run_full(
3170 "(define (square x) (* x x))
3171 (defmacro static-square (n) (square n))
3172 (static-square 7)",
3173 );
3174 assert!(matches!(v, Value::Int(49)));
3175 }
3176
3177 #[test]
3178 fn macro_emitting_quoted_form_round_trips() {
3179 let v = run_full(
3182 "(defmacro literal-list (&rest xs)
3183 `(quote ,xs))
3184 (literal-list a b c)",
3185 );
3186 let s = format!("{v}");
3187 assert!(s.contains('a') && s.contains('b') && s.contains('c'));
3188 }
3189
3190 #[test]
3191 fn quasiquote_inside_quasiquote_in_macro_output_is_preserved() {
3192 let v = run_full(
3195 "(defmacro emit-qq (x) `(quasiquote (a (unquote ,x) c)))
3196 (let ((q (emit-qq 99))) q)",
3197 );
3198 assert_eq!(format!("{v}"), "(a 99 c)");
3200 }
3201
3202 #[test]
3203 fn macro_body_can_define_locals_and_dispatch() {
3204 let v = run_full(
3206 "(defmacro classify-args (&rest xs)
3207 (let ((evens (filter even? xs))
3208 (odds (filter odd? xs)))
3209 `(list (list :evens ,@evens)
3210 (list :odds ,@odds))))
3211 (classify-args 1 2 3 4 5 6)",
3212 );
3213 let s = format!("{v}");
3214 assert!(s.contains(":evens 2 4 6"));
3215 assert!(s.contains(":odds 1 3 5"));
3216 }
3217
3218 #[test]
3227 fn tco_self_recursion_via_if() {
3228 let v = run_full(
3232 "(define (sum n acc)
3233 (if (= n 0)
3234 acc
3235 (sum (- n 1) (+ acc n))))
3236 (sum 100000 0)",
3237 );
3238 assert!(matches!(v, Value::Int(5_000_050_000)));
3240 }
3241
3242 #[test]
3243 fn tco_mutual_recursion() {
3244 let v = run_full(
3247 "(define (even-r? n) (if (= n 0) #t (odd-r? (- n 1))))
3248 (define (odd-r? n) (if (= n 0) #f (even-r? (- n 1))))
3249 (even-r? 50000)",
3250 );
3251 assert!(matches!(v, Value::Bool(true)));
3252 }
3253
3254 #[test]
3255 fn tco_via_cond_branch() {
3256 let v = run_full(
3257 "(define (countdown n)
3258 (cond
3259 ((<= n 0) :done)
3260 (else (countdown (- n 1)))))
3261 (countdown 50000)",
3262 );
3263 assert!(matches!(v, Value::Keyword(s) if &*s == "done"));
3264 }
3265
3266 #[test]
3267 fn tco_via_let_body() {
3268 let v = run_full(
3271 "(define (loop-let n)
3272 (let ((m (- n 1)))
3273 (if (<= n 0) :done (loop-let m))))
3274 (loop-let 50000)",
3275 );
3276 assert!(matches!(v, Value::Keyword(s) if &*s == "done"));
3277 }
3278
3279 #[test]
3280 fn tco_via_begin_last_form() {
3281 let v = run_full(
3282 "(define (counter n)
3283 (begin
3284 (+ 1 1)
3285 (+ 2 2)
3286 (if (<= n 0) :done (counter (- n 1)))))
3287 (counter 50000)",
3288 );
3289 assert!(matches!(v, Value::Keyword(s) if &*s == "done"));
3290 }
3291
3292 #[test]
3293 fn tco_via_when_unless() {
3294 let v = run_full(
3295 "(define (drain n)
3296 (when (> n 0)
3297 (drain (- n 1))))
3298 (drain 50000)",
3299 );
3300 assert!(matches!(v, Value::Nil));
3302 }
3303
3304 #[test]
3305 fn tco_through_and_or_short_circuit_last() {
3306 let v = run_full(
3309 "(define (loop-and n)
3310 (and #t #t (if (<= n 0) :done (loop-and (- n 1)))))
3311 (loop-and 30000)",
3312 );
3313 assert!(matches!(v, Value::Keyword(s) if &*s == "done"));
3314 }
3315
3316 #[test]
3317 fn non_tail_recursion_still_works_for_small_n() {
3318 let v = run_full(
3322 "(define (fact n)
3323 (if (= n 0) 1 (* n (fact (- n 1)))))
3324 (fact 12)",
3325 );
3326 assert!(matches!(v, Value::Int(479_001_600)));
3328 }
3329
3330 #[test]
3333 fn error_constructor_returns_error_value() {
3334 let v = run_full("(error :validation \"bad input\")");
3335 match v {
3336 Value::Error(e) => {
3337 assert_eq!(&*e.tag, "validation");
3338 assert_eq!(&*e.message, "bad input");
3339 assert!(e.data.is_empty());
3340 }
3341 other => panic!("{other:?}"),
3342 }
3343 }
3344
3345 #[test]
3346 fn ex_info_uses_default_tag() {
3347 let v = run_full("(ex-info \"validation failed\" (list :field \"email\" :code 42))");
3348 match v {
3349 Value::Error(e) => {
3350 assert_eq!(&*e.tag, "ex-info");
3351 assert_eq!(&*e.message, "validation failed");
3352 assert_eq!(e.data.len(), 2);
3353 }
3354 other => panic!("{other:?}"),
3355 }
3356 }
3357
3358 #[test]
3359 fn error_predicate() {
3360 let v = run_full("(error? (error :x \"y\"))");
3361 assert!(matches!(v, Value::Bool(true)));
3362 let v = run_full("(error? 42)");
3363 assert!(matches!(v, Value::Bool(false)));
3364 }
3365
3366 #[test]
3367 fn error_accessors() {
3368 let v = run_full(
3369 "(let ((e (ex-info \"oops\" (list :user-id 42))))
3370 (list (error-tag e) (error-message e) (error-data-get e :user-id)))",
3371 );
3372 assert_eq!(format!("{v}"), "(:ex-info \"oops\" 42)");
3373 }
3374
3375 #[test]
3376 fn try_catches_thrown_error() {
3377 let v = run_full(
3378 "(try
3379 (throw (ex-info \"boom\" (list :code 500)))
3380 (catch (e)
3381 (error-message e)))",
3382 );
3383 assert_eq!(format!("{v}"), "\"boom\"");
3384 }
3385
3386 #[test]
3387 fn try_returns_body_value_when_no_throw() {
3388 let v = run_full(
3389 "(try
3390 (+ 1 2 3)
3391 (catch (e) :unreachable))",
3392 );
3393 assert!(matches!(v, Value::Int(6)));
3394 }
3395
3396 #[test]
3397 fn try_catches_runtime_errors_too() {
3398 let v = run_full(
3402 "(try
3403 (/ 1 0)
3404 (catch (e) (error-tag e)))",
3405 );
3406 assert!(matches!(v, Value::Keyword(s) if &*s == "division-by-zero"));
3407 }
3408
3409 #[test]
3410 fn try_catches_unbound_symbol_error() {
3411 let v = run_full(
3412 "(try
3413 undefined-var
3414 (catch (e) (error-tag e)))",
3415 );
3416 assert!(matches!(v, Value::Keyword(s) if &*s == "unbound-symbol"));
3417 }
3418
3419 #[test]
3420 fn try_catches_arity_mismatch() {
3421 let v = run_full(
3422 "(try
3423 ((lambda (x y) (+ x y)) 1)
3424 (catch (e) (error-tag e)))",
3425 );
3426 assert!(matches!(v, Value::Keyword(s) if &*s == "arity-mismatch"));
3427 }
3428
3429 #[test]
3430 fn nested_try_inner_handler_takes_precedence() {
3431 let v = run_full(
3432 "(try
3433 (try
3434 (throw (ex-info \"inner\" ()))
3435 (catch (e) :inner-caught))
3436 (catch (e) :outer-caught))",
3437 );
3438 assert!(matches!(v, Value::Keyword(s) if &*s == "inner-caught"));
3439 }
3440
3441 #[test]
3442 fn outer_try_catches_when_handler_rethrows() {
3443 let v = run_full(
3444 "(try
3445 (try
3446 (throw (ex-info \"first\" ()))
3447 (catch (e) (throw (ex-info \"rethrown\" ()))))
3448 (catch (e) (error-message e)))",
3449 );
3450 assert_eq!(format!("{v}"), "\"rethrown\"");
3451 }
3452
3453 #[test]
3454 fn throw_propagates_when_no_try() {
3455 let mut i: Interpreter<NoHost> = Interpreter::new();
3457 install_full_stdlib_with(&mut i, &mut NoHost);
3458 let forms = read_spanned("(throw (ex-info \"unhandled\" (list :code 99)))").unwrap();
3459 let err = i.eval_program(&forms, &mut NoHost).unwrap_err();
3460 match err {
3461 EvalError::User { value, .. } => match value {
3462 Value::Error(e) => {
3463 assert_eq!(&*e.message, "unhandled");
3464 }
3465 other => panic!("{other:?}"),
3466 },
3467 other => panic!("{other:?}"),
3468 }
3469 }
3470
3471 #[test]
3474 fn macroexpand_one_step() {
3475 let v = run_full(
3476 "(defmacro twice (x) `(* ,x 2))
3477 (macroexpand-1 '(twice 7))",
3478 );
3479 assert_eq!(format!("{v}"), "(* 7 2)");
3481 }
3482
3483 #[test]
3484 fn macroexpand_full_until_fixed_point() {
3485 let v = run_full(
3486 "(defmacro twice (x) `(* ,x 2))
3487 (defmacro quad (x) `(twice (twice ,x)))
3488 (macroexpand '(quad 5))",
3489 );
3490 assert_eq!(format!("{v}"), "(* (* 5 2) 2)");
3492 }
3493
3494 #[test]
3495 fn macroexpand_returns_unchanged_for_non_macro() {
3496 let v = run_full("(macroexpand-1 '(+ 1 2 3))");
3497 assert_eq!(format!("{v}"), "(+ 1 2 3)");
3499 }
3500
3501 #[test]
3502 fn macroexpand_one_does_not_recurse_into_children() {
3503 let v = run_full(
3505 "(defmacro twice (x) `(* ,x 2))
3506 (defmacro outer (x) `(list ,x))
3507 (macroexpand-1 '(outer (twice 3)))",
3508 );
3509 assert_eq!(format!("{v}"), "(list (twice 3))");
3511 }
3512
3513 #[test]
3514 fn macroexpand_recurses_into_children() {
3515 let v = run_full(
3516 "(defmacro twice (x) `(* ,x 2))
3517 (defmacro outer (x) `(list ,x))
3518 (macroexpand '(outer (twice 3)))",
3519 );
3520 assert_eq!(format!("{v}"), "(list (* 3 2))");
3522 }
3523
3524 fn run_with_modules(modules: &[(&str, &str)], src: &str) -> Value {
3527 use crate::module::MapLoader;
3528 let mut i: Interpreter<NoHost> = Interpreter::new();
3529 install_full_stdlib_with(&mut i, &mut NoHost);
3530 let mut loader = MapLoader::new();
3531 for (path, source) in modules {
3532 loader.insert(*path, *source);
3533 }
3534 i.set_loader(Arc::new(loader));
3535 let forms = read_spanned(src).unwrap();
3536 i.eval_program(&forms, &mut NoHost).unwrap()
3537 }
3538
3539 fn run_with_modules_err(modules: &[(&str, &str)], src: &str) -> EvalError {
3540 use crate::module::MapLoader;
3541 let mut i: Interpreter<NoHost> = Interpreter::new();
3542 install_full_stdlib_with(&mut i, &mut NoHost);
3543 let mut loader = MapLoader::new();
3544 for (path, source) in modules {
3545 loader.insert(*path, *source);
3546 }
3547 i.set_loader(Arc::new(loader));
3548 let forms = read_spanned(src).unwrap();
3549 i.eval_program(&forms, &mut NoHost).unwrap_err()
3550 }
3551
3552 #[test]
3553 fn require_with_explicit_alias_imports_qualified_names() {
3554 let v = run_with_modules(
3555 &[(
3556 "lib/math",
3557 "(define square (lambda (x) (* x x)))
3558 (define cube (lambda (x) (* x x x)))
3559 (provide square cube)",
3560 )],
3561 "(require \"lib/math\" :as math)
3562 (math/square 7)",
3563 );
3564 assert!(matches!(v, Value::Int(49)));
3565 }
3566
3567 #[test]
3568 fn require_uses_path_as_default_alias() {
3569 let v = run_with_modules(
3570 &[("lib/math", "(define double (lambda (x) (* x 2))) (provide double)")],
3571 "(require \"lib/math\")
3572 (lib/math/double 21)",
3573 );
3574 assert!(matches!(v, Value::Int(42)));
3577 }
3578
3579 #[test]
3580 fn require_refer_imports_unqualified_names() {
3581 let v = run_with_modules(
3582 &[(
3583 "lib/math",
3584 "(define square (lambda (x) (* x x)))
3585 (define cube (lambda (x) (* x x x)))
3586 (provide square cube)",
3587 )],
3588 "(require \"lib/math\" :refer (square))
3589 (square 6)",
3590 );
3591 assert!(matches!(v, Value::Int(36)));
3592 }
3593
3594 #[test]
3595 fn require_does_not_import_non_provided() {
3596 let err = run_with_modules_err(
3599 &[(
3600 "lib/secret",
3601 "(define public 1)
3602 (define private 2)
3603 (provide public)",
3604 )],
3605 "(require \"lib/secret\" :as s)
3606 s/private",
3607 );
3608 match err {
3609 EvalError::UnboundSymbol { name, .. } => assert_eq!(&*name, "s/private"),
3610 other => panic!("{other:?}"),
3611 }
3612 }
3613
3614 #[test]
3615 fn require_chain_a_imports_b() {
3616 let v = run_with_modules(
3617 &[
3618 (
3619 "lib/util",
3620 "(define inc1 (lambda (n) (+ n 1)))
3621 (provide inc1)",
3622 ),
3623 (
3624 "lib/wrapper",
3625 "(require \"lib/util\" :as u)
3626 (define inc2 (lambda (n) (u/inc1 (u/inc1 n))))
3627 (provide inc2)",
3628 ),
3629 ],
3630 "(require \"lib/wrapper\" :as w)
3631 (w/inc2 10)",
3632 );
3633 assert!(matches!(v, Value::Int(12)));
3634 }
3635
3636 #[test]
3637 fn require_module_not_found() {
3638 let err = run_with_modules_err(&[], "(require \"missing/module\")");
3639 match err {
3641 EvalError::User { value, .. } => match value {
3642 Value::Error(e) => {
3643 assert_eq!(&*e.tag, "module-not-found");
3644 assert!(e.message.contains("missing/module"));
3645 }
3646 other => panic!("{other:?}"),
3647 },
3648 other => panic!("{other:?}"),
3649 }
3650 }
3651
3652 #[test]
3653 fn circular_require_detected() {
3654 let err = run_with_modules_err(
3655 &[
3656 ("a", "(require \"b\") (provide x) (define x 1)"),
3657 ("b", "(require \"a\") (provide y) (define y 2)"),
3658 ],
3659 "(require \"a\")",
3660 );
3661 match err {
3662 EvalError::User { value, .. } => match value {
3663 Value::Error(e) => assert_eq!(&*e.tag, "circular-require"),
3664 other => panic!("{other:?}"),
3665 },
3666 other => panic!("{other:?}"),
3667 }
3668 }
3669
3670 #[test]
3671 fn provide_at_top_level_errors() {
3672 let mut i: Interpreter<NoHost> = Interpreter::new();
3674 install_full_stdlib_with(&mut i, &mut NoHost);
3675 let forms = read_spanned("(provide x)").unwrap();
3676 let err = i.eval_program(&forms, &mut NoHost).unwrap_err();
3677 assert!(matches!(err, EvalError::BadSpecialForm { form, .. } if &*form == "provide"));
3678 }
3679
3680 #[test]
3681 fn require_refer_unknown_name_errors() {
3682 let err = run_with_modules_err(
3683 &[(
3684 "lib/math",
3685 "(define square (lambda (x) (* x x))) (provide square)",
3686 )],
3687 "(require \"lib/math\" :refer (square cube))",
3688 );
3689 match err {
3690 EvalError::User { value, .. } => match value {
3691 Value::Error(e) => {
3692 assert!(matches!(&*e.tag, "not-defined" | "not-exported"));
3693 }
3694 other => panic!("{other:?}"),
3695 },
3696 other => panic!("{other:?}"),
3697 }
3698 }
3699
3700 #[test]
3701 fn require_caches_module_load_once() {
3702 let v = run_with_modules(
3703 &[(
3704 "lib/foo",
3705 "(define x 42) (provide x)",
3706 )],
3707 "(require \"lib/foo\" :as a)
3708 (require \"lib/foo\" :as b)
3709 (+ a/x b/x)",
3710 );
3711 assert!(matches!(v, Value::Int(84)));
3713 }
3714
3715 #[test]
3724 fn macro_body_cannot_set_a_global() {
3725 let mut interp = Interpreter::new();
3726 install_primitives(&mut interp);
3727 let src = "(define *g* 0) (defmacro leak () (set! *g* 99)) (leak)";
3728 let forms = tatara_lisp::read_spanned(src).expect("parse");
3729 let err = interp
3730 .eval_program(&forms, &mut ())
3731 .expect_err("a macro must not be able to set! a global");
3732 let msg = format!("{err}");
3733 assert!(
3734 msg.contains("sealed") || msg.contains("cannot `set!`"),
3735 "expected a sealed-write diagnostic, got: {msg}"
3736 );
3737 }
3738
3739 #[test]
3740 fn the_global_is_actually_unchanged_after_a_refused_macro_set() {
3741 let mut interp = Interpreter::new();
3742 install_primitives(&mut interp);
3743 let forms = tatara_lisp::read_spanned(
3744 "(define *g* 0) (defmacro leak () (set! *g* 99))",
3745 )
3746 .expect("parse");
3747 interp.eval_program(&forms, &mut ()).expect("setup");
3748 let call = tatara_lisp::read_spanned("(leak)").expect("parse");
3750 let _ = interp.eval_program(&call, &mut ());
3751 let read = tatara_lisp::read_spanned("*g*").expect("parse");
3752 let v = interp.eval_program(&read, &mut ()).expect("read *g*");
3753 assert!(
3754 matches!(v, Value::Int(0)),
3755 "global was mutated by a macro body despite the seal: {v:?}"
3756 );
3757 }
3758
3759 #[test]
3762 fn ordinary_set_still_works_at_runtime() {
3763 let mut interp = Interpreter::new();
3764 install_primitives(&mut interp);
3765 let forms =
3766 tatara_lisp::read_spanned("(define x 1) (set! x 42) x").expect("parse");
3767 let v = interp.eval_program(&forms, &mut ()).expect("runtime set!");
3768 assert!(matches!(v, Value::Int(42)), "got {v:?}");
3769 }
3770
3771 #[test]
3774 fn macro_body_can_mutate_its_own_locals() {
3775 let mut interp = Interpreter::new();
3776 install_primitives(&mut interp);
3777 let src = "(defmacro m () (begin (define n 1) (set! n 2) n)) (m)";
3778 let forms = tatara_lisp::read_spanned(src).expect("parse");
3779 let v = interp
3780 .eval_program(&forms, &mut ())
3781 .expect("a macro must be able to mutate its own locals");
3782 assert!(matches!(v, Value::Int(2)), "got {v:?}");
3783 }
3784
3785}