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_interrupt(&mut self, flag: Arc<std::sync::atomic::AtomicBool>) {
345 self.registry.halt = flag;
346 }
347
348 #[must_use]
350 pub fn interrupt(&self) -> Arc<std::sync::atomic::AtomicBool> {
351 Arc::clone(&self.registry.halt)
352 }
353
354 pub fn set_macro_expansion_limit(&mut self, limit: usize) {
355 self.macro_expansion_limit = limit;
356 }
357
358 pub fn set_budget(&mut self, budget: crate::vm::Budget) -> Result<()> {
377 if budget.quantum.is_some() {
378 return Err(EvalError::NotImplemented(
379 "a budget quantum on the tree-walker (it cannot park; use the VM)",
380 ));
381 }
382 self.registry.meter = crate::ffi::Meter::new(budget);
383 Ok(())
384 }
385
386 #[must_use]
388 pub fn budget(&self) -> crate::vm::Budget {
389 self.registry.meter.budget
390 }
391
392 #[must_use]
395 pub fn steps_spent(&self) -> usize {
396 self.registry.meter.spent()
397 }
398
399 pub fn set_call_observer(&mut self, observer: Option<Arc<dyn crate::observe::CallObserver>>) {
403 self.registry.observer = observer;
404 }
405
406 pub fn take_trace(&self) -> crate::observe::Trace {
410 self.registry.unwind.take()
411 }
412
413 pub fn eval_spanned(&mut self, form: &Spanned, host: &mut H) -> Result<Value> {
418 self.registry.unwind.clear();
419 let expanded = self.fully_expand(form, host)?;
420 eval_in(
421 &mut self.globals,
422 &self.registry,
423 &self.expander,
424 &expanded,
425 host,
426 )
427 }
428
429 pub fn eval_program(&mut self, forms: &[Spanned], host: &mut H) -> Result<Value> {
441 let mut last = Value::Nil;
442 for form in forms {
443 last = self.eval_top_form(form, host)?;
444 }
445 Ok(last)
446 }
447
448 pub fn eval_top_form(&mut self, form: &Spanned, host: &mut H) -> Result<Value> {
454 self.registry.unwind.clear();
455 if self.expander.try_register_macro(form)? {
456 return Ok(Value::Nil);
457 }
458 if let Some(head) = head_symbol(form) {
462 match head {
463 "provide" => return self.eval_provide(form, host),
464 "require" => return self.eval_require(form, host),
465 _ => {}
466 }
467 }
468 let expanded = self.fully_expand(form, host)?;
469 eval_in(
470 &mut self.globals,
471 &self.registry,
472 &self.expander,
473 &expanded,
474 host,
475 )
476 }
477
478 fn eval_provide(&mut self, form: &Spanned, _host: &mut H) -> Result<Value> {
482 let items = form.as_list().unwrap_or(&[]);
483 let span = form.span;
484 let Some(current) = self.current_module.clone() else {
485 return Err(EvalError::bad_form(
486 "provide",
487 "`provide` only valid at module top level — embedder evaluating top-level code has no current module",
488 span,
489 ));
490 };
491 let mut names: Vec<Arc<str>> = Vec::with_capacity(items.len().saturating_sub(1));
493 for item in &items[1..] {
494 let name = item.as_symbol().ok_or_else(|| {
495 EvalError::bad_form(
496 "provide",
497 "expected symbol — every arg must name a binding to export",
498 item.span,
499 )
500 })?;
501 names.push(Arc::<str>::from(name));
502 }
503 {
508 let mut g = self.modules.inner_lock();
509 g.exports_staging
513 .entry(current.to_string())
514 .or_default()
515 .extend(names.iter().cloned());
516 }
517 Ok(Value::Nil)
518 }
519
520 fn eval_require(&mut self, form: &Spanned, host: &mut H) -> Result<Value> {
529 let items = form.as_list().unwrap_or(&[]);
530 let span = form.span;
531 if items.len() < 2 {
532 return Err(EvalError::bad_form(
533 "require",
534 "expected (require \"path\" [:as alias] [:refer (...)])",
535 span,
536 ));
537 }
538 let path: Arc<str> = match items[1].as_string() {
539 Some(s) => Arc::from(s),
540 None => {
541 return Err(EvalError::bad_form(
542 "require",
543 "first arg must be a string path",
544 items[1].span,
545 ))
546 }
547 };
548
549 let mut alias: Option<Arc<str>> = None;
551 let mut refer: Option<Vec<Arc<str>>> = None;
552 let mut i = 2usize;
553 while i < items.len() {
554 let kw = items[i].as_keyword().ok_or_else(|| {
555 EvalError::bad_form(
556 "require",
557 "expected keyword (:as / :refer) after path",
558 items[i].span,
559 )
560 })?;
561 let val = items.get(i + 1).ok_or_else(|| {
562 EvalError::bad_form("require", "keyword without value", items[i].span)
563 })?;
564 match kw {
565 "as" => {
566 alias = Some(Arc::from(val.as_symbol().ok_or_else(|| {
567 EvalError::bad_form("require", ":as needs a symbol alias", val.span)
568 })?));
569 }
570 "refer" => {
571 let names_list = val.as_list().ok_or_else(|| {
572 EvalError::bad_form(
573 "require",
574 ":refer needs a parenthesized list of symbols",
575 val.span,
576 )
577 })?;
578 let mut names = Vec::with_capacity(names_list.len());
579 for n in names_list {
580 names.push(Arc::<str>::from(n.as_symbol().ok_or_else(|| {
581 EvalError::bad_form(
582 "require",
583 ":refer list must contain symbols only",
584 n.span,
585 )
586 })?));
587 }
588 refer = Some(names);
589 }
590 other => {
591 return Err(EvalError::bad_form(
592 "require",
593 format!("unknown require option :{other}"),
594 items[i].span,
595 ));
596 }
597 }
598 i += 2;
599 }
600
601 if !self.modules.has(&path) {
603 self.load_module(&path, span, host)?;
604 }
605 let module = self.modules.get(&path).ok_or_else(|| {
606 EvalError::native_fn("require", "module disappeared after load", span)
607 })?;
608
609 let chosen_alias = alias.unwrap_or_else(|| path.clone());
611 for name in &module.exports {
612 let value = module.bindings.get(name).cloned().unwrap_or(Value::Nil);
613 let qualified: Arc<str> = Arc::from(format!("{chosen_alias}/{name}"));
614 self.globals.define(qualified, value);
615 }
616 if let Some(names) = refer {
617 for name in names {
618 if let Some(value) = module.bindings.get(&name) {
619 if module.exports.contains(&name) {
620 self.globals.define(name.clone(), value.clone());
621 } else {
622 return Err(EvalError::User {
623 value: error_value(
624 "not-exported",
625 &format!("{path} does not export {name}"),
626 ),
627 at: span,
628 });
629 }
630 } else {
631 return Err(EvalError::User {
632 value: error_value(
633 "not-defined",
634 &format!("{path} does not define {name}"),
635 ),
636 at: span,
637 });
638 }
639 }
640 }
641 Ok(Value::Nil)
642 }
643
644 fn load_module(&mut self, path: &str, span: Span, host: &mut H) -> Result<()> {
650 self.modules
652 .begin_load(path)
653 .map_err(|e| module_error_to_eval(e, span))?;
654
655 let source = match self.loader.load(path) {
657 Ok(s) => s,
658 Err(e) => {
659 self.modules.abort_load(path);
660 return Err(module_error_to_eval(e, span));
661 }
662 };
663
664 let forms = match tatara_lisp::read_spanned(&source) {
666 Ok(f) => f,
667 Err(e) => {
668 self.modules.abort_load(path);
669 return Err(EvalError::Reader(e));
670 }
671 };
672
673 let saved_globals = std::mem::replace(&mut self.globals, Env::new());
677 for (name, value) in saved_globals.iter_top_level() {
681 if matches!(value, Value::NativeFn(_) | Value::Closure(_)) {
685 self.globals.define(name.clone(), value.clone());
686 }
687 }
688 let saved_current = self.current_module.replace(Arc::from(path));
689
690 let mut eval_err: Option<EvalError> = None;
692 for f in &forms {
693 if let Err(e) = self.eval_top_form(f, host) {
697 eval_err = Some(e);
698 break;
699 }
700 }
701
702 let module_globals = std::mem::replace(&mut self.globals, saved_globals);
704 self.current_module = saved_current;
705
706 if let Some(e) = eval_err {
707 self.modules.abort_load(path);
708 return Err(e);
709 }
710
711 let mut module = Module::new(path);
714 for (name, value) in module_globals.iter_top_level() {
715 if !matches!(value, Value::NativeFn(_)) {
718 module.define(name.clone(), value.clone());
719 }
720 }
721 let staged = {
723 let mut g = self.modules.inner_lock();
724 g.exports_staging.remove(path).unwrap_or_default()
725 };
726 for n in staged {
727 module.add_export(n);
728 }
729 self.modules.finish_load(module);
730 Ok(())
731 }
732
733 pub fn fully_expand(&mut self, form: &Spanned, host: &mut H) -> Result<Spanned> {
744 if self.expander.is_empty() {
746 return Ok(form.clone());
747 }
748 self.expand_recursive(form, host)
749 }
750
751 fn expand_recursive(&mut self, form: &Spanned, host: &mut H) -> Result<Spanned> {
752 self.expand_at_depth(form, host, 0)
753 }
754
755 fn expand_at_depth(&mut self, form: &Spanned, host: &mut H, depth: usize) -> Result<Spanned> {
772 match &form.form {
773 SpannedForm::List(items) if !items.is_empty() => {
774 if let Some(head) = items[0].as_symbol() {
775 if self.expander.has(head) {
776 if depth >= self.macro_expansion_limit {
777 return Err(EvalError::MacroExpansionLimit {
782 macro_name: head.into(),
783 limit: self.macro_expansion_limit,
784 at: form.span,
785 });
786 }
787 let expanded =
791 self.expand_macro_call(head, &items[1..], form.span, host)?;
792 return self.expand_at_depth(&expanded, host, depth + 1);
793 }
794 }
795 let mut out = Vec::with_capacity(items.len());
799 for child in items {
800 out.push(self.expand_at_depth(child, host, depth)?);
801 }
802 Ok(Spanned::new(form.span, SpannedForm::List(out)))
803 }
804 SpannedForm::Quote(_) => {
805 Ok(form.clone())
807 }
808 SpannedForm::Quasiquote(inner) => {
809 Ok(Spanned::new(
811 form.span,
812 SpannedForm::Quasiquote(Box::new(self.expand_inside_quasiquote(inner, host)?)),
813 ))
814 }
815 _ => Ok(form.clone()),
817 }
818 }
819
820 fn expand_inside_quasiquote(&mut self, form: &Spanned, host: &mut H) -> Result<Spanned> {
821 match &form.form {
822 SpannedForm::Unquote(inner) => Ok(Spanned::new(
823 form.span,
824 SpannedForm::Unquote(Box::new(self.expand_recursive(inner, host)?)),
825 )),
826 SpannedForm::UnquoteSplice(inner) => Ok(Spanned::new(
827 form.span,
828 SpannedForm::UnquoteSplice(Box::new(self.expand_recursive(inner, host)?)),
829 )),
830 SpannedForm::List(items) => {
831 let mut out = Vec::with_capacity(items.len());
832 for item in items {
833 out.push(self.expand_inside_quasiquote(item, host)?);
834 }
835 Ok(Spanned::new(form.span, SpannedForm::List(out)))
836 }
837 _ => Ok(form.clone()),
838 }
839 }
840
841 fn expand_macro_call(
845 &mut self,
846 macro_name: &str,
847 args: &[Spanned],
848 call_span: Span,
849 host: &mut H,
850 ) -> Result<Spanned> {
851 let def: MacroDef = self
854 .expander
855 .get_macro(macro_name)
856 .cloned()
857 .ok_or_else(|| {
858 EvalError::native_fn(
859 Arc::<str>::from(macro_name),
860 "macro disappeared during expansion",
861 call_span,
862 )
863 })?;
864
865 let body_spanned = Spanned::from_sexp_at(&def.body, call_span);
870
871 let body_expanded = self.fully_expand(&body_spanned, host)?;
877
878 let mut macro_env = self.globals.sealed_below_top(Seal::MacroExpansion);
886 bind_macro_args(&mut macro_env, &def.name, &def.params, args, call_span)?;
887
888 let result = eval_in(
891 &mut macro_env,
892 &self.registry,
893 &self.expander,
894 &body_expanded,
895 host,
896 )?;
897
898 value_to_spanned(&result, call_span).map_err(|reason| {
902 EvalError::native_fn(
903 Arc::<str>::from(format!("macro {macro_name}")),
904 reason,
905 call_span,
906 )
907 })
908 }
909
910 pub fn expander(&self) -> &SpannedExpander {
913 &self.expander
914 }
915
916 pub fn expander_mut(&mut self) -> &mut SpannedExpander {
920 &mut self.expander
921 }
922
923 pub fn lookup_global(&self, name: &str) -> Option<Value> {
925 self.globals.lookup(name)
926 }
927
928 pub fn define_global(&mut self, name: impl Into<Arc<str>>, value: Value) {
930 self.globals.define(name, value);
931 }
932
933 pub fn globals_snapshot(&self) -> &Env {
936 &self.globals
937 }
938
939 #[must_use]
961 pub fn resolve_head(&self, name: &str) -> Option<HeadBinding> {
962 if SpecialForm::from_symbol(name).is_some() {
963 Some(HeadBinding::SpecialForm)
964 } else if self.expander.has(name) {
965 Some(HeadBinding::Macro)
966 } else if self.globals.lookup(name).is_some() {
967 Some(HeadBinding::Value)
968 } else {
969 None
970 }
971 }
972
973 #[must_use]
980 pub fn reserved_head_names(&self) -> std::collections::BTreeSet<Arc<str>> {
981 let mut out: std::collections::BTreeSet<Arc<str>> = SpecialForm::ALL
982 .iter()
983 .map(|sf| Arc::from(sf.symbol()))
984 .collect();
985 out.extend(
986 self.expander
987 .macro_names()
988 .map(Arc::from)
989 .collect::<Vec<Arc<str>>>(),
990 );
991 out.extend(self.globals.iter_top_level().into_iter().map(|(n, _)| n));
992 out
993 }
994
995 pub(crate) fn callee_may_park(&self, callee: &Value) -> bool {
1010 match callee {
1011 Value::NativeFn(nfn) => self
1012 .registry
1013 .lookup(&nfn.name)
1014 .is_none_or(|entry| entry.callable.may_park()),
1015 _ => true,
1016 }
1017 }
1018
1019 pub fn apply_external_value(
1023 &mut self,
1024 callee: &Value,
1025 args: Vec<Value>,
1026 host: &mut H,
1027 call_span: Span,
1028 ) -> Result<Value> {
1029 apply_external(
1030 callee,
1031 args,
1032 call_span,
1033 &self.registry,
1034 &self.expander,
1035 host,
1036 )
1037 }
1038
1039 pub fn expand_program(&mut self, forms: &[Spanned], host: &mut H) -> Result<Vec<Spanned>> {
1058 let mut expanded: Vec<Spanned> = Vec::with_capacity(forms.len());
1059 for form in forms {
1060 if self.expander.try_register_macro(form)? {
1061 continue;
1062 }
1063 expanded.push(self.fully_expand(form, host)?);
1064 }
1065 Ok(expanded)
1066 }
1067
1068 pub fn eval_program_vm(&mut self, forms: &[Spanned], host: &mut H) -> Result<Value> {
1075 let expanded = self.expand_program(forms, host)?;
1076 let chunk = crate::vm::compile_program(&expanded).map_err(|e| match e {
1077 crate::vm::CompileError::Bad { at, message } => {
1078 EvalError::bad_form(Arc::<str>::from("vm:compile"), message, at)
1079 }
1080 })?;
1081 let mut vm = crate::vm::Vm::with_budget(self.budget());
1084 vm.run(&chunk, self, host).map_err(|e| match e {
1085 crate::vm::VmError::Eval(inner) => inner,
1086 budget @ crate::vm::VmError::BudgetExhausted { .. } => {
1087 budget.budget_as_eval().expect("a budget refusal")
1088 }
1089 other => EvalError::native_fn(
1090 Arc::<str>::from("vm"),
1091 format!("{other}"),
1092 Span::synthetic(),
1093 ),
1094 })
1095 }
1096
1097 pub fn register_typed0<R, F>(&mut self, name: impl Into<Arc<str>>, f: F)
1101 where
1102 R: IntoValue + 'static,
1103 F: Fn(&mut H) -> Result<R> + Send + Sync + 'static,
1104 {
1105 self.register_fn(
1106 name,
1107 Arity::Exact(0),
1108 move |_args: &[Value], host: &mut H, _sp| f(host).map(IntoValue::into_value),
1109 );
1110 }
1111
1112 pub fn register_typed1<A, R, F>(&mut self, name: impl Into<Arc<str>>, f: F)
1114 where
1115 A: FromValue + 'static,
1116 R: IntoValue + 'static,
1117 F: Fn(&mut H, A) -> Result<R> + Send + Sync + 'static,
1118 {
1119 self.register_fn(
1120 name,
1121 Arity::Exact(1),
1122 move |args: &[Value], host: &mut H, sp| {
1123 let a = A::from_value(&args[0], sp)?;
1124 f(host, a).map(IntoValue::into_value)
1125 },
1126 );
1127 }
1128
1129 pub fn register_typed2<A, B, R, F>(&mut self, name: impl Into<Arc<str>>, f: F)
1131 where
1132 A: FromValue + 'static,
1133 B: FromValue + 'static,
1134 R: IntoValue + 'static,
1135 F: Fn(&mut H, A, B) -> Result<R> + Send + Sync + 'static,
1136 {
1137 self.register_fn(
1138 name,
1139 Arity::Exact(2),
1140 move |args: &[Value], host: &mut H, sp| {
1141 let a = A::from_value(&args[0], sp)?;
1142 let b = B::from_value(&args[1], sp)?;
1143 f(host, a, b).map(IntoValue::into_value)
1144 },
1145 );
1146 }
1147
1148 pub fn register_typed3<A, B, C, R, F>(&mut self, name: impl Into<Arc<str>>, f: F)
1150 where
1151 A: FromValue + 'static,
1152 B: FromValue + 'static,
1153 C: FromValue + 'static,
1154 R: IntoValue + 'static,
1155 F: Fn(&mut H, A, B, C) -> Result<R> + Send + Sync + 'static,
1156 {
1157 self.register_fn(
1158 name,
1159 Arity::Exact(3),
1160 move |args: &[Value], host: &mut H, sp| {
1161 let a = A::from_value(&args[0], sp)?;
1162 let b = B::from_value(&args[1], sp)?;
1163 let c = C::from_value(&args[2], sp)?;
1164 f(host, a, b, c).map(IntoValue::into_value)
1165 },
1166 );
1167 }
1168
1169 pub fn register_typed4<A, B, C, D, R, F>(&mut self, name: impl Into<Arc<str>>, f: F)
1171 where
1172 A: FromValue + 'static,
1173 B: FromValue + 'static,
1174 C: FromValue + 'static,
1175 D: FromValue + 'static,
1176 R: IntoValue + 'static,
1177 F: Fn(&mut H, A, B, C, D) -> Result<R> + Send + Sync + 'static,
1178 {
1179 self.register_fn(
1180 name,
1181 Arity::Exact(4),
1182 move |args: &[Value], host: &mut H, sp| {
1183 let a = A::from_value(&args[0], sp)?;
1184 let b = B::from_value(&args[1], sp)?;
1185 let c = C::from_value(&args[2], sp)?;
1186 let d = D::from_value(&args[3], sp)?;
1187 f(host, a, b, c, d).map(IntoValue::into_value)
1188 },
1189 );
1190 }
1191}
1192
1193impl<H: 'static> Default for Interpreter<H> {
1194 fn default() -> Self {
1195 Self::new()
1196 }
1197}
1198
1199pub(crate) fn eval_in<H: 'static>(
1204 env: &mut Env,
1205 registry: &FnRegistry<H>,
1206 expander: &SpannedExpander,
1207 form: &Spanned,
1208 host: &mut H,
1209) -> Result<Value> {
1210 registry.step(form.span)?;
1211 match &form.form {
1212 SpannedForm::Nil => Ok(Value::Nil),
1213 SpannedForm::Atom(a) => eval_atom(a, form.span, env),
1214 SpannedForm::Quote(inner) => Ok(quoted_value(inner)),
1215 SpannedForm::Quasiquote(inner) => quasiquote_eval(inner, env, registry, expander, host),
1216 SpannedForm::Unquote(_) | SpannedForm::UnquoteSplice(_) => Err(EvalError::bad_form(
1217 "unquote",
1218 "unquote outside of quasiquote",
1219 form.span,
1220 )),
1221 SpannedForm::List(items) => {
1222 if items.is_empty() {
1223 return Ok(Value::Nil);
1224 }
1225 if let Some(head_sym) = items[0].as_symbol() {
1229 if let Some(sf) = SpecialForm::from_symbol(head_sym) {
1230 return eval_special(sf, items, form.span, env, registry, expander, host);
1231 }
1232 }
1233 eval_application(items, form.span, env, registry, expander, host)
1234 }
1235 }
1236}
1237
1238fn eval_atom(a: &Atom, span: Span, env: &Env) -> Result<Value> {
1239 match a {
1240 Atom::Symbol(name) => env
1241 .lookup(name)
1242 .ok_or_else(|| EvalError::unbound(name.as_str(), span)),
1243 Atom::Keyword(s) => Ok(Value::Keyword(crate::interner::intern(s.as_str()))),
1244 Atom::Str(s) => Ok(Value::Str(Arc::from(s.as_str()))),
1245 Atom::Int(n) => Ok(Value::Int(*n)),
1246 Atom::Float(n) => Ok(Value::Float(*n)),
1247 Atom::Bool(b) => Ok(Value::Bool(*b)),
1248 }
1249}
1250
1251fn quoted_value(inner: &Spanned) -> Value {
1255 crate::code::spanned_to_value(inner)
1256}
1257
1258fn quasiquote_eval<H: 'static>(
1264 form: &Spanned,
1265 env: &mut Env,
1266 registry: &FnRegistry<H>,
1267 expander: &SpannedExpander,
1268 host: &mut H,
1269) -> Result<Value> {
1270 match &form.form {
1271 SpannedForm::Unquote(inner) => eval_in(env, registry, expander, inner, host),
1272 SpannedForm::UnquoteSplice(_) => Err(EvalError::bad_form(
1273 "unquote-splice",
1274 "`,@` only valid directly inside a list",
1275 form.span,
1276 )),
1277 SpannedForm::List(items) => {
1278 let mut out: Vec<Value> = Vec::with_capacity(items.len());
1279 for item in items {
1280 if let SpannedForm::UnquoteSplice(inner) = &item.form {
1281 let v = eval_in(env, registry, expander, inner, host)?;
1282 match v {
1283 Value::List(xs) => out.extend(xs.iter().cloned()),
1284 Value::Nil => {}
1285 other => {
1286 return Err(EvalError::type_mismatch(
1287 "list",
1288 other.type_name(),
1289 item.span,
1290 ))
1291 }
1292 }
1293 } else {
1294 out.push(quasiquote_eval(item, env, registry, expander, host)?);
1295 }
1296 }
1297 if out.is_empty() {
1298 Ok(Value::Nil)
1299 } else {
1300 Ok(Value::list(out))
1301 }
1302 }
1303 SpannedForm::Nil => Ok(Value::Nil),
1304 SpannedForm::Atom(a) => Ok(match a {
1305 Atom::Symbol(s) => Value::Symbol(crate::interner::intern(s.as_str())),
1306 Atom::Keyword(s) => Value::Keyword(crate::interner::intern(s.as_str())),
1307 Atom::Str(s) => Value::Str(Arc::from(s.as_str())),
1308 Atom::Int(n) => Value::Int(*n),
1309 Atom::Float(n) => Value::Float(*n),
1310 Atom::Bool(b) => Value::Bool(*b),
1311 }),
1312 SpannedForm::Quote(_) | SpannedForm::Quasiquote(_) => {
1316 Ok(Value::Sexp(form.to_sexp(), form.span))
1317 }
1318 }
1319}
1320
1321fn eval_application<H: 'static>(
1324 items: &[Spanned],
1325 call_span: Span,
1326 env: &mut Env,
1327 registry: &FnRegistry<H>,
1328 expander: &SpannedExpander,
1329 host: &mut H,
1330) -> Result<Value> {
1331 let head_val = eval_in(env, registry, expander, &items[0], host)?;
1332 let mut args: Vec<Value> = Vec::with_capacity(items.len().saturating_sub(1));
1333 for arg_form in &items[1..] {
1334 args.push(eval_in(env, registry, expander, arg_form, host)?);
1335 }
1336 apply(&head_val, args, call_span, registry, expander, host)
1337}
1338
1339fn apply<H: 'static>(
1340 callee: &Value,
1341 args: Vec<Value>,
1342 call_span: Span,
1343 registry: &FnRegistry<H>,
1344 expander: &SpannedExpander,
1345 host: &mut H,
1346) -> Result<Value> {
1347 match callee {
1348 Value::NativeFn(nfn) => {
1349 if nfn.arity.check(args.len()).is_err() {
1350 return Err(EvalError::ArityMismatch {
1351 fn_name: nfn.name.clone(),
1352 expected: nfn.arity,
1353 got: args.len(),
1354 at: call_span,
1355 });
1356 }
1357 let entry = registry.lookup(&nfn.name).ok_or_else(|| {
1358 EvalError::native_fn(
1359 nfn.name.clone(),
1360 format!("native fn {} is not registered", nfn.name),
1361 call_span,
1362 )
1363 })?;
1364 match &entry.callable {
1365 FnImpl::Native(f) => f.call(&args, host, call_span),
1366 FnImpl::Owned(f) => f.call(args, host, call_span),
1371 FnImpl::Higher(f) => {
1372 let caller = Caller { registry, expander };
1373 f.call(&args, host, &caller, call_span)
1374 }
1375 FnImpl::Awaitable(f) => {
1380 if f.ready(&args, host) {
1381 f.call(&args, host, call_span)
1382 } else {
1383 Ok(crate::vm::Vm::park())
1384 }
1385 }
1386 }
1387 }
1388 Value::Closure(c) => call_closure(c.clone(), args, call_span, registry, expander, host),
1389 Value::Foreign(any) => {
1394 if let Some(cc) = any
1395 .clone()
1396 .downcast::<crate::vm::run::CompiledClosure>()
1397 .ok()
1398 {
1399 let lifted = cc.lift_to_closure();
1400 return call_closure(lifted, args, call_span, registry, expander, host);
1401 }
1402 Err(EvalError::NotCallable {
1403 value_kind: callee.type_name(),
1404 at: call_span,
1405 })
1406 }
1407 other => Err(EvalError::NotCallable {
1408 value_kind: other.type_name(),
1409 at: call_span,
1410 }),
1411 }
1412}
1413
1414enum TailResult {
1437 Done(Value),
1439 Resume(Arc<Closure>, Vec<Value>, Span),
1444}
1445
1446fn eval_in_tail<H: 'static>(
1450 env: &mut Env,
1451 registry: &FnRegistry<H>,
1452 expander: &SpannedExpander,
1453 form: &Spanned,
1454 host: &mut H,
1455) -> Result<TailResult> {
1456 registry.step(form.span)?;
1457 match &form.form {
1458 SpannedForm::List(items) if !items.is_empty() => {
1459 if let Some(head_sym) = items[0].as_symbol() {
1461 if let Some(sf) = SpecialForm::from_symbol(head_sym) {
1462 return eval_special_tail(sf, items, form.span, env, registry, expander, host);
1463 }
1464 }
1465 let head_val = eval_in(env, registry, expander, &items[0], host)?;
1468 let mut args: Vec<Value> = Vec::with_capacity(items.len().saturating_sub(1));
1469 for arg_form in &items[1..] {
1470 args.push(eval_in(env, registry, expander, arg_form, host)?);
1471 }
1472 match head_val {
1473 Value::Closure(c) => Ok(TailResult::Resume(c, args, form.span)),
1474 _ => apply(&head_val, args, form.span, registry, expander, host)
1475 .map(TailResult::Done),
1476 }
1477 }
1478 _ => eval_in(env, registry, expander, form, host).map(TailResult::Done),
1480 }
1481}
1482
1483fn eval_special_tail<H: 'static>(
1484 sf: SpecialForm,
1485 items: &[Spanned],
1486 call_span: Span,
1487 env: &mut Env,
1488 registry: &FnRegistry<H>,
1489 expander: &SpannedExpander,
1490 host: &mut H,
1491) -> Result<TailResult> {
1492 match sf {
1493 SpecialForm::If => {
1494 if items.len() < 3 || items.len() > 4 {
1495 return eval_special(sf, items, call_span, env, registry, expander, host)
1496 .map(TailResult::Done);
1497 }
1498 let c = eval_in(env, registry, expander, &items[1], host)?;
1499 if c.is_truthy() {
1500 eval_in_tail(env, registry, expander, &items[2], host)
1501 } else if items.len() == 4 {
1502 eval_in_tail(env, registry, expander, &items[3], host)
1503 } else {
1504 Ok(TailResult::Done(Value::Nil))
1505 }
1506 }
1507 SpecialForm::Begin => {
1508 let body = &items[1..];
1509 if body.is_empty() {
1510 return Ok(TailResult::Done(Value::Nil));
1511 }
1512 for form in &body[..body.len() - 1] {
1513 eval_in(env, registry, expander, form, host)?;
1514 }
1515 eval_in_tail(env, registry, expander, body.last().unwrap(), host)
1516 }
1517 SpecialForm::When | SpecialForm::Unless => {
1518 if items.len() < 2 {
1519 return eval_special(sf, items, call_span, env, registry, expander, host)
1520 .map(TailResult::Done);
1521 }
1522 let invert = matches!(sf, SpecialForm::Unless);
1523 let cond = eval_in(env, registry, expander, &items[1], host)?;
1524 let run = cond.is_truthy() ^ invert;
1525 if !run {
1526 return Ok(TailResult::Done(Value::Nil));
1527 }
1528 let body = &items[2..];
1529 if body.is_empty() {
1530 return Ok(TailResult::Done(Value::Nil));
1531 }
1532 for form in &body[..body.len() - 1] {
1533 eval_in(env, registry, expander, form, host)?;
1534 }
1535 eval_in_tail(env, registry, expander, body.last().unwrap(), host)
1536 }
1537 SpecialForm::Cond => {
1538 for clause in &items[1..] {
1539 let Some(clause_list) = clause.as_list() else {
1540 return eval_special(sf, items, call_span, env, registry, expander, host)
1541 .map(TailResult::Done);
1542 };
1543 if clause_list.is_empty() {
1544 return eval_special(sf, items, call_span, env, registry, expander, host)
1545 .map(TailResult::Done);
1546 }
1547 let is_else = clause_list[0].as_symbol() == Some("else");
1548 let cond_matches = if is_else {
1549 true
1550 } else {
1551 eval_in(env, registry, expander, &clause_list[0], host)?.is_truthy()
1552 };
1553 if cond_matches {
1554 let body = &clause_list[1..];
1555 if body.is_empty() {
1556 return Ok(TailResult::Done(Value::Nil));
1557 }
1558 for form in &body[..body.len() - 1] {
1559 eval_in(env, registry, expander, form, host)?;
1560 }
1561 return eval_in_tail(env, registry, expander, body.last().unwrap(), host);
1562 }
1563 }
1564 Ok(TailResult::Done(Value::Nil))
1565 }
1566 SpecialForm::Let | SpecialForm::LetStar | SpecialForm::LetRec => {
1567 eval_let_family_tail(sf, items, call_span, env, registry, expander, host)
1568 }
1569 SpecialForm::And => {
1570 let exprs = &items[1..];
1571 if exprs.is_empty() {
1572 return Ok(TailResult::Done(Value::Bool(true)));
1573 }
1574 for e in &exprs[..exprs.len() - 1] {
1576 let v = eval_in(env, registry, expander, e, host)?;
1577 if !v.is_truthy() {
1578 return Ok(TailResult::Done(v));
1579 }
1580 }
1581 eval_in_tail(env, registry, expander, exprs.last().unwrap(), host)
1583 }
1584 SpecialForm::Or => {
1585 let exprs = &items[1..];
1586 if exprs.is_empty() {
1587 return Ok(TailResult::Done(Value::Bool(false)));
1588 }
1589 for e in &exprs[..exprs.len() - 1] {
1590 let v = eval_in(env, registry, expander, e, host)?;
1591 if v.is_truthy() {
1592 return Ok(TailResult::Done(v));
1593 }
1594 }
1595 eval_in_tail(env, registry, expander, exprs.last().unwrap(), host)
1596 }
1597 SpecialForm::Try => {
1598 sf_try(items, call_span, env, registry, expander, host).map(TailResult::Done)
1604 }
1605 SpecialForm::MacroexpandOne => {
1606 sf_macroexpand(items, call_span, env, registry, expander, host, false)
1607 .map(TailResult::Done)
1608 }
1609 SpecialForm::MacroexpandAll => {
1610 sf_macroexpand(items, call_span, env, registry, expander, host, true)
1611 .map(TailResult::Done)
1612 }
1613 SpecialForm::Delay => sf_delay(items, call_span, env).map(TailResult::Done),
1614 SpecialForm::Eval => {
1615 sf_eval(items, call_span, env, registry, expander, host).map(TailResult::Done)
1616 }
1617 _ => {
1619 eval_special(sf, items, call_span, env, registry, expander, host).map(TailResult::Done)
1620 }
1621 }
1622}
1623
1624fn eval_let_family_tail<H: 'static>(
1628 sf: SpecialForm,
1629 items: &[Spanned],
1630 call_span: Span,
1631 env: &mut Env,
1632 registry: &FnRegistry<H>,
1633 expander: &SpannedExpander,
1634 host: &mut H,
1635) -> Result<TailResult> {
1636 if items.len() < 3 {
1637 return Err(EvalError::bad_form(
1638 match sf {
1639 SpecialForm::Let => "let",
1640 SpecialForm::LetStar => "let*",
1641 SpecialForm::LetRec => "letrec",
1642 _ => "let-family",
1643 },
1644 "expected ((name expr)...) body...",
1645 call_span,
1646 ));
1647 }
1648 let bindings = parse_binding_list(
1649 &items[1],
1650 match sf {
1651 SpecialForm::Let => "let",
1652 SpecialForm::LetStar => "let*",
1653 SpecialForm::LetRec => "letrec",
1654 _ => "let-family",
1655 },
1656 )?;
1657
1658 match sf {
1659 SpecialForm::Let => {
1660 let mut values = Vec::with_capacity(bindings.len());
1661 for (_, expr) in &bindings {
1662 values.push(eval_in(env, registry, expander, expr, host)?);
1663 }
1664 env.push();
1665 for ((name, _), val) in bindings.into_iter().zip(values) {
1666 env.define(name, val);
1667 }
1668 }
1669 SpecialForm::LetStar => {
1670 env.push();
1671 for (name, expr) in bindings {
1672 let v = eval_in(env, registry, expander, expr, host)?;
1673 env.define(name, v);
1674 }
1675 }
1676 SpecialForm::LetRec => {
1677 env.push();
1678 for (name, _) in &bindings {
1679 env.define(name.clone(), Value::Nil);
1680 }
1681 for (name, expr) in &bindings {
1682 let v = eval_in(env, registry, expander, expr, host)?;
1683 env.define(name.clone(), v);
1684 }
1685 }
1686 _ => unreachable!(),
1687 }
1688
1689 let body = &items[2..];
1690 let result = if body.is_empty() {
1691 Ok(TailResult::Done(Value::Nil))
1692 } else {
1693 for form in &body[..body.len() - 1] {
1694 if let Err(e) = eval_in(env, registry, expander, form, host) {
1695 env.pop();
1696 return Err(e);
1697 }
1698 }
1699 eval_in_tail(env, registry, expander, body.last().unwrap(), host)
1700 };
1701 env.pop();
1702 result
1703}
1704
1705pub(crate) fn apply_external<H: 'static>(
1711 callee: &Value,
1712 args: Vec<Value>,
1713 call_span: Span,
1714 registry: &FnRegistry<H>,
1715 expander: &SpannedExpander,
1716 host: &mut H,
1717) -> Result<Value> {
1718 apply(callee, args, call_span, registry, expander, host)
1719}
1720
1721fn bind_macro_args(
1730 env: &mut Env,
1731 macro_name: &str,
1732 params: &MacroParams,
1733 args: &[Spanned],
1734 call_span: Span,
1735) -> Result<()> {
1736 let bound = params
1737 .bind_carrier(macro_name, args, call_span)
1738 .map_err(|e| {
1739 EvalError::native_fn(
1740 Arc::<str>::from(format!("macro {macro_name}")),
1741 e.to_string(),
1742 call_span,
1743 )
1744 })?;
1745 for (name, value) in params.names().into_iter().zip(bound.iter()) {
1746 env.define(Arc::<str>::from(name), spanned_to_value(value));
1747 }
1748 Ok(())
1749}
1750
1751#[cfg(not(target_family = "wasm"))]
1760const STACK_RED_ZONE: usize = 256 * 1024;
1761
1762#[cfg(not(target_family = "wasm"))]
1765const STACK_SEGMENT: usize = 8 * 1024 * 1024;
1766
1767fn call_closure<H: 'static>(
1785 closure: Arc<Closure>,
1786 args: Vec<Value>,
1787 call_span: Span,
1788 registry: &FnRegistry<H>,
1789 expander: &SpannedExpander,
1790 host: &mut H,
1791) -> Result<Value> {
1792 let _depth = registry
1793 .meter
1794 .enter(call_span)
1795 .map_err(|e| e.in_function(closure.name.as_ref()))?;
1796 #[cfg(not(target_family = "wasm"))]
1797 {
1798 stacker::maybe_grow(STACK_RED_ZONE, STACK_SEGMENT, || {
1799 call_closure_body(closure, args, call_span, registry, expander, host)
1800 })
1801 }
1802 #[cfg(target_family = "wasm")]
1803 {
1804 call_closure_body(closure, args, call_span, registry, expander, host)
1805 }
1806}
1807
1808fn call_closure_body<H: 'static>(
1809 closure: Arc<Closure>,
1810 args: Vec<Value>,
1811 call_span: Span,
1812 registry: &FnRegistry<H>,
1813 expander: &SpannedExpander,
1814 host: &mut H,
1815) -> Result<Value> {
1816 let mut current = closure;
1817 let mut current_args = args;
1818 let mut current_span = call_span;
1819 loop {
1820 let required = current.params.len();
1823 let has_rest = current.rest.is_some();
1824 if !has_rest && current_args.len() != required {
1825 return Err(EvalError::ArityMismatch {
1826 fn_name: Arc::from("<closure>"),
1827 expected: Arity::Exact(required),
1828 got: current_args.len(),
1829 at: current_span,
1830 });
1831 }
1832 if has_rest && current_args.len() < required {
1833 return Err(EvalError::ArityMismatch {
1834 fn_name: Arc::from("<closure>"),
1835 expected: Arity::AtLeast(required),
1836 got: current_args.len(),
1837 at: current_span,
1838 });
1839 }
1840
1841 let call = crate::observe::Call {
1844 name: current.name.as_ref(),
1845 source: current.source,
1846 at: current_span,
1847 };
1848 if let Some(observer) = ®istry.observer {
1849 if let Some(v) = observer.enter(&call, ¤t_args) {
1850 observer.leave(&call, crate::observe::Exit::Supplied(&v));
1851 return Ok(v);
1852 }
1853 }
1854 let outcome = activate(¤t, ¤t_args, registry, expander, host);
1855 match outcome {
1856 Ok(TailResult::Done(v)) => {
1857 if let Some(observer) = ®istry.observer {
1858 observer.leave(&call, crate::observe::Exit::Returned(&v));
1859 }
1860 return Ok(v);
1861 }
1862 Ok(TailResult::Resume(next, next_args, next_span)) => {
1863 if let Some(observer) = ®istry.observer {
1864 observer.leave(&call, crate::observe::Exit::TailCalled);
1865 }
1866 current = next;
1869 current_args = next_args;
1870 current_span = next_span;
1871 }
1872 Err(e) => {
1873 if let Some(observer) = ®istry.observer {
1874 observer.leave(&call, crate::observe::Exit::Raised(&e));
1875 }
1876 registry.unwind.push(&call);
1877 return Err(e);
1878 }
1879 }
1880 }
1881}
1882
1883#[inline]
1886fn activate<H: 'static>(
1887 current: &Arc<Closure>,
1888 current_args: &[Value],
1889 registry: &FnRegistry<H>,
1890 expander: &SpannedExpander,
1891 host: &mut H,
1892) -> Result<TailResult> {
1893 let required = current.params.len();
1896 let mut env = current.captured_env.clone();
1897 env.push();
1898 for (param, arg) in current.params.iter().zip(current_args.iter()) {
1899 env.define(param.clone(), arg.clone());
1900 }
1901 if let Some(rest_name) = ¤t.rest {
1902 let rest_args: Vec<Value> = current_args.iter().skip(required).cloned().collect();
1903 env.define(rest_name.clone(), Value::list(rest_args));
1904 }
1905
1906 let body = ¤t.body;
1907 let Some((last, init)) = body.split_last() else {
1908 return Ok(TailResult::Done(Value::Nil));
1909 };
1910 let named = |e: EvalError| e.in_function(current.name.as_ref());
1911 for body_form in init {
1912 eval_in(&mut env, registry, expander, body_form, host).map_err(named)?;
1913 }
1914 eval_in_tail(&mut env, registry, expander, last, host).map_err(named)
1915}
1916
1917fn eval_special<H: 'static>(
1920 sf: SpecialForm,
1921 items: &[Spanned],
1922 call_span: Span,
1923 env: &mut Env,
1924 registry: &FnRegistry<H>,
1925 expander: &SpannedExpander,
1926 host: &mut H,
1927) -> Result<Value> {
1928 match sf {
1929 SpecialForm::Quote => sf_quote(items, call_span),
1930 SpecialForm::Quasiquote => {
1931 if items.len() != 2 {
1932 return Err(EvalError::bad_form(
1933 "quasiquote",
1934 format!("expected 1 arg, got {}", items.len() - 1),
1935 call_span,
1936 ));
1937 }
1938 quasiquote_eval(&items[1], env, registry, expander, host)
1939 }
1940 SpecialForm::If => sf_if(items, call_span, env, registry, expander, host),
1941 SpecialForm::Cond => sf_cond(items, call_span, env, registry, expander, host),
1942 SpecialForm::When => sf_when_unless(items, call_span, env, registry, expander, host, false),
1943 SpecialForm::Unless => {
1944 sf_when_unless(items, call_span, env, registry, expander, host, true)
1945 }
1946 SpecialForm::Let => sf_let(items, call_span, env, registry, expander, host),
1947 SpecialForm::LetStar => sf_let_star(items, call_span, env, registry, expander, host),
1948 SpecialForm::LetRec => sf_letrec(items, call_span, env, registry, expander, host),
1949 SpecialForm::Lambda => sf_lambda(items, call_span, env),
1950 SpecialForm::Define => sf_define(items, call_span, env, registry, expander, host),
1951 SpecialForm::Set => sf_set(items, call_span, env, registry, expander, host),
1952 SpecialForm::Begin => sf_begin(&items[1..], env, registry, expander, host),
1953 SpecialForm::And => sf_and(&items[1..], env, registry, expander, host),
1954 SpecialForm::Or => sf_or(&items[1..], env, registry, expander, host),
1955 SpecialForm::Not => sf_not(items, call_span, env, registry, expander, host),
1956 SpecialForm::Try => sf_try(items, call_span, env, registry, expander, host),
1957 SpecialForm::MacroexpandOne => {
1958 sf_macroexpand(items, call_span, env, registry, expander, host, false)
1959 }
1960 SpecialForm::MacroexpandAll => {
1961 sf_macroexpand(items, call_span, env, registry, expander, host, true)
1962 }
1963 SpecialForm::Delay => sf_delay(items, call_span, env),
1964 SpecialForm::Eval => sf_eval(items, call_span, env, registry, expander, host),
1965 SpecialForm::Provide | SpecialForm::Require => Err(EvalError::bad_form(
1966 if matches!(sf, SpecialForm::Provide) { "provide" } else { "require" },
1967 "module-system forms are only valid at top level — wrap your call in (eval (quote ...)) if you really need it dynamic",
1968 call_span,
1969 )),
1970 }
1971}
1972
1973fn head_symbol(form: &Spanned) -> Option<&str> {
1977 let SpannedForm::List(items) = &form.form else {
1978 return None;
1979 };
1980 items.first().and_then(Spanned::as_symbol)
1981}
1982
1983fn error_value(tag: &str, message: &str) -> Value {
1985 Value::Error(Arc::new(ErrorObj {
1986 tag: Arc::from(tag),
1987 message: Arc::from(message),
1988 data: Vec::new(),
1989 }))
1990}
1991
1992fn module_error_to_eval(e: ModuleError, span: Span) -> EvalError {
1996 let (tag, message) = match &e {
1997 ModuleError::NotFound(_) => ("module-not-found", e.to_string()),
1998 ModuleError::Circular { .. } => ("circular-require", e.to_string()),
1999 ModuleError::NotExported(_, _) => ("not-exported", e.to_string()),
2000 ModuleError::Denied { .. } => ("module-denied", e.to_string()),
2004 };
2005 EvalError::User {
2006 value: error_value(tag, &message),
2007 at: span,
2008 }
2009}
2010
2011fn sf_quote(items: &[Spanned], span: Span) -> Result<Value> {
2012 if items.len() != 2 {
2013 return Err(EvalError::bad_form(
2014 "quote",
2015 format!("expected 1 arg, got {}", items.len() - 1),
2016 span,
2017 ));
2018 }
2019 Ok(crate::code::spanned_to_value(&items[1]))
2025}
2026
2027fn sf_if<H: 'static>(
2028 items: &[Spanned],
2029 span: Span,
2030 env: &mut Env,
2031 registry: &FnRegistry<H>,
2032 expander: &SpannedExpander,
2033 host: &mut H,
2034) -> Result<Value> {
2035 if items.len() < 3 || items.len() > 4 {
2036 return Err(EvalError::bad_form(
2037 "if",
2038 format!("expected (if c t [e]), got {} subforms", items.len()),
2039 span,
2040 ));
2041 }
2042 let c = eval_in(env, registry, expander, &items[1], host)?;
2043 if c.is_truthy() {
2044 eval_in(env, registry, expander, &items[2], host)
2045 } else if items.len() == 4 {
2046 eval_in(env, registry, expander, &items[3], host)
2047 } else {
2048 Ok(Value::Nil)
2049 }
2050}
2051
2052fn sf_cond<H: 'static>(
2053 items: &[Spanned],
2054 span: Span,
2055 env: &mut Env,
2056 registry: &FnRegistry<H>,
2057 expander: &SpannedExpander,
2058 host: &mut H,
2059) -> Result<Value> {
2060 for clause in &items[1..] {
2061 let Some(clause_list) = clause.as_list() else {
2062 return Err(EvalError::bad_form(
2063 "cond",
2064 "clause must be a list",
2065 clause.span,
2066 ));
2067 };
2068 if clause_list.is_empty() {
2069 return Err(EvalError::bad_form("cond", "empty clause", clause.span));
2070 }
2071 let is_else = clause_list[0].as_symbol() == Some("else");
2072 let cond_matches = if is_else {
2073 true
2074 } else {
2075 let v = eval_in(env, registry, expander, &clause_list[0], host)?;
2076 v.is_truthy()
2077 };
2078 if cond_matches {
2079 let mut last = Value::Nil;
2080 for expr in &clause_list[1..] {
2081 last = eval_in(env, registry, expander, expr, host)?;
2082 }
2083 return Ok(last);
2084 }
2085 }
2086 let _ = span;
2088 Ok(Value::Nil)
2089}
2090
2091fn sf_when_unless<H: 'static>(
2092 items: &[Spanned],
2093 span: Span,
2094 env: &mut Env,
2095 registry: &FnRegistry<H>,
2096 expander: &SpannedExpander,
2097 host: &mut H,
2098 invert: bool,
2099) -> Result<Value> {
2100 if items.len() < 2 {
2101 return Err(EvalError::bad_form(
2102 if invert { "unless" } else { "when" },
2103 "need a test",
2104 span,
2105 ));
2106 }
2107 let cond = eval_in(env, registry, expander, &items[1], host)?;
2108 let run = cond.is_truthy() ^ invert;
2109 if run {
2110 let mut last = Value::Nil;
2111 for expr in &items[2..] {
2112 last = eval_in(env, registry, expander, expr, host)?;
2113 }
2114 Ok(last)
2115 } else {
2116 Ok(Value::Nil)
2117 }
2118}
2119
2120fn parse_binding_list<'a>(
2122 list: &'a Spanned,
2123 form_name: &'static str,
2124) -> Result<Vec<(Arc<str>, &'a Spanned)>> {
2125 let bindings = list
2126 .as_list()
2127 .ok_or_else(|| EvalError::bad_form(form_name, "bindings must be a list", list.span))?;
2128 let mut out = Vec::with_capacity(bindings.len());
2129 for binding in bindings {
2130 let pair = binding.as_list().ok_or_else(|| {
2131 EvalError::bad_form(form_name, "each binding must be (name expr)", binding.span)
2132 })?;
2133 if pair.len() != 2 {
2134 return Err(EvalError::bad_form(
2135 form_name,
2136 "binding must be exactly (name expr)",
2137 binding.span,
2138 ));
2139 }
2140 let name = pair[0].as_symbol().ok_or_else(|| {
2141 EvalError::bad_form(form_name, "binding name must be a symbol", pair[0].span)
2142 })?;
2143 out.push((Arc::<str>::from(name), &pair[1]));
2144 }
2145 Ok(out)
2146}
2147
2148fn sf_let<H: 'static>(
2149 items: &[Spanned],
2150 span: Span,
2151 env: &mut Env,
2152 registry: &FnRegistry<H>,
2153 expander: &SpannedExpander,
2154 host: &mut H,
2155) -> Result<Value> {
2156 if items.len() < 3 {
2157 return Err(EvalError::bad_form(
2158 "let",
2159 "expected (let ((name expr)...) body...)",
2160 span,
2161 ));
2162 }
2163 let bindings = parse_binding_list(&items[1], "let")?;
2164 let mut values = Vec::with_capacity(bindings.len());
2167 for (_, expr) in &bindings {
2168 values.push(eval_in(env, registry, expander, expr, host)?);
2169 }
2170 env.push();
2171 for ((name, _), val) in bindings.into_iter().zip(values) {
2172 env.define(name, val);
2173 }
2174 let result = eval_body(&items[2..], env, registry, expander, host);
2175 env.pop();
2176 result
2177}
2178
2179fn sf_let_star<H: 'static>(
2180 items: &[Spanned],
2181 span: Span,
2182 env: &mut Env,
2183 registry: &FnRegistry<H>,
2184 expander: &SpannedExpander,
2185 host: &mut H,
2186) -> Result<Value> {
2187 if items.len() < 3 {
2188 return Err(EvalError::bad_form(
2189 "let*",
2190 "expected (let* ((name expr)...) body...)",
2191 span,
2192 ));
2193 }
2194 let bindings = parse_binding_list(&items[1], "let*")?;
2195 env.push();
2196 for (name, expr) in bindings {
2197 let v = eval_in(env, registry, expander, expr, host)?;
2198 env.define(name, v);
2199 }
2200 let result = eval_body(&items[2..], env, registry, expander, host);
2201 env.pop();
2202 result
2203}
2204
2205fn sf_letrec<H: 'static>(
2206 items: &[Spanned],
2207 span: Span,
2208 env: &mut Env,
2209 registry: &FnRegistry<H>,
2210 expander: &SpannedExpander,
2211 host: &mut H,
2212) -> Result<Value> {
2213 if items.len() < 3 {
2214 return Err(EvalError::bad_form(
2215 "letrec",
2216 "expected (letrec ((name expr)...) body...)",
2217 span,
2218 ));
2219 }
2220 let bindings = parse_binding_list(&items[1], "letrec")?;
2221 env.push();
2222 for (name, _) in &bindings {
2225 env.define(name.clone(), Value::Nil);
2226 }
2227 for (name, expr) in &bindings {
2228 let v = eval_in(env, registry, expander, expr, host)?;
2229 env.define(name.clone(), v);
2230 }
2231 let result = eval_body(&items[2..], env, registry, expander, host);
2232 env.pop();
2233 result
2234}
2235
2236fn eval_body<H: 'static>(
2237 body: &[Spanned],
2238 env: &mut Env,
2239 registry: &FnRegistry<H>,
2240 expander: &SpannedExpander,
2241 host: &mut H,
2242) -> Result<Value> {
2243 let mut last = Value::Nil;
2244 for form in body {
2245 last = eval_in(env, registry, expander, form, host)?;
2246 }
2247 Ok(last)
2248}
2249
2250fn sf_lambda(items: &[Spanned], span: Span, env: &Env) -> Result<Value> {
2251 if items.len() < 3 {
2252 return Err(EvalError::bad_form(
2253 "lambda",
2254 "expected (lambda (params...) body...)",
2255 span,
2256 ));
2257 }
2258 let param_list: &[Spanned] = match &items[1].form {
2261 SpannedForm::Nil => &[],
2262 SpannedForm::List(xs) => xs.as_slice(),
2263 _ => {
2264 return Err(EvalError::bad_form(
2265 "lambda",
2266 "params must be a list",
2267 items[1].span,
2268 ))
2269 }
2270 };
2271 let (params, rest) = parse_lambda_params(param_list, items[1].span)?;
2272 let body = items[2..].to_vec();
2273 Ok(Value::Closure(Arc::new(Closure {
2274 params,
2275 rest,
2276 body,
2277 captured_env: env.clone(),
2278 source: span,
2279 name: None,
2280 })))
2281}
2282
2283fn parse_lambda_params(list: &[Spanned], span: Span) -> Result<(Vec<Arc<str>>, Option<Arc<str>>)> {
2284 let mut params = Vec::new();
2285 let mut rest = None;
2286 let mut i = 0;
2287 while i < list.len() {
2288 let s = list[i]
2289 .as_symbol()
2290 .ok_or_else(|| EvalError::bad_form("lambda", "param must be a symbol", list[i].span))?;
2291 if s == "&rest" {
2292 let name = list
2293 .get(i + 1)
2294 .and_then(Spanned::as_symbol)
2295 .ok_or_else(|| EvalError::bad_form("lambda", "&rest needs a name", span))?;
2296 rest = Some(Arc::<str>::from(name));
2297 if i + 2 != list.len() {
2298 return Err(EvalError::bad_form(
2299 "lambda",
2300 "&rest must be the last param",
2301 span,
2302 ));
2303 }
2304 break;
2305 }
2306 params.push(Arc::<str>::from(s));
2307 i += 1;
2308 }
2309 Ok((params, rest))
2310}
2311
2312fn sf_define<H: 'static>(
2314 items: &[Spanned],
2315 span: Span,
2316 env: &mut Env,
2317 registry: &FnRegistry<H>,
2318 expander: &SpannedExpander,
2319 host: &mut H,
2320) -> Result<Value> {
2321 if items.len() < 3 {
2322 return Err(EvalError::bad_form(
2323 "define",
2324 "expected (define name expr) or (define (name args) body)",
2325 span,
2326 ));
2327 }
2328 match &items[1].form {
2329 SpannedForm::Atom(Atom::Symbol(name)) => {
2330 let v = eval_in(env, registry, expander, &items[2], host)?;
2331 env.define(Arc::<str>::from(name.as_str()), v);
2332 Ok(Value::Nil)
2333 }
2334 SpannedForm::List(head_list) => {
2335 if head_list.is_empty() {
2336 return Err(EvalError::bad_form(
2337 "define",
2338 "empty (name args) list",
2339 items[1].span,
2340 ));
2341 }
2342 let name = head_list[0].as_symbol().ok_or_else(|| {
2343 EvalError::bad_form(
2344 "define",
2345 "first item in (name args) must be a symbol",
2346 head_list[0].span,
2347 )
2348 })?;
2349 let (params, rest) = parse_lambda_params(&head_list[1..], items[1].span)?;
2350 let body = items[2..].to_vec();
2351 let closure = Arc::new(Closure {
2352 params,
2353 rest,
2354 body,
2355 captured_env: env.clone(),
2356 source: span,
2357 name: Some(Arc::<str>::from(name)),
2358 });
2359 env.define(Arc::<str>::from(name), Value::Closure(closure));
2360 Ok(Value::Nil)
2361 }
2362 _ => Err(EvalError::bad_form(
2363 "define",
2364 "second form must be a symbol or (name args) list",
2365 items[1].span,
2366 )),
2367 }
2368}
2369
2370fn sf_set<H: 'static>(
2371 items: &[Spanned],
2372 span: Span,
2373 env: &mut Env,
2374 registry: &FnRegistry<H>,
2375 expander: &SpannedExpander,
2376 host: &mut H,
2377) -> Result<Value> {
2378 if items.len() != 3 {
2379 return Err(EvalError::bad_form(
2380 "set!",
2381 "expected (set! name expr)",
2382 span,
2383 ));
2384 }
2385 let name = items[1]
2386 .as_symbol()
2387 .ok_or_else(|| EvalError::bad_form("set!", "first arg must be a symbol", items[1].span))?;
2388 let v = eval_in(env, registry, expander, &items[2], host)?;
2389 if env.set(name, v) {
2390 Ok(Value::Nil)
2391 } else if let (true, Some(seal)) = (env.is_sealed_binding(name), env.seal()) {
2392 Err(EvalError::SetSealed {
2397 name: name.into(),
2398 seal,
2399 at: items[1].span,
2400 })
2401 } else {
2402 Err(EvalError::unbound(name, items[1].span))
2403 }
2404}
2405
2406fn sf_begin<H: 'static>(
2407 body: &[Spanned],
2408 env: &mut Env,
2409 registry: &FnRegistry<H>,
2410 expander: &SpannedExpander,
2411 host: &mut H,
2412) -> Result<Value> {
2413 eval_body(body, env, registry, expander, host)
2414}
2415
2416fn sf_and<H: 'static>(
2417 exprs: &[Spanned],
2418 env: &mut Env,
2419 registry: &FnRegistry<H>,
2420 expander: &SpannedExpander,
2421 host: &mut H,
2422) -> Result<Value> {
2423 let mut last = Value::Bool(true);
2424 for e in exprs {
2425 last = eval_in(env, registry, expander, e, host)?;
2426 if !last.is_truthy() {
2427 return Ok(last);
2428 }
2429 }
2430 Ok(last)
2431}
2432
2433fn sf_or<H: 'static>(
2434 exprs: &[Spanned],
2435 env: &mut Env,
2436 registry: &FnRegistry<H>,
2437 expander: &SpannedExpander,
2438 host: &mut H,
2439) -> Result<Value> {
2440 let mut last = Value::Bool(false);
2441 for e in exprs {
2442 last = eval_in(env, registry, expander, e, host)?;
2443 if last.is_truthy() {
2444 return Ok(last);
2445 }
2446 }
2447 Ok(last)
2448}
2449
2450fn sf_not<H: 'static>(
2451 items: &[Spanned],
2452 span: Span,
2453 env: &mut Env,
2454 registry: &FnRegistry<H>,
2455 expander: &SpannedExpander,
2456 host: &mut H,
2457) -> Result<Value> {
2458 if items.len() != 2 {
2459 return Err(EvalError::bad_form("not", "expected (not x)", span));
2460 }
2461 let v = eval_in(env, registry, expander, &items[1], host)?;
2462 Ok(Value::Bool(!v.is_truthy()))
2463}
2464
2465fn sf_try<H: 'static>(
2484 items: &[Spanned],
2485 span: Span,
2486 env: &mut Env,
2487 registry: &FnRegistry<H>,
2488 expander: &SpannedExpander,
2489 host: &mut H,
2490) -> Result<Value> {
2491 if items.len() < 3 {
2492 return Err(EvalError::bad_form(
2493 "try",
2494 "expected (try body... (catch (e) handler...))",
2495 span,
2496 ));
2497 }
2498 let catch_form = items.last().unwrap();
2500 let catch_list = catch_form.as_list().ok_or_else(|| {
2501 EvalError::bad_form(
2502 "try",
2503 "last form must be (catch (binding) handler...)",
2504 catch_form.span,
2505 )
2506 })?;
2507 if catch_list.is_empty() || catch_list[0].as_symbol() != Some("catch") {
2508 return Err(EvalError::bad_form(
2509 "try",
2510 "last form must be a (catch ...) clause",
2511 catch_form.span,
2512 ));
2513 }
2514 if catch_list.len() < 3 {
2515 return Err(EvalError::bad_form(
2516 "catch",
2517 "expected (catch (binding) handler...)",
2518 catch_form.span,
2519 ));
2520 }
2521 let binding_list = catch_list[1].as_list().ok_or_else(|| {
2522 EvalError::bad_form(
2523 "catch",
2524 "binding must be a 1-element list (e)",
2525 catch_list[1].span,
2526 )
2527 })?;
2528 if binding_list.len() != 1 {
2529 return Err(EvalError::bad_form(
2530 "catch",
2531 "binding must bind exactly one symbol",
2532 catch_list[1].span,
2533 ));
2534 }
2535 let binding_name = binding_list[0].as_symbol().ok_or_else(|| {
2536 EvalError::bad_form("catch", "binding must be a symbol", binding_list[0].span)
2537 })?;
2538
2539 let body = &items[1..items.len() - 1];
2540 let mut last = Value::Nil;
2541 for form in body {
2542 match eval_in(env, registry, expander, form, host) {
2543 Ok(v) => {
2544 last = v;
2545 }
2546 Err(EvalError::Halted) => return Err(EvalError::Halted),
2548 Err(EvalError::User { value, .. }) => {
2549 registry.unwind.clear();
2550 return run_catch_handler(
2551 binding_name,
2552 value,
2553 &catch_list[2..],
2554 env,
2555 registry,
2556 expander,
2557 host,
2558 );
2559 }
2560 Err(other) => {
2561 let value = rust_err_to_value_error(&other);
2565 registry.unwind.clear();
2566 return run_catch_handler(
2567 binding_name,
2568 value,
2569 &catch_list[2..],
2570 env,
2571 registry,
2572 expander,
2573 host,
2574 );
2575 }
2576 }
2577 }
2578 Ok(last)
2579}
2580
2581fn run_catch_handler<H: 'static>(
2582 binding_name: &str,
2583 error_value: Value,
2584 handler_body: &[Spanned],
2585 env: &mut Env,
2586 registry: &FnRegistry<H>,
2587 expander: &SpannedExpander,
2588 host: &mut H,
2589) -> Result<Value> {
2590 env.push();
2591 env.define(Arc::<str>::from(binding_name), error_value);
2592 let mut last = Value::Nil;
2593 for form in handler_body {
2594 match eval_in(env, registry, expander, form, host) {
2595 Ok(v) => last = v,
2596 Err(e) => {
2597 env.pop();
2598 return Err(e);
2599 }
2600 }
2601 }
2602 env.pop();
2603 Ok(last)
2604}
2605
2606fn sf_eval<H: 'static>(
2615 items: &[Spanned],
2616 call_span: Span,
2617 env: &mut Env,
2618 registry: &FnRegistry<H>,
2619 expander: &SpannedExpander,
2620 host: &mut H,
2621) -> Result<Value> {
2622 if items.len() != 2 {
2623 return Err(EvalError::bad_form(
2624 "eval",
2625 "expected (eval form)",
2626 call_span,
2627 ));
2628 }
2629 let form_value = eval_in(env, registry, expander, &items[1], host)?;
2630 let form_spanned = crate::code::value_to_spanned(&form_value, call_span)
2631 .map_err(|reason| EvalError::native_fn(Arc::<str>::from("eval"), reason, call_span))?;
2632 let expanded = fully_expand_with(&form_spanned, registry, expander, env, host)?;
2633 eval_in(env, registry, expander, &expanded, host)
2634}
2635
2636fn sf_delay(items: &[Spanned], call_span: Span, env: &Env) -> Result<Value> {
2641 if items.len() != 2 {
2642 return Err(EvalError::bad_form(
2643 "delay",
2644 "expected (delay expr)",
2645 call_span,
2646 ));
2647 }
2648 let body = vec![items[1].clone()];
2649 let thunk = Arc::new(Closure {
2650 params: Vec::new(),
2651 rest: None,
2652 body,
2653 captured_env: env.clone(),
2654 source: call_span,
2655 name: None,
2656 });
2657 Ok(Value::Promise(Arc::new(std::sync::Mutex::new(
2658 crate::value::PromiseState::Pending(thunk),
2659 ))))
2660}
2661
2662fn sf_macroexpand<H: 'static>(
2671 items: &[Spanned],
2672 call_span: Span,
2673 env: &mut Env,
2674 registry: &FnRegistry<H>,
2675 expander: &SpannedExpander,
2676 host: &mut H,
2677 fully: bool,
2678) -> Result<Value> {
2679 if items.len() != 2 {
2680 return Err(EvalError::bad_form(
2681 if fully {
2682 "macroexpand"
2683 } else {
2684 "macroexpand-1"
2685 },
2686 "expected (macroexpand[-1] form)",
2687 call_span,
2688 ));
2689 }
2690 let form_value = eval_in(env, registry, expander, &items[1], host)?;
2692 let form_spanned = crate::code::value_to_spanned(&form_value, call_span).map_err(|reason| {
2694 EvalError::native_fn(
2695 Arc::<str>::from(if fully {
2696 "macroexpand"
2697 } else {
2698 "macroexpand-1"
2699 }),
2700 reason,
2701 call_span,
2702 )
2703 })?;
2704
2705 let expanded = if fully {
2711 fully_expand_with(&form_spanned, registry, expander, env, host)?
2712 } else {
2713 macroexpand_one(&form_spanned, registry, expander, env, host)?
2714 };
2715
2716 Ok(crate::code::spanned_to_value(&expanded))
2717}
2718
2719fn expand_one_macro_call<H: 'static>(
2723 macro_name: &str,
2724 args: &[Spanned],
2725 call_span: Span,
2726 registry: &FnRegistry<H>,
2727 expander: &SpannedExpander,
2728 parent_env: &Env,
2729 host: &mut H,
2730) -> Result<Spanned> {
2731 let def: MacroDef = expander.get_macro(macro_name).cloned().ok_or_else(|| {
2732 EvalError::native_fn(
2733 Arc::<str>::from(macro_name),
2734 "macro disappeared during expansion",
2735 call_span,
2736 )
2737 })?;
2738 let body_spanned = Spanned::from_sexp_at(&def.body, call_span);
2739 let body_expanded = fully_expand_with(&body_spanned, registry, expander, parent_env, host)?;
2741
2742 let mut macro_env = parent_env.clone();
2743 macro_env.push();
2744 bind_macro_args(&mut macro_env, &def.name, &def.params, args, call_span)?;
2745 let result = eval_in(&mut macro_env, registry, expander, &body_expanded, host)?;
2746
2747 crate::code::value_to_spanned(&result, call_span).map_err(|reason| {
2748 EvalError::native_fn(
2749 Arc::<str>::from(format!("macro {macro_name}")),
2750 reason,
2751 call_span,
2752 )
2753 })
2754}
2755
2756fn fully_expand_with<H: 'static>(
2760 form: &Spanned,
2761 registry: &FnRegistry<H>,
2762 expander: &SpannedExpander,
2763 parent_env: &Env,
2764 host: &mut H,
2765) -> Result<Spanned> {
2766 if expander.is_empty() {
2767 return Ok(form.clone());
2768 }
2769 expand_recursive_with(form, registry, expander, parent_env, host)
2770}
2771
2772fn expand_recursive_with<H: 'static>(
2773 form: &Spanned,
2774 registry: &FnRegistry<H>,
2775 expander: &SpannedExpander,
2776 parent_env: &Env,
2777 host: &mut H,
2778) -> Result<Spanned> {
2779 match &form.form {
2780 SpannedForm::List(items) if !items.is_empty() => {
2781 if let Some(head) = items[0].as_symbol() {
2782 if expander.has(head) {
2783 let expanded = expand_one_macro_call(
2784 head,
2785 &items[1..],
2786 form.span,
2787 registry,
2788 expander,
2789 parent_env,
2790 host,
2791 )?;
2792 return expand_recursive_with(&expanded, registry, expander, parent_env, host);
2793 }
2794 }
2795 let mut out = Vec::with_capacity(items.len());
2796 for child in items {
2797 out.push(expand_recursive_with(
2798 child, registry, expander, parent_env, host,
2799 )?);
2800 }
2801 Ok(Spanned::new(form.span, SpannedForm::List(out)))
2802 }
2803 SpannedForm::Quote(_) => Ok(form.clone()),
2804 SpannedForm::Quasiquote(inner) => Ok(Spanned::new(
2805 form.span,
2806 SpannedForm::Quasiquote(Box::new(expand_inside_quasiquote_with(
2807 inner, registry, expander, parent_env, host,
2808 )?)),
2809 )),
2810 _ => Ok(form.clone()),
2811 }
2812}
2813
2814fn expand_inside_quasiquote_with<H: 'static>(
2815 form: &Spanned,
2816 registry: &FnRegistry<H>,
2817 expander: &SpannedExpander,
2818 parent_env: &Env,
2819 host: &mut H,
2820) -> Result<Spanned> {
2821 match &form.form {
2822 SpannedForm::Unquote(inner) => Ok(Spanned::new(
2823 form.span,
2824 SpannedForm::Unquote(Box::new(expand_recursive_with(
2825 inner, registry, expander, parent_env, host,
2826 )?)),
2827 )),
2828 SpannedForm::UnquoteSplice(inner) => Ok(Spanned::new(
2829 form.span,
2830 SpannedForm::UnquoteSplice(Box::new(expand_recursive_with(
2831 inner, registry, expander, parent_env, host,
2832 )?)),
2833 )),
2834 SpannedForm::List(items) => {
2835 let mut out = Vec::with_capacity(items.len());
2836 for item in items {
2837 out.push(expand_inside_quasiquote_with(
2838 item, registry, expander, parent_env, host,
2839 )?);
2840 }
2841 Ok(Spanned::new(form.span, SpannedForm::List(out)))
2842 }
2843 _ => Ok(form.clone()),
2844 }
2845}
2846
2847fn macroexpand_one<H: 'static>(
2850 form: &Spanned,
2851 registry: &FnRegistry<H>,
2852 expander: &SpannedExpander,
2853 parent_env: &Env,
2854 host: &mut H,
2855) -> Result<Spanned> {
2856 if let SpannedForm::List(items) = &form.form {
2857 if let Some(head) = items.first().and_then(Spanned::as_symbol) {
2858 if expander.has(head) {
2859 return expand_one_macro_call(
2860 head,
2861 &items[1..],
2862 form.span,
2863 registry,
2864 expander,
2865 parent_env,
2866 host,
2867 );
2868 }
2869 }
2870 }
2871 Ok(form.clone())
2872}
2873
2874fn rust_err_to_value_error(err: &EvalError) -> Value {
2877 use crate::value::ErrorObj;
2878 let tag: Arc<str> = Arc::from(err.tag());
2879 let message: Arc<str> = Arc::from(err.short_message());
2880 Value::Error(Arc::new(ErrorObj {
2881 tag,
2882 message,
2883 data: Vec::new(),
2884 }))
2885}
2886
2887#[cfg(test)]
2888mod tests {
2889 use super::*;
2890 use crate::primitive::install_primitives;
2891 use tatara_lisp::read_spanned;
2892
2893 struct NoHost;
2894
2895 fn eval_ok(src: &str) -> Value {
2896 let forms = read_spanned(src).unwrap();
2897 let mut i: Interpreter<NoHost> = Interpreter::new();
2898 install_primitives(&mut i);
2899 let mut host = NoHost;
2900 i.eval_program(&forms, &mut host).unwrap()
2901 }
2902
2903 fn eval_err(src: &str) -> EvalError {
2904 let forms = read_spanned(src).unwrap();
2905 let mut i: Interpreter<NoHost> = Interpreter::new();
2906 install_primitives(&mut i);
2907 let mut host = NoHost;
2908 i.eval_program(&forms, &mut host).unwrap_err()
2909 }
2910
2911 #[test]
2914 fn literal_int() {
2915 assert!(matches!(eval_ok("42"), Value::Int(42)));
2916 }
2917
2918 #[test]
2919 fn unbound_symbol_errors() {
2920 let e = eval_err("no-such-var");
2921 assert!(matches!(e, EvalError::UnboundSymbol { .. }));
2922 }
2923
2924 #[test]
2925 fn quote_returns_runtime_list_of_symbols() {
2926 let v = eval_ok("'(a b c)");
2929 match v {
2930 Value::List(xs) => {
2931 assert_eq!(xs.len(), 3);
2932 assert!(matches!(&xs[0], Value::Symbol(s) if s.as_ref() == "a"));
2933 assert!(matches!(&xs[1], Value::Symbol(s) if s.as_ref() == "b"));
2934 assert!(matches!(&xs[2], Value::Symbol(s) if s.as_ref() == "c"));
2935 }
2936 other => panic!("{other:?}"),
2937 }
2938 }
2939
2940 #[test]
2943 fn add_ints() {
2944 assert!(matches!(eval_ok("(+ 1 2 3)"), Value::Int(6)));
2945 }
2946
2947 #[test]
2948 fn sub_divides_float() {
2949 match eval_ok("(- 10 3)") {
2950 Value::Int(7) => {}
2951 other => panic!("{other:?}"),
2952 }
2953 }
2954
2955 #[test]
2956 fn division_by_zero_errors() {
2957 assert!(matches!(
2958 eval_err("(/ 1 0)"),
2959 EvalError::DivisionByZero { .. }
2960 ));
2961 }
2962
2963 #[test]
2966 fn if_truthy_branch() {
2967 assert!(matches!(eval_ok("(if #t 1 2)"), Value::Int(1)));
2968 }
2969
2970 #[test]
2971 fn if_falsy_branch() {
2972 assert!(matches!(eval_ok("(if #f 1 2)"), Value::Int(2)));
2973 }
2974
2975 #[test]
2976 fn if_no_else_returns_nil() {
2977 assert!(matches!(eval_ok("(if #f 1)"), Value::Nil));
2978 }
2979
2980 #[test]
2981 fn cond_picks_first_match() {
2982 assert!(matches!(
2983 eval_ok("(cond (#f 1) (#t 2) (else 3))"),
2984 Value::Int(2)
2985 ));
2986 }
2987
2988 #[test]
2989 fn cond_falls_through_to_else() {
2990 assert!(matches!(
2991 eval_ok("(cond (#f 1) (#f 2) (else 3))"),
2992 Value::Int(3)
2993 ));
2994 }
2995
2996 #[test]
2997 fn when_runs_body_if_true() {
2998 assert!(matches!(eval_ok("(when #t 99)"), Value::Int(99)));
2999 assert!(matches!(eval_ok("(when #f 99)"), Value::Nil));
3000 }
3001
3002 #[test]
3005 fn let_binds_and_evaluates_body() {
3006 assert!(matches!(
3007 eval_ok("(let ((x 10) (y 20)) (+ x y))"),
3008 Value::Int(30)
3009 ));
3010 }
3011
3012 #[test]
3013 fn let_star_sequential_bindings() {
3014 assert!(matches!(
3015 eval_ok("(let* ((x 5) (y (+ x 1))) (+ x y))"),
3016 Value::Int(11)
3017 ));
3018 }
3019
3020 #[test]
3021 fn letrec_mutual_recursion() {
3022 let v = eval_ok(
3023 "(letrec ((even? (lambda (n) (if (= n 0) #t (odd? (- n 1)))))
3024 (odd? (lambda (n) (if (= n 0) #f (even? (- n 1))))))
3025 (even? 10))",
3026 );
3027 assert!(matches!(v, Value::Bool(true)));
3028 }
3029
3030 #[test]
3033 fn lambda_applies() {
3034 assert!(matches!(
3035 eval_ok("((lambda (x y) (+ x y)) 3 4)"),
3036 Value::Int(7)
3037 ));
3038 }
3039
3040 #[test]
3041 fn lambda_closes_over_env() {
3042 assert!(matches!(
3043 eval_ok("(let ((n 10)) ((lambda (x) (+ x n)) 5))"),
3044 Value::Int(15)
3045 ));
3046 }
3047
3048 #[test]
3049 fn closure_captures_by_value_at_creation() {
3050 let v = eval_ok(
3053 "(define make-adder (lambda (n) (lambda (x) (+ x n))))
3054 (define add5 (make-adder 5))
3055 (add5 10)",
3056 );
3057 assert!(matches!(v, Value::Int(15)));
3058 }
3059
3060 #[test]
3061 fn rest_args_collect_into_list() {
3062 let v = eval_ok("((lambda (x &rest rs) (length rs)) 1 2 3 4 5)");
3063 assert!(matches!(v, Value::Int(4)));
3064 }
3065
3066 #[test]
3067 fn closure_arity_mismatch() {
3068 let e = eval_err("((lambda (x y) (+ x y)) 1)");
3069 assert!(matches!(e, EvalError::ArityMismatch { .. }));
3070 }
3071
3072 #[test]
3075 fn define_then_use() {
3076 assert!(matches!(eval_ok("(define x 42) x"), Value::Int(42)));
3077 }
3078
3079 #[test]
3080 fn define_function_shorthand() {
3081 assert!(matches!(
3082 eval_ok("(define (sq x) (* x x)) (sq 6)"),
3083 Value::Int(36)
3084 ));
3085 }
3086
3087 #[test]
3088 fn set_mutates_existing() {
3089 assert!(matches!(
3090 eval_ok("(define x 1) (set! x 99) x"),
3091 Value::Int(99)
3092 ));
3093 }
3094
3095 #[test]
3096 fn set_unbound_errors() {
3097 let e = eval_err("(set! nope 1)");
3098 assert!(matches!(e, EvalError::UnboundSymbol { .. }));
3099 }
3100
3101 #[test]
3104 fn begin_returns_last() {
3105 assert!(matches!(eval_ok("(begin 1 2 3)"), Value::Int(3)));
3106 }
3107
3108 #[test]
3109 fn and_short_circuits() {
3110 assert!(matches!(eval_ok("(and 1 #f 2)"), Value::Bool(false)));
3111 assert!(matches!(eval_ok("(and 1 2 3)"), Value::Int(3)));
3112 assert!(matches!(eval_ok("(and)"), Value::Bool(true)));
3113 }
3114
3115 #[test]
3116 fn or_short_circuits() {
3117 assert!(matches!(eval_ok("(or #f #f 7)"), Value::Int(7)));
3118 assert!(matches!(eval_ok("(or #f #f)"), Value::Bool(false)));
3119 assert!(matches!(eval_ok("(or)"), Value::Bool(false)));
3120 }
3121
3122 #[test]
3123 fn not_inverts() {
3124 assert!(matches!(eval_ok("(not #t)"), Value::Bool(false)));
3125 assert!(matches!(eval_ok("(not #f)"), Value::Bool(true)));
3126 assert!(matches!(eval_ok("(not 42)"), Value::Bool(false)));
3127 }
3128
3129 #[test]
3132 fn recursive_factorial() {
3133 let v = eval_ok(
3134 "(define (fact n)
3135 (if (= n 0) 1 (* n (fact (- n 1)))))
3136 (fact 6)",
3137 );
3138 assert!(matches!(v, Value::Int(720)));
3139 }
3140
3141 #[test]
3142 fn recursive_length() {
3143 let v = eval_ok(
3144 "(define (len xs)
3145 (if (null? xs) 0 (+ 1 (len (cdr xs)))))
3146 (len (list 1 2 3 4 5))",
3147 );
3148 assert!(matches!(v, Value::Int(5)));
3149 }
3150
3151 #[test]
3156 fn quasiquote_plain_list_is_runtime_list() {
3157 let v = eval_ok("`(a b c)");
3158 match v {
3159 Value::List(xs) => {
3160 assert_eq!(xs.len(), 3);
3161 assert!(matches!(&xs[0], Value::Symbol(s) if s.as_ref() == "a"));
3162 assert!(matches!(&xs[1], Value::Symbol(s) if s.as_ref() == "b"));
3163 assert!(matches!(&xs[2], Value::Symbol(s) if s.as_ref() == "c"));
3164 }
3165 other => panic!("{other:?}"),
3166 }
3167 }
3168
3169 #[test]
3170 fn quasiquote_unquote_substitutes_evaluated_value() {
3171 let v = eval_ok("(let ((x 42)) `(a ,x c))");
3172 match v {
3173 Value::List(xs) => {
3174 assert_eq!(xs.len(), 3);
3175 assert!(matches!(&xs[1], Value::Int(42)));
3176 }
3177 other => panic!("{other:?}"),
3178 }
3179 }
3180
3181 #[test]
3182 fn quasiquote_unquote_arbitrary_expr() {
3183 let v = eval_ok("`(x ,(+ 1 2 3) y)");
3184 match v {
3185 Value::List(xs) => {
3186 assert!(matches!(&xs[1], Value::Int(6)));
3187 }
3188 other => panic!("{other:?}"),
3189 }
3190 }
3191
3192 #[test]
3193 fn quasiquote_splice_inlines_list() {
3194 let v = eval_ok("`(a ,@(list 1 2 3) b)");
3195 match v {
3196 Value::List(xs) => {
3197 assert_eq!(xs.len(), 5);
3198 assert!(matches!(&xs[0], Value::Symbol(s) if s.as_ref() == "a"));
3199 assert!(matches!(&xs[1], Value::Int(1)));
3200 assert!(matches!(&xs[2], Value::Int(2)));
3201 assert!(matches!(&xs[3], Value::Int(3)));
3202 assert!(matches!(&xs[4], Value::Symbol(s) if s.as_ref() == "b"));
3203 }
3204 other => panic!("{other:?}"),
3205 }
3206 }
3207
3208 #[test]
3209 fn quasiquote_splice_empty_list_splices_nothing() {
3210 let v = eval_ok("`(a ,@(list) b)");
3211 match v {
3212 Value::List(xs) => {
3213 assert_eq!(xs.len(), 2);
3214 assert!(matches!(&xs[0], Value::Symbol(s) if s.as_ref() == "a"));
3215 assert!(matches!(&xs[1], Value::Symbol(s) if s.as_ref() == "b"));
3216 }
3217 other => panic!("{other:?}"),
3218 }
3219 }
3220
3221 #[test]
3222 fn quasiquote_splice_non_list_errors() {
3223 let e = eval_err("`(a ,@42)");
3224 assert!(matches!(e, EvalError::TypeMismatch { .. }));
3225 }
3226
3227 #[test]
3228 fn quasiquote_atom_yields_atom_value() {
3229 assert!(matches!(eval_ok("`foo"), Value::Symbol(s) if s.as_ref() == "foo"));
3230 assert!(matches!(eval_ok("`42"), Value::Int(42)));
3231 }
3232
3233 #[test]
3234 fn quasiquote_with_nested_list_and_unquote() {
3235 let v = eval_ok("(let ((x 99)) `(foo (bar ,x) baz))");
3237 match v {
3238 Value::List(xs) => {
3239 assert_eq!(xs.len(), 3);
3240 match &xs[1] {
3241 Value::List(inner) => {
3242 assert!(matches!(&inner[1], Value::Int(99)));
3243 }
3244 other => panic!("{other:?}"),
3245 }
3246 }
3247 other => panic!("{other:?}"),
3248 }
3249 }
3250
3251 #[test]
3252 fn quasiquote_symbol_keyword_distinction_preserved() {
3253 let v = eval_ok("`(:key val)");
3254 match v {
3255 Value::List(xs) => {
3256 assert!(matches!(&xs[0], Value::Keyword(s) if s.as_ref() == "key"));
3257 assert!(matches!(&xs[1], Value::Symbol(s) if s.as_ref() == "val"));
3258 }
3259 other => panic!("{other:?}"),
3260 }
3261 }
3262
3263 #[test]
3264 fn bare_unquote_outside_quasiquote_errors() {
3265 let e = eval_err(",x");
3266 assert!(matches!(e, EvalError::BadSpecialForm { .. }));
3267 }
3268
3269 #[test]
3272 fn native_fn_reads_host_state() {
3273 struct Counter {
3274 n: i64,
3275 }
3276 let forms = read_spanned("(bump) (bump) (bump) (cur)").unwrap();
3277 let mut i: Interpreter<Counter> = Interpreter::new();
3278 install_primitives(&mut i);
3279 i.register_fn(
3280 "bump",
3281 Arity::Exact(0),
3282 |_args: &[Value], host: &mut Counter, _span| {
3283 host.n += 1;
3284 Ok(Value::Int(host.n))
3285 },
3286 );
3287 i.register_fn(
3288 "cur",
3289 Arity::Exact(0),
3290 |_args: &[Value], host: &mut Counter, _span| Ok(Value::Int(host.n)),
3291 );
3292 let mut host = Counter { n: 0 };
3293 let v = i.eval_program(&forms, &mut host).unwrap();
3294 assert!(matches!(v, Value::Int(3)));
3295 }
3296
3297 struct Ctx {
3300 records: Vec<(String, i64)>,
3301 }
3302
3303 #[test]
3304 fn register_typed1_marshals_string_arg() {
3305 let mut i: Interpreter<Ctx> = Interpreter::new();
3306 install_primitives(&mut i);
3307 i.register_typed1("greet", |_h: &mut Ctx, name: String| -> Result<String> {
3308 Ok(format!("hello {name}"))
3309 });
3310 let forms = read_spanned(r#"(greet "luis")"#).unwrap();
3311 let mut h = Ctx { records: vec![] };
3312 let v = i.eval_program(&forms, &mut h).unwrap();
3313 match v {
3314 Value::Str(s) => assert_eq!(&*s, "hello luis"),
3315 other => panic!("{other:?}"),
3316 }
3317 }
3318
3319 #[test]
3320 fn register_typed2_marshals_host_state_mutation() {
3321 let mut i: Interpreter<Ctx> = Interpreter::new();
3322 install_primitives(&mut i);
3323 i.register_typed2(
3324 "record",
3325 |h: &mut Ctx, name: String, n: i64| -> Result<()> {
3326 h.records.push((name, n));
3327 Ok(())
3328 },
3329 );
3330 let forms = read_spanned(r#"(record "a" 1) (record "b" 2)"#).unwrap();
3331 let mut h = Ctx { records: vec![] };
3332 let _ = i.eval_program(&forms, &mut h).unwrap();
3333 assert_eq!(h.records.len(), 2);
3334 assert_eq!(h.records[0], ("a".to_string(), 1));
3335 assert_eq!(h.records[1], ("b".to_string(), 2));
3336 }
3337
3338 #[test]
3339 fn register_typed_arg_type_mismatch_surfaces_at_call_site() {
3340 let mut i: Interpreter<Ctx> = Interpreter::new();
3341 install_primitives(&mut i);
3342 i.register_typed1("needs-int", |_h: &mut Ctx, n: i64| -> Result<i64> {
3343 Ok(n + 1)
3344 });
3345 let forms = read_spanned(r#"(needs-int "not-a-number")"#).unwrap();
3346 let mut h = Ctx { records: vec![] };
3347 let err = i.eval_program(&forms, &mut h).unwrap_err();
3348 assert!(matches!(
3349 err,
3350 EvalError::TypeMismatch {
3351 expected: "integer",
3352 ..
3353 }
3354 ));
3355 }
3356
3357 #[test]
3358 fn register_typed3_three_args() {
3359 let mut i: Interpreter<Ctx> = Interpreter::new();
3360 install_primitives(&mut i);
3361 i.register_typed3(
3362 "triple-sum",
3363 |_h: &mut Ctx, a: i64, b: i64, c: i64| -> Result<i64> { Ok(a + b + c) },
3364 );
3365 let forms = read_spanned("(triple-sum 10 20 30)").unwrap();
3366 let mut h = Ctx { records: vec![] };
3367 let v = i.eval_program(&forms, &mut h).unwrap();
3368 assert!(matches!(v, Value::Int(60)));
3369 }
3370
3371 #[test]
3387 fn a_runaway_macro_is_a_typed_error_that_names_the_macro() {
3388 let err = eval_err("(defmacro forever (x) `(forever ,x))\n(forever 1)");
3389 match err {
3390 EvalError::MacroExpansionLimit {
3391 ref macro_name,
3392 limit,
3393 ..
3394 } => {
3395 assert_eq!(&**macro_name, "forever", "the error must name the culprit");
3396 assert_eq!(limit, DEFAULT_MACRO_EXPANSION_LIMIT);
3397 }
3398 other => panic!("expected MacroExpansionLimit, got {other:?}"),
3399 }
3400 }
3401
3402 #[test]
3406 fn a_mutually_recursive_macro_pair_is_caught_too() {
3407 let err =
3408 eval_err("(defmacro ping (x) `(pong ,x))\n(defmacro pong (x) `(ping ,x))\n(ping 1)");
3409 assert!(
3410 matches!(err, EvalError::MacroExpansionLimit { .. }),
3411 "a two-macro cycle must be bounded as well: {err:?}"
3412 );
3413 }
3414
3415 #[test]
3423 fn deep_but_finite_nesting_is_not_charged_to_the_expansion_budget() {
3424 let mut src = String::from("(defmacro id1 (x) x)\n");
3425 src.push_str(&"(+ 1 ".repeat(400));
3426 src.push_str("(id1 7)");
3427 src.push_str(&")".repeat(400));
3428 let v = eval_ok(&src);
3429 assert!(matches!(v, Value::Int(407)), "got {v:?}");
3430 }
3431
3432 #[test]
3435 fn a_terminating_chain_under_the_ceiling_still_expands() {
3436 let v =
3438 eval_ok("(defmacro step (x) `(step2 ,x))\n(defmacro step2 (x) `(* ,x 3))\n(step 5)");
3439 assert!(matches!(v, Value::Int(15)), "got {v:?}");
3440 }
3441
3442 #[test]
3445 fn the_expansion_ceiling_is_configurable() {
3446 let forms = read_spanned("(defmacro forever (x) `(forever ,x))\n(forever 1)").unwrap();
3447 let mut i: Interpreter<NoHost> = Interpreter::new();
3448 install_primitives(&mut i);
3449 i.set_macro_expansion_limit(4);
3450 match i.eval_program(&forms, &mut NoHost).unwrap_err() {
3451 EvalError::MacroExpansionLimit { limit, .. } => assert_eq!(limit, 4),
3452 other => panic!("expected MacroExpansionLimit, got {other:?}"),
3453 }
3454 }
3455
3456 #[test]
3457 fn user_macro_expands_and_evaluates() {
3458 let v = eval_ok(
3459 "(defmacro twice (x) `(* ,x 2))
3460 (twice 21)",
3461 );
3462 assert!(matches!(v, Value::Int(42)));
3463 }
3464
3465 #[test]
3466 fn user_macro_definition_returns_nil() {
3467 let v = eval_ok("(defmacro inc (x) `(+ ,x 1))");
3468 assert!(matches!(v, Value::Nil));
3469 }
3470
3471 #[test]
3472 fn user_macro_inside_define_body_expands() {
3473 let v = eval_ok(
3476 "(defmacro inc (x) `(+ ,x 1))
3477 (define (f n) (inc n))
3478 (f 41)",
3479 );
3480 assert!(matches!(v, Value::Int(42)));
3481 }
3482
3483 #[test]
3484 fn user_macro_with_rest_args_splices() {
3485 let v = eval_ok(
3486 "(defmacro sum-all (&rest xs) `(+ ,@xs))
3487 (sum-all 1 2 3 4 5)",
3488 );
3489 assert!(matches!(v, Value::Int(15)));
3490 }
3491
3492 #[test]
3493 fn nested_user_macros_compose() {
3494 let v = eval_ok(
3495 "(defmacro twice (x) `(* ,x 2))
3496 (defmacro quad (x) `(twice (twice ,x)))
3497 (quad 5)",
3498 );
3499 assert!(matches!(v, Value::Int(20)));
3500 }
3501
3502 #[test]
3503 fn user_macro_can_expand_to_special_form() {
3504 let v = eval_ok(
3507 "(defmacro guard (test then) `(if ,test ,then 0))
3508 (guard #t 99)",
3509 );
3510 assert!(matches!(v, Value::Int(99)));
3511 }
3512
3513 #[test]
3514 fn user_macro_redefined_replaces_prior_template() {
3515 let v = eval_ok(
3516 "(defmacro k () `1)
3517 (defmacro k () `2)
3518 (k)",
3519 );
3520 assert!(matches!(v, Value::Int(2)));
3521 }
3522
3523 #[test]
3524 fn user_macro_unbound_template_var_errors() {
3525 let mut i: Interpreter<NoHost> = Interpreter::new();
3531 install_primitives(&mut i);
3532 let forms = read_spanned("(defmacro bad (x) `(list ,y)) (bad 1)").unwrap();
3533 let err = i.eval_program(&forms, &mut NoHost).unwrap_err();
3534 match err {
3535 EvalError::UnboundSymbol { name, .. } => assert_eq!(&*name, "y"),
3536 other => panic!("expected UnboundSymbol, got {other:?}"),
3537 }
3538 }
3539
3540 #[test]
3541 fn defpoint_template_keyword_registers_as_macro() {
3542 let v = eval_ok(
3545 "(defpoint-template double (x) `(* ,x 2))
3546 (double 7)",
3547 );
3548 assert!(matches!(v, Value::Int(14)));
3549 }
3550
3551 #[test]
3552 fn defcheck_keyword_registers_as_macro() {
3553 let v = eval_ok(
3554 "(defcheck always-7 () `7)
3555 (always-7)",
3556 );
3557 assert!(matches!(v, Value::Int(7)));
3558 }
3559
3560 #[test]
3561 fn macro_call_evaluated_with_runtime_arg() {
3562 let v = eval_ok(
3566 "(defmacro double (x) `(+ ,x ,x))
3567 (define n 13)
3568 (double n)",
3569 );
3570 assert!(matches!(v, Value::Int(26)));
3571 }
3572
3573 #[test]
3574 fn macro_persists_across_eval_program_calls() {
3575 let mut i: Interpreter<NoHost> = Interpreter::new();
3578 install_primitives(&mut i);
3579 let mut host = NoHost;
3580 let defs = read_spanned("(defmacro inc (x) `(+ ,x 1))").unwrap();
3581 i.eval_program(&defs, &mut host).unwrap();
3582 assert_eq!(i.expander().len(), 1);
3583
3584 let call = read_spanned("(inc 41)").unwrap();
3585 let v = i.eval_program(&call, &mut host).unwrap();
3586 assert!(matches!(v, Value::Int(42)));
3587 }
3588
3589 #[test]
3590 fn macro_expansion_inside_lambda_body() {
3591 let v = eval_ok(
3592 "(defmacro sq (x) `(* ,x ,x))
3593 ((lambda (n) (sq n)) 9)",
3594 );
3595 assert!(matches!(v, Value::Int(81)));
3596 }
3597
3598 #[test]
3599 fn no_macros_registered_keeps_eval_program_a_passthrough() {
3600 let v = eval_ok("(+ 1 2 3)");
3606 assert!(matches!(v, Value::Int(6)));
3607 }
3608
3609 #[test]
3610 fn an_interrupt_halts_a_loop_from_another_thread_and_no_catch_sees_it() {
3611 use std::sync::atomic::{AtomicBool, Ordering};
3612 let mut interp: Interpreter<NoHost> = Interpreter::new();
3613 install_primitives(&mut interp);
3614 let flag = Arc::new(AtomicBool::new(false));
3615 interp.set_interrupt(Arc::clone(&flag));
3616 assert!(!interp.interrupt().load(Ordering::Relaxed));
3617 let setter = Arc::clone(&flag);
3618 let t = std::thread::spawn(move || {
3619 std::thread::sleep(std::time::Duration::from_millis(50));
3620 setter.store(true, Ordering::Relaxed);
3621 });
3622 let src = "(define (spin n) (spin (+ n 1))) (try (spin 0) (catch (e) :caught))";
3623 let forms = read_spanned(src).unwrap();
3624 let r = interp.eval_program(&forms, &mut NoHost);
3625 t.join().unwrap();
3626 assert!(matches!(r, Err(EvalError::Halted)), "{r:?}");
3627 assert!(matches!(eval_ok("(+ 1 2)"), Value::Int(3)));
3628 }
3629
3630 #[test]
3631 fn eval_top_form_drives_one_form_at_a_time() {
3632 let mut i: Interpreter<NoHost> = Interpreter::new();
3633 install_primitives(&mut i);
3634 let mut host = NoHost;
3635 let forms = read_spanned("(defmacro id (x) `,x) (id 42)").unwrap();
3636
3637 let r0 = i.eval_top_form(&forms[0], &mut host).unwrap();
3639 assert!(matches!(r0, Value::Nil));
3640
3641 let r1 = i.eval_top_form(&forms[1], &mut host).unwrap();
3643 assert!(matches!(r1, Value::Int(42)));
3644 }
3645
3646 use crate::install_full_stdlib_with;
3653
3654 fn run_full(src: &str) -> Value {
3655 let mut i: Interpreter<NoHost> = Interpreter::new();
3656 install_full_stdlib_with(&mut i, &mut NoHost);
3657 let forms = read_spanned(src).unwrap();
3658 i.eval_program(&forms, &mut NoHost).unwrap()
3659 }
3660
3661 #[test]
3662 fn macro_can_use_map_at_expansion_time() {
3663 let v = run_full(
3667 "(defmacro double-each (&rest xs)
3668 `(list ,@(map (lambda (x) (* x 2)) xs)))
3669 (double-each 1 2 3 4 5)",
3670 );
3671 assert_eq!(format!("{v}"), "(2 4 6 8 10)");
3672 }
3673
3674 #[test]
3675 fn macro_can_use_foldl_at_expansion_time() {
3676 let v = run_full(
3680 "(defmacro static-sum (&rest xs)
3681 (foldl + 0 xs))
3682 (static-sum 1 2 3 4 5)",
3683 );
3684 assert!(matches!(v, Value::Int(15)));
3685 }
3686
3687 #[test]
3688 fn macro_can_use_filter_at_expansion_time() {
3689 let v = run_full(
3693 "(defmacro sum-positives (&rest xs)
3694 `(+ ,@(filter positive? xs)))
3695 (sum-positives 1 -2 3 -4 5)",
3696 );
3697 assert!(matches!(v, Value::Int(9)));
3699 }
3700
3701 #[test]
3702 fn macro_can_recursively_emit_let_chain() {
3703 let v = run_full(
3706 "(defmacro chain-let (binding &rest more)
3707 (if (null? more)
3708 `(let (,binding) #t)
3709 `(let (,binding) (chain-let ,@more))))
3710 (chain-let (a 1) (b 2) (c 3))",
3711 );
3712 assert!(matches!(v, Value::Bool(true)));
3713 }
3714
3715 #[test]
3716 fn macro_can_use_gensym_for_hygiene() {
3717 let v = run_full(
3720 "(defmacro swap-bind (init body)
3721 (let ((tmp (gensym \"tmp\")))
3722 `(let ((,tmp ,init))
3723 (+ ,tmp ,tmp))))
3724 (swap-bind 21 #t)",
3725 );
3726 assert!(matches!(v, Value::Int(42)));
3727 }
3728
3729 #[test]
3730 fn macro_can_inspect_arg_shape() {
3731 let v = run_full(
3733 "(defmacro shape-aware (x)
3734 (if (list? x)
3735 `(+ ,@x) ;; sum the children
3736 `,x)) ;; pass through scalars
3737 (+ (shape-aware (1 2 3)) (shape-aware 100))",
3738 );
3739 assert!(matches!(v, Value::Int(106)));
3741 }
3742
3743 #[test]
3744 fn macro_can_call_user_helper_fn() {
3745 let v = run_full(
3747 "(define (square x) (* x x))
3748 (defmacro static-square (n) (square n))
3749 (static-square 7)",
3750 );
3751 assert!(matches!(v, Value::Int(49)));
3752 }
3753
3754 #[test]
3755 fn macro_emitting_quoted_form_round_trips() {
3756 let v = run_full(
3759 "(defmacro literal-list (&rest xs)
3760 `(quote ,xs))
3761 (literal-list a b c)",
3762 );
3763 let s = format!("{v}");
3764 assert!(s.contains('a') && s.contains('b') && s.contains('c'));
3765 }
3766
3767 #[test]
3768 fn quasiquote_inside_quasiquote_in_macro_output_is_preserved() {
3769 let v = run_full(
3772 "(defmacro emit-qq (x) `(quasiquote (a (unquote ,x) c)))
3773 (let ((q (emit-qq 99))) q)",
3774 );
3775 assert_eq!(format!("{v}"), "(a 99 c)");
3777 }
3778
3779 #[test]
3780 fn macro_body_can_define_locals_and_dispatch() {
3781 let v = run_full(
3783 "(defmacro classify-args (&rest xs)
3784 (let ((evens (filter even? xs))
3785 (odds (filter odd? xs)))
3786 `(list (list :evens ,@evens)
3787 (list :odds ,@odds))))
3788 (classify-args 1 2 3 4 5 6)",
3789 );
3790 let s = format!("{v}");
3791 assert!(s.contains(":evens 2 4 6"));
3792 assert!(s.contains(":odds 1 3 5"));
3793 }
3794
3795 #[test]
3804 fn tco_self_recursion_via_if() {
3805 let v = run_full(
3809 "(define (sum n acc)
3810 (if (= n 0)
3811 acc
3812 (sum (- n 1) (+ acc n))))
3813 (sum 100000 0)",
3814 );
3815 assert!(matches!(v, Value::Int(5_000_050_000)));
3817 }
3818
3819 #[test]
3820 fn tco_mutual_recursion() {
3821 let v = run_full(
3824 "(define (even-r? n) (if (= n 0) #t (odd-r? (- n 1))))
3825 (define (odd-r? n) (if (= n 0) #f (even-r? (- n 1))))
3826 (even-r? 50000)",
3827 );
3828 assert!(matches!(v, Value::Bool(true)));
3829 }
3830
3831 #[test]
3832 fn tco_via_cond_branch() {
3833 let v = run_full(
3834 "(define (countdown n)
3835 (cond
3836 ((<= n 0) :done)
3837 (else (countdown (- n 1)))))
3838 (countdown 50000)",
3839 );
3840 assert!(matches!(v, Value::Keyword(s) if &*s == "done"));
3841 }
3842
3843 #[test]
3844 fn tco_via_let_body() {
3845 let v = run_full(
3848 "(define (loop-let n)
3849 (let ((m (- n 1)))
3850 (if (<= n 0) :done (loop-let m))))
3851 (loop-let 50000)",
3852 );
3853 assert!(matches!(v, Value::Keyword(s) if &*s == "done"));
3854 }
3855
3856 #[test]
3857 fn tco_via_begin_last_form() {
3858 let v = run_full(
3859 "(define (counter n)
3860 (begin
3861 (+ 1 1)
3862 (+ 2 2)
3863 (if (<= n 0) :done (counter (- n 1)))))
3864 (counter 50000)",
3865 );
3866 assert!(matches!(v, Value::Keyword(s) if &*s == "done"));
3867 }
3868
3869 #[test]
3870 fn tco_via_when_unless() {
3871 let v = run_full(
3872 "(define (drain n)
3873 (when (> n 0)
3874 (drain (- n 1))))
3875 (drain 50000)",
3876 );
3877 assert!(matches!(v, Value::Nil));
3879 }
3880
3881 #[test]
3882 fn tco_through_and_or_short_circuit_last() {
3883 let v = run_full(
3886 "(define (loop-and n)
3887 (and #t #t (if (<= n 0) :done (loop-and (- n 1)))))
3888 (loop-and 30000)",
3889 );
3890 assert!(matches!(v, Value::Keyword(s) if &*s == "done"));
3891 }
3892
3893 #[test]
3894 fn non_tail_recursion_still_works_for_small_n() {
3895 let v = run_full(
3899 "(define (fact n)
3900 (if (= n 0) 1 (* n (fact (- n 1)))))
3901 (fact 12)",
3902 );
3903 assert!(matches!(v, Value::Int(479_001_600)));
3905 }
3906
3907 #[test]
3910 fn error_constructor_returns_error_value() {
3911 let v = run_full("(error :validation \"bad input\")");
3912 match v {
3913 Value::Error(e) => {
3914 assert_eq!(&*e.tag, "validation");
3915 assert_eq!(&*e.message, "bad input");
3916 assert!(e.data.is_empty());
3917 }
3918 other => panic!("{other:?}"),
3919 }
3920 }
3921
3922 #[test]
3923 fn ex_info_uses_default_tag() {
3924 let v = run_full("(ex-info \"validation failed\" (list :field \"email\" :code 42))");
3925 match v {
3926 Value::Error(e) => {
3927 assert_eq!(&*e.tag, "ex-info");
3928 assert_eq!(&*e.message, "validation failed");
3929 assert_eq!(e.data.len(), 2);
3930 }
3931 other => panic!("{other:?}"),
3932 }
3933 }
3934
3935 #[test]
3936 fn error_predicate() {
3937 let v = run_full("(error? (error :x \"y\"))");
3938 assert!(matches!(v, Value::Bool(true)));
3939 let v = run_full("(error? 42)");
3940 assert!(matches!(v, Value::Bool(false)));
3941 }
3942
3943 #[test]
3944 fn error_accessors() {
3945 let v = run_full(
3946 "(let ((e (ex-info \"oops\" (list :user-id 42))))
3947 (list (error-tag e) (error-message e) (error-data-get e :user-id)))",
3948 );
3949 assert_eq!(format!("{v}"), "(:ex-info \"oops\" 42)");
3950 }
3951
3952 #[test]
3953 fn try_catches_thrown_error() {
3954 let v = run_full(
3955 "(try
3956 (throw (ex-info \"boom\" (list :code 500)))
3957 (catch (e)
3958 (error-message e)))",
3959 );
3960 assert_eq!(format!("{v}"), "\"boom\"");
3961 }
3962
3963 #[test]
3964 fn try_returns_body_value_when_no_throw() {
3965 let v = run_full(
3966 "(try
3967 (+ 1 2 3)
3968 (catch (e) :unreachable))",
3969 );
3970 assert!(matches!(v, Value::Int(6)));
3971 }
3972
3973 #[test]
3974 fn try_catches_runtime_errors_too() {
3975 let v = run_full(
3979 "(try
3980 (/ 1 0)
3981 (catch (e) (error-tag e)))",
3982 );
3983 assert!(matches!(v, Value::Keyword(s) if &*s == "division-by-zero"));
3984 }
3985
3986 #[test]
3987 fn try_catches_unbound_symbol_error() {
3988 let v = run_full(
3989 "(try
3990 undefined-var
3991 (catch (e) (error-tag e)))",
3992 );
3993 assert!(matches!(v, Value::Keyword(s) if &*s == "unbound-symbol"));
3994 }
3995
3996 #[test]
3997 fn try_catches_arity_mismatch() {
3998 let v = run_full(
3999 "(try
4000 ((lambda (x y) (+ x y)) 1)
4001 (catch (e) (error-tag e)))",
4002 );
4003 assert!(matches!(v, Value::Keyword(s) if &*s == "arity-mismatch"));
4004 }
4005
4006 #[test]
4007 fn nested_try_inner_handler_takes_precedence() {
4008 let v = run_full(
4009 "(try
4010 (try
4011 (throw (ex-info \"inner\" ()))
4012 (catch (e) :inner-caught))
4013 (catch (e) :outer-caught))",
4014 );
4015 assert!(matches!(v, Value::Keyword(s) if &*s == "inner-caught"));
4016 }
4017
4018 #[test]
4019 fn outer_try_catches_when_handler_rethrows() {
4020 let v = run_full(
4021 "(try
4022 (try
4023 (throw (ex-info \"first\" ()))
4024 (catch (e) (throw (ex-info \"rethrown\" ()))))
4025 (catch (e) (error-message e)))",
4026 );
4027 assert_eq!(format!("{v}"), "\"rethrown\"");
4028 }
4029
4030 #[test]
4031 fn throw_propagates_when_no_try() {
4032 let mut i: Interpreter<NoHost> = Interpreter::new();
4034 install_full_stdlib_with(&mut i, &mut NoHost);
4035 let forms = read_spanned("(throw (ex-info \"unhandled\" (list :code 99)))").unwrap();
4036 let err = i.eval_program(&forms, &mut NoHost).unwrap_err();
4037 match err {
4038 EvalError::User { value, .. } => match value {
4039 Value::Error(e) => {
4040 assert_eq!(&*e.message, "unhandled");
4041 }
4042 other => panic!("{other:?}"),
4043 },
4044 other => panic!("{other:?}"),
4045 }
4046 }
4047
4048 #[test]
4051 fn macroexpand_one_step() {
4052 let v = run_full(
4053 "(defmacro twice (x) `(* ,x 2))
4054 (macroexpand-1 '(twice 7))",
4055 );
4056 assert_eq!(format!("{v}"), "(* 7 2)");
4058 }
4059
4060 #[test]
4061 fn macroexpand_full_until_fixed_point() {
4062 let v = run_full(
4063 "(defmacro twice (x) `(* ,x 2))
4064 (defmacro quad (x) `(twice (twice ,x)))
4065 (macroexpand '(quad 5))",
4066 );
4067 assert_eq!(format!("{v}"), "(* (* 5 2) 2)");
4069 }
4070
4071 #[test]
4072 fn macroexpand_returns_unchanged_for_non_macro() {
4073 let v = run_full("(macroexpand-1 '(+ 1 2 3))");
4074 assert_eq!(format!("{v}"), "(+ 1 2 3)");
4076 }
4077
4078 #[test]
4079 fn macroexpand_one_does_not_recurse_into_children() {
4080 let v = run_full(
4082 "(defmacro twice (x) `(* ,x 2))
4083 (defmacro outer (x) `(list ,x))
4084 (macroexpand-1 '(outer (twice 3)))",
4085 );
4086 assert_eq!(format!("{v}"), "(list (twice 3))");
4088 }
4089
4090 #[test]
4091 fn macroexpand_recurses_into_children() {
4092 let v = run_full(
4093 "(defmacro twice (x) `(* ,x 2))
4094 (defmacro outer (x) `(list ,x))
4095 (macroexpand '(outer (twice 3)))",
4096 );
4097 assert_eq!(format!("{v}"), "(list (* 3 2))");
4099 }
4100
4101 fn run_with_modules(modules: &[(&str, &str)], src: &str) -> Value {
4104 use crate::module::MapLoader;
4105 let mut i: Interpreter<NoHost> = Interpreter::new();
4106 install_full_stdlib_with(&mut i, &mut NoHost);
4107 let mut loader = MapLoader::new();
4108 for (path, source) in modules {
4109 loader.insert(*path, *source);
4110 }
4111 i.set_loader(Arc::new(loader));
4112 let forms = read_spanned(src).unwrap();
4113 i.eval_program(&forms, &mut NoHost).unwrap()
4114 }
4115
4116 fn run_with_modules_err(modules: &[(&str, &str)], src: &str) -> EvalError {
4117 use crate::module::MapLoader;
4118 let mut i: Interpreter<NoHost> = Interpreter::new();
4119 install_full_stdlib_with(&mut i, &mut NoHost);
4120 let mut loader = MapLoader::new();
4121 for (path, source) in modules {
4122 loader.insert(*path, *source);
4123 }
4124 i.set_loader(Arc::new(loader));
4125 let forms = read_spanned(src).unwrap();
4126 i.eval_program(&forms, &mut NoHost).unwrap_err()
4127 }
4128
4129 #[test]
4130 fn require_with_explicit_alias_imports_qualified_names() {
4131 let v = run_with_modules(
4132 &[(
4133 "lib/math",
4134 "(define square (lambda (x) (* x x)))
4135 (define cube (lambda (x) (* x x x)))
4136 (provide square cube)",
4137 )],
4138 "(require \"lib/math\" :as math)
4139 (math/square 7)",
4140 );
4141 assert!(matches!(v, Value::Int(49)));
4142 }
4143
4144 #[test]
4145 fn require_uses_path_as_default_alias() {
4146 let v = run_with_modules(
4147 &[(
4148 "lib/math",
4149 "(define double (lambda (x) (* x 2))) (provide double)",
4150 )],
4151 "(require \"lib/math\")
4152 (lib/math/double 21)",
4153 );
4154 assert!(matches!(v, Value::Int(42)));
4157 }
4158
4159 #[test]
4160 fn require_refer_imports_unqualified_names() {
4161 let v = run_with_modules(
4162 &[(
4163 "lib/math",
4164 "(define square (lambda (x) (* x x)))
4165 (define cube (lambda (x) (* x x x)))
4166 (provide square cube)",
4167 )],
4168 "(require \"lib/math\" :refer (square))
4169 (square 6)",
4170 );
4171 assert!(matches!(v, Value::Int(36)));
4172 }
4173
4174 #[test]
4175 fn require_does_not_import_non_provided() {
4176 let err = run_with_modules_err(
4179 &[(
4180 "lib/secret",
4181 "(define public 1)
4182 (define private 2)
4183 (provide public)",
4184 )],
4185 "(require \"lib/secret\" :as s)
4186 s/private",
4187 );
4188 match err {
4189 EvalError::UnboundSymbol { name, .. } => assert_eq!(&*name, "s/private"),
4190 other => panic!("{other:?}"),
4191 }
4192 }
4193
4194 #[test]
4195 fn require_chain_a_imports_b() {
4196 let v = run_with_modules(
4197 &[
4198 (
4199 "lib/util",
4200 "(define inc1 (lambda (n) (+ n 1)))
4201 (provide inc1)",
4202 ),
4203 (
4204 "lib/wrapper",
4205 "(require \"lib/util\" :as u)
4206 (define inc2 (lambda (n) (u/inc1 (u/inc1 n))))
4207 (provide inc2)",
4208 ),
4209 ],
4210 "(require \"lib/wrapper\" :as w)
4211 (w/inc2 10)",
4212 );
4213 assert!(matches!(v, Value::Int(12)));
4214 }
4215
4216 #[test]
4217 fn require_module_not_found() {
4218 let err = run_with_modules_err(&[], "(require \"missing/module\")");
4219 match err {
4221 EvalError::User { value, .. } => match value {
4222 Value::Error(e) => {
4223 assert_eq!(&*e.tag, "module-not-found");
4224 assert!(e.message.contains("missing/module"));
4225 }
4226 other => panic!("{other:?}"),
4227 },
4228 other => panic!("{other:?}"),
4229 }
4230 }
4231
4232 #[test]
4233 fn circular_require_detected() {
4234 let err = run_with_modules_err(
4235 &[
4236 ("a", "(require \"b\") (provide x) (define x 1)"),
4237 ("b", "(require \"a\") (provide y) (define y 2)"),
4238 ],
4239 "(require \"a\")",
4240 );
4241 match err {
4242 EvalError::User { value, .. } => match value {
4243 Value::Error(e) => assert_eq!(&*e.tag, "circular-require"),
4244 other => panic!("{other:?}"),
4245 },
4246 other => panic!("{other:?}"),
4247 }
4248 }
4249
4250 #[test]
4251 fn provide_at_top_level_errors() {
4252 let mut i: Interpreter<NoHost> = Interpreter::new();
4254 install_full_stdlib_with(&mut i, &mut NoHost);
4255 let forms = read_spanned("(provide x)").unwrap();
4256 let err = i.eval_program(&forms, &mut NoHost).unwrap_err();
4257 assert!(matches!(err, EvalError::BadSpecialForm { form, .. } if &*form == "provide"));
4258 }
4259
4260 #[test]
4261 fn require_refer_unknown_name_errors() {
4262 let err = run_with_modules_err(
4263 &[(
4264 "lib/math",
4265 "(define square (lambda (x) (* x x))) (provide square)",
4266 )],
4267 "(require \"lib/math\" :refer (square cube))",
4268 );
4269 match err {
4270 EvalError::User { value, .. } => match value {
4271 Value::Error(e) => {
4272 assert!(matches!(&*e.tag, "not-defined" | "not-exported"));
4273 }
4274 other => panic!("{other:?}"),
4275 },
4276 other => panic!("{other:?}"),
4277 }
4278 }
4279
4280 #[test]
4281 fn require_caches_module_load_once() {
4282 let v = run_with_modules(
4283 &[("lib/foo", "(define x 42) (provide x)")],
4284 "(require \"lib/foo\" :as a)
4285 (require \"lib/foo\" :as b)
4286 (+ a/x b/x)",
4287 );
4288 assert!(matches!(v, Value::Int(84)));
4290 }
4291
4292 #[test]
4301 fn macro_body_cannot_set_a_global() {
4302 let mut interp = Interpreter::new();
4303 install_primitives(&mut interp);
4304 let src = "(define *g* 0) (defmacro leak () (set! *g* 99)) (leak)";
4305 let forms = tatara_lisp::read_spanned(src).expect("parse");
4306 let err = interp
4307 .eval_program(&forms, &mut ())
4308 .expect_err("a macro must not be able to set! a global");
4309 let msg = format!("{err}");
4310 assert!(
4311 msg.contains("sealed") || msg.contains("cannot `set!`"),
4312 "expected a sealed-write diagnostic, got: {msg}"
4313 );
4314 }
4315
4316 #[test]
4317 fn the_global_is_actually_unchanged_after_a_refused_macro_set() {
4318 let mut interp = Interpreter::new();
4319 install_primitives(&mut interp);
4320 let forms = tatara_lisp::read_spanned("(define *g* 0) (defmacro leak () (set! *g* 99))")
4321 .expect("parse");
4322 interp.eval_program(&forms, &mut ()).expect("setup");
4323 let call = tatara_lisp::read_spanned("(leak)").expect("parse");
4325 let _ = interp.eval_program(&call, &mut ());
4326 let read = tatara_lisp::read_spanned("*g*").expect("parse");
4327 let v = interp.eval_program(&read, &mut ()).expect("read *g*");
4328 assert!(
4329 matches!(v, Value::Int(0)),
4330 "global was mutated by a macro body despite the seal: {v:?}"
4331 );
4332 }
4333
4334 #[test]
4337 fn ordinary_set_still_works_at_runtime() {
4338 let mut interp = Interpreter::new();
4339 install_primitives(&mut interp);
4340 let forms = tatara_lisp::read_spanned("(define x 1) (set! x 42) x").expect("parse");
4341 let v = interp.eval_program(&forms, &mut ()).expect("runtime set!");
4342 assert!(matches!(v, Value::Int(42)), "got {v:?}");
4343 }
4344
4345 #[test]
4348 fn macro_body_can_mutate_its_own_locals() {
4349 let mut interp = Interpreter::new();
4350 install_primitives(&mut interp);
4351 let src = "(defmacro m () (begin (define n 1) (set! n 2) n)) (m)";
4352 let forms = tatara_lisp::read_spanned(src).expect("parse");
4353 let v = interp
4354 .eval_program(&forms, &mut ())
4355 .expect("a macro must be able to mutate its own locals");
4356 assert!(matches!(v, Value::Int(2)), "got {v:?}");
4357 }
4358}