1use std::sync::Arc;
10
11use tatara_lisp::{Atom, MacroDef, MacroParams, Span, Spanned, SpannedExpander, SpannedForm};
12
13use crate::code::{spanned_to_value, value_to_spanned};
14use crate::env::{Env, Seal};
15use crate::error::{EvalError, Result};
16use crate::ffi::{
17 Arity, Caller, FnEntry, FnImpl, FnRegistry, FromValue, HigherOrderCallable, IntoValue,
18 NativeCallable,
19};
20use crate::module::{Loader, Module, ModuleError, ModuleRegistry, NoLoader};
21use crate::special::SpecialForm;
22use crate::value::{Closure, ErrorObj, NativeFn, Value};
23
24pub const DEFAULT_MACRO_EXPANSION_LIMIT: usize = 256;
34
35#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
39pub enum HeadBinding {
40 SpecialForm,
43 Macro,
46 Value,
48}
49
50pub struct Interpreter<H> {
51 pub(crate) registry: FnRegistry<H>,
52 pub(crate) globals: Env,
53 pub(crate) expander: SpannedExpander,
58 pub(crate) modules: ModuleRegistry,
62 pub(crate) loader: Arc<dyn Loader>,
65 pub(crate) macro_expansion_limit: usize,
72 pub(crate) current_module: Option<Arc<str>>,
77}
78
79impl<H> Drop for Interpreter<H> {
103 fn drop(&mut self) {
104 self.globals.release_own_frames();
105 }
106}
107
108impl<H: 'static> Interpreter<H> {
109 pub fn new() -> Self {
110 Self {
111 registry: FnRegistry::new(),
112 globals: Env::new(),
113 expander: SpannedExpander::new(),
114 modules: ModuleRegistry::new(),
115 loader: Arc::new(NoLoader),
116 macro_expansion_limit: DEFAULT_MACRO_EXPANSION_LIMIT,
117 current_module: None,
118 }
119 }
120
121 pub fn fork(&self) -> Self {
160 Self {
161 registry: self.registry.clone(),
162 globals: self.globals.sealed_below_top(Seal::Fork),
163 expander: self.expander.clone(),
164 modules: self.modules.clone(),
165 loader: Arc::clone(&self.loader),
166 macro_expansion_limit: self.macro_expansion_limit,
167 current_module: self.current_module.clone(),
168 }
169 }
170
171 pub fn set_loader(&mut self, loader: Arc<dyn Loader>) {
174 self.loader = loader;
175 }
176
177 pub fn modules(&self) -> &ModuleRegistry {
179 &self.modules
180 }
181
182 pub fn register_fn<F>(&mut self, name: impl Into<Arc<str>>, arity: Arity, callable: F)
186 where
187 F: NativeCallable<H>,
188 {
189 let name = name.into();
190 self.registry.insert(FnEntry {
191 name: name.clone(),
192 arity,
193 callable: FnImpl::Native(Arc::new(callable)),
194 });
195 self.globals.define(
196 name.clone(),
197 Value::NativeFn(Arc::new(NativeFn { name, arity })),
198 );
199 }
200
201 pub fn register_owned_fn<F>(&mut self, name: impl Into<Arc<str>>, arity: Arity, callable: F)
225 where
226 F: crate::ffi::OwnedCallable<H>,
227 {
228 let name = name.into();
229 self.registry.insert(FnEntry {
230 name: name.clone(),
231 arity,
232 callable: FnImpl::Owned(Arc::new(callable)),
233 });
234 self.globals.define(
235 name.clone(),
236 Value::NativeFn(Arc::new(NativeFn { name, arity })),
237 );
238 }
239
240 pub fn register_higher_order_fn<F>(
245 &mut self,
246 name: impl Into<Arc<str>>,
247 arity: Arity,
248 callable: F,
249 ) where
250 F: HigherOrderCallable<H>,
251 {
252 let name = name.into();
253 self.registry.insert(FnEntry {
254 name: name.clone(),
255 arity,
256 callable: FnImpl::Higher(Arc::new(callable)),
257 });
258 self.globals.define(
259 name.clone(),
260 Value::NativeFn(Arc::new(NativeFn { name, arity })),
261 );
262 }
263
264 pub fn register_awaitable_fn<R, C>(
314 &mut self,
315 name: impl Into<Arc<str>>,
316 arity: Arity,
317 ready: R,
318 call: C,
319 ) where
320 R: Fn(&[Value], &H) -> bool + Send + Sync + 'static,
321 C: Fn(&[Value], &mut H, Span) -> Result<Value> + Send + Sync + 'static,
322 {
323 let name = name.into();
324 self.registry.insert(FnEntry {
325 name: name.clone(),
326 arity,
327 callable: FnImpl::Awaitable(Arc::new(crate::ffi::Awaitable { ready, call })),
328 });
329 self.globals.define(
330 name.clone(),
331 Value::NativeFn(Arc::new(NativeFn { name, arity })),
332 );
333 }
334
335 pub fn set_macro_expansion_limit(&mut self, limit: usize) {
340 self.macro_expansion_limit = limit;
341 }
342
343 pub fn eval_spanned(&mut self, form: &Spanned, host: &mut H) -> Result<Value> {
348 let expanded = self.fully_expand(form, host)?;
349 eval_in(
350 &mut self.globals,
351 &self.registry,
352 &self.expander,
353 &expanded,
354 host,
355 )
356 }
357
358 pub fn eval_program(&mut self, forms: &[Spanned], host: &mut H) -> Result<Value> {
370 let mut last = Value::Nil;
371 for form in forms {
372 last = self.eval_top_form(form, host)?;
373 }
374 Ok(last)
375 }
376
377 pub fn eval_top_form(&mut self, form: &Spanned, host: &mut H) -> Result<Value> {
383 if self.expander.try_register_macro(form)? {
384 return Ok(Value::Nil);
385 }
386 if let Some(head) = head_symbol(form) {
390 match head {
391 "provide" => return self.eval_provide(form, host),
392 "require" => return self.eval_require(form, host),
393 _ => {}
394 }
395 }
396 let expanded = self.fully_expand(form, host)?;
397 eval_in(
398 &mut self.globals,
399 &self.registry,
400 &self.expander,
401 &expanded,
402 host,
403 )
404 }
405
406 fn eval_provide(&mut self, form: &Spanned, _host: &mut H) -> Result<Value> {
410 let items = form.as_list().unwrap_or(&[]);
411 let span = form.span;
412 let Some(current) = self.current_module.clone() else {
413 return Err(EvalError::bad_form(
414 "provide",
415 "`provide` only valid at module top level — embedder evaluating top-level code has no current module",
416 span,
417 ));
418 };
419 let mut names: Vec<Arc<str>> = Vec::with_capacity(items.len().saturating_sub(1));
421 for item in &items[1..] {
422 let name = item.as_symbol().ok_or_else(|| {
423 EvalError::bad_form(
424 "provide",
425 "expected symbol — every arg must name a binding to export",
426 item.span,
427 )
428 })?;
429 names.push(Arc::<str>::from(name));
430 }
431 {
436 let mut g = self.modules.inner_lock();
437 g.exports_staging
441 .entry(current.to_string())
442 .or_default()
443 .extend(names.iter().cloned());
444 }
445 Ok(Value::Nil)
446 }
447
448 fn eval_require(&mut self, form: &Spanned, host: &mut H) -> Result<Value> {
457 let items = form.as_list().unwrap_or(&[]);
458 let span = form.span;
459 if items.len() < 2 {
460 return Err(EvalError::bad_form(
461 "require",
462 "expected (require \"path\" [:as alias] [:refer (...)])",
463 span,
464 ));
465 }
466 let path: Arc<str> = match items[1].as_string() {
467 Some(s) => Arc::from(s),
468 None => {
469 return Err(EvalError::bad_form(
470 "require",
471 "first arg must be a string path",
472 items[1].span,
473 ))
474 }
475 };
476
477 let mut alias: Option<Arc<str>> = None;
479 let mut refer: Option<Vec<Arc<str>>> = None;
480 let mut i = 2usize;
481 while i < items.len() {
482 let kw = items[i].as_keyword().ok_or_else(|| {
483 EvalError::bad_form(
484 "require",
485 "expected keyword (:as / :refer) after path",
486 items[i].span,
487 )
488 })?;
489 let val = items.get(i + 1).ok_or_else(|| {
490 EvalError::bad_form("require", "keyword without value", items[i].span)
491 })?;
492 match kw {
493 "as" => {
494 alias = Some(Arc::from(val.as_symbol().ok_or_else(|| {
495 EvalError::bad_form("require", ":as needs a symbol alias", val.span)
496 })?));
497 }
498 "refer" => {
499 let names_list = val.as_list().ok_or_else(|| {
500 EvalError::bad_form(
501 "require",
502 ":refer needs a parenthesized list of symbols",
503 val.span,
504 )
505 })?;
506 let mut names = Vec::with_capacity(names_list.len());
507 for n in names_list {
508 names.push(Arc::<str>::from(n.as_symbol().ok_or_else(|| {
509 EvalError::bad_form(
510 "require",
511 ":refer list must contain symbols only",
512 n.span,
513 )
514 })?));
515 }
516 refer = Some(names);
517 }
518 other => {
519 return Err(EvalError::bad_form(
520 "require",
521 format!("unknown require option :{other}"),
522 items[i].span,
523 ));
524 }
525 }
526 i += 2;
527 }
528
529 if !self.modules.has(&path) {
531 self.load_module(&path, span, host)?;
532 }
533 let module = self.modules.get(&path).ok_or_else(|| {
534 EvalError::native_fn("require", "module disappeared after load", span)
535 })?;
536
537 let chosen_alias = alias.unwrap_or_else(|| path.clone());
539 for name in &module.exports {
540 let value = module.bindings.get(name).cloned().unwrap_or(Value::Nil);
541 let qualified: Arc<str> = Arc::from(format!("{chosen_alias}/{name}"));
542 self.globals.define(qualified, value);
543 }
544 if let Some(names) = refer {
545 for name in names {
546 if let Some(value) = module.bindings.get(&name) {
547 if module.exports.contains(&name) {
548 self.globals.define(name.clone(), value.clone());
549 } else {
550 return Err(EvalError::User {
551 value: error_value(
552 "not-exported",
553 &format!("{path} does not export {name}"),
554 ),
555 at: span,
556 });
557 }
558 } else {
559 return Err(EvalError::User {
560 value: error_value(
561 "not-defined",
562 &format!("{path} does not define {name}"),
563 ),
564 at: span,
565 });
566 }
567 }
568 }
569 Ok(Value::Nil)
570 }
571
572 fn load_module(&mut self, path: &str, span: Span, host: &mut H) -> Result<()> {
578 self.modules
580 .begin_load(path)
581 .map_err(|e| module_error_to_eval(e, span))?;
582
583 let source = match self.loader.load(path) {
585 Ok(s) => s,
586 Err(e) => {
587 self.modules.abort_load(path);
588 return Err(module_error_to_eval(e, span));
589 }
590 };
591
592 let forms = match tatara_lisp::read_spanned(&source) {
594 Ok(f) => f,
595 Err(e) => {
596 self.modules.abort_load(path);
597 return Err(EvalError::Reader(e));
598 }
599 };
600
601 let saved_globals = std::mem::replace(&mut self.globals, Env::new());
605 for (name, value) in saved_globals.iter_top_level() {
609 if matches!(value, Value::NativeFn(_) | Value::Closure(_)) {
613 self.globals.define(name.clone(), value.clone());
614 }
615 }
616 let saved_current = self.current_module.replace(Arc::from(path));
617
618 let mut eval_err: Option<EvalError> = None;
620 for f in &forms {
621 if let Err(e) = self.eval_top_form(f, host) {
625 eval_err = Some(e);
626 break;
627 }
628 }
629
630 let module_globals = std::mem::replace(&mut self.globals, saved_globals);
632 self.current_module = saved_current;
633
634 if let Some(e) = eval_err {
635 self.modules.abort_load(path);
636 return Err(e);
637 }
638
639 let mut module = Module::new(path);
642 for (name, value) in module_globals.iter_top_level() {
643 if !matches!(value, Value::NativeFn(_)) {
646 module.define(name.clone(), value.clone());
647 }
648 }
649 let staged = {
651 let mut g = self.modules.inner_lock();
652 g.exports_staging.remove(path).unwrap_or_default()
653 };
654 for n in staged {
655 module.add_export(n);
656 }
657 self.modules.finish_load(module);
658 Ok(())
659 }
660
661 pub fn fully_expand(&mut self, form: &Spanned, host: &mut H) -> Result<Spanned> {
672 if self.expander.is_empty() {
674 return Ok(form.clone());
675 }
676 self.expand_recursive(form, host)
677 }
678
679 fn expand_recursive(&mut self, form: &Spanned, host: &mut H) -> Result<Spanned> {
680 self.expand_at_depth(form, host, 0)
681 }
682
683 fn expand_at_depth(&mut self, form: &Spanned, host: &mut H, depth: usize) -> Result<Spanned> {
700 match &form.form {
701 SpannedForm::List(items) if !items.is_empty() => {
702 if let Some(head) = items[0].as_symbol() {
703 if self.expander.has(head) {
704 if depth >= self.macro_expansion_limit {
705 return Err(EvalError::MacroExpansionLimit {
710 macro_name: head.into(),
711 limit: self.macro_expansion_limit,
712 at: form.span,
713 });
714 }
715 let expanded =
719 self.expand_macro_call(head, &items[1..], form.span, host)?;
720 return self.expand_at_depth(&expanded, host, depth + 1);
721 }
722 }
723 let mut out = Vec::with_capacity(items.len());
727 for child in items {
728 out.push(self.expand_at_depth(child, host, depth)?);
729 }
730 Ok(Spanned::new(form.span, SpannedForm::List(out)))
731 }
732 SpannedForm::Quote(_) => {
733 Ok(form.clone())
735 }
736 SpannedForm::Quasiquote(inner) => {
737 Ok(Spanned::new(
739 form.span,
740 SpannedForm::Quasiquote(Box::new(self.expand_inside_quasiquote(inner, host)?)),
741 ))
742 }
743 _ => Ok(form.clone()),
745 }
746 }
747
748 fn expand_inside_quasiquote(&mut self, form: &Spanned, host: &mut H) -> Result<Spanned> {
749 match &form.form {
750 SpannedForm::Unquote(inner) => Ok(Spanned::new(
751 form.span,
752 SpannedForm::Unquote(Box::new(self.expand_recursive(inner, host)?)),
753 )),
754 SpannedForm::UnquoteSplice(inner) => Ok(Spanned::new(
755 form.span,
756 SpannedForm::UnquoteSplice(Box::new(self.expand_recursive(inner, host)?)),
757 )),
758 SpannedForm::List(items) => {
759 let mut out = Vec::with_capacity(items.len());
760 for item in items {
761 out.push(self.expand_inside_quasiquote(item, host)?);
762 }
763 Ok(Spanned::new(form.span, SpannedForm::List(out)))
764 }
765 _ => Ok(form.clone()),
766 }
767 }
768
769 fn expand_macro_call(
773 &mut self,
774 macro_name: &str,
775 args: &[Spanned],
776 call_span: Span,
777 host: &mut H,
778 ) -> Result<Spanned> {
779 let def: MacroDef = self
782 .expander
783 .get_macro(macro_name)
784 .cloned()
785 .ok_or_else(|| {
786 EvalError::native_fn(
787 Arc::<str>::from(macro_name),
788 "macro disappeared during expansion",
789 call_span,
790 )
791 })?;
792
793 let body_spanned = Spanned::from_sexp_at(&def.body, call_span);
798
799 let body_expanded = self.fully_expand(&body_spanned, host)?;
805
806 let mut macro_env = self.globals.sealed_below_top(Seal::MacroExpansion);
814 bind_macro_args(&mut macro_env, &def.name, &def.params, args, call_span)?;
815
816 let result = eval_in(
819 &mut macro_env,
820 &self.registry,
821 &self.expander,
822 &body_expanded,
823 host,
824 )?;
825
826 value_to_spanned(&result, call_span).map_err(|reason| {
830 EvalError::native_fn(
831 Arc::<str>::from(format!("macro {macro_name}")),
832 reason,
833 call_span,
834 )
835 })
836 }
837
838 pub fn expander(&self) -> &SpannedExpander {
841 &self.expander
842 }
843
844 pub fn expander_mut(&mut self) -> &mut SpannedExpander {
848 &mut self.expander
849 }
850
851 pub fn lookup_global(&self, name: &str) -> Option<Value> {
853 self.globals.lookup(name)
854 }
855
856 pub fn define_global(&mut self, name: impl Into<Arc<str>>, value: Value) {
858 self.globals.define(name, value);
859 }
860
861 pub fn globals_snapshot(&self) -> &Env {
864 &self.globals
865 }
866
867 #[must_use]
889 pub fn resolve_head(&self, name: &str) -> Option<HeadBinding> {
890 if SpecialForm::from_symbol(name).is_some() {
891 Some(HeadBinding::SpecialForm)
892 } else if self.expander.has(name) {
893 Some(HeadBinding::Macro)
894 } else if self.globals.lookup(name).is_some() {
895 Some(HeadBinding::Value)
896 } else {
897 None
898 }
899 }
900
901 #[must_use]
908 pub fn reserved_head_names(&self) -> std::collections::BTreeSet<Arc<str>> {
909 let mut out: std::collections::BTreeSet<Arc<str>> = SpecialForm::ALL
910 .iter()
911 .map(|sf| Arc::from(sf.symbol()))
912 .collect();
913 out.extend(
914 self.expander
915 .macro_names()
916 .map(Arc::from)
917 .collect::<Vec<Arc<str>>>(),
918 );
919 out.extend(self.globals.iter_top_level().into_iter().map(|(n, _)| n));
920 out
921 }
922
923 pub(crate) fn callee_may_park(&self, callee: &Value) -> bool {
938 match callee {
939 Value::NativeFn(nfn) => self
940 .registry
941 .lookup(&nfn.name)
942 .is_none_or(|entry| entry.callable.may_park()),
943 _ => true,
944 }
945 }
946
947 pub fn apply_external_value(
951 &mut self,
952 callee: &Value,
953 args: Vec<Value>,
954 host: &mut H,
955 call_span: Span,
956 ) -> Result<Value> {
957 apply_external(
958 callee,
959 args,
960 call_span,
961 &self.registry,
962 &self.expander,
963 host,
964 )
965 }
966
967 pub fn expand_program(&mut self, forms: &[Spanned], host: &mut H) -> Result<Vec<Spanned>> {
986 let mut expanded: Vec<Spanned> = Vec::with_capacity(forms.len());
987 for form in forms {
988 if self.expander.try_register_macro(form)? {
989 continue;
990 }
991 expanded.push(self.fully_expand(form, host)?);
992 }
993 Ok(expanded)
994 }
995
996 pub fn eval_program_vm(&mut self, forms: &[Spanned], host: &mut H) -> Result<Value> {
1003 let expanded = self.expand_program(forms, host)?;
1004 let chunk = crate::vm::compile_program(&expanded).map_err(|e| match e {
1005 crate::vm::CompileError::Bad { at, message } => {
1006 EvalError::bad_form(Arc::<str>::from("vm:compile"), message, at)
1007 }
1008 })?;
1009 let mut vm = crate::vm::Vm::new();
1010 vm.run(&chunk, self, host).map_err(|e| match e {
1011 crate::vm::VmError::Eval(inner) => inner,
1012 other => EvalError::native_fn(
1013 Arc::<str>::from("vm"),
1014 format!("{other}"),
1015 Span::synthetic(),
1016 ),
1017 })
1018 }
1019
1020 pub fn register_typed0<R, F>(&mut self, name: impl Into<Arc<str>>, f: F)
1024 where
1025 R: IntoValue + 'static,
1026 F: Fn(&mut H) -> Result<R> + Send + Sync + 'static,
1027 {
1028 self.register_fn(
1029 name,
1030 Arity::Exact(0),
1031 move |_args: &[Value], host: &mut H, _sp| f(host).map(IntoValue::into_value),
1032 );
1033 }
1034
1035 pub fn register_typed1<A, R, F>(&mut self, name: impl Into<Arc<str>>, f: F)
1037 where
1038 A: FromValue + 'static,
1039 R: IntoValue + 'static,
1040 F: Fn(&mut H, A) -> Result<R> + Send + Sync + 'static,
1041 {
1042 self.register_fn(
1043 name,
1044 Arity::Exact(1),
1045 move |args: &[Value], host: &mut H, sp| {
1046 let a = A::from_value(&args[0], sp)?;
1047 f(host, a).map(IntoValue::into_value)
1048 },
1049 );
1050 }
1051
1052 pub fn register_typed2<A, B, R, F>(&mut self, name: impl Into<Arc<str>>, f: F)
1054 where
1055 A: FromValue + 'static,
1056 B: FromValue + 'static,
1057 R: IntoValue + 'static,
1058 F: Fn(&mut H, A, B) -> Result<R> + Send + Sync + 'static,
1059 {
1060 self.register_fn(
1061 name,
1062 Arity::Exact(2),
1063 move |args: &[Value], host: &mut H, sp| {
1064 let a = A::from_value(&args[0], sp)?;
1065 let b = B::from_value(&args[1], sp)?;
1066 f(host, a, b).map(IntoValue::into_value)
1067 },
1068 );
1069 }
1070
1071 pub fn register_typed3<A, B, C, R, F>(&mut self, name: impl Into<Arc<str>>, f: F)
1073 where
1074 A: FromValue + 'static,
1075 B: FromValue + 'static,
1076 C: FromValue + 'static,
1077 R: IntoValue + 'static,
1078 F: Fn(&mut H, A, B, C) -> Result<R> + Send + Sync + 'static,
1079 {
1080 self.register_fn(
1081 name,
1082 Arity::Exact(3),
1083 move |args: &[Value], host: &mut H, sp| {
1084 let a = A::from_value(&args[0], sp)?;
1085 let b = B::from_value(&args[1], sp)?;
1086 let c = C::from_value(&args[2], sp)?;
1087 f(host, a, b, c).map(IntoValue::into_value)
1088 },
1089 );
1090 }
1091
1092 pub fn register_typed4<A, B, C, D, R, F>(&mut self, name: impl Into<Arc<str>>, f: F)
1094 where
1095 A: FromValue + 'static,
1096 B: FromValue + 'static,
1097 C: FromValue + 'static,
1098 D: FromValue + 'static,
1099 R: IntoValue + 'static,
1100 F: Fn(&mut H, A, B, C, D) -> Result<R> + Send + Sync + 'static,
1101 {
1102 self.register_fn(
1103 name,
1104 Arity::Exact(4),
1105 move |args: &[Value], host: &mut H, sp| {
1106 let a = A::from_value(&args[0], sp)?;
1107 let b = B::from_value(&args[1], sp)?;
1108 let c = C::from_value(&args[2], sp)?;
1109 let d = D::from_value(&args[3], sp)?;
1110 f(host, a, b, c, d).map(IntoValue::into_value)
1111 },
1112 );
1113 }
1114}
1115
1116impl<H: 'static> Default for Interpreter<H> {
1117 fn default() -> Self {
1118 Self::new()
1119 }
1120}
1121
1122pub(crate) fn eval_in<H: 'static>(
1127 env: &mut Env,
1128 registry: &FnRegistry<H>,
1129 expander: &SpannedExpander,
1130 form: &Spanned,
1131 host: &mut H,
1132) -> Result<Value> {
1133 match &form.form {
1134 SpannedForm::Nil => Ok(Value::Nil),
1135 SpannedForm::Atom(a) => eval_atom(a, form.span, env),
1136 SpannedForm::Quote(inner) => Ok(quoted_value(inner)),
1137 SpannedForm::Quasiquote(inner) => quasiquote_eval(inner, env, registry, expander, host),
1138 SpannedForm::Unquote(_) | SpannedForm::UnquoteSplice(_) => Err(EvalError::bad_form(
1139 "unquote",
1140 "unquote outside of quasiquote",
1141 form.span,
1142 )),
1143 SpannedForm::List(items) => {
1144 if items.is_empty() {
1145 return Ok(Value::Nil);
1146 }
1147 if let Some(head_sym) = items[0].as_symbol() {
1151 if let Some(sf) = SpecialForm::from_symbol(head_sym) {
1152 return eval_special(sf, items, form.span, env, registry, expander, host);
1153 }
1154 }
1155 eval_application(items, form.span, env, registry, expander, host)
1156 }
1157 }
1158}
1159
1160fn eval_atom(a: &Atom, span: Span, env: &Env) -> Result<Value> {
1161 match a {
1162 Atom::Symbol(name) => env
1163 .lookup(name)
1164 .ok_or_else(|| EvalError::unbound(name.as_str(), span)),
1165 Atom::Keyword(s) => Ok(Value::Keyword(crate::interner::intern(s.as_str()))),
1166 Atom::Str(s) => Ok(Value::Str(Arc::from(s.as_str()))),
1167 Atom::Int(n) => Ok(Value::Int(*n)),
1168 Atom::Float(n) => Ok(Value::Float(*n)),
1169 Atom::Bool(b) => Ok(Value::Bool(*b)),
1170 }
1171}
1172
1173fn quoted_value(inner: &Spanned) -> Value {
1177 crate::code::spanned_to_value(inner)
1178}
1179
1180fn quasiquote_eval<H: 'static>(
1186 form: &Spanned,
1187 env: &mut Env,
1188 registry: &FnRegistry<H>,
1189 expander: &SpannedExpander,
1190 host: &mut H,
1191) -> Result<Value> {
1192 match &form.form {
1193 SpannedForm::Unquote(inner) => eval_in(env, registry, expander, inner, host),
1194 SpannedForm::UnquoteSplice(_) => Err(EvalError::bad_form(
1195 "unquote-splice",
1196 "`,@` only valid directly inside a list",
1197 form.span,
1198 )),
1199 SpannedForm::List(items) => {
1200 let mut out: Vec<Value> = Vec::with_capacity(items.len());
1201 for item in items {
1202 if let SpannedForm::UnquoteSplice(inner) = &item.form {
1203 let v = eval_in(env, registry, expander, inner, host)?;
1204 match v {
1205 Value::List(xs) => out.extend(xs.iter().cloned()),
1206 Value::Nil => {}
1207 other => {
1208 return Err(EvalError::type_mismatch(
1209 "list",
1210 other.type_name(),
1211 item.span,
1212 ))
1213 }
1214 }
1215 } else {
1216 out.push(quasiquote_eval(item, env, registry, expander, host)?);
1217 }
1218 }
1219 if out.is_empty() {
1220 Ok(Value::Nil)
1221 } else {
1222 Ok(Value::list(out))
1223 }
1224 }
1225 SpannedForm::Nil => Ok(Value::Nil),
1226 SpannedForm::Atom(a) => Ok(match a {
1227 Atom::Symbol(s) => Value::Symbol(crate::interner::intern(s.as_str())),
1228 Atom::Keyword(s) => Value::Keyword(crate::interner::intern(s.as_str())),
1229 Atom::Str(s) => Value::Str(Arc::from(s.as_str())),
1230 Atom::Int(n) => Value::Int(*n),
1231 Atom::Float(n) => Value::Float(*n),
1232 Atom::Bool(b) => Value::Bool(*b),
1233 }),
1234 SpannedForm::Quote(_) | SpannedForm::Quasiquote(_) => {
1238 Ok(Value::Sexp(form.to_sexp(), form.span))
1239 }
1240 }
1241}
1242
1243fn eval_application<H: 'static>(
1246 items: &[Spanned],
1247 call_span: Span,
1248 env: &mut Env,
1249 registry: &FnRegistry<H>,
1250 expander: &SpannedExpander,
1251 host: &mut H,
1252) -> Result<Value> {
1253 let head_val = eval_in(env, registry, expander, &items[0], host)?;
1254 let mut args: Vec<Value> = Vec::with_capacity(items.len().saturating_sub(1));
1255 for arg_form in &items[1..] {
1256 args.push(eval_in(env, registry, expander, arg_form, host)?);
1257 }
1258 apply(&head_val, args, call_span, registry, expander, host)
1259}
1260
1261fn apply<H: 'static>(
1262 callee: &Value,
1263 args: Vec<Value>,
1264 call_span: Span,
1265 registry: &FnRegistry<H>,
1266 expander: &SpannedExpander,
1267 host: &mut H,
1268) -> Result<Value> {
1269 match callee {
1270 Value::NativeFn(nfn) => {
1271 if nfn.arity.check(args.len()).is_err() {
1272 return Err(EvalError::ArityMismatch {
1273 fn_name: nfn.name.clone(),
1274 expected: nfn.arity,
1275 got: args.len(),
1276 at: call_span,
1277 });
1278 }
1279 let entry = registry.lookup(&nfn.name).ok_or_else(|| {
1280 EvalError::native_fn(
1281 nfn.name.clone(),
1282 format!("native fn {} is not registered", nfn.name),
1283 call_span,
1284 )
1285 })?;
1286 match &entry.callable {
1287 FnImpl::Native(f) => f.call(&args, host, call_span),
1288 FnImpl::Owned(f) => f.call(args, host, call_span),
1293 FnImpl::Higher(f) => {
1294 let caller = Caller { registry, expander };
1295 f.call(&args, host, &caller, call_span)
1296 }
1297 FnImpl::Awaitable(f) => {
1302 if f.ready(&args, host) {
1303 f.call(&args, host, call_span)
1304 } else {
1305 Ok(crate::vm::Vm::park())
1306 }
1307 }
1308 }
1309 }
1310 Value::Closure(c) => call_closure(c.clone(), args, call_span, registry, expander, host),
1311 Value::Foreign(any) => {
1316 if let Some(cc) = any
1317 .clone()
1318 .downcast::<crate::vm::run::CompiledClosure>()
1319 .ok()
1320 {
1321 let lifted = cc.lift_to_closure();
1322 return call_closure(lifted, args, call_span, registry, expander, host);
1323 }
1324 Err(EvalError::NotCallable {
1325 value_kind: callee.type_name(),
1326 at: call_span,
1327 })
1328 }
1329 other => Err(EvalError::NotCallable {
1330 value_kind: other.type_name(),
1331 at: call_span,
1332 }),
1333 }
1334}
1335
1336enum TailResult {
1359 Done(Value),
1361 Resume(Arc<Closure>, Vec<Value>, Span),
1366}
1367
1368fn eval_in_tail<H: 'static>(
1372 env: &mut Env,
1373 registry: &FnRegistry<H>,
1374 expander: &SpannedExpander,
1375 form: &Spanned,
1376 host: &mut H,
1377) -> Result<TailResult> {
1378 match &form.form {
1379 SpannedForm::List(items) if !items.is_empty() => {
1380 if let Some(head_sym) = items[0].as_symbol() {
1382 if let Some(sf) = SpecialForm::from_symbol(head_sym) {
1383 return eval_special_tail(sf, items, form.span, env, registry, expander, host);
1384 }
1385 }
1386 let head_val = eval_in(env, registry, expander, &items[0], host)?;
1389 let mut args: Vec<Value> = Vec::with_capacity(items.len().saturating_sub(1));
1390 for arg_form in &items[1..] {
1391 args.push(eval_in(env, registry, expander, arg_form, host)?);
1392 }
1393 match head_val {
1394 Value::Closure(c) => Ok(TailResult::Resume(c, args, form.span)),
1395 _ => apply(&head_val, args, form.span, registry, expander, host)
1396 .map(TailResult::Done),
1397 }
1398 }
1399 _ => eval_in(env, registry, expander, form, host).map(TailResult::Done),
1401 }
1402}
1403
1404fn eval_special_tail<H: 'static>(
1405 sf: SpecialForm,
1406 items: &[Spanned],
1407 call_span: Span,
1408 env: &mut Env,
1409 registry: &FnRegistry<H>,
1410 expander: &SpannedExpander,
1411 host: &mut H,
1412) -> Result<TailResult> {
1413 match sf {
1414 SpecialForm::If => {
1415 if items.len() < 3 || items.len() > 4 {
1416 return eval_special(sf, items, call_span, env, registry, expander, host)
1417 .map(TailResult::Done);
1418 }
1419 let c = eval_in(env, registry, expander, &items[1], host)?;
1420 if c.is_truthy() {
1421 eval_in_tail(env, registry, expander, &items[2], host)
1422 } else if items.len() == 4 {
1423 eval_in_tail(env, registry, expander, &items[3], host)
1424 } else {
1425 Ok(TailResult::Done(Value::Nil))
1426 }
1427 }
1428 SpecialForm::Begin => {
1429 let body = &items[1..];
1430 if body.is_empty() {
1431 return Ok(TailResult::Done(Value::Nil));
1432 }
1433 for form in &body[..body.len() - 1] {
1434 eval_in(env, registry, expander, form, host)?;
1435 }
1436 eval_in_tail(env, registry, expander, body.last().unwrap(), host)
1437 }
1438 SpecialForm::When | SpecialForm::Unless => {
1439 if items.len() < 2 {
1440 return eval_special(sf, items, call_span, env, registry, expander, host)
1441 .map(TailResult::Done);
1442 }
1443 let invert = matches!(sf, SpecialForm::Unless);
1444 let cond = eval_in(env, registry, expander, &items[1], host)?;
1445 let run = cond.is_truthy() ^ invert;
1446 if !run {
1447 return Ok(TailResult::Done(Value::Nil));
1448 }
1449 let body = &items[2..];
1450 if body.is_empty() {
1451 return Ok(TailResult::Done(Value::Nil));
1452 }
1453 for form in &body[..body.len() - 1] {
1454 eval_in(env, registry, expander, form, host)?;
1455 }
1456 eval_in_tail(env, registry, expander, body.last().unwrap(), host)
1457 }
1458 SpecialForm::Cond => {
1459 for clause in &items[1..] {
1460 let Some(clause_list) = clause.as_list() else {
1461 return eval_special(sf, items, call_span, env, registry, expander, host)
1462 .map(TailResult::Done);
1463 };
1464 if clause_list.is_empty() {
1465 return eval_special(sf, items, call_span, env, registry, expander, host)
1466 .map(TailResult::Done);
1467 }
1468 let is_else = clause_list[0].as_symbol() == Some("else");
1469 let cond_matches = if is_else {
1470 true
1471 } else {
1472 eval_in(env, registry, expander, &clause_list[0], host)?.is_truthy()
1473 };
1474 if cond_matches {
1475 let body = &clause_list[1..];
1476 if body.is_empty() {
1477 return Ok(TailResult::Done(Value::Nil));
1478 }
1479 for form in &body[..body.len() - 1] {
1480 eval_in(env, registry, expander, form, host)?;
1481 }
1482 return eval_in_tail(env, registry, expander, body.last().unwrap(), host);
1483 }
1484 }
1485 Ok(TailResult::Done(Value::Nil))
1486 }
1487 SpecialForm::Let | SpecialForm::LetStar | SpecialForm::LetRec => {
1488 eval_let_family_tail(sf, items, call_span, env, registry, expander, host)
1489 }
1490 SpecialForm::And => {
1491 let exprs = &items[1..];
1492 if exprs.is_empty() {
1493 return Ok(TailResult::Done(Value::Bool(true)));
1494 }
1495 for e in &exprs[..exprs.len() - 1] {
1497 let v = eval_in(env, registry, expander, e, host)?;
1498 if !v.is_truthy() {
1499 return Ok(TailResult::Done(v));
1500 }
1501 }
1502 eval_in_tail(env, registry, expander, exprs.last().unwrap(), host)
1504 }
1505 SpecialForm::Or => {
1506 let exprs = &items[1..];
1507 if exprs.is_empty() {
1508 return Ok(TailResult::Done(Value::Bool(false)));
1509 }
1510 for e in &exprs[..exprs.len() - 1] {
1511 let v = eval_in(env, registry, expander, e, host)?;
1512 if v.is_truthy() {
1513 return Ok(TailResult::Done(v));
1514 }
1515 }
1516 eval_in_tail(env, registry, expander, exprs.last().unwrap(), host)
1517 }
1518 SpecialForm::Try => {
1519 sf_try(items, call_span, env, registry, expander, host).map(TailResult::Done)
1525 }
1526 SpecialForm::MacroexpandOne => {
1527 sf_macroexpand(items, call_span, env, registry, expander, host, false)
1528 .map(TailResult::Done)
1529 }
1530 SpecialForm::MacroexpandAll => {
1531 sf_macroexpand(items, call_span, env, registry, expander, host, true)
1532 .map(TailResult::Done)
1533 }
1534 SpecialForm::Delay => sf_delay(items, call_span, env).map(TailResult::Done),
1535 SpecialForm::Eval => {
1536 sf_eval(items, call_span, env, registry, expander, host).map(TailResult::Done)
1537 }
1538 _ => {
1540 eval_special(sf, items, call_span, env, registry, expander, host).map(TailResult::Done)
1541 }
1542 }
1543}
1544
1545fn eval_let_family_tail<H: 'static>(
1549 sf: SpecialForm,
1550 items: &[Spanned],
1551 call_span: Span,
1552 env: &mut Env,
1553 registry: &FnRegistry<H>,
1554 expander: &SpannedExpander,
1555 host: &mut H,
1556) -> Result<TailResult> {
1557 if items.len() < 3 {
1558 return Err(EvalError::bad_form(
1559 match sf {
1560 SpecialForm::Let => "let",
1561 SpecialForm::LetStar => "let*",
1562 SpecialForm::LetRec => "letrec",
1563 _ => "let-family",
1564 },
1565 "expected ((name expr)...) body...",
1566 call_span,
1567 ));
1568 }
1569 let bindings = parse_binding_list(
1570 &items[1],
1571 match sf {
1572 SpecialForm::Let => "let",
1573 SpecialForm::LetStar => "let*",
1574 SpecialForm::LetRec => "letrec",
1575 _ => "let-family",
1576 },
1577 )?;
1578
1579 match sf {
1580 SpecialForm::Let => {
1581 let mut values = Vec::with_capacity(bindings.len());
1582 for (_, expr) in &bindings {
1583 values.push(eval_in(env, registry, expander, expr, host)?);
1584 }
1585 env.push();
1586 for ((name, _), val) in bindings.into_iter().zip(values) {
1587 env.define(name, val);
1588 }
1589 }
1590 SpecialForm::LetStar => {
1591 env.push();
1592 for (name, expr) in bindings {
1593 let v = eval_in(env, registry, expander, expr, host)?;
1594 env.define(name, v);
1595 }
1596 }
1597 SpecialForm::LetRec => {
1598 env.push();
1599 for (name, _) in &bindings {
1600 env.define(name.clone(), Value::Nil);
1601 }
1602 for (name, expr) in &bindings {
1603 let v = eval_in(env, registry, expander, expr, host)?;
1604 env.define(name.clone(), v);
1605 }
1606 }
1607 _ => unreachable!(),
1608 }
1609
1610 let body = &items[2..];
1611 let result = if body.is_empty() {
1612 Ok(TailResult::Done(Value::Nil))
1613 } else {
1614 for form in &body[..body.len() - 1] {
1615 if let Err(e) = eval_in(env, registry, expander, form, host) {
1616 env.pop();
1617 return Err(e);
1618 }
1619 }
1620 eval_in_tail(env, registry, expander, body.last().unwrap(), host)
1621 };
1622 env.pop();
1623 result
1624}
1625
1626pub(crate) fn apply_external<H: 'static>(
1632 callee: &Value,
1633 args: Vec<Value>,
1634 call_span: Span,
1635 registry: &FnRegistry<H>,
1636 expander: &SpannedExpander,
1637 host: &mut H,
1638) -> Result<Value> {
1639 apply(callee, args, call_span, registry, expander, host)
1640}
1641
1642fn bind_macro_args(
1651 env: &mut Env,
1652 macro_name: &str,
1653 params: &MacroParams,
1654 args: &[Spanned],
1655 call_span: Span,
1656) -> Result<()> {
1657 let bound = params
1658 .bind_carrier(macro_name, args, call_span)
1659 .map_err(|e| {
1660 EvalError::native_fn(
1661 Arc::<str>::from(format!("macro {macro_name}")),
1662 e.to_string(),
1663 call_span,
1664 )
1665 })?;
1666 for (name, value) in params.names().into_iter().zip(bound.iter()) {
1667 env.define(Arc::<str>::from(name), spanned_to_value(value));
1668 }
1669 Ok(())
1670}
1671
1672fn call_closure<H: 'static>(
1677 closure: Arc<Closure>,
1678 args: Vec<Value>,
1679 call_span: Span,
1680 registry: &FnRegistry<H>,
1681 expander: &SpannedExpander,
1682 host: &mut H,
1683) -> Result<Value> {
1684 let mut current = closure;
1685 let mut current_args = args;
1686 let mut current_span = call_span;
1687 loop {
1688 let required = current.params.len();
1690 let has_rest = current.rest.is_some();
1691 if !has_rest && current_args.len() != required {
1692 return Err(EvalError::ArityMismatch {
1693 fn_name: Arc::from("<closure>"),
1694 expected: Arity::Exact(required),
1695 got: current_args.len(),
1696 at: current_span,
1697 });
1698 }
1699 if has_rest && current_args.len() < required {
1700 return Err(EvalError::ArityMismatch {
1701 fn_name: Arc::from("<closure>"),
1702 expected: Arity::AtLeast(required),
1703 got: current_args.len(),
1704 at: current_span,
1705 });
1706 }
1707
1708 let mut env = current.captured_env.clone();
1711 env.push();
1712 for (param, arg) in current.params.iter().zip(current_args.iter()) {
1713 env.define(param.clone(), arg.clone());
1714 }
1715 if let Some(rest_name) = ¤t.rest {
1716 let rest_args: Vec<Value> = current_args.iter().skip(required).cloned().collect();
1717 env.define(rest_name.clone(), Value::list(rest_args));
1718 }
1719
1720 let body = ¤t.body;
1723 if body.is_empty() {
1724 return Ok(Value::Nil);
1725 }
1726 for body_form in &body[..body.len() - 1] {
1727 eval_in(&mut env, registry, expander, body_form, host)?;
1728 }
1729 match eval_in_tail(&mut env, registry, expander, body.last().unwrap(), host)? {
1730 TailResult::Done(v) => return Ok(v),
1731 TailResult::Resume(next, next_args, next_span) => {
1732 current = next;
1735 current_args = next_args;
1736 current_span = next_span;
1737 }
1738 }
1739 }
1740}
1741
1742fn eval_special<H: 'static>(
1745 sf: SpecialForm,
1746 items: &[Spanned],
1747 call_span: Span,
1748 env: &mut Env,
1749 registry: &FnRegistry<H>,
1750 expander: &SpannedExpander,
1751 host: &mut H,
1752) -> Result<Value> {
1753 match sf {
1754 SpecialForm::Quote => sf_quote(items, call_span),
1755 SpecialForm::Quasiquote => {
1756 if items.len() != 2 {
1757 return Err(EvalError::bad_form(
1758 "quasiquote",
1759 format!("expected 1 arg, got {}", items.len() - 1),
1760 call_span,
1761 ));
1762 }
1763 quasiquote_eval(&items[1], env, registry, expander, host)
1764 }
1765 SpecialForm::If => sf_if(items, call_span, env, registry, expander, host),
1766 SpecialForm::Cond => sf_cond(items, call_span, env, registry, expander, host),
1767 SpecialForm::When => sf_when_unless(items, call_span, env, registry, expander, host, false),
1768 SpecialForm::Unless => {
1769 sf_when_unless(items, call_span, env, registry, expander, host, true)
1770 }
1771 SpecialForm::Let => sf_let(items, call_span, env, registry, expander, host),
1772 SpecialForm::LetStar => sf_let_star(items, call_span, env, registry, expander, host),
1773 SpecialForm::LetRec => sf_letrec(items, call_span, env, registry, expander, host),
1774 SpecialForm::Lambda => sf_lambda(items, call_span, env),
1775 SpecialForm::Define => sf_define(items, call_span, env, registry, expander, host),
1776 SpecialForm::Set => sf_set(items, call_span, env, registry, expander, host),
1777 SpecialForm::Begin => sf_begin(&items[1..], env, registry, expander, host),
1778 SpecialForm::And => sf_and(&items[1..], env, registry, expander, host),
1779 SpecialForm::Or => sf_or(&items[1..], env, registry, expander, host),
1780 SpecialForm::Not => sf_not(items, call_span, env, registry, expander, host),
1781 SpecialForm::Try => sf_try(items, call_span, env, registry, expander, host),
1782 SpecialForm::MacroexpandOne => {
1783 sf_macroexpand(items, call_span, env, registry, expander, host, false)
1784 }
1785 SpecialForm::MacroexpandAll => {
1786 sf_macroexpand(items, call_span, env, registry, expander, host, true)
1787 }
1788 SpecialForm::Delay => sf_delay(items, call_span, env),
1789 SpecialForm::Eval => sf_eval(items, call_span, env, registry, expander, host),
1790 SpecialForm::Provide | SpecialForm::Require => Err(EvalError::bad_form(
1791 if matches!(sf, SpecialForm::Provide) { "provide" } else { "require" },
1792 "module-system forms are only valid at top level — wrap your call in (eval (quote ...)) if you really need it dynamic",
1793 call_span,
1794 )),
1795 }
1796}
1797
1798fn head_symbol(form: &Spanned) -> Option<&str> {
1802 let SpannedForm::List(items) = &form.form else {
1803 return None;
1804 };
1805 items.first().and_then(Spanned::as_symbol)
1806}
1807
1808fn error_value(tag: &str, message: &str) -> Value {
1810 Value::Error(Arc::new(ErrorObj {
1811 tag: Arc::from(tag),
1812 message: Arc::from(message),
1813 data: Vec::new(),
1814 }))
1815}
1816
1817fn module_error_to_eval(e: ModuleError, span: Span) -> EvalError {
1821 let (tag, message) = match &e {
1822 ModuleError::NotFound(_) => ("module-not-found", e.to_string()),
1823 ModuleError::Circular { .. } => ("circular-require", e.to_string()),
1824 ModuleError::NotExported(_, _) => ("not-exported", e.to_string()),
1825 ModuleError::Denied { .. } => ("module-denied", e.to_string()),
1829 };
1830 EvalError::User {
1831 value: error_value(tag, &message),
1832 at: span,
1833 }
1834}
1835
1836fn sf_quote(items: &[Spanned], span: Span) -> Result<Value> {
1837 if items.len() != 2 {
1838 return Err(EvalError::bad_form(
1839 "quote",
1840 format!("expected 1 arg, got {}", items.len() - 1),
1841 span,
1842 ));
1843 }
1844 Ok(crate::code::spanned_to_value(&items[1]))
1850}
1851
1852fn sf_if<H: 'static>(
1853 items: &[Spanned],
1854 span: Span,
1855 env: &mut Env,
1856 registry: &FnRegistry<H>,
1857 expander: &SpannedExpander,
1858 host: &mut H,
1859) -> Result<Value> {
1860 if items.len() < 3 || items.len() > 4 {
1861 return Err(EvalError::bad_form(
1862 "if",
1863 format!("expected (if c t [e]), got {} subforms", items.len()),
1864 span,
1865 ));
1866 }
1867 let c = eval_in(env, registry, expander, &items[1], host)?;
1868 if c.is_truthy() {
1869 eval_in(env, registry, expander, &items[2], host)
1870 } else if items.len() == 4 {
1871 eval_in(env, registry, expander, &items[3], host)
1872 } else {
1873 Ok(Value::Nil)
1874 }
1875}
1876
1877fn sf_cond<H: 'static>(
1878 items: &[Spanned],
1879 span: Span,
1880 env: &mut Env,
1881 registry: &FnRegistry<H>,
1882 expander: &SpannedExpander,
1883 host: &mut H,
1884) -> Result<Value> {
1885 for clause in &items[1..] {
1886 let Some(clause_list) = clause.as_list() else {
1887 return Err(EvalError::bad_form(
1888 "cond",
1889 "clause must be a list",
1890 clause.span,
1891 ));
1892 };
1893 if clause_list.is_empty() {
1894 return Err(EvalError::bad_form("cond", "empty clause", clause.span));
1895 }
1896 let is_else = clause_list[0].as_symbol() == Some("else");
1897 let cond_matches = if is_else {
1898 true
1899 } else {
1900 let v = eval_in(env, registry, expander, &clause_list[0], host)?;
1901 v.is_truthy()
1902 };
1903 if cond_matches {
1904 let mut last = Value::Nil;
1905 for expr in &clause_list[1..] {
1906 last = eval_in(env, registry, expander, expr, host)?;
1907 }
1908 return Ok(last);
1909 }
1910 }
1911 let _ = span;
1913 Ok(Value::Nil)
1914}
1915
1916fn sf_when_unless<H: 'static>(
1917 items: &[Spanned],
1918 span: Span,
1919 env: &mut Env,
1920 registry: &FnRegistry<H>,
1921 expander: &SpannedExpander,
1922 host: &mut H,
1923 invert: bool,
1924) -> Result<Value> {
1925 if items.len() < 2 {
1926 return Err(EvalError::bad_form(
1927 if invert { "unless" } else { "when" },
1928 "need a test",
1929 span,
1930 ));
1931 }
1932 let cond = eval_in(env, registry, expander, &items[1], host)?;
1933 let run = cond.is_truthy() ^ invert;
1934 if run {
1935 let mut last = Value::Nil;
1936 for expr in &items[2..] {
1937 last = eval_in(env, registry, expander, expr, host)?;
1938 }
1939 Ok(last)
1940 } else {
1941 Ok(Value::Nil)
1942 }
1943}
1944
1945fn parse_binding_list<'a>(
1947 list: &'a Spanned,
1948 form_name: &'static str,
1949) -> Result<Vec<(Arc<str>, &'a Spanned)>> {
1950 let bindings = list
1951 .as_list()
1952 .ok_or_else(|| EvalError::bad_form(form_name, "bindings must be a list", list.span))?;
1953 let mut out = Vec::with_capacity(bindings.len());
1954 for binding in bindings {
1955 let pair = binding.as_list().ok_or_else(|| {
1956 EvalError::bad_form(form_name, "each binding must be (name expr)", binding.span)
1957 })?;
1958 if pair.len() != 2 {
1959 return Err(EvalError::bad_form(
1960 form_name,
1961 "binding must be exactly (name expr)",
1962 binding.span,
1963 ));
1964 }
1965 let name = pair[0].as_symbol().ok_or_else(|| {
1966 EvalError::bad_form(form_name, "binding name must be a symbol", pair[0].span)
1967 })?;
1968 out.push((Arc::<str>::from(name), &pair[1]));
1969 }
1970 Ok(out)
1971}
1972
1973fn sf_let<H: 'static>(
1974 items: &[Spanned],
1975 span: Span,
1976 env: &mut Env,
1977 registry: &FnRegistry<H>,
1978 expander: &SpannedExpander,
1979 host: &mut H,
1980) -> Result<Value> {
1981 if items.len() < 3 {
1982 return Err(EvalError::bad_form(
1983 "let",
1984 "expected (let ((name expr)...) body...)",
1985 span,
1986 ));
1987 }
1988 let bindings = parse_binding_list(&items[1], "let")?;
1989 let mut values = Vec::with_capacity(bindings.len());
1992 for (_, expr) in &bindings {
1993 values.push(eval_in(env, registry, expander, expr, host)?);
1994 }
1995 env.push();
1996 for ((name, _), val) in bindings.into_iter().zip(values) {
1997 env.define(name, val);
1998 }
1999 let result = eval_body(&items[2..], env, registry, expander, host);
2000 env.pop();
2001 result
2002}
2003
2004fn sf_let_star<H: 'static>(
2005 items: &[Spanned],
2006 span: Span,
2007 env: &mut Env,
2008 registry: &FnRegistry<H>,
2009 expander: &SpannedExpander,
2010 host: &mut H,
2011) -> Result<Value> {
2012 if items.len() < 3 {
2013 return Err(EvalError::bad_form(
2014 "let*",
2015 "expected (let* ((name expr)...) body...)",
2016 span,
2017 ));
2018 }
2019 let bindings = parse_binding_list(&items[1], "let*")?;
2020 env.push();
2021 for (name, expr) in bindings {
2022 let v = eval_in(env, registry, expander, expr, host)?;
2023 env.define(name, v);
2024 }
2025 let result = eval_body(&items[2..], env, registry, expander, host);
2026 env.pop();
2027 result
2028}
2029
2030fn sf_letrec<H: 'static>(
2031 items: &[Spanned],
2032 span: Span,
2033 env: &mut Env,
2034 registry: &FnRegistry<H>,
2035 expander: &SpannedExpander,
2036 host: &mut H,
2037) -> Result<Value> {
2038 if items.len() < 3 {
2039 return Err(EvalError::bad_form(
2040 "letrec",
2041 "expected (letrec ((name expr)...) body...)",
2042 span,
2043 ));
2044 }
2045 let bindings = parse_binding_list(&items[1], "letrec")?;
2046 env.push();
2047 for (name, _) in &bindings {
2050 env.define(name.clone(), Value::Nil);
2051 }
2052 for (name, expr) in &bindings {
2053 let v = eval_in(env, registry, expander, expr, host)?;
2054 env.define(name.clone(), v);
2055 }
2056 let result = eval_body(&items[2..], env, registry, expander, host);
2057 env.pop();
2058 result
2059}
2060
2061fn eval_body<H: 'static>(
2062 body: &[Spanned],
2063 env: &mut Env,
2064 registry: &FnRegistry<H>,
2065 expander: &SpannedExpander,
2066 host: &mut H,
2067) -> Result<Value> {
2068 let mut last = Value::Nil;
2069 for form in body {
2070 last = eval_in(env, registry, expander, form, host)?;
2071 }
2072 Ok(last)
2073}
2074
2075fn sf_lambda(items: &[Spanned], span: Span, env: &Env) -> Result<Value> {
2076 if items.len() < 3 {
2077 return Err(EvalError::bad_form(
2078 "lambda",
2079 "expected (lambda (params...) body...)",
2080 span,
2081 ));
2082 }
2083 let param_list: &[Spanned] = match &items[1].form {
2086 SpannedForm::Nil => &[],
2087 SpannedForm::List(xs) => xs.as_slice(),
2088 _ => {
2089 return Err(EvalError::bad_form(
2090 "lambda",
2091 "params must be a list",
2092 items[1].span,
2093 ))
2094 }
2095 };
2096 let (params, rest) = parse_lambda_params(param_list, items[1].span)?;
2097 let body = items[2..].to_vec();
2098 Ok(Value::Closure(Arc::new(Closure {
2099 params,
2100 rest,
2101 body,
2102 captured_env: env.clone(),
2103 source: span,
2104 })))
2105}
2106
2107fn parse_lambda_params(list: &[Spanned], span: Span) -> Result<(Vec<Arc<str>>, Option<Arc<str>>)> {
2108 let mut params = Vec::new();
2109 let mut rest = None;
2110 let mut i = 0;
2111 while i < list.len() {
2112 let s = list[i]
2113 .as_symbol()
2114 .ok_or_else(|| EvalError::bad_form("lambda", "param must be a symbol", list[i].span))?;
2115 if s == "&rest" {
2116 let name = list
2117 .get(i + 1)
2118 .and_then(Spanned::as_symbol)
2119 .ok_or_else(|| EvalError::bad_form("lambda", "&rest needs a name", span))?;
2120 rest = Some(Arc::<str>::from(name));
2121 if i + 2 != list.len() {
2122 return Err(EvalError::bad_form(
2123 "lambda",
2124 "&rest must be the last param",
2125 span,
2126 ));
2127 }
2128 break;
2129 }
2130 params.push(Arc::<str>::from(s));
2131 i += 1;
2132 }
2133 Ok((params, rest))
2134}
2135
2136fn sf_define<H: 'static>(
2138 items: &[Spanned],
2139 span: Span,
2140 env: &mut Env,
2141 registry: &FnRegistry<H>,
2142 expander: &SpannedExpander,
2143 host: &mut H,
2144) -> Result<Value> {
2145 if items.len() < 3 {
2146 return Err(EvalError::bad_form(
2147 "define",
2148 "expected (define name expr) or (define (name args) body)",
2149 span,
2150 ));
2151 }
2152 match &items[1].form {
2153 SpannedForm::Atom(Atom::Symbol(name)) => {
2154 let v = eval_in(env, registry, expander, &items[2], host)?;
2155 env.define(Arc::<str>::from(name.as_str()), v);
2156 Ok(Value::Nil)
2157 }
2158 SpannedForm::List(head_list) => {
2159 if head_list.is_empty() {
2160 return Err(EvalError::bad_form(
2161 "define",
2162 "empty (name args) list",
2163 items[1].span,
2164 ));
2165 }
2166 let name = head_list[0].as_symbol().ok_or_else(|| {
2167 EvalError::bad_form(
2168 "define",
2169 "first item in (name args) must be a symbol",
2170 head_list[0].span,
2171 )
2172 })?;
2173 let (params, rest) = parse_lambda_params(&head_list[1..], items[1].span)?;
2174 let body = items[2..].to_vec();
2175 let closure = Arc::new(Closure {
2176 params,
2177 rest,
2178 body,
2179 captured_env: env.clone(),
2180 source: span,
2181 });
2182 env.define(Arc::<str>::from(name), Value::Closure(closure));
2183 Ok(Value::Nil)
2184 }
2185 _ => Err(EvalError::bad_form(
2186 "define",
2187 "second form must be a symbol or (name args) list",
2188 items[1].span,
2189 )),
2190 }
2191}
2192
2193fn sf_set<H: 'static>(
2194 items: &[Spanned],
2195 span: Span,
2196 env: &mut Env,
2197 registry: &FnRegistry<H>,
2198 expander: &SpannedExpander,
2199 host: &mut H,
2200) -> Result<Value> {
2201 if items.len() != 3 {
2202 return Err(EvalError::bad_form(
2203 "set!",
2204 "expected (set! name expr)",
2205 span,
2206 ));
2207 }
2208 let name = items[1]
2209 .as_symbol()
2210 .ok_or_else(|| EvalError::bad_form("set!", "first arg must be a symbol", items[1].span))?;
2211 let v = eval_in(env, registry, expander, &items[2], host)?;
2212 if env.set(name, v) {
2213 Ok(Value::Nil)
2214 } else if let (true, Some(seal)) = (env.is_sealed_binding(name), env.seal()) {
2215 Err(EvalError::SetSealed {
2220 name: name.into(),
2221 seal,
2222 at: items[1].span,
2223 })
2224 } else {
2225 Err(EvalError::unbound(name, items[1].span))
2226 }
2227}
2228
2229fn sf_begin<H: 'static>(
2230 body: &[Spanned],
2231 env: &mut Env,
2232 registry: &FnRegistry<H>,
2233 expander: &SpannedExpander,
2234 host: &mut H,
2235) -> Result<Value> {
2236 eval_body(body, env, registry, expander, host)
2237}
2238
2239fn sf_and<H: 'static>(
2240 exprs: &[Spanned],
2241 env: &mut Env,
2242 registry: &FnRegistry<H>,
2243 expander: &SpannedExpander,
2244 host: &mut H,
2245) -> Result<Value> {
2246 let mut last = Value::Bool(true);
2247 for e in exprs {
2248 last = eval_in(env, registry, expander, e, host)?;
2249 if !last.is_truthy() {
2250 return Ok(last);
2251 }
2252 }
2253 Ok(last)
2254}
2255
2256fn sf_or<H: 'static>(
2257 exprs: &[Spanned],
2258 env: &mut Env,
2259 registry: &FnRegistry<H>,
2260 expander: &SpannedExpander,
2261 host: &mut H,
2262) -> Result<Value> {
2263 let mut last = Value::Bool(false);
2264 for e in exprs {
2265 last = eval_in(env, registry, expander, e, host)?;
2266 if last.is_truthy() {
2267 return Ok(last);
2268 }
2269 }
2270 Ok(last)
2271}
2272
2273fn sf_not<H: 'static>(
2274 items: &[Spanned],
2275 span: Span,
2276 env: &mut Env,
2277 registry: &FnRegistry<H>,
2278 expander: &SpannedExpander,
2279 host: &mut H,
2280) -> Result<Value> {
2281 if items.len() != 2 {
2282 return Err(EvalError::bad_form("not", "expected (not x)", span));
2283 }
2284 let v = eval_in(env, registry, expander, &items[1], host)?;
2285 Ok(Value::Bool(!v.is_truthy()))
2286}
2287
2288fn sf_try<H: 'static>(
2307 items: &[Spanned],
2308 span: Span,
2309 env: &mut Env,
2310 registry: &FnRegistry<H>,
2311 expander: &SpannedExpander,
2312 host: &mut H,
2313) -> Result<Value> {
2314 if items.len() < 3 {
2315 return Err(EvalError::bad_form(
2316 "try",
2317 "expected (try body... (catch (e) handler...))",
2318 span,
2319 ));
2320 }
2321 let catch_form = items.last().unwrap();
2323 let catch_list = catch_form.as_list().ok_or_else(|| {
2324 EvalError::bad_form(
2325 "try",
2326 "last form must be (catch (binding) handler...)",
2327 catch_form.span,
2328 )
2329 })?;
2330 if catch_list.is_empty() || catch_list[0].as_symbol() != Some("catch") {
2331 return Err(EvalError::bad_form(
2332 "try",
2333 "last form must be a (catch ...) clause",
2334 catch_form.span,
2335 ));
2336 }
2337 if catch_list.len() < 3 {
2338 return Err(EvalError::bad_form(
2339 "catch",
2340 "expected (catch (binding) handler...)",
2341 catch_form.span,
2342 ));
2343 }
2344 let binding_list = catch_list[1].as_list().ok_or_else(|| {
2345 EvalError::bad_form(
2346 "catch",
2347 "binding must be a 1-element list (e)",
2348 catch_list[1].span,
2349 )
2350 })?;
2351 if binding_list.len() != 1 {
2352 return Err(EvalError::bad_form(
2353 "catch",
2354 "binding must bind exactly one symbol",
2355 catch_list[1].span,
2356 ));
2357 }
2358 let binding_name = binding_list[0].as_symbol().ok_or_else(|| {
2359 EvalError::bad_form("catch", "binding must be a symbol", binding_list[0].span)
2360 })?;
2361
2362 let body = &items[1..items.len() - 1];
2363 let mut last = Value::Nil;
2364 for form in body {
2365 match eval_in(env, registry, expander, form, host) {
2366 Ok(v) => {
2367 last = v;
2368 }
2369 Err(EvalError::User { value, .. }) => {
2370 return run_catch_handler(
2371 binding_name,
2372 value,
2373 &catch_list[2..],
2374 env,
2375 registry,
2376 expander,
2377 host,
2378 );
2379 }
2380 Err(other) => {
2381 let value = rust_err_to_value_error(&other);
2385 return run_catch_handler(
2386 binding_name,
2387 value,
2388 &catch_list[2..],
2389 env,
2390 registry,
2391 expander,
2392 host,
2393 );
2394 }
2395 }
2396 }
2397 Ok(last)
2398}
2399
2400fn run_catch_handler<H: 'static>(
2401 binding_name: &str,
2402 error_value: Value,
2403 handler_body: &[Spanned],
2404 env: &mut Env,
2405 registry: &FnRegistry<H>,
2406 expander: &SpannedExpander,
2407 host: &mut H,
2408) -> Result<Value> {
2409 env.push();
2410 env.define(Arc::<str>::from(binding_name), error_value);
2411 let mut last = Value::Nil;
2412 for form in handler_body {
2413 match eval_in(env, registry, expander, form, host) {
2414 Ok(v) => last = v,
2415 Err(e) => {
2416 env.pop();
2417 return Err(e);
2418 }
2419 }
2420 }
2421 env.pop();
2422 Ok(last)
2423}
2424
2425fn sf_eval<H: 'static>(
2434 items: &[Spanned],
2435 call_span: Span,
2436 env: &mut Env,
2437 registry: &FnRegistry<H>,
2438 expander: &SpannedExpander,
2439 host: &mut H,
2440) -> Result<Value> {
2441 if items.len() != 2 {
2442 return Err(EvalError::bad_form(
2443 "eval",
2444 "expected (eval form)",
2445 call_span,
2446 ));
2447 }
2448 let form_value = eval_in(env, registry, expander, &items[1], host)?;
2449 let form_spanned = crate::code::value_to_spanned(&form_value, call_span)
2450 .map_err(|reason| EvalError::native_fn(Arc::<str>::from("eval"), reason, call_span))?;
2451 let expanded = fully_expand_with(&form_spanned, registry, expander, env, host)?;
2452 eval_in(env, registry, expander, &expanded, host)
2453}
2454
2455fn sf_delay(items: &[Spanned], call_span: Span, env: &Env) -> Result<Value> {
2460 if items.len() != 2 {
2461 return Err(EvalError::bad_form(
2462 "delay",
2463 "expected (delay expr)",
2464 call_span,
2465 ));
2466 }
2467 let body = vec![items[1].clone()];
2468 let thunk = Arc::new(Closure {
2469 params: Vec::new(),
2470 rest: None,
2471 body,
2472 captured_env: env.clone(),
2473 source: call_span,
2474 });
2475 Ok(Value::Promise(Arc::new(std::sync::Mutex::new(
2476 crate::value::PromiseState::Pending(thunk),
2477 ))))
2478}
2479
2480fn sf_macroexpand<H: 'static>(
2489 items: &[Spanned],
2490 call_span: Span,
2491 env: &mut Env,
2492 registry: &FnRegistry<H>,
2493 expander: &SpannedExpander,
2494 host: &mut H,
2495 fully: bool,
2496) -> Result<Value> {
2497 if items.len() != 2 {
2498 return Err(EvalError::bad_form(
2499 if fully {
2500 "macroexpand"
2501 } else {
2502 "macroexpand-1"
2503 },
2504 "expected (macroexpand[-1] form)",
2505 call_span,
2506 ));
2507 }
2508 let form_value = eval_in(env, registry, expander, &items[1], host)?;
2510 let form_spanned = crate::code::value_to_spanned(&form_value, call_span).map_err(|reason| {
2512 EvalError::native_fn(
2513 Arc::<str>::from(if fully {
2514 "macroexpand"
2515 } else {
2516 "macroexpand-1"
2517 }),
2518 reason,
2519 call_span,
2520 )
2521 })?;
2522
2523 let expanded = if fully {
2529 fully_expand_with(&form_spanned, registry, expander, env, host)?
2530 } else {
2531 macroexpand_one(&form_spanned, registry, expander, env, host)?
2532 };
2533
2534 Ok(crate::code::spanned_to_value(&expanded))
2535}
2536
2537fn expand_one_macro_call<H: 'static>(
2541 macro_name: &str,
2542 args: &[Spanned],
2543 call_span: Span,
2544 registry: &FnRegistry<H>,
2545 expander: &SpannedExpander,
2546 parent_env: &Env,
2547 host: &mut H,
2548) -> Result<Spanned> {
2549 let def: MacroDef = expander.get_macro(macro_name).cloned().ok_or_else(|| {
2550 EvalError::native_fn(
2551 Arc::<str>::from(macro_name),
2552 "macro disappeared during expansion",
2553 call_span,
2554 )
2555 })?;
2556 let body_spanned = Spanned::from_sexp_at(&def.body, call_span);
2557 let body_expanded = fully_expand_with(&body_spanned, registry, expander, parent_env, host)?;
2559
2560 let mut macro_env = parent_env.clone();
2561 macro_env.push();
2562 bind_macro_args(&mut macro_env, &def.name, &def.params, args, call_span)?;
2563 let result = eval_in(&mut macro_env, registry, expander, &body_expanded, host)?;
2564
2565 crate::code::value_to_spanned(&result, call_span).map_err(|reason| {
2566 EvalError::native_fn(
2567 Arc::<str>::from(format!("macro {macro_name}")),
2568 reason,
2569 call_span,
2570 )
2571 })
2572}
2573
2574fn fully_expand_with<H: 'static>(
2578 form: &Spanned,
2579 registry: &FnRegistry<H>,
2580 expander: &SpannedExpander,
2581 parent_env: &Env,
2582 host: &mut H,
2583) -> Result<Spanned> {
2584 if expander.is_empty() {
2585 return Ok(form.clone());
2586 }
2587 expand_recursive_with(form, registry, expander, parent_env, host)
2588}
2589
2590fn expand_recursive_with<H: 'static>(
2591 form: &Spanned,
2592 registry: &FnRegistry<H>,
2593 expander: &SpannedExpander,
2594 parent_env: &Env,
2595 host: &mut H,
2596) -> Result<Spanned> {
2597 match &form.form {
2598 SpannedForm::List(items) if !items.is_empty() => {
2599 if let Some(head) = items[0].as_symbol() {
2600 if expander.has(head) {
2601 let expanded = expand_one_macro_call(
2602 head,
2603 &items[1..],
2604 form.span,
2605 registry,
2606 expander,
2607 parent_env,
2608 host,
2609 )?;
2610 return expand_recursive_with(&expanded, registry, expander, parent_env, host);
2611 }
2612 }
2613 let mut out = Vec::with_capacity(items.len());
2614 for child in items {
2615 out.push(expand_recursive_with(
2616 child, registry, expander, parent_env, host,
2617 )?);
2618 }
2619 Ok(Spanned::new(form.span, SpannedForm::List(out)))
2620 }
2621 SpannedForm::Quote(_) => Ok(form.clone()),
2622 SpannedForm::Quasiquote(inner) => Ok(Spanned::new(
2623 form.span,
2624 SpannedForm::Quasiquote(Box::new(expand_inside_quasiquote_with(
2625 inner, registry, expander, parent_env, host,
2626 )?)),
2627 )),
2628 _ => Ok(form.clone()),
2629 }
2630}
2631
2632fn expand_inside_quasiquote_with<H: 'static>(
2633 form: &Spanned,
2634 registry: &FnRegistry<H>,
2635 expander: &SpannedExpander,
2636 parent_env: &Env,
2637 host: &mut H,
2638) -> Result<Spanned> {
2639 match &form.form {
2640 SpannedForm::Unquote(inner) => Ok(Spanned::new(
2641 form.span,
2642 SpannedForm::Unquote(Box::new(expand_recursive_with(
2643 inner, registry, expander, parent_env, host,
2644 )?)),
2645 )),
2646 SpannedForm::UnquoteSplice(inner) => Ok(Spanned::new(
2647 form.span,
2648 SpannedForm::UnquoteSplice(Box::new(expand_recursive_with(
2649 inner, registry, expander, parent_env, host,
2650 )?)),
2651 )),
2652 SpannedForm::List(items) => {
2653 let mut out = Vec::with_capacity(items.len());
2654 for item in items {
2655 out.push(expand_inside_quasiquote_with(
2656 item, registry, expander, parent_env, host,
2657 )?);
2658 }
2659 Ok(Spanned::new(form.span, SpannedForm::List(out)))
2660 }
2661 _ => Ok(form.clone()),
2662 }
2663}
2664
2665fn macroexpand_one<H: 'static>(
2668 form: &Spanned,
2669 registry: &FnRegistry<H>,
2670 expander: &SpannedExpander,
2671 parent_env: &Env,
2672 host: &mut H,
2673) -> Result<Spanned> {
2674 if let SpannedForm::List(items) = &form.form {
2675 if let Some(head) = items.first().and_then(Spanned::as_symbol) {
2676 if expander.has(head) {
2677 return expand_one_macro_call(
2678 head,
2679 &items[1..],
2680 form.span,
2681 registry,
2682 expander,
2683 parent_env,
2684 host,
2685 );
2686 }
2687 }
2688 }
2689 Ok(form.clone())
2690}
2691
2692fn rust_err_to_value_error(err: &EvalError) -> Value {
2695 use crate::value::ErrorObj;
2696 let tag: Arc<str> = Arc::from(err.tag());
2697 let message: Arc<str> = Arc::from(err.short_message());
2698 Value::Error(Arc::new(ErrorObj {
2699 tag,
2700 message,
2701 data: Vec::new(),
2702 }))
2703}
2704
2705#[cfg(test)]
2706mod tests {
2707 use super::*;
2708 use crate::primitive::install_primitives;
2709 use tatara_lisp::read_spanned;
2710
2711 struct NoHost;
2712
2713 fn eval_ok(src: &str) -> Value {
2714 let forms = read_spanned(src).unwrap();
2715 let mut i: Interpreter<NoHost> = Interpreter::new();
2716 install_primitives(&mut i);
2717 let mut host = NoHost;
2718 i.eval_program(&forms, &mut host).unwrap()
2719 }
2720
2721 fn eval_err(src: &str) -> EvalError {
2722 let forms = read_spanned(src).unwrap();
2723 let mut i: Interpreter<NoHost> = Interpreter::new();
2724 install_primitives(&mut i);
2725 let mut host = NoHost;
2726 i.eval_program(&forms, &mut host).unwrap_err()
2727 }
2728
2729 #[test]
2732 fn literal_int() {
2733 assert!(matches!(eval_ok("42"), Value::Int(42)));
2734 }
2735
2736 #[test]
2737 fn unbound_symbol_errors() {
2738 let e = eval_err("no-such-var");
2739 assert!(matches!(e, EvalError::UnboundSymbol { .. }));
2740 }
2741
2742 #[test]
2743 fn quote_returns_runtime_list_of_symbols() {
2744 let v = eval_ok("'(a b c)");
2747 match v {
2748 Value::List(xs) => {
2749 assert_eq!(xs.len(), 3);
2750 assert!(matches!(&xs[0], Value::Symbol(s) if s.as_ref() == "a"));
2751 assert!(matches!(&xs[1], Value::Symbol(s) if s.as_ref() == "b"));
2752 assert!(matches!(&xs[2], Value::Symbol(s) if s.as_ref() == "c"));
2753 }
2754 other => panic!("{other:?}"),
2755 }
2756 }
2757
2758 #[test]
2761 fn add_ints() {
2762 assert!(matches!(eval_ok("(+ 1 2 3)"), Value::Int(6)));
2763 }
2764
2765 #[test]
2766 fn sub_divides_float() {
2767 match eval_ok("(- 10 3)") {
2768 Value::Int(7) => {}
2769 other => panic!("{other:?}"),
2770 }
2771 }
2772
2773 #[test]
2774 fn division_by_zero_errors() {
2775 assert!(matches!(
2776 eval_err("(/ 1 0)"),
2777 EvalError::DivisionByZero { .. }
2778 ));
2779 }
2780
2781 #[test]
2784 fn if_truthy_branch() {
2785 assert!(matches!(eval_ok("(if #t 1 2)"), Value::Int(1)));
2786 }
2787
2788 #[test]
2789 fn if_falsy_branch() {
2790 assert!(matches!(eval_ok("(if #f 1 2)"), Value::Int(2)));
2791 }
2792
2793 #[test]
2794 fn if_no_else_returns_nil() {
2795 assert!(matches!(eval_ok("(if #f 1)"), Value::Nil));
2796 }
2797
2798 #[test]
2799 fn cond_picks_first_match() {
2800 assert!(matches!(
2801 eval_ok("(cond (#f 1) (#t 2) (else 3))"),
2802 Value::Int(2)
2803 ));
2804 }
2805
2806 #[test]
2807 fn cond_falls_through_to_else() {
2808 assert!(matches!(
2809 eval_ok("(cond (#f 1) (#f 2) (else 3))"),
2810 Value::Int(3)
2811 ));
2812 }
2813
2814 #[test]
2815 fn when_runs_body_if_true() {
2816 assert!(matches!(eval_ok("(when #t 99)"), Value::Int(99)));
2817 assert!(matches!(eval_ok("(when #f 99)"), Value::Nil));
2818 }
2819
2820 #[test]
2823 fn let_binds_and_evaluates_body() {
2824 assert!(matches!(
2825 eval_ok("(let ((x 10) (y 20)) (+ x y))"),
2826 Value::Int(30)
2827 ));
2828 }
2829
2830 #[test]
2831 fn let_star_sequential_bindings() {
2832 assert!(matches!(
2833 eval_ok("(let* ((x 5) (y (+ x 1))) (+ x y))"),
2834 Value::Int(11)
2835 ));
2836 }
2837
2838 #[test]
2839 fn letrec_mutual_recursion() {
2840 let v = eval_ok(
2841 "(letrec ((even? (lambda (n) (if (= n 0) #t (odd? (- n 1)))))
2842 (odd? (lambda (n) (if (= n 0) #f (even? (- n 1))))))
2843 (even? 10))",
2844 );
2845 assert!(matches!(v, Value::Bool(true)));
2846 }
2847
2848 #[test]
2851 fn lambda_applies() {
2852 assert!(matches!(
2853 eval_ok("((lambda (x y) (+ x y)) 3 4)"),
2854 Value::Int(7)
2855 ));
2856 }
2857
2858 #[test]
2859 fn lambda_closes_over_env() {
2860 assert!(matches!(
2861 eval_ok("(let ((n 10)) ((lambda (x) (+ x n)) 5))"),
2862 Value::Int(15)
2863 ));
2864 }
2865
2866 #[test]
2867 fn closure_captures_by_value_at_creation() {
2868 let v = eval_ok(
2871 "(define make-adder (lambda (n) (lambda (x) (+ x n))))
2872 (define add5 (make-adder 5))
2873 (add5 10)",
2874 );
2875 assert!(matches!(v, Value::Int(15)));
2876 }
2877
2878 #[test]
2879 fn rest_args_collect_into_list() {
2880 let v = eval_ok("((lambda (x &rest rs) (length rs)) 1 2 3 4 5)");
2881 assert!(matches!(v, Value::Int(4)));
2882 }
2883
2884 #[test]
2885 fn closure_arity_mismatch() {
2886 let e = eval_err("((lambda (x y) (+ x y)) 1)");
2887 assert!(matches!(e, EvalError::ArityMismatch { .. }));
2888 }
2889
2890 #[test]
2893 fn define_then_use() {
2894 assert!(matches!(eval_ok("(define x 42) x"), Value::Int(42)));
2895 }
2896
2897 #[test]
2898 fn define_function_shorthand() {
2899 assert!(matches!(
2900 eval_ok("(define (sq x) (* x x)) (sq 6)"),
2901 Value::Int(36)
2902 ));
2903 }
2904
2905 #[test]
2906 fn set_mutates_existing() {
2907 assert!(matches!(
2908 eval_ok("(define x 1) (set! x 99) x"),
2909 Value::Int(99)
2910 ));
2911 }
2912
2913 #[test]
2914 fn set_unbound_errors() {
2915 let e = eval_err("(set! nope 1)");
2916 assert!(matches!(e, EvalError::UnboundSymbol { .. }));
2917 }
2918
2919 #[test]
2922 fn begin_returns_last() {
2923 assert!(matches!(eval_ok("(begin 1 2 3)"), Value::Int(3)));
2924 }
2925
2926 #[test]
2927 fn and_short_circuits() {
2928 assert!(matches!(eval_ok("(and 1 #f 2)"), Value::Bool(false)));
2929 assert!(matches!(eval_ok("(and 1 2 3)"), Value::Int(3)));
2930 assert!(matches!(eval_ok("(and)"), Value::Bool(true)));
2931 }
2932
2933 #[test]
2934 fn or_short_circuits() {
2935 assert!(matches!(eval_ok("(or #f #f 7)"), Value::Int(7)));
2936 assert!(matches!(eval_ok("(or #f #f)"), Value::Bool(false)));
2937 assert!(matches!(eval_ok("(or)"), Value::Bool(false)));
2938 }
2939
2940 #[test]
2941 fn not_inverts() {
2942 assert!(matches!(eval_ok("(not #t)"), Value::Bool(false)));
2943 assert!(matches!(eval_ok("(not #f)"), Value::Bool(true)));
2944 assert!(matches!(eval_ok("(not 42)"), Value::Bool(false)));
2945 }
2946
2947 #[test]
2950 fn recursive_factorial() {
2951 let v = eval_ok(
2952 "(define (fact n)
2953 (if (= n 0) 1 (* n (fact (- n 1)))))
2954 (fact 6)",
2955 );
2956 assert!(matches!(v, Value::Int(720)));
2957 }
2958
2959 #[test]
2960 fn recursive_length() {
2961 let v = eval_ok(
2962 "(define (len xs)
2963 (if (null? xs) 0 (+ 1 (len (cdr xs)))))
2964 (len (list 1 2 3 4 5))",
2965 );
2966 assert!(matches!(v, Value::Int(5)));
2967 }
2968
2969 #[test]
2974 fn quasiquote_plain_list_is_runtime_list() {
2975 let v = eval_ok("`(a b c)");
2976 match v {
2977 Value::List(xs) => {
2978 assert_eq!(xs.len(), 3);
2979 assert!(matches!(&xs[0], Value::Symbol(s) if s.as_ref() == "a"));
2980 assert!(matches!(&xs[1], Value::Symbol(s) if s.as_ref() == "b"));
2981 assert!(matches!(&xs[2], Value::Symbol(s) if s.as_ref() == "c"));
2982 }
2983 other => panic!("{other:?}"),
2984 }
2985 }
2986
2987 #[test]
2988 fn quasiquote_unquote_substitutes_evaluated_value() {
2989 let v = eval_ok("(let ((x 42)) `(a ,x c))");
2990 match v {
2991 Value::List(xs) => {
2992 assert_eq!(xs.len(), 3);
2993 assert!(matches!(&xs[1], Value::Int(42)));
2994 }
2995 other => panic!("{other:?}"),
2996 }
2997 }
2998
2999 #[test]
3000 fn quasiquote_unquote_arbitrary_expr() {
3001 let v = eval_ok("`(x ,(+ 1 2 3) y)");
3002 match v {
3003 Value::List(xs) => {
3004 assert!(matches!(&xs[1], Value::Int(6)));
3005 }
3006 other => panic!("{other:?}"),
3007 }
3008 }
3009
3010 #[test]
3011 fn quasiquote_splice_inlines_list() {
3012 let v = eval_ok("`(a ,@(list 1 2 3) b)");
3013 match v {
3014 Value::List(xs) => {
3015 assert_eq!(xs.len(), 5);
3016 assert!(matches!(&xs[0], Value::Symbol(s) if s.as_ref() == "a"));
3017 assert!(matches!(&xs[1], Value::Int(1)));
3018 assert!(matches!(&xs[2], Value::Int(2)));
3019 assert!(matches!(&xs[3], Value::Int(3)));
3020 assert!(matches!(&xs[4], Value::Symbol(s) if s.as_ref() == "b"));
3021 }
3022 other => panic!("{other:?}"),
3023 }
3024 }
3025
3026 #[test]
3027 fn quasiquote_splice_empty_list_splices_nothing() {
3028 let v = eval_ok("`(a ,@(list) b)");
3029 match v {
3030 Value::List(xs) => {
3031 assert_eq!(xs.len(), 2);
3032 assert!(matches!(&xs[0], Value::Symbol(s) if s.as_ref() == "a"));
3033 assert!(matches!(&xs[1], Value::Symbol(s) if s.as_ref() == "b"));
3034 }
3035 other => panic!("{other:?}"),
3036 }
3037 }
3038
3039 #[test]
3040 fn quasiquote_splice_non_list_errors() {
3041 let e = eval_err("`(a ,@42)");
3042 assert!(matches!(e, EvalError::TypeMismatch { .. }));
3043 }
3044
3045 #[test]
3046 fn quasiquote_atom_yields_atom_value() {
3047 assert!(matches!(eval_ok("`foo"), Value::Symbol(s) if s.as_ref() == "foo"));
3048 assert!(matches!(eval_ok("`42"), Value::Int(42)));
3049 }
3050
3051 #[test]
3052 fn quasiquote_with_nested_list_and_unquote() {
3053 let v = eval_ok("(let ((x 99)) `(foo (bar ,x) baz))");
3055 match v {
3056 Value::List(xs) => {
3057 assert_eq!(xs.len(), 3);
3058 match &xs[1] {
3059 Value::List(inner) => {
3060 assert!(matches!(&inner[1], Value::Int(99)));
3061 }
3062 other => panic!("{other:?}"),
3063 }
3064 }
3065 other => panic!("{other:?}"),
3066 }
3067 }
3068
3069 #[test]
3070 fn quasiquote_symbol_keyword_distinction_preserved() {
3071 let v = eval_ok("`(:key val)");
3072 match v {
3073 Value::List(xs) => {
3074 assert!(matches!(&xs[0], Value::Keyword(s) if s.as_ref() == "key"));
3075 assert!(matches!(&xs[1], Value::Symbol(s) if s.as_ref() == "val"));
3076 }
3077 other => panic!("{other:?}"),
3078 }
3079 }
3080
3081 #[test]
3082 fn bare_unquote_outside_quasiquote_errors() {
3083 let e = eval_err(",x");
3084 assert!(matches!(e, EvalError::BadSpecialForm { .. }));
3085 }
3086
3087 #[test]
3090 fn native_fn_reads_host_state() {
3091 struct Counter {
3092 n: i64,
3093 }
3094 let forms = read_spanned("(bump) (bump) (bump) (cur)").unwrap();
3095 let mut i: Interpreter<Counter> = Interpreter::new();
3096 install_primitives(&mut i);
3097 i.register_fn(
3098 "bump",
3099 Arity::Exact(0),
3100 |_args: &[Value], host: &mut Counter, _span| {
3101 host.n += 1;
3102 Ok(Value::Int(host.n))
3103 },
3104 );
3105 i.register_fn(
3106 "cur",
3107 Arity::Exact(0),
3108 |_args: &[Value], host: &mut Counter, _span| Ok(Value::Int(host.n)),
3109 );
3110 let mut host = Counter { n: 0 };
3111 let v = i.eval_program(&forms, &mut host).unwrap();
3112 assert!(matches!(v, Value::Int(3)));
3113 }
3114
3115 struct Ctx {
3118 records: Vec<(String, i64)>,
3119 }
3120
3121 #[test]
3122 fn register_typed1_marshals_string_arg() {
3123 let mut i: Interpreter<Ctx> = Interpreter::new();
3124 install_primitives(&mut i);
3125 i.register_typed1("greet", |_h: &mut Ctx, name: String| -> Result<String> {
3126 Ok(format!("hello {name}"))
3127 });
3128 let forms = read_spanned(r#"(greet "luis")"#).unwrap();
3129 let mut h = Ctx { records: vec![] };
3130 let v = i.eval_program(&forms, &mut h).unwrap();
3131 match v {
3132 Value::Str(s) => assert_eq!(&*s, "hello luis"),
3133 other => panic!("{other:?}"),
3134 }
3135 }
3136
3137 #[test]
3138 fn register_typed2_marshals_host_state_mutation() {
3139 let mut i: Interpreter<Ctx> = Interpreter::new();
3140 install_primitives(&mut i);
3141 i.register_typed2(
3142 "record",
3143 |h: &mut Ctx, name: String, n: i64| -> Result<()> {
3144 h.records.push((name, n));
3145 Ok(())
3146 },
3147 );
3148 let forms = read_spanned(r#"(record "a" 1) (record "b" 2)"#).unwrap();
3149 let mut h = Ctx { records: vec![] };
3150 let _ = i.eval_program(&forms, &mut h).unwrap();
3151 assert_eq!(h.records.len(), 2);
3152 assert_eq!(h.records[0], ("a".to_string(), 1));
3153 assert_eq!(h.records[1], ("b".to_string(), 2));
3154 }
3155
3156 #[test]
3157 fn register_typed_arg_type_mismatch_surfaces_at_call_site() {
3158 let mut i: Interpreter<Ctx> = Interpreter::new();
3159 install_primitives(&mut i);
3160 i.register_typed1("needs-int", |_h: &mut Ctx, n: i64| -> Result<i64> {
3161 Ok(n + 1)
3162 });
3163 let forms = read_spanned(r#"(needs-int "not-a-number")"#).unwrap();
3164 let mut h = Ctx { records: vec![] };
3165 let err = i.eval_program(&forms, &mut h).unwrap_err();
3166 assert!(matches!(
3167 err,
3168 EvalError::TypeMismatch {
3169 expected: "integer",
3170 ..
3171 }
3172 ));
3173 }
3174
3175 #[test]
3176 fn register_typed3_three_args() {
3177 let mut i: Interpreter<Ctx> = Interpreter::new();
3178 install_primitives(&mut i);
3179 i.register_typed3(
3180 "triple-sum",
3181 |_h: &mut Ctx, a: i64, b: i64, c: i64| -> Result<i64> { Ok(a + b + c) },
3182 );
3183 let forms = read_spanned("(triple-sum 10 20 30)").unwrap();
3184 let mut h = Ctx { records: vec![] };
3185 let v = i.eval_program(&forms, &mut h).unwrap();
3186 assert!(matches!(v, Value::Int(60)));
3187 }
3188
3189 #[test]
3205 fn a_runaway_macro_is_a_typed_error_that_names_the_macro() {
3206 let err = eval_err("(defmacro forever (x) `(forever ,x))\n(forever 1)");
3207 match err {
3208 EvalError::MacroExpansionLimit {
3209 ref macro_name,
3210 limit,
3211 ..
3212 } => {
3213 assert_eq!(&**macro_name, "forever", "the error must name the culprit");
3214 assert_eq!(limit, DEFAULT_MACRO_EXPANSION_LIMIT);
3215 }
3216 other => panic!("expected MacroExpansionLimit, got {other:?}"),
3217 }
3218 }
3219
3220 #[test]
3224 fn a_mutually_recursive_macro_pair_is_caught_too() {
3225 let err =
3226 eval_err("(defmacro ping (x) `(pong ,x))\n(defmacro pong (x) `(ping ,x))\n(ping 1)");
3227 assert!(
3228 matches!(err, EvalError::MacroExpansionLimit { .. }),
3229 "a two-macro cycle must be bounded as well: {err:?}"
3230 );
3231 }
3232
3233 #[test]
3241 fn deep_but_finite_nesting_is_not_charged_to_the_expansion_budget() {
3242 let mut src = String::from("(defmacro id1 (x) x)\n");
3243 src.push_str(&"(+ 1 ".repeat(400));
3244 src.push_str("(id1 7)");
3245 src.push_str(&")".repeat(400));
3246 let v = eval_ok(&src);
3247 assert!(matches!(v, Value::Int(407)), "got {v:?}");
3248 }
3249
3250 #[test]
3253 fn a_terminating_chain_under_the_ceiling_still_expands() {
3254 let v =
3256 eval_ok("(defmacro step (x) `(step2 ,x))\n(defmacro step2 (x) `(* ,x 3))\n(step 5)");
3257 assert!(matches!(v, Value::Int(15)), "got {v:?}");
3258 }
3259
3260 #[test]
3263 fn the_expansion_ceiling_is_configurable() {
3264 let forms = read_spanned("(defmacro forever (x) `(forever ,x))\n(forever 1)").unwrap();
3265 let mut i: Interpreter<NoHost> = Interpreter::new();
3266 install_primitives(&mut i);
3267 i.set_macro_expansion_limit(4);
3268 match i.eval_program(&forms, &mut NoHost).unwrap_err() {
3269 EvalError::MacroExpansionLimit { limit, .. } => assert_eq!(limit, 4),
3270 other => panic!("expected MacroExpansionLimit, got {other:?}"),
3271 }
3272 }
3273
3274 #[test]
3275 fn user_macro_expands_and_evaluates() {
3276 let v = eval_ok(
3277 "(defmacro twice (x) `(* ,x 2))
3278 (twice 21)",
3279 );
3280 assert!(matches!(v, Value::Int(42)));
3281 }
3282
3283 #[test]
3284 fn user_macro_definition_returns_nil() {
3285 let v = eval_ok("(defmacro inc (x) `(+ ,x 1))");
3286 assert!(matches!(v, Value::Nil));
3287 }
3288
3289 #[test]
3290 fn user_macro_inside_define_body_expands() {
3291 let v = eval_ok(
3294 "(defmacro inc (x) `(+ ,x 1))
3295 (define (f n) (inc n))
3296 (f 41)",
3297 );
3298 assert!(matches!(v, Value::Int(42)));
3299 }
3300
3301 #[test]
3302 fn user_macro_with_rest_args_splices() {
3303 let v = eval_ok(
3304 "(defmacro sum-all (&rest xs) `(+ ,@xs))
3305 (sum-all 1 2 3 4 5)",
3306 );
3307 assert!(matches!(v, Value::Int(15)));
3308 }
3309
3310 #[test]
3311 fn nested_user_macros_compose() {
3312 let v = eval_ok(
3313 "(defmacro twice (x) `(* ,x 2))
3314 (defmacro quad (x) `(twice (twice ,x)))
3315 (quad 5)",
3316 );
3317 assert!(matches!(v, Value::Int(20)));
3318 }
3319
3320 #[test]
3321 fn user_macro_can_expand_to_special_form() {
3322 let v = eval_ok(
3325 "(defmacro guard (test then) `(if ,test ,then 0))
3326 (guard #t 99)",
3327 );
3328 assert!(matches!(v, Value::Int(99)));
3329 }
3330
3331 #[test]
3332 fn user_macro_redefined_replaces_prior_template() {
3333 let v = eval_ok(
3334 "(defmacro k () `1)
3335 (defmacro k () `2)
3336 (k)",
3337 );
3338 assert!(matches!(v, Value::Int(2)));
3339 }
3340
3341 #[test]
3342 fn user_macro_unbound_template_var_errors() {
3343 let mut i: Interpreter<NoHost> = Interpreter::new();
3349 install_primitives(&mut i);
3350 let forms = read_spanned("(defmacro bad (x) `(list ,y)) (bad 1)").unwrap();
3351 let err = i.eval_program(&forms, &mut NoHost).unwrap_err();
3352 match err {
3353 EvalError::UnboundSymbol { name, .. } => assert_eq!(&*name, "y"),
3354 other => panic!("expected UnboundSymbol, got {other:?}"),
3355 }
3356 }
3357
3358 #[test]
3359 fn defpoint_template_keyword_registers_as_macro() {
3360 let v = eval_ok(
3363 "(defpoint-template double (x) `(* ,x 2))
3364 (double 7)",
3365 );
3366 assert!(matches!(v, Value::Int(14)));
3367 }
3368
3369 #[test]
3370 fn defcheck_keyword_registers_as_macro() {
3371 let v = eval_ok(
3372 "(defcheck always-7 () `7)
3373 (always-7)",
3374 );
3375 assert!(matches!(v, Value::Int(7)));
3376 }
3377
3378 #[test]
3379 fn macro_call_evaluated_with_runtime_arg() {
3380 let v = eval_ok(
3384 "(defmacro double (x) `(+ ,x ,x))
3385 (define n 13)
3386 (double n)",
3387 );
3388 assert!(matches!(v, Value::Int(26)));
3389 }
3390
3391 #[test]
3392 fn macro_persists_across_eval_program_calls() {
3393 let mut i: Interpreter<NoHost> = Interpreter::new();
3396 install_primitives(&mut i);
3397 let mut host = NoHost;
3398 let defs = read_spanned("(defmacro inc (x) `(+ ,x 1))").unwrap();
3399 i.eval_program(&defs, &mut host).unwrap();
3400 assert_eq!(i.expander().len(), 1);
3401
3402 let call = read_spanned("(inc 41)").unwrap();
3403 let v = i.eval_program(&call, &mut host).unwrap();
3404 assert!(matches!(v, Value::Int(42)));
3405 }
3406
3407 #[test]
3408 fn macro_expansion_inside_lambda_body() {
3409 let v = eval_ok(
3410 "(defmacro sq (x) `(* ,x ,x))
3411 ((lambda (n) (sq n)) 9)",
3412 );
3413 assert!(matches!(v, Value::Int(81)));
3414 }
3415
3416 #[test]
3417 fn no_macros_registered_keeps_eval_program_a_passthrough() {
3418 let v = eval_ok("(+ 1 2 3)");
3424 assert!(matches!(v, Value::Int(6)));
3425 }
3426
3427 #[test]
3428 fn eval_top_form_drives_one_form_at_a_time() {
3429 let mut i: Interpreter<NoHost> = Interpreter::new();
3430 install_primitives(&mut i);
3431 let mut host = NoHost;
3432 let forms = read_spanned("(defmacro id (x) `,x) (id 42)").unwrap();
3433
3434 let r0 = i.eval_top_form(&forms[0], &mut host).unwrap();
3436 assert!(matches!(r0, Value::Nil));
3437
3438 let r1 = i.eval_top_form(&forms[1], &mut host).unwrap();
3440 assert!(matches!(r1, Value::Int(42)));
3441 }
3442
3443 use crate::install_full_stdlib_with;
3450
3451 fn run_full(src: &str) -> Value {
3452 let mut i: Interpreter<NoHost> = Interpreter::new();
3453 install_full_stdlib_with(&mut i, &mut NoHost);
3454 let forms = read_spanned(src).unwrap();
3455 i.eval_program(&forms, &mut NoHost).unwrap()
3456 }
3457
3458 #[test]
3459 fn macro_can_use_map_at_expansion_time() {
3460 let v = run_full(
3464 "(defmacro double-each (&rest xs)
3465 `(list ,@(map (lambda (x) (* x 2)) xs)))
3466 (double-each 1 2 3 4 5)",
3467 );
3468 assert_eq!(format!("{v}"), "(2 4 6 8 10)");
3469 }
3470
3471 #[test]
3472 fn macro_can_use_foldl_at_expansion_time() {
3473 let v = run_full(
3477 "(defmacro static-sum (&rest xs)
3478 (foldl + 0 xs))
3479 (static-sum 1 2 3 4 5)",
3480 );
3481 assert!(matches!(v, Value::Int(15)));
3482 }
3483
3484 #[test]
3485 fn macro_can_use_filter_at_expansion_time() {
3486 let v = run_full(
3490 "(defmacro sum-positives (&rest xs)
3491 `(+ ,@(filter positive? xs)))
3492 (sum-positives 1 -2 3 -4 5)",
3493 );
3494 assert!(matches!(v, Value::Int(9)));
3496 }
3497
3498 #[test]
3499 fn macro_can_recursively_emit_let_chain() {
3500 let v = run_full(
3503 "(defmacro chain-let (binding &rest more)
3504 (if (null? more)
3505 `(let (,binding) #t)
3506 `(let (,binding) (chain-let ,@more))))
3507 (chain-let (a 1) (b 2) (c 3))",
3508 );
3509 assert!(matches!(v, Value::Bool(true)));
3510 }
3511
3512 #[test]
3513 fn macro_can_use_gensym_for_hygiene() {
3514 let v = run_full(
3517 "(defmacro swap-bind (init body)
3518 (let ((tmp (gensym \"tmp\")))
3519 `(let ((,tmp ,init))
3520 (+ ,tmp ,tmp))))
3521 (swap-bind 21 #t)",
3522 );
3523 assert!(matches!(v, Value::Int(42)));
3524 }
3525
3526 #[test]
3527 fn macro_can_inspect_arg_shape() {
3528 let v = run_full(
3530 "(defmacro shape-aware (x)
3531 (if (list? x)
3532 `(+ ,@x) ;; sum the children
3533 `,x)) ;; pass through scalars
3534 (+ (shape-aware (1 2 3)) (shape-aware 100))",
3535 );
3536 assert!(matches!(v, Value::Int(106)));
3538 }
3539
3540 #[test]
3541 fn macro_can_call_user_helper_fn() {
3542 let v = run_full(
3544 "(define (square x) (* x x))
3545 (defmacro static-square (n) (square n))
3546 (static-square 7)",
3547 );
3548 assert!(matches!(v, Value::Int(49)));
3549 }
3550
3551 #[test]
3552 fn macro_emitting_quoted_form_round_trips() {
3553 let v = run_full(
3556 "(defmacro literal-list (&rest xs)
3557 `(quote ,xs))
3558 (literal-list a b c)",
3559 );
3560 let s = format!("{v}");
3561 assert!(s.contains('a') && s.contains('b') && s.contains('c'));
3562 }
3563
3564 #[test]
3565 fn quasiquote_inside_quasiquote_in_macro_output_is_preserved() {
3566 let v = run_full(
3569 "(defmacro emit-qq (x) `(quasiquote (a (unquote ,x) c)))
3570 (let ((q (emit-qq 99))) q)",
3571 );
3572 assert_eq!(format!("{v}"), "(a 99 c)");
3574 }
3575
3576 #[test]
3577 fn macro_body_can_define_locals_and_dispatch() {
3578 let v = run_full(
3580 "(defmacro classify-args (&rest xs)
3581 (let ((evens (filter even? xs))
3582 (odds (filter odd? xs)))
3583 `(list (list :evens ,@evens)
3584 (list :odds ,@odds))))
3585 (classify-args 1 2 3 4 5 6)",
3586 );
3587 let s = format!("{v}");
3588 assert!(s.contains(":evens 2 4 6"));
3589 assert!(s.contains(":odds 1 3 5"));
3590 }
3591
3592 #[test]
3601 fn tco_self_recursion_via_if() {
3602 let v = run_full(
3606 "(define (sum n acc)
3607 (if (= n 0)
3608 acc
3609 (sum (- n 1) (+ acc n))))
3610 (sum 100000 0)",
3611 );
3612 assert!(matches!(v, Value::Int(5_000_050_000)));
3614 }
3615
3616 #[test]
3617 fn tco_mutual_recursion() {
3618 let v = run_full(
3621 "(define (even-r? n) (if (= n 0) #t (odd-r? (- n 1))))
3622 (define (odd-r? n) (if (= n 0) #f (even-r? (- n 1))))
3623 (even-r? 50000)",
3624 );
3625 assert!(matches!(v, Value::Bool(true)));
3626 }
3627
3628 #[test]
3629 fn tco_via_cond_branch() {
3630 let v = run_full(
3631 "(define (countdown n)
3632 (cond
3633 ((<= n 0) :done)
3634 (else (countdown (- n 1)))))
3635 (countdown 50000)",
3636 );
3637 assert!(matches!(v, Value::Keyword(s) if &*s == "done"));
3638 }
3639
3640 #[test]
3641 fn tco_via_let_body() {
3642 let v = run_full(
3645 "(define (loop-let n)
3646 (let ((m (- n 1)))
3647 (if (<= n 0) :done (loop-let m))))
3648 (loop-let 50000)",
3649 );
3650 assert!(matches!(v, Value::Keyword(s) if &*s == "done"));
3651 }
3652
3653 #[test]
3654 fn tco_via_begin_last_form() {
3655 let v = run_full(
3656 "(define (counter n)
3657 (begin
3658 (+ 1 1)
3659 (+ 2 2)
3660 (if (<= n 0) :done (counter (- n 1)))))
3661 (counter 50000)",
3662 );
3663 assert!(matches!(v, Value::Keyword(s) if &*s == "done"));
3664 }
3665
3666 #[test]
3667 fn tco_via_when_unless() {
3668 let v = run_full(
3669 "(define (drain n)
3670 (when (> n 0)
3671 (drain (- n 1))))
3672 (drain 50000)",
3673 );
3674 assert!(matches!(v, Value::Nil));
3676 }
3677
3678 #[test]
3679 fn tco_through_and_or_short_circuit_last() {
3680 let v = run_full(
3683 "(define (loop-and n)
3684 (and #t #t (if (<= n 0) :done (loop-and (- n 1)))))
3685 (loop-and 30000)",
3686 );
3687 assert!(matches!(v, Value::Keyword(s) if &*s == "done"));
3688 }
3689
3690 #[test]
3691 fn non_tail_recursion_still_works_for_small_n() {
3692 let v = run_full(
3696 "(define (fact n)
3697 (if (= n 0) 1 (* n (fact (- n 1)))))
3698 (fact 12)",
3699 );
3700 assert!(matches!(v, Value::Int(479_001_600)));
3702 }
3703
3704 #[test]
3707 fn error_constructor_returns_error_value() {
3708 let v = run_full("(error :validation \"bad input\")");
3709 match v {
3710 Value::Error(e) => {
3711 assert_eq!(&*e.tag, "validation");
3712 assert_eq!(&*e.message, "bad input");
3713 assert!(e.data.is_empty());
3714 }
3715 other => panic!("{other:?}"),
3716 }
3717 }
3718
3719 #[test]
3720 fn ex_info_uses_default_tag() {
3721 let v = run_full("(ex-info \"validation failed\" (list :field \"email\" :code 42))");
3722 match v {
3723 Value::Error(e) => {
3724 assert_eq!(&*e.tag, "ex-info");
3725 assert_eq!(&*e.message, "validation failed");
3726 assert_eq!(e.data.len(), 2);
3727 }
3728 other => panic!("{other:?}"),
3729 }
3730 }
3731
3732 #[test]
3733 fn error_predicate() {
3734 let v = run_full("(error? (error :x \"y\"))");
3735 assert!(matches!(v, Value::Bool(true)));
3736 let v = run_full("(error? 42)");
3737 assert!(matches!(v, Value::Bool(false)));
3738 }
3739
3740 #[test]
3741 fn error_accessors() {
3742 let v = run_full(
3743 "(let ((e (ex-info \"oops\" (list :user-id 42))))
3744 (list (error-tag e) (error-message e) (error-data-get e :user-id)))",
3745 );
3746 assert_eq!(format!("{v}"), "(:ex-info \"oops\" 42)");
3747 }
3748
3749 #[test]
3750 fn try_catches_thrown_error() {
3751 let v = run_full(
3752 "(try
3753 (throw (ex-info \"boom\" (list :code 500)))
3754 (catch (e)
3755 (error-message e)))",
3756 );
3757 assert_eq!(format!("{v}"), "\"boom\"");
3758 }
3759
3760 #[test]
3761 fn try_returns_body_value_when_no_throw() {
3762 let v = run_full(
3763 "(try
3764 (+ 1 2 3)
3765 (catch (e) :unreachable))",
3766 );
3767 assert!(matches!(v, Value::Int(6)));
3768 }
3769
3770 #[test]
3771 fn try_catches_runtime_errors_too() {
3772 let v = run_full(
3776 "(try
3777 (/ 1 0)
3778 (catch (e) (error-tag e)))",
3779 );
3780 assert!(matches!(v, Value::Keyword(s) if &*s == "division-by-zero"));
3781 }
3782
3783 #[test]
3784 fn try_catches_unbound_symbol_error() {
3785 let v = run_full(
3786 "(try
3787 undefined-var
3788 (catch (e) (error-tag e)))",
3789 );
3790 assert!(matches!(v, Value::Keyword(s) if &*s == "unbound-symbol"));
3791 }
3792
3793 #[test]
3794 fn try_catches_arity_mismatch() {
3795 let v = run_full(
3796 "(try
3797 ((lambda (x y) (+ x y)) 1)
3798 (catch (e) (error-tag e)))",
3799 );
3800 assert!(matches!(v, Value::Keyword(s) if &*s == "arity-mismatch"));
3801 }
3802
3803 #[test]
3804 fn nested_try_inner_handler_takes_precedence() {
3805 let v = run_full(
3806 "(try
3807 (try
3808 (throw (ex-info \"inner\" ()))
3809 (catch (e) :inner-caught))
3810 (catch (e) :outer-caught))",
3811 );
3812 assert!(matches!(v, Value::Keyword(s) if &*s == "inner-caught"));
3813 }
3814
3815 #[test]
3816 fn outer_try_catches_when_handler_rethrows() {
3817 let v = run_full(
3818 "(try
3819 (try
3820 (throw (ex-info \"first\" ()))
3821 (catch (e) (throw (ex-info \"rethrown\" ()))))
3822 (catch (e) (error-message e)))",
3823 );
3824 assert_eq!(format!("{v}"), "\"rethrown\"");
3825 }
3826
3827 #[test]
3828 fn throw_propagates_when_no_try() {
3829 let mut i: Interpreter<NoHost> = Interpreter::new();
3831 install_full_stdlib_with(&mut i, &mut NoHost);
3832 let forms = read_spanned("(throw (ex-info \"unhandled\" (list :code 99)))").unwrap();
3833 let err = i.eval_program(&forms, &mut NoHost).unwrap_err();
3834 match err {
3835 EvalError::User { value, .. } => match value {
3836 Value::Error(e) => {
3837 assert_eq!(&*e.message, "unhandled");
3838 }
3839 other => panic!("{other:?}"),
3840 },
3841 other => panic!("{other:?}"),
3842 }
3843 }
3844
3845 #[test]
3848 fn macroexpand_one_step() {
3849 let v = run_full(
3850 "(defmacro twice (x) `(* ,x 2))
3851 (macroexpand-1 '(twice 7))",
3852 );
3853 assert_eq!(format!("{v}"), "(* 7 2)");
3855 }
3856
3857 #[test]
3858 fn macroexpand_full_until_fixed_point() {
3859 let v = run_full(
3860 "(defmacro twice (x) `(* ,x 2))
3861 (defmacro quad (x) `(twice (twice ,x)))
3862 (macroexpand '(quad 5))",
3863 );
3864 assert_eq!(format!("{v}"), "(* (* 5 2) 2)");
3866 }
3867
3868 #[test]
3869 fn macroexpand_returns_unchanged_for_non_macro() {
3870 let v = run_full("(macroexpand-1 '(+ 1 2 3))");
3871 assert_eq!(format!("{v}"), "(+ 1 2 3)");
3873 }
3874
3875 #[test]
3876 fn macroexpand_one_does_not_recurse_into_children() {
3877 let v = run_full(
3879 "(defmacro twice (x) `(* ,x 2))
3880 (defmacro outer (x) `(list ,x))
3881 (macroexpand-1 '(outer (twice 3)))",
3882 );
3883 assert_eq!(format!("{v}"), "(list (twice 3))");
3885 }
3886
3887 #[test]
3888 fn macroexpand_recurses_into_children() {
3889 let v = run_full(
3890 "(defmacro twice (x) `(* ,x 2))
3891 (defmacro outer (x) `(list ,x))
3892 (macroexpand '(outer (twice 3)))",
3893 );
3894 assert_eq!(format!("{v}"), "(list (* 3 2))");
3896 }
3897
3898 fn run_with_modules(modules: &[(&str, &str)], src: &str) -> Value {
3901 use crate::module::MapLoader;
3902 let mut i: Interpreter<NoHost> = Interpreter::new();
3903 install_full_stdlib_with(&mut i, &mut NoHost);
3904 let mut loader = MapLoader::new();
3905 for (path, source) in modules {
3906 loader.insert(*path, *source);
3907 }
3908 i.set_loader(Arc::new(loader));
3909 let forms = read_spanned(src).unwrap();
3910 i.eval_program(&forms, &mut NoHost).unwrap()
3911 }
3912
3913 fn run_with_modules_err(modules: &[(&str, &str)], src: &str) -> EvalError {
3914 use crate::module::MapLoader;
3915 let mut i: Interpreter<NoHost> = Interpreter::new();
3916 install_full_stdlib_with(&mut i, &mut NoHost);
3917 let mut loader = MapLoader::new();
3918 for (path, source) in modules {
3919 loader.insert(*path, *source);
3920 }
3921 i.set_loader(Arc::new(loader));
3922 let forms = read_spanned(src).unwrap();
3923 i.eval_program(&forms, &mut NoHost).unwrap_err()
3924 }
3925
3926 #[test]
3927 fn require_with_explicit_alias_imports_qualified_names() {
3928 let v = run_with_modules(
3929 &[(
3930 "lib/math",
3931 "(define square (lambda (x) (* x x)))
3932 (define cube (lambda (x) (* x x x)))
3933 (provide square cube)",
3934 )],
3935 "(require \"lib/math\" :as math)
3936 (math/square 7)",
3937 );
3938 assert!(matches!(v, Value::Int(49)));
3939 }
3940
3941 #[test]
3942 fn require_uses_path_as_default_alias() {
3943 let v = run_with_modules(
3944 &[(
3945 "lib/math",
3946 "(define double (lambda (x) (* x 2))) (provide double)",
3947 )],
3948 "(require \"lib/math\")
3949 (lib/math/double 21)",
3950 );
3951 assert!(matches!(v, Value::Int(42)));
3954 }
3955
3956 #[test]
3957 fn require_refer_imports_unqualified_names() {
3958 let v = run_with_modules(
3959 &[(
3960 "lib/math",
3961 "(define square (lambda (x) (* x x)))
3962 (define cube (lambda (x) (* x x x)))
3963 (provide square cube)",
3964 )],
3965 "(require \"lib/math\" :refer (square))
3966 (square 6)",
3967 );
3968 assert!(matches!(v, Value::Int(36)));
3969 }
3970
3971 #[test]
3972 fn require_does_not_import_non_provided() {
3973 let err = run_with_modules_err(
3976 &[(
3977 "lib/secret",
3978 "(define public 1)
3979 (define private 2)
3980 (provide public)",
3981 )],
3982 "(require \"lib/secret\" :as s)
3983 s/private",
3984 );
3985 match err {
3986 EvalError::UnboundSymbol { name, .. } => assert_eq!(&*name, "s/private"),
3987 other => panic!("{other:?}"),
3988 }
3989 }
3990
3991 #[test]
3992 fn require_chain_a_imports_b() {
3993 let v = run_with_modules(
3994 &[
3995 (
3996 "lib/util",
3997 "(define inc1 (lambda (n) (+ n 1)))
3998 (provide inc1)",
3999 ),
4000 (
4001 "lib/wrapper",
4002 "(require \"lib/util\" :as u)
4003 (define inc2 (lambda (n) (u/inc1 (u/inc1 n))))
4004 (provide inc2)",
4005 ),
4006 ],
4007 "(require \"lib/wrapper\" :as w)
4008 (w/inc2 10)",
4009 );
4010 assert!(matches!(v, Value::Int(12)));
4011 }
4012
4013 #[test]
4014 fn require_module_not_found() {
4015 let err = run_with_modules_err(&[], "(require \"missing/module\")");
4016 match err {
4018 EvalError::User { value, .. } => match value {
4019 Value::Error(e) => {
4020 assert_eq!(&*e.tag, "module-not-found");
4021 assert!(e.message.contains("missing/module"));
4022 }
4023 other => panic!("{other:?}"),
4024 },
4025 other => panic!("{other:?}"),
4026 }
4027 }
4028
4029 #[test]
4030 fn circular_require_detected() {
4031 let err = run_with_modules_err(
4032 &[
4033 ("a", "(require \"b\") (provide x) (define x 1)"),
4034 ("b", "(require \"a\") (provide y) (define y 2)"),
4035 ],
4036 "(require \"a\")",
4037 );
4038 match err {
4039 EvalError::User { value, .. } => match value {
4040 Value::Error(e) => assert_eq!(&*e.tag, "circular-require"),
4041 other => panic!("{other:?}"),
4042 },
4043 other => panic!("{other:?}"),
4044 }
4045 }
4046
4047 #[test]
4048 fn provide_at_top_level_errors() {
4049 let mut i: Interpreter<NoHost> = Interpreter::new();
4051 install_full_stdlib_with(&mut i, &mut NoHost);
4052 let forms = read_spanned("(provide x)").unwrap();
4053 let err = i.eval_program(&forms, &mut NoHost).unwrap_err();
4054 assert!(matches!(err, EvalError::BadSpecialForm { form, .. } if &*form == "provide"));
4055 }
4056
4057 #[test]
4058 fn require_refer_unknown_name_errors() {
4059 let err = run_with_modules_err(
4060 &[(
4061 "lib/math",
4062 "(define square (lambda (x) (* x x))) (provide square)",
4063 )],
4064 "(require \"lib/math\" :refer (square cube))",
4065 );
4066 match err {
4067 EvalError::User { value, .. } => match value {
4068 Value::Error(e) => {
4069 assert!(matches!(&*e.tag, "not-defined" | "not-exported"));
4070 }
4071 other => panic!("{other:?}"),
4072 },
4073 other => panic!("{other:?}"),
4074 }
4075 }
4076
4077 #[test]
4078 fn require_caches_module_load_once() {
4079 let v = run_with_modules(
4080 &[("lib/foo", "(define x 42) (provide x)")],
4081 "(require \"lib/foo\" :as a)
4082 (require \"lib/foo\" :as b)
4083 (+ a/x b/x)",
4084 );
4085 assert!(matches!(v, Value::Int(84)));
4087 }
4088
4089 #[test]
4098 fn macro_body_cannot_set_a_global() {
4099 let mut interp = Interpreter::new();
4100 install_primitives(&mut interp);
4101 let src = "(define *g* 0) (defmacro leak () (set! *g* 99)) (leak)";
4102 let forms = tatara_lisp::read_spanned(src).expect("parse");
4103 let err = interp
4104 .eval_program(&forms, &mut ())
4105 .expect_err("a macro must not be able to set! a global");
4106 let msg = format!("{err}");
4107 assert!(
4108 msg.contains("sealed") || msg.contains("cannot `set!`"),
4109 "expected a sealed-write diagnostic, got: {msg}"
4110 );
4111 }
4112
4113 #[test]
4114 fn the_global_is_actually_unchanged_after_a_refused_macro_set() {
4115 let mut interp = Interpreter::new();
4116 install_primitives(&mut interp);
4117 let forms = tatara_lisp::read_spanned("(define *g* 0) (defmacro leak () (set! *g* 99))")
4118 .expect("parse");
4119 interp.eval_program(&forms, &mut ()).expect("setup");
4120 let call = tatara_lisp::read_spanned("(leak)").expect("parse");
4122 let _ = interp.eval_program(&call, &mut ());
4123 let read = tatara_lisp::read_spanned("*g*").expect("parse");
4124 let v = interp.eval_program(&read, &mut ()).expect("read *g*");
4125 assert!(
4126 matches!(v, Value::Int(0)),
4127 "global was mutated by a macro body despite the seal: {v:?}"
4128 );
4129 }
4130
4131 #[test]
4134 fn ordinary_set_still_works_at_runtime() {
4135 let mut interp = Interpreter::new();
4136 install_primitives(&mut interp);
4137 let forms = tatara_lisp::read_spanned("(define x 1) (set! x 42) x").expect("parse");
4138 let v = interp.eval_program(&forms, &mut ()).expect("runtime set!");
4139 assert!(matches!(v, Value::Int(42)), "got {v:?}");
4140 }
4141
4142 #[test]
4145 fn macro_body_can_mutate_its_own_locals() {
4146 let mut interp = Interpreter::new();
4147 install_primitives(&mut interp);
4148 let src = "(defmacro m () (begin (define n 1) (set! n 2) n)) (m)";
4149 let forms = tatara_lisp::read_spanned(src).expect("parse");
4150 let v = interp
4151 .eval_program(&forms, &mut ())
4152 .expect("a macro must be able to mutate its own locals");
4153 assert!(matches!(v, Value::Int(2)), "got {v:?}");
4154 }
4155}