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: 'static> Interpreter<H> {
80 pub fn new() -> Self {
81 Self {
82 registry: FnRegistry::new(),
83 globals: Env::new(),
84 expander: SpannedExpander::new(),
85 modules: ModuleRegistry::new(),
86 loader: Arc::new(NoLoader),
87 macro_expansion_limit: DEFAULT_MACRO_EXPANSION_LIMIT,
88 current_module: None,
89 }
90 }
91
92 pub fn fork(&self) -> Self {
131 Self {
132 registry: self.registry.clone(),
133 globals: self.globals.sealed_below_top(Seal::Fork),
134 expander: self.expander.clone(),
135 modules: self.modules.clone(),
136 loader: Arc::clone(&self.loader),
137 macro_expansion_limit: self.macro_expansion_limit,
138 current_module: self.current_module.clone(),
139 }
140 }
141
142 pub fn set_loader(&mut self, loader: Arc<dyn Loader>) {
145 self.loader = loader;
146 }
147
148 pub fn modules(&self) -> &ModuleRegistry {
150 &self.modules
151 }
152
153 pub fn register_fn<F>(&mut self, name: impl Into<Arc<str>>, arity: Arity, callable: F)
157 where
158 F: NativeCallable<H>,
159 {
160 let name = name.into();
161 self.registry.insert(FnEntry {
162 name: name.clone(),
163 arity,
164 callable: FnImpl::Native(Arc::new(callable)),
165 });
166 self.globals.define(
167 name.clone(),
168 Value::NativeFn(Arc::new(NativeFn { name, arity })),
169 );
170 }
171
172 pub fn register_higher_order_fn<F>(
177 &mut self,
178 name: impl Into<Arc<str>>,
179 arity: Arity,
180 callable: F,
181 ) where
182 F: HigherOrderCallable<H>,
183 {
184 let name = name.into();
185 self.registry.insert(FnEntry {
186 name: name.clone(),
187 arity,
188 callable: FnImpl::Higher(Arc::new(callable)),
189 });
190 self.globals.define(
191 name.clone(),
192 Value::NativeFn(Arc::new(NativeFn { name, arity })),
193 );
194 }
195
196 pub fn register_awaitable_fn<R, C>(
246 &mut self,
247 name: impl Into<Arc<str>>,
248 arity: Arity,
249 ready: R,
250 call: C,
251 ) where
252 R: Fn(&[Value], &H) -> bool + Send + Sync + 'static,
253 C: Fn(&[Value], &mut H, Span) -> Result<Value> + Send + Sync + 'static,
254 {
255 let name = name.into();
256 self.registry.insert(FnEntry {
257 name: name.clone(),
258 arity,
259 callable: FnImpl::Awaitable(Arc::new(crate::ffi::Awaitable { ready, call })),
260 });
261 self.globals.define(
262 name.clone(),
263 Value::NativeFn(Arc::new(NativeFn { name, arity })),
264 );
265 }
266
267 pub fn set_macro_expansion_limit(&mut self, limit: usize) {
272 self.macro_expansion_limit = limit;
273 }
274
275 pub fn eval_spanned(&mut self, form: &Spanned, host: &mut H) -> Result<Value> {
280 let expanded = self.fully_expand(form, host)?;
281 eval_in(
282 &mut self.globals,
283 &self.registry,
284 &self.expander,
285 &expanded,
286 host,
287 )
288 }
289
290 pub fn eval_program(&mut self, forms: &[Spanned], host: &mut H) -> Result<Value> {
302 let mut last = Value::Nil;
303 for form in forms {
304 last = self.eval_top_form(form, host)?;
305 }
306 Ok(last)
307 }
308
309 pub fn eval_top_form(&mut self, form: &Spanned, host: &mut H) -> Result<Value> {
315 if self.expander.try_register_macro(form)? {
316 return Ok(Value::Nil);
317 }
318 if let Some(head) = head_symbol(form) {
322 match head {
323 "provide" => return self.eval_provide(form, host),
324 "require" => return self.eval_require(form, host),
325 _ => {}
326 }
327 }
328 let expanded = self.fully_expand(form, host)?;
329 eval_in(
330 &mut self.globals,
331 &self.registry,
332 &self.expander,
333 &expanded,
334 host,
335 )
336 }
337
338 fn eval_provide(&mut self, form: &Spanned, _host: &mut H) -> Result<Value> {
342 let items = form.as_list().unwrap_or(&[]);
343 let span = form.span;
344 let Some(current) = self.current_module.clone() else {
345 return Err(EvalError::bad_form(
346 "provide",
347 "`provide` only valid at module top level — embedder evaluating top-level code has no current module",
348 span,
349 ));
350 };
351 let mut names: Vec<Arc<str>> = Vec::with_capacity(items.len().saturating_sub(1));
353 for item in &items[1..] {
354 let name = item.as_symbol().ok_or_else(|| {
355 EvalError::bad_form(
356 "provide",
357 "expected symbol — every arg must name a binding to export",
358 item.span,
359 )
360 })?;
361 names.push(Arc::<str>::from(name));
362 }
363 {
368 let mut g = self.modules.inner_lock();
369 g.exports_staging
373 .entry(current.to_string())
374 .or_default()
375 .extend(names.iter().cloned());
376 }
377 Ok(Value::Nil)
378 }
379
380 fn eval_require(&mut self, form: &Spanned, host: &mut H) -> Result<Value> {
389 let items = form.as_list().unwrap_or(&[]);
390 let span = form.span;
391 if items.len() < 2 {
392 return Err(EvalError::bad_form(
393 "require",
394 "expected (require \"path\" [:as alias] [:refer (...)])",
395 span,
396 ));
397 }
398 let path: Arc<str> = match items[1].as_string() {
399 Some(s) => Arc::from(s),
400 None => {
401 return Err(EvalError::bad_form(
402 "require",
403 "first arg must be a string path",
404 items[1].span,
405 ))
406 }
407 };
408
409 let mut alias: Option<Arc<str>> = None;
411 let mut refer: Option<Vec<Arc<str>>> = None;
412 let mut i = 2usize;
413 while i < items.len() {
414 let kw = items[i].as_keyword().ok_or_else(|| {
415 EvalError::bad_form(
416 "require",
417 "expected keyword (:as / :refer) after path",
418 items[i].span,
419 )
420 })?;
421 let val = items.get(i + 1).ok_or_else(|| {
422 EvalError::bad_form("require", "keyword without value", items[i].span)
423 })?;
424 match kw {
425 "as" => {
426 alias = Some(Arc::from(val.as_symbol().ok_or_else(|| {
427 EvalError::bad_form("require", ":as needs a symbol alias", val.span)
428 })?));
429 }
430 "refer" => {
431 let names_list = val.as_list().ok_or_else(|| {
432 EvalError::bad_form(
433 "require",
434 ":refer needs a parenthesized list of symbols",
435 val.span,
436 )
437 })?;
438 let mut names = Vec::with_capacity(names_list.len());
439 for n in names_list {
440 names.push(Arc::<str>::from(n.as_symbol().ok_or_else(|| {
441 EvalError::bad_form(
442 "require",
443 ":refer list must contain symbols only",
444 n.span,
445 )
446 })?));
447 }
448 refer = Some(names);
449 }
450 other => {
451 return Err(EvalError::bad_form(
452 "require",
453 format!("unknown require option :{other}"),
454 items[i].span,
455 ));
456 }
457 }
458 i += 2;
459 }
460
461 if !self.modules.has(&path) {
463 self.load_module(&path, span, host)?;
464 }
465 let module = self.modules.get(&path).ok_or_else(|| {
466 EvalError::native_fn("require", "module disappeared after load", span)
467 })?;
468
469 let chosen_alias = alias.unwrap_or_else(|| path.clone());
471 for name in &module.exports {
472 let value = module.bindings.get(name).cloned().unwrap_or(Value::Nil);
473 let qualified: Arc<str> = Arc::from(format!("{chosen_alias}/{name}"));
474 self.globals.define(qualified, value);
475 }
476 if let Some(names) = refer {
477 for name in names {
478 if let Some(value) = module.bindings.get(&name) {
479 if module.exports.contains(&name) {
480 self.globals.define(name.clone(), value.clone());
481 } else {
482 return Err(EvalError::User {
483 value: error_value(
484 "not-exported",
485 &format!("{path} does not export {name}"),
486 ),
487 at: span,
488 });
489 }
490 } else {
491 return Err(EvalError::User {
492 value: error_value(
493 "not-defined",
494 &format!("{path} does not define {name}"),
495 ),
496 at: span,
497 });
498 }
499 }
500 }
501 Ok(Value::Nil)
502 }
503
504 fn load_module(&mut self, path: &str, span: Span, host: &mut H) -> Result<()> {
510 self.modules
512 .begin_load(path)
513 .map_err(|e| module_error_to_eval(e, span))?;
514
515 let source = match self.loader.load(path) {
517 Ok(s) => s,
518 Err(e) => {
519 self.modules.abort_load(path);
520 return Err(module_error_to_eval(e, span));
521 }
522 };
523
524 let forms = match tatara_lisp::read_spanned(&source) {
526 Ok(f) => f,
527 Err(e) => {
528 self.modules.abort_load(path);
529 return Err(EvalError::Reader(e));
530 }
531 };
532
533 let saved_globals = std::mem::replace(&mut self.globals, Env::new());
537 for (name, value) in saved_globals.iter_top_level() {
541 if matches!(value, Value::NativeFn(_) | Value::Closure(_)) {
545 self.globals.define(name.clone(), value.clone());
546 }
547 }
548 let saved_current = self.current_module.replace(Arc::from(path));
549
550 let mut eval_err: Option<EvalError> = None;
552 for f in &forms {
553 if let Err(e) = self.eval_top_form(f, host) {
557 eval_err = Some(e);
558 break;
559 }
560 }
561
562 let module_globals = std::mem::replace(&mut self.globals, saved_globals);
564 self.current_module = saved_current;
565
566 if let Some(e) = eval_err {
567 self.modules.abort_load(path);
568 return Err(e);
569 }
570
571 let mut module = Module::new(path);
574 for (name, value) in module_globals.iter_top_level() {
575 if !matches!(value, Value::NativeFn(_)) {
578 module.define(name.clone(), value.clone());
579 }
580 }
581 let staged = {
583 let mut g = self.modules.inner_lock();
584 g.exports_staging.remove(path).unwrap_or_default()
585 };
586 for n in staged {
587 module.add_export(n);
588 }
589 self.modules.finish_load(module);
590 Ok(())
591 }
592
593 pub fn fully_expand(&mut self, form: &Spanned, host: &mut H) -> Result<Spanned> {
604 if self.expander.is_empty() {
606 return Ok(form.clone());
607 }
608 self.expand_recursive(form, host)
609 }
610
611 fn expand_recursive(&mut self, form: &Spanned, host: &mut H) -> Result<Spanned> {
612 self.expand_at_depth(form, host, 0)
613 }
614
615 fn expand_at_depth(&mut self, form: &Spanned, host: &mut H, depth: usize) -> Result<Spanned> {
632 match &form.form {
633 SpannedForm::List(items) if !items.is_empty() => {
634 if let Some(head) = items[0].as_symbol() {
635 if self.expander.has(head) {
636 if depth >= self.macro_expansion_limit {
637 return Err(EvalError::MacroExpansionLimit {
642 macro_name: head.into(),
643 limit: self.macro_expansion_limit,
644 at: form.span,
645 });
646 }
647 let expanded =
651 self.expand_macro_call(head, &items[1..], form.span, host)?;
652 return self.expand_at_depth(&expanded, host, depth + 1);
653 }
654 }
655 let mut out = Vec::with_capacity(items.len());
659 for child in items {
660 out.push(self.expand_at_depth(child, host, depth)?);
661 }
662 Ok(Spanned::new(form.span, SpannedForm::List(out)))
663 }
664 SpannedForm::Quote(_) => {
665 Ok(form.clone())
667 }
668 SpannedForm::Quasiquote(inner) => {
669 Ok(Spanned::new(
671 form.span,
672 SpannedForm::Quasiquote(Box::new(self.expand_inside_quasiquote(inner, host)?)),
673 ))
674 }
675 _ => Ok(form.clone()),
677 }
678 }
679
680 fn expand_inside_quasiquote(&mut self, form: &Spanned, host: &mut H) -> Result<Spanned> {
681 match &form.form {
682 SpannedForm::Unquote(inner) => Ok(Spanned::new(
683 form.span,
684 SpannedForm::Unquote(Box::new(self.expand_recursive(inner, host)?)),
685 )),
686 SpannedForm::UnquoteSplice(inner) => Ok(Spanned::new(
687 form.span,
688 SpannedForm::UnquoteSplice(Box::new(self.expand_recursive(inner, host)?)),
689 )),
690 SpannedForm::List(items) => {
691 let mut out = Vec::with_capacity(items.len());
692 for item in items {
693 out.push(self.expand_inside_quasiquote(item, host)?);
694 }
695 Ok(Spanned::new(form.span, SpannedForm::List(out)))
696 }
697 _ => Ok(form.clone()),
698 }
699 }
700
701 fn expand_macro_call(
705 &mut self,
706 macro_name: &str,
707 args: &[Spanned],
708 call_span: Span,
709 host: &mut H,
710 ) -> Result<Spanned> {
711 let def: MacroDef = self
714 .expander
715 .get_macro(macro_name)
716 .cloned()
717 .ok_or_else(|| {
718 EvalError::native_fn(
719 Arc::<str>::from(macro_name),
720 "macro disappeared during expansion",
721 call_span,
722 )
723 })?;
724
725 let body_spanned = Spanned::from_sexp_at(&def.body, call_span);
730
731 let body_expanded = self.fully_expand(&body_spanned, host)?;
737
738 let mut macro_env = self.globals.sealed_below_top(Seal::MacroExpansion);
746 bind_macro_args(&mut macro_env, &def.name, &def.params, args, call_span)?;
747
748 let result = eval_in(
751 &mut macro_env,
752 &self.registry,
753 &self.expander,
754 &body_expanded,
755 host,
756 )?;
757
758 value_to_spanned(&result, call_span).map_err(|reason| {
762 EvalError::native_fn(
763 Arc::<str>::from(format!("macro {macro_name}")),
764 reason,
765 call_span,
766 )
767 })
768 }
769
770 pub fn expander(&self) -> &SpannedExpander {
773 &self.expander
774 }
775
776 pub fn expander_mut(&mut self) -> &mut SpannedExpander {
780 &mut self.expander
781 }
782
783 pub fn lookup_global(&self, name: &str) -> Option<Value> {
785 self.globals.lookup(name)
786 }
787
788 pub fn define_global(&mut self, name: impl Into<Arc<str>>, value: Value) {
790 self.globals.define(name, value);
791 }
792
793 pub fn globals_snapshot(&self) -> &Env {
796 &self.globals
797 }
798
799 #[must_use]
821 pub fn resolve_head(&self, name: &str) -> Option<HeadBinding> {
822 if SpecialForm::from_symbol(name).is_some() {
823 Some(HeadBinding::SpecialForm)
824 } else if self.expander.has(name) {
825 Some(HeadBinding::Macro)
826 } else if self.globals.lookup(name).is_some() {
827 Some(HeadBinding::Value)
828 } else {
829 None
830 }
831 }
832
833 #[must_use]
840 pub fn reserved_head_names(&self) -> std::collections::BTreeSet<Arc<str>> {
841 let mut out: std::collections::BTreeSet<Arc<str>> = SpecialForm::ALL
842 .iter()
843 .map(|sf| Arc::from(sf.symbol()))
844 .collect();
845 out.extend(
846 self.expander
847 .macro_names()
848 .map(Arc::from)
849 .collect::<Vec<Arc<str>>>(),
850 );
851 out.extend(self.globals.iter_top_level().into_iter().map(|(n, _)| n));
852 out
853 }
854
855 pub fn apply_external_value(
859 &mut self,
860 callee: &Value,
861 args: Vec<Value>,
862 host: &mut H,
863 call_span: Span,
864 ) -> Result<Value> {
865 apply_external(
866 callee,
867 args,
868 call_span,
869 &self.registry,
870 &self.expander,
871 host,
872 )
873 }
874
875 pub fn expand_program(&mut self, forms: &[Spanned], host: &mut H) -> Result<Vec<Spanned>> {
894 let mut expanded: Vec<Spanned> = Vec::with_capacity(forms.len());
895 for form in forms {
896 if self.expander.try_register_macro(form)? {
897 continue;
898 }
899 expanded.push(self.fully_expand(form, host)?);
900 }
901 Ok(expanded)
902 }
903
904 pub fn eval_program_vm(&mut self, forms: &[Spanned], host: &mut H) -> Result<Value> {
911 let expanded = self.expand_program(forms, host)?;
912 let chunk = crate::vm::compile_program(&expanded).map_err(|e| match e {
913 crate::vm::CompileError::Bad { at, message } => {
914 EvalError::bad_form(Arc::<str>::from("vm:compile"), message, at)
915 }
916 })?;
917 let mut vm = crate::vm::Vm::new();
918 vm.run(&chunk, self, host).map_err(|e| match e {
919 crate::vm::VmError::Eval(inner) => inner,
920 other => EvalError::native_fn(
921 Arc::<str>::from("vm"),
922 format!("{other}"),
923 Span::synthetic(),
924 ),
925 })
926 }
927
928 pub fn register_typed0<R, F>(&mut self, name: impl Into<Arc<str>>, f: F)
932 where
933 R: IntoValue + 'static,
934 F: Fn(&mut H) -> Result<R> + Send + Sync + 'static,
935 {
936 self.register_fn(
937 name,
938 Arity::Exact(0),
939 move |_args: &[Value], host: &mut H, _sp| f(host).map(IntoValue::into_value),
940 );
941 }
942
943 pub fn register_typed1<A, R, F>(&mut self, name: impl Into<Arc<str>>, f: F)
945 where
946 A: FromValue + 'static,
947 R: IntoValue + 'static,
948 F: Fn(&mut H, A) -> Result<R> + Send + Sync + 'static,
949 {
950 self.register_fn(
951 name,
952 Arity::Exact(1),
953 move |args: &[Value], host: &mut H, sp| {
954 let a = A::from_value(&args[0], sp)?;
955 f(host, a).map(IntoValue::into_value)
956 },
957 );
958 }
959
960 pub fn register_typed2<A, B, R, F>(&mut self, name: impl Into<Arc<str>>, f: F)
962 where
963 A: FromValue + 'static,
964 B: FromValue + 'static,
965 R: IntoValue + 'static,
966 F: Fn(&mut H, A, B) -> Result<R> + Send + Sync + 'static,
967 {
968 self.register_fn(
969 name,
970 Arity::Exact(2),
971 move |args: &[Value], host: &mut H, sp| {
972 let a = A::from_value(&args[0], sp)?;
973 let b = B::from_value(&args[1], sp)?;
974 f(host, a, b).map(IntoValue::into_value)
975 },
976 );
977 }
978
979 pub fn register_typed3<A, B, C, R, F>(&mut self, name: impl Into<Arc<str>>, f: F)
981 where
982 A: FromValue + 'static,
983 B: FromValue + 'static,
984 C: FromValue + 'static,
985 R: IntoValue + 'static,
986 F: Fn(&mut H, A, B, C) -> Result<R> + Send + Sync + 'static,
987 {
988 self.register_fn(
989 name,
990 Arity::Exact(3),
991 move |args: &[Value], host: &mut H, sp| {
992 let a = A::from_value(&args[0], sp)?;
993 let b = B::from_value(&args[1], sp)?;
994 let c = C::from_value(&args[2], sp)?;
995 f(host, a, b, c).map(IntoValue::into_value)
996 },
997 );
998 }
999
1000 pub fn register_typed4<A, B, C, D, R, F>(&mut self, name: impl Into<Arc<str>>, f: F)
1002 where
1003 A: FromValue + 'static,
1004 B: FromValue + 'static,
1005 C: FromValue + 'static,
1006 D: FromValue + 'static,
1007 R: IntoValue + 'static,
1008 F: Fn(&mut H, A, B, C, D) -> Result<R> + Send + Sync + 'static,
1009 {
1010 self.register_fn(
1011 name,
1012 Arity::Exact(4),
1013 move |args: &[Value], host: &mut H, sp| {
1014 let a = A::from_value(&args[0], sp)?;
1015 let b = B::from_value(&args[1], sp)?;
1016 let c = C::from_value(&args[2], sp)?;
1017 let d = D::from_value(&args[3], sp)?;
1018 f(host, a, b, c, d).map(IntoValue::into_value)
1019 },
1020 );
1021 }
1022}
1023
1024impl<H: 'static> Default for Interpreter<H> {
1025 fn default() -> Self {
1026 Self::new()
1027 }
1028}
1029
1030pub(crate) fn eval_in<H: 'static>(
1035 env: &mut Env,
1036 registry: &FnRegistry<H>,
1037 expander: &SpannedExpander,
1038 form: &Spanned,
1039 host: &mut H,
1040) -> Result<Value> {
1041 match &form.form {
1042 SpannedForm::Nil => Ok(Value::Nil),
1043 SpannedForm::Atom(a) => eval_atom(a, form.span, env),
1044 SpannedForm::Quote(inner) => Ok(quoted_value(inner)),
1045 SpannedForm::Quasiquote(inner) => quasiquote_eval(inner, env, registry, expander, host),
1046 SpannedForm::Unquote(_) | SpannedForm::UnquoteSplice(_) => Err(EvalError::bad_form(
1047 "unquote",
1048 "unquote outside of quasiquote",
1049 form.span,
1050 )),
1051 SpannedForm::List(items) => {
1052 if items.is_empty() {
1053 return Ok(Value::Nil);
1054 }
1055 if let Some(head_sym) = items[0].as_symbol() {
1059 if let Some(sf) = SpecialForm::from_symbol(head_sym) {
1060 return eval_special(sf, items, form.span, env, registry, expander, host);
1061 }
1062 }
1063 eval_application(items, form.span, env, registry, expander, host)
1064 }
1065 }
1066}
1067
1068fn eval_atom(a: &Atom, span: Span, env: &Env) -> Result<Value> {
1069 match a {
1070 Atom::Symbol(name) => env
1071 .lookup(name)
1072 .ok_or_else(|| EvalError::unbound(name.as_str(), span)),
1073 Atom::Keyword(s) => Ok(Value::Keyword(crate::interner::intern(s.as_str()))),
1074 Atom::Str(s) => Ok(Value::Str(Arc::from(s.as_str()))),
1075 Atom::Int(n) => Ok(Value::Int(*n)),
1076 Atom::Float(n) => Ok(Value::Float(*n)),
1077 Atom::Bool(b) => Ok(Value::Bool(*b)),
1078 }
1079}
1080
1081fn quoted_value(inner: &Spanned) -> Value {
1085 crate::code::spanned_to_value(inner)
1086}
1087
1088fn quasiquote_eval<H: 'static>(
1094 form: &Spanned,
1095 env: &mut Env,
1096 registry: &FnRegistry<H>,
1097 expander: &SpannedExpander,
1098 host: &mut H,
1099) -> Result<Value> {
1100 match &form.form {
1101 SpannedForm::Unquote(inner) => eval_in(env, registry, expander, inner, host),
1102 SpannedForm::UnquoteSplice(_) => Err(EvalError::bad_form(
1103 "unquote-splice",
1104 "`,@` only valid directly inside a list",
1105 form.span,
1106 )),
1107 SpannedForm::List(items) => {
1108 let mut out: Vec<Value> = Vec::with_capacity(items.len());
1109 for item in items {
1110 if let SpannedForm::UnquoteSplice(inner) = &item.form {
1111 let v = eval_in(env, registry, expander, inner, host)?;
1112 match v {
1113 Value::List(xs) => out.extend(xs.iter().cloned()),
1114 Value::Nil => {}
1115 other => {
1116 return Err(EvalError::type_mismatch(
1117 "list",
1118 other.type_name(),
1119 item.span,
1120 ))
1121 }
1122 }
1123 } else {
1124 out.push(quasiquote_eval(item, env, registry, expander, host)?);
1125 }
1126 }
1127 if out.is_empty() {
1128 Ok(Value::Nil)
1129 } else {
1130 Ok(Value::list(out))
1131 }
1132 }
1133 SpannedForm::Nil => Ok(Value::Nil),
1134 SpannedForm::Atom(a) => Ok(match a {
1135 Atom::Symbol(s) => Value::Symbol(crate::interner::intern(s.as_str())),
1136 Atom::Keyword(s) => Value::Keyword(crate::interner::intern(s.as_str())),
1137 Atom::Str(s) => Value::Str(Arc::from(s.as_str())),
1138 Atom::Int(n) => Value::Int(*n),
1139 Atom::Float(n) => Value::Float(*n),
1140 Atom::Bool(b) => Value::Bool(*b),
1141 }),
1142 SpannedForm::Quote(_) | SpannedForm::Quasiquote(_) => {
1146 Ok(Value::Sexp(form.to_sexp(), form.span))
1147 }
1148 }
1149}
1150
1151fn eval_application<H: 'static>(
1154 items: &[Spanned],
1155 call_span: Span,
1156 env: &mut Env,
1157 registry: &FnRegistry<H>,
1158 expander: &SpannedExpander,
1159 host: &mut H,
1160) -> Result<Value> {
1161 let head_val = eval_in(env, registry, expander, &items[0], host)?;
1162 let mut args: Vec<Value> = Vec::with_capacity(items.len().saturating_sub(1));
1163 for arg_form in &items[1..] {
1164 args.push(eval_in(env, registry, expander, arg_form, host)?);
1165 }
1166 apply(&head_val, args, call_span, registry, expander, host)
1167}
1168
1169fn apply<H: 'static>(
1170 callee: &Value,
1171 args: Vec<Value>,
1172 call_span: Span,
1173 registry: &FnRegistry<H>,
1174 expander: &SpannedExpander,
1175 host: &mut H,
1176) -> Result<Value> {
1177 match callee {
1178 Value::NativeFn(nfn) => {
1179 if nfn.arity.check(args.len()).is_err() {
1180 return Err(EvalError::ArityMismatch {
1181 fn_name: nfn.name.clone(),
1182 expected: nfn.arity,
1183 got: args.len(),
1184 at: call_span,
1185 });
1186 }
1187 let entry = registry.lookup(&nfn.name).ok_or_else(|| {
1188 EvalError::native_fn(
1189 nfn.name.clone(),
1190 format!("native fn {} is not registered", nfn.name),
1191 call_span,
1192 )
1193 })?;
1194 match &entry.callable {
1195 FnImpl::Native(f) => f.call(&args, host, call_span),
1196 FnImpl::Higher(f) => {
1197 let caller = Caller { registry, expander };
1198 f.call(&args, host, &caller, call_span)
1199 }
1200 FnImpl::Awaitable(f) => {
1205 if f.ready(&args, host) {
1206 f.call(&args, host, call_span)
1207 } else {
1208 Ok(crate::vm::Vm::park())
1209 }
1210 }
1211 }
1212 }
1213 Value::Closure(c) => call_closure(c.clone(), args, call_span, registry, expander, host),
1214 Value::Foreign(any) => {
1219 if let Some(cc) = any
1220 .clone()
1221 .downcast::<crate::vm::run::CompiledClosure>()
1222 .ok()
1223 {
1224 let lifted = cc.lift_to_closure();
1225 return call_closure(lifted, args, call_span, registry, expander, host);
1226 }
1227 Err(EvalError::NotCallable {
1228 value_kind: callee.type_name(),
1229 at: call_span,
1230 })
1231 }
1232 other => Err(EvalError::NotCallable {
1233 value_kind: other.type_name(),
1234 at: call_span,
1235 }),
1236 }
1237}
1238
1239enum TailResult {
1262 Done(Value),
1264 Resume(Arc<Closure>, Vec<Value>, Span),
1269}
1270
1271fn eval_in_tail<H: 'static>(
1275 env: &mut Env,
1276 registry: &FnRegistry<H>,
1277 expander: &SpannedExpander,
1278 form: &Spanned,
1279 host: &mut H,
1280) -> Result<TailResult> {
1281 match &form.form {
1282 SpannedForm::List(items) if !items.is_empty() => {
1283 if let Some(head_sym) = items[0].as_symbol() {
1285 if let Some(sf) = SpecialForm::from_symbol(head_sym) {
1286 return eval_special_tail(sf, items, form.span, env, registry, expander, host);
1287 }
1288 }
1289 let head_val = eval_in(env, registry, expander, &items[0], host)?;
1292 let mut args: Vec<Value> = Vec::with_capacity(items.len().saturating_sub(1));
1293 for arg_form in &items[1..] {
1294 args.push(eval_in(env, registry, expander, arg_form, host)?);
1295 }
1296 match head_val {
1297 Value::Closure(c) => Ok(TailResult::Resume(c, args, form.span)),
1298 _ => apply(&head_val, args, form.span, registry, expander, host)
1299 .map(TailResult::Done),
1300 }
1301 }
1302 _ => eval_in(env, registry, expander, form, host).map(TailResult::Done),
1304 }
1305}
1306
1307fn eval_special_tail<H: 'static>(
1308 sf: SpecialForm,
1309 items: &[Spanned],
1310 call_span: Span,
1311 env: &mut Env,
1312 registry: &FnRegistry<H>,
1313 expander: &SpannedExpander,
1314 host: &mut H,
1315) -> Result<TailResult> {
1316 match sf {
1317 SpecialForm::If => {
1318 if items.len() < 3 || items.len() > 4 {
1319 return eval_special(sf, items, call_span, env, registry, expander, host)
1320 .map(TailResult::Done);
1321 }
1322 let c = eval_in(env, registry, expander, &items[1], host)?;
1323 if c.is_truthy() {
1324 eval_in_tail(env, registry, expander, &items[2], host)
1325 } else if items.len() == 4 {
1326 eval_in_tail(env, registry, expander, &items[3], host)
1327 } else {
1328 Ok(TailResult::Done(Value::Nil))
1329 }
1330 }
1331 SpecialForm::Begin => {
1332 let body = &items[1..];
1333 if body.is_empty() {
1334 return Ok(TailResult::Done(Value::Nil));
1335 }
1336 for form in &body[..body.len() - 1] {
1337 eval_in(env, registry, expander, form, host)?;
1338 }
1339 eval_in_tail(env, registry, expander, body.last().unwrap(), host)
1340 }
1341 SpecialForm::When | SpecialForm::Unless => {
1342 if items.len() < 2 {
1343 return eval_special(sf, items, call_span, env, registry, expander, host)
1344 .map(TailResult::Done);
1345 }
1346 let invert = matches!(sf, SpecialForm::Unless);
1347 let cond = eval_in(env, registry, expander, &items[1], host)?;
1348 let run = cond.is_truthy() ^ invert;
1349 if !run {
1350 return Ok(TailResult::Done(Value::Nil));
1351 }
1352 let body = &items[2..];
1353 if body.is_empty() {
1354 return Ok(TailResult::Done(Value::Nil));
1355 }
1356 for form in &body[..body.len() - 1] {
1357 eval_in(env, registry, expander, form, host)?;
1358 }
1359 eval_in_tail(env, registry, expander, body.last().unwrap(), host)
1360 }
1361 SpecialForm::Cond => {
1362 for clause in &items[1..] {
1363 let Some(clause_list) = clause.as_list() else {
1364 return eval_special(sf, items, call_span, env, registry, expander, host)
1365 .map(TailResult::Done);
1366 };
1367 if clause_list.is_empty() {
1368 return eval_special(sf, items, call_span, env, registry, expander, host)
1369 .map(TailResult::Done);
1370 }
1371 let is_else = clause_list[0].as_symbol() == Some("else");
1372 let cond_matches = if is_else {
1373 true
1374 } else {
1375 eval_in(env, registry, expander, &clause_list[0], host)?.is_truthy()
1376 };
1377 if cond_matches {
1378 let body = &clause_list[1..];
1379 if body.is_empty() {
1380 return Ok(TailResult::Done(Value::Nil));
1381 }
1382 for form in &body[..body.len() - 1] {
1383 eval_in(env, registry, expander, form, host)?;
1384 }
1385 return eval_in_tail(env, registry, expander, body.last().unwrap(), host);
1386 }
1387 }
1388 Ok(TailResult::Done(Value::Nil))
1389 }
1390 SpecialForm::Let | SpecialForm::LetStar | SpecialForm::LetRec => {
1391 eval_let_family_tail(sf, items, call_span, env, registry, expander, host)
1392 }
1393 SpecialForm::And => {
1394 let exprs = &items[1..];
1395 if exprs.is_empty() {
1396 return Ok(TailResult::Done(Value::Bool(true)));
1397 }
1398 for e in &exprs[..exprs.len() - 1] {
1400 let v = eval_in(env, registry, expander, e, host)?;
1401 if !v.is_truthy() {
1402 return Ok(TailResult::Done(v));
1403 }
1404 }
1405 eval_in_tail(env, registry, expander, exprs.last().unwrap(), host)
1407 }
1408 SpecialForm::Or => {
1409 let exprs = &items[1..];
1410 if exprs.is_empty() {
1411 return Ok(TailResult::Done(Value::Bool(false)));
1412 }
1413 for e in &exprs[..exprs.len() - 1] {
1414 let v = eval_in(env, registry, expander, e, host)?;
1415 if v.is_truthy() {
1416 return Ok(TailResult::Done(v));
1417 }
1418 }
1419 eval_in_tail(env, registry, expander, exprs.last().unwrap(), host)
1420 }
1421 SpecialForm::Try => {
1422 sf_try(items, call_span, env, registry, expander, host).map(TailResult::Done)
1428 }
1429 SpecialForm::MacroexpandOne => {
1430 sf_macroexpand(items, call_span, env, registry, expander, host, false)
1431 .map(TailResult::Done)
1432 }
1433 SpecialForm::MacroexpandAll => {
1434 sf_macroexpand(items, call_span, env, registry, expander, host, true)
1435 .map(TailResult::Done)
1436 }
1437 SpecialForm::Delay => sf_delay(items, call_span, env).map(TailResult::Done),
1438 SpecialForm::Eval => {
1439 sf_eval(items, call_span, env, registry, expander, host).map(TailResult::Done)
1440 }
1441 _ => {
1443 eval_special(sf, items, call_span, env, registry, expander, host).map(TailResult::Done)
1444 }
1445 }
1446}
1447
1448fn eval_let_family_tail<H: 'static>(
1452 sf: SpecialForm,
1453 items: &[Spanned],
1454 call_span: Span,
1455 env: &mut Env,
1456 registry: &FnRegistry<H>,
1457 expander: &SpannedExpander,
1458 host: &mut H,
1459) -> Result<TailResult> {
1460 if items.len() < 3 {
1461 return Err(EvalError::bad_form(
1462 match sf {
1463 SpecialForm::Let => "let",
1464 SpecialForm::LetStar => "let*",
1465 SpecialForm::LetRec => "letrec",
1466 _ => "let-family",
1467 },
1468 "expected ((name expr)...) body...",
1469 call_span,
1470 ));
1471 }
1472 let bindings = parse_binding_list(
1473 &items[1],
1474 match sf {
1475 SpecialForm::Let => "let",
1476 SpecialForm::LetStar => "let*",
1477 SpecialForm::LetRec => "letrec",
1478 _ => "let-family",
1479 },
1480 )?;
1481
1482 match sf {
1483 SpecialForm::Let => {
1484 let mut values = Vec::with_capacity(bindings.len());
1485 for (_, expr) in &bindings {
1486 values.push(eval_in(env, registry, expander, expr, host)?);
1487 }
1488 env.push();
1489 for ((name, _), val) in bindings.into_iter().zip(values) {
1490 env.define(name, val);
1491 }
1492 }
1493 SpecialForm::LetStar => {
1494 env.push();
1495 for (name, expr) in bindings {
1496 let v = eval_in(env, registry, expander, expr, host)?;
1497 env.define(name, v);
1498 }
1499 }
1500 SpecialForm::LetRec => {
1501 env.push();
1502 for (name, _) in &bindings {
1503 env.define(name.clone(), Value::Nil);
1504 }
1505 for (name, expr) in &bindings {
1506 let v = eval_in(env, registry, expander, expr, host)?;
1507 env.define(name.clone(), v);
1508 }
1509 }
1510 _ => unreachable!(),
1511 }
1512
1513 let body = &items[2..];
1514 let result = if body.is_empty() {
1515 Ok(TailResult::Done(Value::Nil))
1516 } else {
1517 for form in &body[..body.len() - 1] {
1518 if let Err(e) = eval_in(env, registry, expander, form, host) {
1519 env.pop();
1520 return Err(e);
1521 }
1522 }
1523 eval_in_tail(env, registry, expander, body.last().unwrap(), host)
1524 };
1525 env.pop();
1526 result
1527}
1528
1529pub(crate) fn apply_external<H: 'static>(
1535 callee: &Value,
1536 args: Vec<Value>,
1537 call_span: Span,
1538 registry: &FnRegistry<H>,
1539 expander: &SpannedExpander,
1540 host: &mut H,
1541) -> Result<Value> {
1542 apply(callee, args, call_span, registry, expander, host)
1543}
1544
1545fn bind_macro_args(
1554 env: &mut Env,
1555 macro_name: &str,
1556 params: &MacroParams,
1557 args: &[Spanned],
1558 call_span: Span,
1559) -> Result<()> {
1560 let bound = params
1561 .bind_carrier(macro_name, args, call_span)
1562 .map_err(|e| {
1563 EvalError::native_fn(
1564 Arc::<str>::from(format!("macro {macro_name}")),
1565 e.to_string(),
1566 call_span,
1567 )
1568 })?;
1569 for (name, value) in params.names().into_iter().zip(bound.iter()) {
1570 env.define(Arc::<str>::from(name), spanned_to_value(value));
1571 }
1572 Ok(())
1573}
1574
1575fn call_closure<H: 'static>(
1580 closure: Arc<Closure>,
1581 args: Vec<Value>,
1582 call_span: Span,
1583 registry: &FnRegistry<H>,
1584 expander: &SpannedExpander,
1585 host: &mut H,
1586) -> Result<Value> {
1587 let mut current = closure;
1588 let mut current_args = args;
1589 let mut current_span = call_span;
1590 loop {
1591 let required = current.params.len();
1593 let has_rest = current.rest.is_some();
1594 if !has_rest && current_args.len() != required {
1595 return Err(EvalError::ArityMismatch {
1596 fn_name: Arc::from("<closure>"),
1597 expected: Arity::Exact(required),
1598 got: current_args.len(),
1599 at: current_span,
1600 });
1601 }
1602 if has_rest && current_args.len() < required {
1603 return Err(EvalError::ArityMismatch {
1604 fn_name: Arc::from("<closure>"),
1605 expected: Arity::AtLeast(required),
1606 got: current_args.len(),
1607 at: current_span,
1608 });
1609 }
1610
1611 let mut env = current.captured_env.clone();
1614 env.push();
1615 for (param, arg) in current.params.iter().zip(current_args.iter()) {
1616 env.define(param.clone(), arg.clone());
1617 }
1618 if let Some(rest_name) = ¤t.rest {
1619 let rest_args: Vec<Value> = current_args.iter().skip(required).cloned().collect();
1620 env.define(rest_name.clone(), Value::list(rest_args));
1621 }
1622
1623 let body = ¤t.body;
1626 if body.is_empty() {
1627 return Ok(Value::Nil);
1628 }
1629 for body_form in &body[..body.len() - 1] {
1630 eval_in(&mut env, registry, expander, body_form, host)?;
1631 }
1632 match eval_in_tail(&mut env, registry, expander, body.last().unwrap(), host)? {
1633 TailResult::Done(v) => return Ok(v),
1634 TailResult::Resume(next, next_args, next_span) => {
1635 current = next;
1638 current_args = next_args;
1639 current_span = next_span;
1640 }
1641 }
1642 }
1643}
1644
1645fn eval_special<H: 'static>(
1648 sf: SpecialForm,
1649 items: &[Spanned],
1650 call_span: Span,
1651 env: &mut Env,
1652 registry: &FnRegistry<H>,
1653 expander: &SpannedExpander,
1654 host: &mut H,
1655) -> Result<Value> {
1656 match sf {
1657 SpecialForm::Quote => sf_quote(items, call_span),
1658 SpecialForm::Quasiquote => {
1659 if items.len() != 2 {
1660 return Err(EvalError::bad_form(
1661 "quasiquote",
1662 format!("expected 1 arg, got {}", items.len() - 1),
1663 call_span,
1664 ));
1665 }
1666 quasiquote_eval(&items[1], env, registry, expander, host)
1667 }
1668 SpecialForm::If => sf_if(items, call_span, env, registry, expander, host),
1669 SpecialForm::Cond => sf_cond(items, call_span, env, registry, expander, host),
1670 SpecialForm::When => sf_when_unless(items, call_span, env, registry, expander, host, false),
1671 SpecialForm::Unless => {
1672 sf_when_unless(items, call_span, env, registry, expander, host, true)
1673 }
1674 SpecialForm::Let => sf_let(items, call_span, env, registry, expander, host),
1675 SpecialForm::LetStar => sf_let_star(items, call_span, env, registry, expander, host),
1676 SpecialForm::LetRec => sf_letrec(items, call_span, env, registry, expander, host),
1677 SpecialForm::Lambda => sf_lambda(items, call_span, env),
1678 SpecialForm::Define => sf_define(items, call_span, env, registry, expander, host),
1679 SpecialForm::Set => sf_set(items, call_span, env, registry, expander, host),
1680 SpecialForm::Begin => sf_begin(&items[1..], env, registry, expander, host),
1681 SpecialForm::And => sf_and(&items[1..], env, registry, expander, host),
1682 SpecialForm::Or => sf_or(&items[1..], env, registry, expander, host),
1683 SpecialForm::Not => sf_not(items, call_span, env, registry, expander, host),
1684 SpecialForm::Try => sf_try(items, call_span, env, registry, expander, host),
1685 SpecialForm::MacroexpandOne => {
1686 sf_macroexpand(items, call_span, env, registry, expander, host, false)
1687 }
1688 SpecialForm::MacroexpandAll => {
1689 sf_macroexpand(items, call_span, env, registry, expander, host, true)
1690 }
1691 SpecialForm::Delay => sf_delay(items, call_span, env),
1692 SpecialForm::Eval => sf_eval(items, call_span, env, registry, expander, host),
1693 SpecialForm::Provide | SpecialForm::Require => Err(EvalError::bad_form(
1694 if matches!(sf, SpecialForm::Provide) { "provide" } else { "require" },
1695 "module-system forms are only valid at top level — wrap your call in (eval (quote ...)) if you really need it dynamic",
1696 call_span,
1697 )),
1698 }
1699}
1700
1701fn head_symbol(form: &Spanned) -> Option<&str> {
1705 let SpannedForm::List(items) = &form.form else {
1706 return None;
1707 };
1708 items.first().and_then(Spanned::as_symbol)
1709}
1710
1711fn error_value(tag: &str, message: &str) -> Value {
1713 Value::Error(Arc::new(ErrorObj {
1714 tag: Arc::from(tag),
1715 message: Arc::from(message),
1716 data: Vec::new(),
1717 }))
1718}
1719
1720fn module_error_to_eval(e: ModuleError, span: Span) -> EvalError {
1724 let (tag, message) = match &e {
1725 ModuleError::NotFound(_) => ("module-not-found", e.to_string()),
1726 ModuleError::Circular { .. } => ("circular-require", e.to_string()),
1727 ModuleError::NotExported(_, _) => ("not-exported", e.to_string()),
1728 ModuleError::Denied { .. } => ("module-denied", e.to_string()),
1732 };
1733 EvalError::User {
1734 value: error_value(tag, &message),
1735 at: span,
1736 }
1737}
1738
1739fn sf_quote(items: &[Spanned], span: Span) -> Result<Value> {
1740 if items.len() != 2 {
1741 return Err(EvalError::bad_form(
1742 "quote",
1743 format!("expected 1 arg, got {}", items.len() - 1),
1744 span,
1745 ));
1746 }
1747 Ok(crate::code::spanned_to_value(&items[1]))
1753}
1754
1755fn sf_if<H: 'static>(
1756 items: &[Spanned],
1757 span: Span,
1758 env: &mut Env,
1759 registry: &FnRegistry<H>,
1760 expander: &SpannedExpander,
1761 host: &mut H,
1762) -> Result<Value> {
1763 if items.len() < 3 || items.len() > 4 {
1764 return Err(EvalError::bad_form(
1765 "if",
1766 format!("expected (if c t [e]), got {} subforms", items.len()),
1767 span,
1768 ));
1769 }
1770 let c = eval_in(env, registry, expander, &items[1], host)?;
1771 if c.is_truthy() {
1772 eval_in(env, registry, expander, &items[2], host)
1773 } else if items.len() == 4 {
1774 eval_in(env, registry, expander, &items[3], host)
1775 } else {
1776 Ok(Value::Nil)
1777 }
1778}
1779
1780fn sf_cond<H: 'static>(
1781 items: &[Spanned],
1782 span: Span,
1783 env: &mut Env,
1784 registry: &FnRegistry<H>,
1785 expander: &SpannedExpander,
1786 host: &mut H,
1787) -> Result<Value> {
1788 for clause in &items[1..] {
1789 let Some(clause_list) = clause.as_list() else {
1790 return Err(EvalError::bad_form(
1791 "cond",
1792 "clause must be a list",
1793 clause.span,
1794 ));
1795 };
1796 if clause_list.is_empty() {
1797 return Err(EvalError::bad_form("cond", "empty clause", clause.span));
1798 }
1799 let is_else = clause_list[0].as_symbol() == Some("else");
1800 let cond_matches = if is_else {
1801 true
1802 } else {
1803 let v = eval_in(env, registry, expander, &clause_list[0], host)?;
1804 v.is_truthy()
1805 };
1806 if cond_matches {
1807 let mut last = Value::Nil;
1808 for expr in &clause_list[1..] {
1809 last = eval_in(env, registry, expander, expr, host)?;
1810 }
1811 return Ok(last);
1812 }
1813 }
1814 let _ = span;
1816 Ok(Value::Nil)
1817}
1818
1819fn sf_when_unless<H: 'static>(
1820 items: &[Spanned],
1821 span: Span,
1822 env: &mut Env,
1823 registry: &FnRegistry<H>,
1824 expander: &SpannedExpander,
1825 host: &mut H,
1826 invert: bool,
1827) -> Result<Value> {
1828 if items.len() < 2 {
1829 return Err(EvalError::bad_form(
1830 if invert { "unless" } else { "when" },
1831 "need a test",
1832 span,
1833 ));
1834 }
1835 let cond = eval_in(env, registry, expander, &items[1], host)?;
1836 let run = cond.is_truthy() ^ invert;
1837 if run {
1838 let mut last = Value::Nil;
1839 for expr in &items[2..] {
1840 last = eval_in(env, registry, expander, expr, host)?;
1841 }
1842 Ok(last)
1843 } else {
1844 Ok(Value::Nil)
1845 }
1846}
1847
1848fn parse_binding_list<'a>(
1850 list: &'a Spanned,
1851 form_name: &'static str,
1852) -> Result<Vec<(Arc<str>, &'a Spanned)>> {
1853 let bindings = list
1854 .as_list()
1855 .ok_or_else(|| EvalError::bad_form(form_name, "bindings must be a list", list.span))?;
1856 let mut out = Vec::with_capacity(bindings.len());
1857 for binding in bindings {
1858 let pair = binding.as_list().ok_or_else(|| {
1859 EvalError::bad_form(form_name, "each binding must be (name expr)", binding.span)
1860 })?;
1861 if pair.len() != 2 {
1862 return Err(EvalError::bad_form(
1863 form_name,
1864 "binding must be exactly (name expr)",
1865 binding.span,
1866 ));
1867 }
1868 let name = pair[0].as_symbol().ok_or_else(|| {
1869 EvalError::bad_form(form_name, "binding name must be a symbol", pair[0].span)
1870 })?;
1871 out.push((Arc::<str>::from(name), &pair[1]));
1872 }
1873 Ok(out)
1874}
1875
1876fn sf_let<H: 'static>(
1877 items: &[Spanned],
1878 span: Span,
1879 env: &mut Env,
1880 registry: &FnRegistry<H>,
1881 expander: &SpannedExpander,
1882 host: &mut H,
1883) -> Result<Value> {
1884 if items.len() < 3 {
1885 return Err(EvalError::bad_form(
1886 "let",
1887 "expected (let ((name expr)...) body...)",
1888 span,
1889 ));
1890 }
1891 let bindings = parse_binding_list(&items[1], "let")?;
1892 let mut values = Vec::with_capacity(bindings.len());
1895 for (_, expr) in &bindings {
1896 values.push(eval_in(env, registry, expander, expr, host)?);
1897 }
1898 env.push();
1899 for ((name, _), val) in bindings.into_iter().zip(values) {
1900 env.define(name, val);
1901 }
1902 let result = eval_body(&items[2..], env, registry, expander, host);
1903 env.pop();
1904 result
1905}
1906
1907fn sf_let_star<H: 'static>(
1908 items: &[Spanned],
1909 span: Span,
1910 env: &mut Env,
1911 registry: &FnRegistry<H>,
1912 expander: &SpannedExpander,
1913 host: &mut H,
1914) -> Result<Value> {
1915 if items.len() < 3 {
1916 return Err(EvalError::bad_form(
1917 "let*",
1918 "expected (let* ((name expr)...) body...)",
1919 span,
1920 ));
1921 }
1922 let bindings = parse_binding_list(&items[1], "let*")?;
1923 env.push();
1924 for (name, expr) in bindings {
1925 let v = eval_in(env, registry, expander, expr, host)?;
1926 env.define(name, v);
1927 }
1928 let result = eval_body(&items[2..], env, registry, expander, host);
1929 env.pop();
1930 result
1931}
1932
1933fn sf_letrec<H: 'static>(
1934 items: &[Spanned],
1935 span: Span,
1936 env: &mut Env,
1937 registry: &FnRegistry<H>,
1938 expander: &SpannedExpander,
1939 host: &mut H,
1940) -> Result<Value> {
1941 if items.len() < 3 {
1942 return Err(EvalError::bad_form(
1943 "letrec",
1944 "expected (letrec ((name expr)...) body...)",
1945 span,
1946 ));
1947 }
1948 let bindings = parse_binding_list(&items[1], "letrec")?;
1949 env.push();
1950 for (name, _) in &bindings {
1953 env.define(name.clone(), Value::Nil);
1954 }
1955 for (name, expr) in &bindings {
1956 let v = eval_in(env, registry, expander, expr, host)?;
1957 env.define(name.clone(), v);
1958 }
1959 let result = eval_body(&items[2..], env, registry, expander, host);
1960 env.pop();
1961 result
1962}
1963
1964fn eval_body<H: 'static>(
1965 body: &[Spanned],
1966 env: &mut Env,
1967 registry: &FnRegistry<H>,
1968 expander: &SpannedExpander,
1969 host: &mut H,
1970) -> Result<Value> {
1971 let mut last = Value::Nil;
1972 for form in body {
1973 last = eval_in(env, registry, expander, form, host)?;
1974 }
1975 Ok(last)
1976}
1977
1978fn sf_lambda(items: &[Spanned], span: Span, env: &Env) -> Result<Value> {
1979 if items.len() < 3 {
1980 return Err(EvalError::bad_form(
1981 "lambda",
1982 "expected (lambda (params...) body...)",
1983 span,
1984 ));
1985 }
1986 let param_list: &[Spanned] = match &items[1].form {
1989 SpannedForm::Nil => &[],
1990 SpannedForm::List(xs) => xs.as_slice(),
1991 _ => {
1992 return Err(EvalError::bad_form(
1993 "lambda",
1994 "params must be a list",
1995 items[1].span,
1996 ))
1997 }
1998 };
1999 let (params, rest) = parse_lambda_params(param_list, items[1].span)?;
2000 let body = items[2..].to_vec();
2001 Ok(Value::Closure(Arc::new(Closure {
2002 params,
2003 rest,
2004 body,
2005 captured_env: env.clone(),
2006 source: span,
2007 })))
2008}
2009
2010fn parse_lambda_params(list: &[Spanned], span: Span) -> Result<(Vec<Arc<str>>, Option<Arc<str>>)> {
2011 let mut params = Vec::new();
2012 let mut rest = None;
2013 let mut i = 0;
2014 while i < list.len() {
2015 let s = list[i]
2016 .as_symbol()
2017 .ok_or_else(|| EvalError::bad_form("lambda", "param must be a symbol", list[i].span))?;
2018 if s == "&rest" {
2019 let name = list
2020 .get(i + 1)
2021 .and_then(Spanned::as_symbol)
2022 .ok_or_else(|| EvalError::bad_form("lambda", "&rest needs a name", span))?;
2023 rest = Some(Arc::<str>::from(name));
2024 if i + 2 != list.len() {
2025 return Err(EvalError::bad_form(
2026 "lambda",
2027 "&rest must be the last param",
2028 span,
2029 ));
2030 }
2031 break;
2032 }
2033 params.push(Arc::<str>::from(s));
2034 i += 1;
2035 }
2036 Ok((params, rest))
2037}
2038
2039fn sf_define<H: 'static>(
2041 items: &[Spanned],
2042 span: Span,
2043 env: &mut Env,
2044 registry: &FnRegistry<H>,
2045 expander: &SpannedExpander,
2046 host: &mut H,
2047) -> Result<Value> {
2048 if items.len() < 3 {
2049 return Err(EvalError::bad_form(
2050 "define",
2051 "expected (define name expr) or (define (name args) body)",
2052 span,
2053 ));
2054 }
2055 match &items[1].form {
2056 SpannedForm::Atom(Atom::Symbol(name)) => {
2057 let v = eval_in(env, registry, expander, &items[2], host)?;
2058 env.define(Arc::<str>::from(name.as_str()), v);
2059 Ok(Value::Nil)
2060 }
2061 SpannedForm::List(head_list) => {
2062 if head_list.is_empty() {
2063 return Err(EvalError::bad_form(
2064 "define",
2065 "empty (name args) list",
2066 items[1].span,
2067 ));
2068 }
2069 let name = head_list[0].as_symbol().ok_or_else(|| {
2070 EvalError::bad_form(
2071 "define",
2072 "first item in (name args) must be a symbol",
2073 head_list[0].span,
2074 )
2075 })?;
2076 let (params, rest) = parse_lambda_params(&head_list[1..], items[1].span)?;
2077 let body = items[2..].to_vec();
2078 let closure = Arc::new(Closure {
2079 params,
2080 rest,
2081 body,
2082 captured_env: env.clone(),
2083 source: span,
2084 });
2085 env.define(Arc::<str>::from(name), Value::Closure(closure));
2086 Ok(Value::Nil)
2087 }
2088 _ => Err(EvalError::bad_form(
2089 "define",
2090 "second form must be a symbol or (name args) list",
2091 items[1].span,
2092 )),
2093 }
2094}
2095
2096fn sf_set<H: 'static>(
2097 items: &[Spanned],
2098 span: Span,
2099 env: &mut Env,
2100 registry: &FnRegistry<H>,
2101 expander: &SpannedExpander,
2102 host: &mut H,
2103) -> Result<Value> {
2104 if items.len() != 3 {
2105 return Err(EvalError::bad_form(
2106 "set!",
2107 "expected (set! name expr)",
2108 span,
2109 ));
2110 }
2111 let name = items[1]
2112 .as_symbol()
2113 .ok_or_else(|| EvalError::bad_form("set!", "first arg must be a symbol", items[1].span))?;
2114 let v = eval_in(env, registry, expander, &items[2], host)?;
2115 if env.set(name, v) {
2116 Ok(Value::Nil)
2117 } else if let (true, Some(seal)) = (env.is_sealed_binding(name), env.seal()) {
2118 Err(EvalError::SetSealed {
2123 name: name.into(),
2124 seal,
2125 at: items[1].span,
2126 })
2127 } else {
2128 Err(EvalError::unbound(name, items[1].span))
2129 }
2130}
2131
2132fn sf_begin<H: 'static>(
2133 body: &[Spanned],
2134 env: &mut Env,
2135 registry: &FnRegistry<H>,
2136 expander: &SpannedExpander,
2137 host: &mut H,
2138) -> Result<Value> {
2139 eval_body(body, env, registry, expander, host)
2140}
2141
2142fn sf_and<H: 'static>(
2143 exprs: &[Spanned],
2144 env: &mut Env,
2145 registry: &FnRegistry<H>,
2146 expander: &SpannedExpander,
2147 host: &mut H,
2148) -> Result<Value> {
2149 let mut last = Value::Bool(true);
2150 for e in exprs {
2151 last = eval_in(env, registry, expander, e, host)?;
2152 if !last.is_truthy() {
2153 return Ok(last);
2154 }
2155 }
2156 Ok(last)
2157}
2158
2159fn sf_or<H: 'static>(
2160 exprs: &[Spanned],
2161 env: &mut Env,
2162 registry: &FnRegistry<H>,
2163 expander: &SpannedExpander,
2164 host: &mut H,
2165) -> Result<Value> {
2166 let mut last = Value::Bool(false);
2167 for e in exprs {
2168 last = eval_in(env, registry, expander, e, host)?;
2169 if last.is_truthy() {
2170 return Ok(last);
2171 }
2172 }
2173 Ok(last)
2174}
2175
2176fn sf_not<H: 'static>(
2177 items: &[Spanned],
2178 span: Span,
2179 env: &mut Env,
2180 registry: &FnRegistry<H>,
2181 expander: &SpannedExpander,
2182 host: &mut H,
2183) -> Result<Value> {
2184 if items.len() != 2 {
2185 return Err(EvalError::bad_form("not", "expected (not x)", span));
2186 }
2187 let v = eval_in(env, registry, expander, &items[1], host)?;
2188 Ok(Value::Bool(!v.is_truthy()))
2189}
2190
2191fn sf_try<H: 'static>(
2210 items: &[Spanned],
2211 span: Span,
2212 env: &mut Env,
2213 registry: &FnRegistry<H>,
2214 expander: &SpannedExpander,
2215 host: &mut H,
2216) -> Result<Value> {
2217 if items.len() < 3 {
2218 return Err(EvalError::bad_form(
2219 "try",
2220 "expected (try body... (catch (e) handler...))",
2221 span,
2222 ));
2223 }
2224 let catch_form = items.last().unwrap();
2226 let catch_list = catch_form.as_list().ok_or_else(|| {
2227 EvalError::bad_form(
2228 "try",
2229 "last form must be (catch (binding) handler...)",
2230 catch_form.span,
2231 )
2232 })?;
2233 if catch_list.is_empty() || catch_list[0].as_symbol() != Some("catch") {
2234 return Err(EvalError::bad_form(
2235 "try",
2236 "last form must be a (catch ...) clause",
2237 catch_form.span,
2238 ));
2239 }
2240 if catch_list.len() < 3 {
2241 return Err(EvalError::bad_form(
2242 "catch",
2243 "expected (catch (binding) handler...)",
2244 catch_form.span,
2245 ));
2246 }
2247 let binding_list = catch_list[1].as_list().ok_or_else(|| {
2248 EvalError::bad_form(
2249 "catch",
2250 "binding must be a 1-element list (e)",
2251 catch_list[1].span,
2252 )
2253 })?;
2254 if binding_list.len() != 1 {
2255 return Err(EvalError::bad_form(
2256 "catch",
2257 "binding must bind exactly one symbol",
2258 catch_list[1].span,
2259 ));
2260 }
2261 let binding_name = binding_list[0].as_symbol().ok_or_else(|| {
2262 EvalError::bad_form("catch", "binding must be a symbol", binding_list[0].span)
2263 })?;
2264
2265 let body = &items[1..items.len() - 1];
2266 let mut last = Value::Nil;
2267 for form in body {
2268 match eval_in(env, registry, expander, form, host) {
2269 Ok(v) => {
2270 last = v;
2271 }
2272 Err(EvalError::User { value, .. }) => {
2273 return run_catch_handler(
2274 binding_name,
2275 value,
2276 &catch_list[2..],
2277 env,
2278 registry,
2279 expander,
2280 host,
2281 );
2282 }
2283 Err(other) => {
2284 let value = rust_err_to_value_error(&other);
2288 return run_catch_handler(
2289 binding_name,
2290 value,
2291 &catch_list[2..],
2292 env,
2293 registry,
2294 expander,
2295 host,
2296 );
2297 }
2298 }
2299 }
2300 Ok(last)
2301}
2302
2303fn run_catch_handler<H: 'static>(
2304 binding_name: &str,
2305 error_value: Value,
2306 handler_body: &[Spanned],
2307 env: &mut Env,
2308 registry: &FnRegistry<H>,
2309 expander: &SpannedExpander,
2310 host: &mut H,
2311) -> Result<Value> {
2312 env.push();
2313 env.define(Arc::<str>::from(binding_name), error_value);
2314 let mut last = Value::Nil;
2315 for form in handler_body {
2316 match eval_in(env, registry, expander, form, host) {
2317 Ok(v) => last = v,
2318 Err(e) => {
2319 env.pop();
2320 return Err(e);
2321 }
2322 }
2323 }
2324 env.pop();
2325 Ok(last)
2326}
2327
2328fn sf_eval<H: 'static>(
2337 items: &[Spanned],
2338 call_span: Span,
2339 env: &mut Env,
2340 registry: &FnRegistry<H>,
2341 expander: &SpannedExpander,
2342 host: &mut H,
2343) -> Result<Value> {
2344 if items.len() != 2 {
2345 return Err(EvalError::bad_form(
2346 "eval",
2347 "expected (eval form)",
2348 call_span,
2349 ));
2350 }
2351 let form_value = eval_in(env, registry, expander, &items[1], host)?;
2352 let form_spanned = crate::code::value_to_spanned(&form_value, call_span)
2353 .map_err(|reason| EvalError::native_fn(Arc::<str>::from("eval"), reason, call_span))?;
2354 let expanded = fully_expand_with(&form_spanned, registry, expander, env, host)?;
2355 eval_in(env, registry, expander, &expanded, host)
2356}
2357
2358fn sf_delay(items: &[Spanned], call_span: Span, env: &Env) -> Result<Value> {
2363 if items.len() != 2 {
2364 return Err(EvalError::bad_form(
2365 "delay",
2366 "expected (delay expr)",
2367 call_span,
2368 ));
2369 }
2370 let body = vec![items[1].clone()];
2371 let thunk = Arc::new(Closure {
2372 params: Vec::new(),
2373 rest: None,
2374 body,
2375 captured_env: env.clone(),
2376 source: call_span,
2377 });
2378 Ok(Value::Promise(Arc::new(std::sync::Mutex::new(
2379 crate::value::PromiseState::Pending(thunk),
2380 ))))
2381}
2382
2383fn sf_macroexpand<H: 'static>(
2392 items: &[Spanned],
2393 call_span: Span,
2394 env: &mut Env,
2395 registry: &FnRegistry<H>,
2396 expander: &SpannedExpander,
2397 host: &mut H,
2398 fully: bool,
2399) -> Result<Value> {
2400 if items.len() != 2 {
2401 return Err(EvalError::bad_form(
2402 if fully {
2403 "macroexpand"
2404 } else {
2405 "macroexpand-1"
2406 },
2407 "expected (macroexpand[-1] form)",
2408 call_span,
2409 ));
2410 }
2411 let form_value = eval_in(env, registry, expander, &items[1], host)?;
2413 let form_spanned = crate::code::value_to_spanned(&form_value, call_span).map_err(|reason| {
2415 EvalError::native_fn(
2416 Arc::<str>::from(if fully {
2417 "macroexpand"
2418 } else {
2419 "macroexpand-1"
2420 }),
2421 reason,
2422 call_span,
2423 )
2424 })?;
2425
2426 let expanded = if fully {
2432 fully_expand_with(&form_spanned, registry, expander, env, host)?
2433 } else {
2434 macroexpand_one(&form_spanned, registry, expander, env, host)?
2435 };
2436
2437 Ok(crate::code::spanned_to_value(&expanded))
2438}
2439
2440fn expand_one_macro_call<H: 'static>(
2444 macro_name: &str,
2445 args: &[Spanned],
2446 call_span: Span,
2447 registry: &FnRegistry<H>,
2448 expander: &SpannedExpander,
2449 parent_env: &Env,
2450 host: &mut H,
2451) -> Result<Spanned> {
2452 let def: MacroDef = expander.get_macro(macro_name).cloned().ok_or_else(|| {
2453 EvalError::native_fn(
2454 Arc::<str>::from(macro_name),
2455 "macro disappeared during expansion",
2456 call_span,
2457 )
2458 })?;
2459 let body_spanned = Spanned::from_sexp_at(&def.body, call_span);
2460 let body_expanded = fully_expand_with(&body_spanned, registry, expander, parent_env, host)?;
2462
2463 let mut macro_env = parent_env.clone();
2464 macro_env.push();
2465 bind_macro_args(&mut macro_env, &def.name, &def.params, args, call_span)?;
2466 let result = eval_in(&mut macro_env, registry, expander, &body_expanded, host)?;
2467
2468 crate::code::value_to_spanned(&result, call_span).map_err(|reason| {
2469 EvalError::native_fn(
2470 Arc::<str>::from(format!("macro {macro_name}")),
2471 reason,
2472 call_span,
2473 )
2474 })
2475}
2476
2477fn fully_expand_with<H: 'static>(
2481 form: &Spanned,
2482 registry: &FnRegistry<H>,
2483 expander: &SpannedExpander,
2484 parent_env: &Env,
2485 host: &mut H,
2486) -> Result<Spanned> {
2487 if expander.is_empty() {
2488 return Ok(form.clone());
2489 }
2490 expand_recursive_with(form, registry, expander, parent_env, host)
2491}
2492
2493fn expand_recursive_with<H: 'static>(
2494 form: &Spanned,
2495 registry: &FnRegistry<H>,
2496 expander: &SpannedExpander,
2497 parent_env: &Env,
2498 host: &mut H,
2499) -> Result<Spanned> {
2500 match &form.form {
2501 SpannedForm::List(items) if !items.is_empty() => {
2502 if let Some(head) = items[0].as_symbol() {
2503 if expander.has(head) {
2504 let expanded = expand_one_macro_call(
2505 head,
2506 &items[1..],
2507 form.span,
2508 registry,
2509 expander,
2510 parent_env,
2511 host,
2512 )?;
2513 return expand_recursive_with(&expanded, registry, expander, parent_env, host);
2514 }
2515 }
2516 let mut out = Vec::with_capacity(items.len());
2517 for child in items {
2518 out.push(expand_recursive_with(
2519 child, registry, expander, parent_env, host,
2520 )?);
2521 }
2522 Ok(Spanned::new(form.span, SpannedForm::List(out)))
2523 }
2524 SpannedForm::Quote(_) => Ok(form.clone()),
2525 SpannedForm::Quasiquote(inner) => Ok(Spanned::new(
2526 form.span,
2527 SpannedForm::Quasiquote(Box::new(expand_inside_quasiquote_with(
2528 inner, registry, expander, parent_env, host,
2529 )?)),
2530 )),
2531 _ => Ok(form.clone()),
2532 }
2533}
2534
2535fn expand_inside_quasiquote_with<H: 'static>(
2536 form: &Spanned,
2537 registry: &FnRegistry<H>,
2538 expander: &SpannedExpander,
2539 parent_env: &Env,
2540 host: &mut H,
2541) -> Result<Spanned> {
2542 match &form.form {
2543 SpannedForm::Unquote(inner) => Ok(Spanned::new(
2544 form.span,
2545 SpannedForm::Unquote(Box::new(expand_recursive_with(
2546 inner, registry, expander, parent_env, host,
2547 )?)),
2548 )),
2549 SpannedForm::UnquoteSplice(inner) => Ok(Spanned::new(
2550 form.span,
2551 SpannedForm::UnquoteSplice(Box::new(expand_recursive_with(
2552 inner, registry, expander, parent_env, host,
2553 )?)),
2554 )),
2555 SpannedForm::List(items) => {
2556 let mut out = Vec::with_capacity(items.len());
2557 for item in items {
2558 out.push(expand_inside_quasiquote_with(
2559 item, registry, expander, parent_env, host,
2560 )?);
2561 }
2562 Ok(Spanned::new(form.span, SpannedForm::List(out)))
2563 }
2564 _ => Ok(form.clone()),
2565 }
2566}
2567
2568fn macroexpand_one<H: 'static>(
2571 form: &Spanned,
2572 registry: &FnRegistry<H>,
2573 expander: &SpannedExpander,
2574 parent_env: &Env,
2575 host: &mut H,
2576) -> Result<Spanned> {
2577 if let SpannedForm::List(items) = &form.form {
2578 if let Some(head) = items.first().and_then(Spanned::as_symbol) {
2579 if expander.has(head) {
2580 return expand_one_macro_call(
2581 head,
2582 &items[1..],
2583 form.span,
2584 registry,
2585 expander,
2586 parent_env,
2587 host,
2588 );
2589 }
2590 }
2591 }
2592 Ok(form.clone())
2593}
2594
2595fn rust_err_to_value_error(err: &EvalError) -> Value {
2598 use crate::value::ErrorObj;
2599 let tag: Arc<str> = Arc::from(err.tag());
2600 let message: Arc<str> = Arc::from(err.short_message());
2601 Value::Error(Arc::new(ErrorObj {
2602 tag,
2603 message,
2604 data: Vec::new(),
2605 }))
2606}
2607
2608#[cfg(test)]
2609mod tests {
2610 use super::*;
2611 use crate::primitive::install_primitives;
2612 use tatara_lisp::read_spanned;
2613
2614 struct NoHost;
2615
2616 fn eval_ok(src: &str) -> Value {
2617 let forms = read_spanned(src).unwrap();
2618 let mut i: Interpreter<NoHost> = Interpreter::new();
2619 install_primitives(&mut i);
2620 let mut host = NoHost;
2621 i.eval_program(&forms, &mut host).unwrap()
2622 }
2623
2624 fn eval_err(src: &str) -> EvalError {
2625 let forms = read_spanned(src).unwrap();
2626 let mut i: Interpreter<NoHost> = Interpreter::new();
2627 install_primitives(&mut i);
2628 let mut host = NoHost;
2629 i.eval_program(&forms, &mut host).unwrap_err()
2630 }
2631
2632 #[test]
2635 fn literal_int() {
2636 assert!(matches!(eval_ok("42"), Value::Int(42)));
2637 }
2638
2639 #[test]
2640 fn unbound_symbol_errors() {
2641 let e = eval_err("no-such-var");
2642 assert!(matches!(e, EvalError::UnboundSymbol { .. }));
2643 }
2644
2645 #[test]
2646 fn quote_returns_runtime_list_of_symbols() {
2647 let v = eval_ok("'(a b c)");
2650 match v {
2651 Value::List(xs) => {
2652 assert_eq!(xs.len(), 3);
2653 assert!(matches!(&xs[0], Value::Symbol(s) if s.as_ref() == "a"));
2654 assert!(matches!(&xs[1], Value::Symbol(s) if s.as_ref() == "b"));
2655 assert!(matches!(&xs[2], Value::Symbol(s) if s.as_ref() == "c"));
2656 }
2657 other => panic!("{other:?}"),
2658 }
2659 }
2660
2661 #[test]
2664 fn add_ints() {
2665 assert!(matches!(eval_ok("(+ 1 2 3)"), Value::Int(6)));
2666 }
2667
2668 #[test]
2669 fn sub_divides_float() {
2670 match eval_ok("(- 10 3)") {
2671 Value::Int(7) => {}
2672 other => panic!("{other:?}"),
2673 }
2674 }
2675
2676 #[test]
2677 fn division_by_zero_errors() {
2678 assert!(matches!(
2679 eval_err("(/ 1 0)"),
2680 EvalError::DivisionByZero { .. }
2681 ));
2682 }
2683
2684 #[test]
2687 fn if_truthy_branch() {
2688 assert!(matches!(eval_ok("(if #t 1 2)"), Value::Int(1)));
2689 }
2690
2691 #[test]
2692 fn if_falsy_branch() {
2693 assert!(matches!(eval_ok("(if #f 1 2)"), Value::Int(2)));
2694 }
2695
2696 #[test]
2697 fn if_no_else_returns_nil() {
2698 assert!(matches!(eval_ok("(if #f 1)"), Value::Nil));
2699 }
2700
2701 #[test]
2702 fn cond_picks_first_match() {
2703 assert!(matches!(
2704 eval_ok("(cond (#f 1) (#t 2) (else 3))"),
2705 Value::Int(2)
2706 ));
2707 }
2708
2709 #[test]
2710 fn cond_falls_through_to_else() {
2711 assert!(matches!(
2712 eval_ok("(cond (#f 1) (#f 2) (else 3))"),
2713 Value::Int(3)
2714 ));
2715 }
2716
2717 #[test]
2718 fn when_runs_body_if_true() {
2719 assert!(matches!(eval_ok("(when #t 99)"), Value::Int(99)));
2720 assert!(matches!(eval_ok("(when #f 99)"), Value::Nil));
2721 }
2722
2723 #[test]
2726 fn let_binds_and_evaluates_body() {
2727 assert!(matches!(
2728 eval_ok("(let ((x 10) (y 20)) (+ x y))"),
2729 Value::Int(30)
2730 ));
2731 }
2732
2733 #[test]
2734 fn let_star_sequential_bindings() {
2735 assert!(matches!(
2736 eval_ok("(let* ((x 5) (y (+ x 1))) (+ x y))"),
2737 Value::Int(11)
2738 ));
2739 }
2740
2741 #[test]
2742 fn letrec_mutual_recursion() {
2743 let v = eval_ok(
2744 "(letrec ((even? (lambda (n) (if (= n 0) #t (odd? (- n 1)))))
2745 (odd? (lambda (n) (if (= n 0) #f (even? (- n 1))))))
2746 (even? 10))",
2747 );
2748 assert!(matches!(v, Value::Bool(true)));
2749 }
2750
2751 #[test]
2754 fn lambda_applies() {
2755 assert!(matches!(
2756 eval_ok("((lambda (x y) (+ x y)) 3 4)"),
2757 Value::Int(7)
2758 ));
2759 }
2760
2761 #[test]
2762 fn lambda_closes_over_env() {
2763 assert!(matches!(
2764 eval_ok("(let ((n 10)) ((lambda (x) (+ x n)) 5))"),
2765 Value::Int(15)
2766 ));
2767 }
2768
2769 #[test]
2770 fn closure_captures_by_value_at_creation() {
2771 let v = eval_ok(
2774 "(define make-adder (lambda (n) (lambda (x) (+ x n))))
2775 (define add5 (make-adder 5))
2776 (add5 10)",
2777 );
2778 assert!(matches!(v, Value::Int(15)));
2779 }
2780
2781 #[test]
2782 fn rest_args_collect_into_list() {
2783 let v = eval_ok("((lambda (x &rest rs) (length rs)) 1 2 3 4 5)");
2784 assert!(matches!(v, Value::Int(4)));
2785 }
2786
2787 #[test]
2788 fn closure_arity_mismatch() {
2789 let e = eval_err("((lambda (x y) (+ x y)) 1)");
2790 assert!(matches!(e, EvalError::ArityMismatch { .. }));
2791 }
2792
2793 #[test]
2796 fn define_then_use() {
2797 assert!(matches!(eval_ok("(define x 42) x"), Value::Int(42)));
2798 }
2799
2800 #[test]
2801 fn define_function_shorthand() {
2802 assert!(matches!(
2803 eval_ok("(define (sq x) (* x x)) (sq 6)"),
2804 Value::Int(36)
2805 ));
2806 }
2807
2808 #[test]
2809 fn set_mutates_existing() {
2810 assert!(matches!(
2811 eval_ok("(define x 1) (set! x 99) x"),
2812 Value::Int(99)
2813 ));
2814 }
2815
2816 #[test]
2817 fn set_unbound_errors() {
2818 let e = eval_err("(set! nope 1)");
2819 assert!(matches!(e, EvalError::UnboundSymbol { .. }));
2820 }
2821
2822 #[test]
2825 fn begin_returns_last() {
2826 assert!(matches!(eval_ok("(begin 1 2 3)"), Value::Int(3)));
2827 }
2828
2829 #[test]
2830 fn and_short_circuits() {
2831 assert!(matches!(eval_ok("(and 1 #f 2)"), Value::Bool(false)));
2832 assert!(matches!(eval_ok("(and 1 2 3)"), Value::Int(3)));
2833 assert!(matches!(eval_ok("(and)"), Value::Bool(true)));
2834 }
2835
2836 #[test]
2837 fn or_short_circuits() {
2838 assert!(matches!(eval_ok("(or #f #f 7)"), Value::Int(7)));
2839 assert!(matches!(eval_ok("(or #f #f)"), Value::Bool(false)));
2840 assert!(matches!(eval_ok("(or)"), Value::Bool(false)));
2841 }
2842
2843 #[test]
2844 fn not_inverts() {
2845 assert!(matches!(eval_ok("(not #t)"), Value::Bool(false)));
2846 assert!(matches!(eval_ok("(not #f)"), Value::Bool(true)));
2847 assert!(matches!(eval_ok("(not 42)"), Value::Bool(false)));
2848 }
2849
2850 #[test]
2853 fn recursive_factorial() {
2854 let v = eval_ok(
2855 "(define (fact n)
2856 (if (= n 0) 1 (* n (fact (- n 1)))))
2857 (fact 6)",
2858 );
2859 assert!(matches!(v, Value::Int(720)));
2860 }
2861
2862 #[test]
2863 fn recursive_length() {
2864 let v = eval_ok(
2865 "(define (len xs)
2866 (if (null? xs) 0 (+ 1 (len (cdr xs)))))
2867 (len (list 1 2 3 4 5))",
2868 );
2869 assert!(matches!(v, Value::Int(5)));
2870 }
2871
2872 #[test]
2877 fn quasiquote_plain_list_is_runtime_list() {
2878 let v = eval_ok("`(a b c)");
2879 match v {
2880 Value::List(xs) => {
2881 assert_eq!(xs.len(), 3);
2882 assert!(matches!(&xs[0], Value::Symbol(s) if s.as_ref() == "a"));
2883 assert!(matches!(&xs[1], Value::Symbol(s) if s.as_ref() == "b"));
2884 assert!(matches!(&xs[2], Value::Symbol(s) if s.as_ref() == "c"));
2885 }
2886 other => panic!("{other:?}"),
2887 }
2888 }
2889
2890 #[test]
2891 fn quasiquote_unquote_substitutes_evaluated_value() {
2892 let v = eval_ok("(let ((x 42)) `(a ,x c))");
2893 match v {
2894 Value::List(xs) => {
2895 assert_eq!(xs.len(), 3);
2896 assert!(matches!(&xs[1], Value::Int(42)));
2897 }
2898 other => panic!("{other:?}"),
2899 }
2900 }
2901
2902 #[test]
2903 fn quasiquote_unquote_arbitrary_expr() {
2904 let v = eval_ok("`(x ,(+ 1 2 3) y)");
2905 match v {
2906 Value::List(xs) => {
2907 assert!(matches!(&xs[1], Value::Int(6)));
2908 }
2909 other => panic!("{other:?}"),
2910 }
2911 }
2912
2913 #[test]
2914 fn quasiquote_splice_inlines_list() {
2915 let v = eval_ok("`(a ,@(list 1 2 3) b)");
2916 match v {
2917 Value::List(xs) => {
2918 assert_eq!(xs.len(), 5);
2919 assert!(matches!(&xs[0], Value::Symbol(s) if s.as_ref() == "a"));
2920 assert!(matches!(&xs[1], Value::Int(1)));
2921 assert!(matches!(&xs[2], Value::Int(2)));
2922 assert!(matches!(&xs[3], Value::Int(3)));
2923 assert!(matches!(&xs[4], Value::Symbol(s) if s.as_ref() == "b"));
2924 }
2925 other => panic!("{other:?}"),
2926 }
2927 }
2928
2929 #[test]
2930 fn quasiquote_splice_empty_list_splices_nothing() {
2931 let v = eval_ok("`(a ,@(list) b)");
2932 match v {
2933 Value::List(xs) => {
2934 assert_eq!(xs.len(), 2);
2935 assert!(matches!(&xs[0], Value::Symbol(s) if s.as_ref() == "a"));
2936 assert!(matches!(&xs[1], Value::Symbol(s) if s.as_ref() == "b"));
2937 }
2938 other => panic!("{other:?}"),
2939 }
2940 }
2941
2942 #[test]
2943 fn quasiquote_splice_non_list_errors() {
2944 let e = eval_err("`(a ,@42)");
2945 assert!(matches!(e, EvalError::TypeMismatch { .. }));
2946 }
2947
2948 #[test]
2949 fn quasiquote_atom_yields_atom_value() {
2950 assert!(matches!(eval_ok("`foo"), Value::Symbol(s) if s.as_ref() == "foo"));
2951 assert!(matches!(eval_ok("`42"), Value::Int(42)));
2952 }
2953
2954 #[test]
2955 fn quasiquote_with_nested_list_and_unquote() {
2956 let v = eval_ok("(let ((x 99)) `(foo (bar ,x) baz))");
2958 match v {
2959 Value::List(xs) => {
2960 assert_eq!(xs.len(), 3);
2961 match &xs[1] {
2962 Value::List(inner) => {
2963 assert!(matches!(&inner[1], Value::Int(99)));
2964 }
2965 other => panic!("{other:?}"),
2966 }
2967 }
2968 other => panic!("{other:?}"),
2969 }
2970 }
2971
2972 #[test]
2973 fn quasiquote_symbol_keyword_distinction_preserved() {
2974 let v = eval_ok("`(:key val)");
2975 match v {
2976 Value::List(xs) => {
2977 assert!(matches!(&xs[0], Value::Keyword(s) if s.as_ref() == "key"));
2978 assert!(matches!(&xs[1], Value::Symbol(s) if s.as_ref() == "val"));
2979 }
2980 other => panic!("{other:?}"),
2981 }
2982 }
2983
2984 #[test]
2985 fn bare_unquote_outside_quasiquote_errors() {
2986 let e = eval_err(",x");
2987 assert!(matches!(e, EvalError::BadSpecialForm { .. }));
2988 }
2989
2990 #[test]
2993 fn native_fn_reads_host_state() {
2994 struct Counter {
2995 n: i64,
2996 }
2997 let forms = read_spanned("(bump) (bump) (bump) (cur)").unwrap();
2998 let mut i: Interpreter<Counter> = Interpreter::new();
2999 install_primitives(&mut i);
3000 i.register_fn(
3001 "bump",
3002 Arity::Exact(0),
3003 |_args: &[Value], host: &mut Counter, _span| {
3004 host.n += 1;
3005 Ok(Value::Int(host.n))
3006 },
3007 );
3008 i.register_fn(
3009 "cur",
3010 Arity::Exact(0),
3011 |_args: &[Value], host: &mut Counter, _span| Ok(Value::Int(host.n)),
3012 );
3013 let mut host = Counter { n: 0 };
3014 let v = i.eval_program(&forms, &mut host).unwrap();
3015 assert!(matches!(v, Value::Int(3)));
3016 }
3017
3018 struct Ctx {
3021 records: Vec<(String, i64)>,
3022 }
3023
3024 #[test]
3025 fn register_typed1_marshals_string_arg() {
3026 let mut i: Interpreter<Ctx> = Interpreter::new();
3027 install_primitives(&mut i);
3028 i.register_typed1("greet", |_h: &mut Ctx, name: String| -> Result<String> {
3029 Ok(format!("hello {name}"))
3030 });
3031 let forms = read_spanned(r#"(greet "luis")"#).unwrap();
3032 let mut h = Ctx { records: vec![] };
3033 let v = i.eval_program(&forms, &mut h).unwrap();
3034 match v {
3035 Value::Str(s) => assert_eq!(&*s, "hello luis"),
3036 other => panic!("{other:?}"),
3037 }
3038 }
3039
3040 #[test]
3041 fn register_typed2_marshals_host_state_mutation() {
3042 let mut i: Interpreter<Ctx> = Interpreter::new();
3043 install_primitives(&mut i);
3044 i.register_typed2(
3045 "record",
3046 |h: &mut Ctx, name: String, n: i64| -> Result<()> {
3047 h.records.push((name, n));
3048 Ok(())
3049 },
3050 );
3051 let forms = read_spanned(r#"(record "a" 1) (record "b" 2)"#).unwrap();
3052 let mut h = Ctx { records: vec![] };
3053 let _ = i.eval_program(&forms, &mut h).unwrap();
3054 assert_eq!(h.records.len(), 2);
3055 assert_eq!(h.records[0], ("a".to_string(), 1));
3056 assert_eq!(h.records[1], ("b".to_string(), 2));
3057 }
3058
3059 #[test]
3060 fn register_typed_arg_type_mismatch_surfaces_at_call_site() {
3061 let mut i: Interpreter<Ctx> = Interpreter::new();
3062 install_primitives(&mut i);
3063 i.register_typed1("needs-int", |_h: &mut Ctx, n: i64| -> Result<i64> {
3064 Ok(n + 1)
3065 });
3066 let forms = read_spanned(r#"(needs-int "not-a-number")"#).unwrap();
3067 let mut h = Ctx { records: vec![] };
3068 let err = i.eval_program(&forms, &mut h).unwrap_err();
3069 assert!(matches!(
3070 err,
3071 EvalError::TypeMismatch {
3072 expected: "integer",
3073 ..
3074 }
3075 ));
3076 }
3077
3078 #[test]
3079 fn register_typed3_three_args() {
3080 let mut i: Interpreter<Ctx> = Interpreter::new();
3081 install_primitives(&mut i);
3082 i.register_typed3(
3083 "triple-sum",
3084 |_h: &mut Ctx, a: i64, b: i64, c: i64| -> Result<i64> { Ok(a + b + c) },
3085 );
3086 let forms = read_spanned("(triple-sum 10 20 30)").unwrap();
3087 let mut h = Ctx { records: vec![] };
3088 let v = i.eval_program(&forms, &mut h).unwrap();
3089 assert!(matches!(v, Value::Int(60)));
3090 }
3091
3092 #[test]
3108 fn a_runaway_macro_is_a_typed_error_that_names_the_macro() {
3109 let err = eval_err("(defmacro forever (x) `(forever ,x))\n(forever 1)");
3110 match err {
3111 EvalError::MacroExpansionLimit {
3112 ref macro_name,
3113 limit,
3114 ..
3115 } => {
3116 assert_eq!(&**macro_name, "forever", "the error must name the culprit");
3117 assert_eq!(limit, DEFAULT_MACRO_EXPANSION_LIMIT);
3118 }
3119 other => panic!("expected MacroExpansionLimit, got {other:?}"),
3120 }
3121 }
3122
3123 #[test]
3127 fn a_mutually_recursive_macro_pair_is_caught_too() {
3128 let err =
3129 eval_err("(defmacro ping (x) `(pong ,x))\n(defmacro pong (x) `(ping ,x))\n(ping 1)");
3130 assert!(
3131 matches!(err, EvalError::MacroExpansionLimit { .. }),
3132 "a two-macro cycle must be bounded as well: {err:?}"
3133 );
3134 }
3135
3136 #[test]
3144 fn deep_but_finite_nesting_is_not_charged_to_the_expansion_budget() {
3145 let mut src = String::from("(defmacro id1 (x) x)\n");
3146 src.push_str(&"(+ 1 ".repeat(400));
3147 src.push_str("(id1 7)");
3148 src.push_str(&")".repeat(400));
3149 let v = eval_ok(&src);
3150 assert!(matches!(v, Value::Int(407)), "got {v:?}");
3151 }
3152
3153 #[test]
3156 fn a_terminating_chain_under_the_ceiling_still_expands() {
3157 let v =
3159 eval_ok("(defmacro step (x) `(step2 ,x))\n(defmacro step2 (x) `(* ,x 3))\n(step 5)");
3160 assert!(matches!(v, Value::Int(15)), "got {v:?}");
3161 }
3162
3163 #[test]
3166 fn the_expansion_ceiling_is_configurable() {
3167 let forms = read_spanned("(defmacro forever (x) `(forever ,x))\n(forever 1)").unwrap();
3168 let mut i: Interpreter<NoHost> = Interpreter::new();
3169 install_primitives(&mut i);
3170 i.set_macro_expansion_limit(4);
3171 match i.eval_program(&forms, &mut NoHost).unwrap_err() {
3172 EvalError::MacroExpansionLimit { limit, .. } => assert_eq!(limit, 4),
3173 other => panic!("expected MacroExpansionLimit, got {other:?}"),
3174 }
3175 }
3176
3177 #[test]
3178 fn user_macro_expands_and_evaluates() {
3179 let v = eval_ok(
3180 "(defmacro twice (x) `(* ,x 2))
3181 (twice 21)",
3182 );
3183 assert!(matches!(v, Value::Int(42)));
3184 }
3185
3186 #[test]
3187 fn user_macro_definition_returns_nil() {
3188 let v = eval_ok("(defmacro inc (x) `(+ ,x 1))");
3189 assert!(matches!(v, Value::Nil));
3190 }
3191
3192 #[test]
3193 fn user_macro_inside_define_body_expands() {
3194 let v = eval_ok(
3197 "(defmacro inc (x) `(+ ,x 1))
3198 (define (f n) (inc n))
3199 (f 41)",
3200 );
3201 assert!(matches!(v, Value::Int(42)));
3202 }
3203
3204 #[test]
3205 fn user_macro_with_rest_args_splices() {
3206 let v = eval_ok(
3207 "(defmacro sum-all (&rest xs) `(+ ,@xs))
3208 (sum-all 1 2 3 4 5)",
3209 );
3210 assert!(matches!(v, Value::Int(15)));
3211 }
3212
3213 #[test]
3214 fn nested_user_macros_compose() {
3215 let v = eval_ok(
3216 "(defmacro twice (x) `(* ,x 2))
3217 (defmacro quad (x) `(twice (twice ,x)))
3218 (quad 5)",
3219 );
3220 assert!(matches!(v, Value::Int(20)));
3221 }
3222
3223 #[test]
3224 fn user_macro_can_expand_to_special_form() {
3225 let v = eval_ok(
3228 "(defmacro guard (test then) `(if ,test ,then 0))
3229 (guard #t 99)",
3230 );
3231 assert!(matches!(v, Value::Int(99)));
3232 }
3233
3234 #[test]
3235 fn user_macro_redefined_replaces_prior_template() {
3236 let v = eval_ok(
3237 "(defmacro k () `1)
3238 (defmacro k () `2)
3239 (k)",
3240 );
3241 assert!(matches!(v, Value::Int(2)));
3242 }
3243
3244 #[test]
3245 fn user_macro_unbound_template_var_errors() {
3246 let mut i: Interpreter<NoHost> = Interpreter::new();
3252 install_primitives(&mut i);
3253 let forms = read_spanned("(defmacro bad (x) `(list ,y)) (bad 1)").unwrap();
3254 let err = i.eval_program(&forms, &mut NoHost).unwrap_err();
3255 match err {
3256 EvalError::UnboundSymbol { name, .. } => assert_eq!(&*name, "y"),
3257 other => panic!("expected UnboundSymbol, got {other:?}"),
3258 }
3259 }
3260
3261 #[test]
3262 fn defpoint_template_keyword_registers_as_macro() {
3263 let v = eval_ok(
3266 "(defpoint-template double (x) `(* ,x 2))
3267 (double 7)",
3268 );
3269 assert!(matches!(v, Value::Int(14)));
3270 }
3271
3272 #[test]
3273 fn defcheck_keyword_registers_as_macro() {
3274 let v = eval_ok(
3275 "(defcheck always-7 () `7)
3276 (always-7)",
3277 );
3278 assert!(matches!(v, Value::Int(7)));
3279 }
3280
3281 #[test]
3282 fn macro_call_evaluated_with_runtime_arg() {
3283 let v = eval_ok(
3287 "(defmacro double (x) `(+ ,x ,x))
3288 (define n 13)
3289 (double n)",
3290 );
3291 assert!(matches!(v, Value::Int(26)));
3292 }
3293
3294 #[test]
3295 fn macro_persists_across_eval_program_calls() {
3296 let mut i: Interpreter<NoHost> = Interpreter::new();
3299 install_primitives(&mut i);
3300 let mut host = NoHost;
3301 let defs = read_spanned("(defmacro inc (x) `(+ ,x 1))").unwrap();
3302 i.eval_program(&defs, &mut host).unwrap();
3303 assert_eq!(i.expander().len(), 1);
3304
3305 let call = read_spanned("(inc 41)").unwrap();
3306 let v = i.eval_program(&call, &mut host).unwrap();
3307 assert!(matches!(v, Value::Int(42)));
3308 }
3309
3310 #[test]
3311 fn macro_expansion_inside_lambda_body() {
3312 let v = eval_ok(
3313 "(defmacro sq (x) `(* ,x ,x))
3314 ((lambda (n) (sq n)) 9)",
3315 );
3316 assert!(matches!(v, Value::Int(81)));
3317 }
3318
3319 #[test]
3320 fn no_macros_registered_keeps_eval_program_a_passthrough() {
3321 let v = eval_ok("(+ 1 2 3)");
3327 assert!(matches!(v, Value::Int(6)));
3328 }
3329
3330 #[test]
3331 fn eval_top_form_drives_one_form_at_a_time() {
3332 let mut i: Interpreter<NoHost> = Interpreter::new();
3333 install_primitives(&mut i);
3334 let mut host = NoHost;
3335 let forms = read_spanned("(defmacro id (x) `,x) (id 42)").unwrap();
3336
3337 let r0 = i.eval_top_form(&forms[0], &mut host).unwrap();
3339 assert!(matches!(r0, Value::Nil));
3340
3341 let r1 = i.eval_top_form(&forms[1], &mut host).unwrap();
3343 assert!(matches!(r1, Value::Int(42)));
3344 }
3345
3346 use crate::install_full_stdlib_with;
3353
3354 fn run_full(src: &str) -> Value {
3355 let mut i: Interpreter<NoHost> = Interpreter::new();
3356 install_full_stdlib_with(&mut i, &mut NoHost);
3357 let forms = read_spanned(src).unwrap();
3358 i.eval_program(&forms, &mut NoHost).unwrap()
3359 }
3360
3361 #[test]
3362 fn macro_can_use_map_at_expansion_time() {
3363 let v = run_full(
3367 "(defmacro double-each (&rest xs)
3368 `(list ,@(map (lambda (x) (* x 2)) xs)))
3369 (double-each 1 2 3 4 5)",
3370 );
3371 assert_eq!(format!("{v}"), "(2 4 6 8 10)");
3372 }
3373
3374 #[test]
3375 fn macro_can_use_foldl_at_expansion_time() {
3376 let v = run_full(
3380 "(defmacro static-sum (&rest xs)
3381 (foldl + 0 xs))
3382 (static-sum 1 2 3 4 5)",
3383 );
3384 assert!(matches!(v, Value::Int(15)));
3385 }
3386
3387 #[test]
3388 fn macro_can_use_filter_at_expansion_time() {
3389 let v = run_full(
3393 "(defmacro sum-positives (&rest xs)
3394 `(+ ,@(filter positive? xs)))
3395 (sum-positives 1 -2 3 -4 5)",
3396 );
3397 assert!(matches!(v, Value::Int(9)));
3399 }
3400
3401 #[test]
3402 fn macro_can_recursively_emit_let_chain() {
3403 let v = run_full(
3406 "(defmacro chain-let (binding &rest more)
3407 (if (null? more)
3408 `(let (,binding) #t)
3409 `(let (,binding) (chain-let ,@more))))
3410 (chain-let (a 1) (b 2) (c 3))",
3411 );
3412 assert!(matches!(v, Value::Bool(true)));
3413 }
3414
3415 #[test]
3416 fn macro_can_use_gensym_for_hygiene() {
3417 let v = run_full(
3420 "(defmacro swap-bind (init body)
3421 (let ((tmp (gensym \"tmp\")))
3422 `(let ((,tmp ,init))
3423 (+ ,tmp ,tmp))))
3424 (swap-bind 21 #t)",
3425 );
3426 assert!(matches!(v, Value::Int(42)));
3427 }
3428
3429 #[test]
3430 fn macro_can_inspect_arg_shape() {
3431 let v = run_full(
3433 "(defmacro shape-aware (x)
3434 (if (list? x)
3435 `(+ ,@x) ;; sum the children
3436 `,x)) ;; pass through scalars
3437 (+ (shape-aware (1 2 3)) (shape-aware 100))",
3438 );
3439 assert!(matches!(v, Value::Int(106)));
3441 }
3442
3443 #[test]
3444 fn macro_can_call_user_helper_fn() {
3445 let v = run_full(
3447 "(define (square x) (* x x))
3448 (defmacro static-square (n) (square n))
3449 (static-square 7)",
3450 );
3451 assert!(matches!(v, Value::Int(49)));
3452 }
3453
3454 #[test]
3455 fn macro_emitting_quoted_form_round_trips() {
3456 let v = run_full(
3459 "(defmacro literal-list (&rest xs)
3460 `(quote ,xs))
3461 (literal-list a b c)",
3462 );
3463 let s = format!("{v}");
3464 assert!(s.contains('a') && s.contains('b') && s.contains('c'));
3465 }
3466
3467 #[test]
3468 fn quasiquote_inside_quasiquote_in_macro_output_is_preserved() {
3469 let v = run_full(
3472 "(defmacro emit-qq (x) `(quasiquote (a (unquote ,x) c)))
3473 (let ((q (emit-qq 99))) q)",
3474 );
3475 assert_eq!(format!("{v}"), "(a 99 c)");
3477 }
3478
3479 #[test]
3480 fn macro_body_can_define_locals_and_dispatch() {
3481 let v = run_full(
3483 "(defmacro classify-args (&rest xs)
3484 (let ((evens (filter even? xs))
3485 (odds (filter odd? xs)))
3486 `(list (list :evens ,@evens)
3487 (list :odds ,@odds))))
3488 (classify-args 1 2 3 4 5 6)",
3489 );
3490 let s = format!("{v}");
3491 assert!(s.contains(":evens 2 4 6"));
3492 assert!(s.contains(":odds 1 3 5"));
3493 }
3494
3495 #[test]
3504 fn tco_self_recursion_via_if() {
3505 let v = run_full(
3509 "(define (sum n acc)
3510 (if (= n 0)
3511 acc
3512 (sum (- n 1) (+ acc n))))
3513 (sum 100000 0)",
3514 );
3515 assert!(matches!(v, Value::Int(5_000_050_000)));
3517 }
3518
3519 #[test]
3520 fn tco_mutual_recursion() {
3521 let v = run_full(
3524 "(define (even-r? n) (if (= n 0) #t (odd-r? (- n 1))))
3525 (define (odd-r? n) (if (= n 0) #f (even-r? (- n 1))))
3526 (even-r? 50000)",
3527 );
3528 assert!(matches!(v, Value::Bool(true)));
3529 }
3530
3531 #[test]
3532 fn tco_via_cond_branch() {
3533 let v = run_full(
3534 "(define (countdown n)
3535 (cond
3536 ((<= n 0) :done)
3537 (else (countdown (- n 1)))))
3538 (countdown 50000)",
3539 );
3540 assert!(matches!(v, Value::Keyword(s) if &*s == "done"));
3541 }
3542
3543 #[test]
3544 fn tco_via_let_body() {
3545 let v = run_full(
3548 "(define (loop-let n)
3549 (let ((m (- n 1)))
3550 (if (<= n 0) :done (loop-let m))))
3551 (loop-let 50000)",
3552 );
3553 assert!(matches!(v, Value::Keyword(s) if &*s == "done"));
3554 }
3555
3556 #[test]
3557 fn tco_via_begin_last_form() {
3558 let v = run_full(
3559 "(define (counter n)
3560 (begin
3561 (+ 1 1)
3562 (+ 2 2)
3563 (if (<= n 0) :done (counter (- n 1)))))
3564 (counter 50000)",
3565 );
3566 assert!(matches!(v, Value::Keyword(s) if &*s == "done"));
3567 }
3568
3569 #[test]
3570 fn tco_via_when_unless() {
3571 let v = run_full(
3572 "(define (drain n)
3573 (when (> n 0)
3574 (drain (- n 1))))
3575 (drain 50000)",
3576 );
3577 assert!(matches!(v, Value::Nil));
3579 }
3580
3581 #[test]
3582 fn tco_through_and_or_short_circuit_last() {
3583 let v = run_full(
3586 "(define (loop-and n)
3587 (and #t #t (if (<= n 0) :done (loop-and (- n 1)))))
3588 (loop-and 30000)",
3589 );
3590 assert!(matches!(v, Value::Keyword(s) if &*s == "done"));
3591 }
3592
3593 #[test]
3594 fn non_tail_recursion_still_works_for_small_n() {
3595 let v = run_full(
3599 "(define (fact n)
3600 (if (= n 0) 1 (* n (fact (- n 1)))))
3601 (fact 12)",
3602 );
3603 assert!(matches!(v, Value::Int(479_001_600)));
3605 }
3606
3607 #[test]
3610 fn error_constructor_returns_error_value() {
3611 let v = run_full("(error :validation \"bad input\")");
3612 match v {
3613 Value::Error(e) => {
3614 assert_eq!(&*e.tag, "validation");
3615 assert_eq!(&*e.message, "bad input");
3616 assert!(e.data.is_empty());
3617 }
3618 other => panic!("{other:?}"),
3619 }
3620 }
3621
3622 #[test]
3623 fn ex_info_uses_default_tag() {
3624 let v = run_full("(ex-info \"validation failed\" (list :field \"email\" :code 42))");
3625 match v {
3626 Value::Error(e) => {
3627 assert_eq!(&*e.tag, "ex-info");
3628 assert_eq!(&*e.message, "validation failed");
3629 assert_eq!(e.data.len(), 2);
3630 }
3631 other => panic!("{other:?}"),
3632 }
3633 }
3634
3635 #[test]
3636 fn error_predicate() {
3637 let v = run_full("(error? (error :x \"y\"))");
3638 assert!(matches!(v, Value::Bool(true)));
3639 let v = run_full("(error? 42)");
3640 assert!(matches!(v, Value::Bool(false)));
3641 }
3642
3643 #[test]
3644 fn error_accessors() {
3645 let v = run_full(
3646 "(let ((e (ex-info \"oops\" (list :user-id 42))))
3647 (list (error-tag e) (error-message e) (error-data-get e :user-id)))",
3648 );
3649 assert_eq!(format!("{v}"), "(:ex-info \"oops\" 42)");
3650 }
3651
3652 #[test]
3653 fn try_catches_thrown_error() {
3654 let v = run_full(
3655 "(try
3656 (throw (ex-info \"boom\" (list :code 500)))
3657 (catch (e)
3658 (error-message e)))",
3659 );
3660 assert_eq!(format!("{v}"), "\"boom\"");
3661 }
3662
3663 #[test]
3664 fn try_returns_body_value_when_no_throw() {
3665 let v = run_full(
3666 "(try
3667 (+ 1 2 3)
3668 (catch (e) :unreachable))",
3669 );
3670 assert!(matches!(v, Value::Int(6)));
3671 }
3672
3673 #[test]
3674 fn try_catches_runtime_errors_too() {
3675 let v = run_full(
3679 "(try
3680 (/ 1 0)
3681 (catch (e) (error-tag e)))",
3682 );
3683 assert!(matches!(v, Value::Keyword(s) if &*s == "division-by-zero"));
3684 }
3685
3686 #[test]
3687 fn try_catches_unbound_symbol_error() {
3688 let v = run_full(
3689 "(try
3690 undefined-var
3691 (catch (e) (error-tag e)))",
3692 );
3693 assert!(matches!(v, Value::Keyword(s) if &*s == "unbound-symbol"));
3694 }
3695
3696 #[test]
3697 fn try_catches_arity_mismatch() {
3698 let v = run_full(
3699 "(try
3700 ((lambda (x y) (+ x y)) 1)
3701 (catch (e) (error-tag e)))",
3702 );
3703 assert!(matches!(v, Value::Keyword(s) if &*s == "arity-mismatch"));
3704 }
3705
3706 #[test]
3707 fn nested_try_inner_handler_takes_precedence() {
3708 let v = run_full(
3709 "(try
3710 (try
3711 (throw (ex-info \"inner\" ()))
3712 (catch (e) :inner-caught))
3713 (catch (e) :outer-caught))",
3714 );
3715 assert!(matches!(v, Value::Keyword(s) if &*s == "inner-caught"));
3716 }
3717
3718 #[test]
3719 fn outer_try_catches_when_handler_rethrows() {
3720 let v = run_full(
3721 "(try
3722 (try
3723 (throw (ex-info \"first\" ()))
3724 (catch (e) (throw (ex-info \"rethrown\" ()))))
3725 (catch (e) (error-message e)))",
3726 );
3727 assert_eq!(format!("{v}"), "\"rethrown\"");
3728 }
3729
3730 #[test]
3731 fn throw_propagates_when_no_try() {
3732 let mut i: Interpreter<NoHost> = Interpreter::new();
3734 install_full_stdlib_with(&mut i, &mut NoHost);
3735 let forms = read_spanned("(throw (ex-info \"unhandled\" (list :code 99)))").unwrap();
3736 let err = i.eval_program(&forms, &mut NoHost).unwrap_err();
3737 match err {
3738 EvalError::User { value, .. } => match value {
3739 Value::Error(e) => {
3740 assert_eq!(&*e.message, "unhandled");
3741 }
3742 other => panic!("{other:?}"),
3743 },
3744 other => panic!("{other:?}"),
3745 }
3746 }
3747
3748 #[test]
3751 fn macroexpand_one_step() {
3752 let v = run_full(
3753 "(defmacro twice (x) `(* ,x 2))
3754 (macroexpand-1 '(twice 7))",
3755 );
3756 assert_eq!(format!("{v}"), "(* 7 2)");
3758 }
3759
3760 #[test]
3761 fn macroexpand_full_until_fixed_point() {
3762 let v = run_full(
3763 "(defmacro twice (x) `(* ,x 2))
3764 (defmacro quad (x) `(twice (twice ,x)))
3765 (macroexpand '(quad 5))",
3766 );
3767 assert_eq!(format!("{v}"), "(* (* 5 2) 2)");
3769 }
3770
3771 #[test]
3772 fn macroexpand_returns_unchanged_for_non_macro() {
3773 let v = run_full("(macroexpand-1 '(+ 1 2 3))");
3774 assert_eq!(format!("{v}"), "(+ 1 2 3)");
3776 }
3777
3778 #[test]
3779 fn macroexpand_one_does_not_recurse_into_children() {
3780 let v = run_full(
3782 "(defmacro twice (x) `(* ,x 2))
3783 (defmacro outer (x) `(list ,x))
3784 (macroexpand-1 '(outer (twice 3)))",
3785 );
3786 assert_eq!(format!("{v}"), "(list (twice 3))");
3788 }
3789
3790 #[test]
3791 fn macroexpand_recurses_into_children() {
3792 let v = run_full(
3793 "(defmacro twice (x) `(* ,x 2))
3794 (defmacro outer (x) `(list ,x))
3795 (macroexpand '(outer (twice 3)))",
3796 );
3797 assert_eq!(format!("{v}"), "(list (* 3 2))");
3799 }
3800
3801 fn run_with_modules(modules: &[(&str, &str)], src: &str) -> Value {
3804 use crate::module::MapLoader;
3805 let mut i: Interpreter<NoHost> = Interpreter::new();
3806 install_full_stdlib_with(&mut i, &mut NoHost);
3807 let mut loader = MapLoader::new();
3808 for (path, source) in modules {
3809 loader.insert(*path, *source);
3810 }
3811 i.set_loader(Arc::new(loader));
3812 let forms = read_spanned(src).unwrap();
3813 i.eval_program(&forms, &mut NoHost).unwrap()
3814 }
3815
3816 fn run_with_modules_err(modules: &[(&str, &str)], src: &str) -> EvalError {
3817 use crate::module::MapLoader;
3818 let mut i: Interpreter<NoHost> = Interpreter::new();
3819 install_full_stdlib_with(&mut i, &mut NoHost);
3820 let mut loader = MapLoader::new();
3821 for (path, source) in modules {
3822 loader.insert(*path, *source);
3823 }
3824 i.set_loader(Arc::new(loader));
3825 let forms = read_spanned(src).unwrap();
3826 i.eval_program(&forms, &mut NoHost).unwrap_err()
3827 }
3828
3829 #[test]
3830 fn require_with_explicit_alias_imports_qualified_names() {
3831 let v = run_with_modules(
3832 &[(
3833 "lib/math",
3834 "(define square (lambda (x) (* x x)))
3835 (define cube (lambda (x) (* x x x)))
3836 (provide square cube)",
3837 )],
3838 "(require \"lib/math\" :as math)
3839 (math/square 7)",
3840 );
3841 assert!(matches!(v, Value::Int(49)));
3842 }
3843
3844 #[test]
3845 fn require_uses_path_as_default_alias() {
3846 let v = run_with_modules(
3847 &[(
3848 "lib/math",
3849 "(define double (lambda (x) (* x 2))) (provide double)",
3850 )],
3851 "(require \"lib/math\")
3852 (lib/math/double 21)",
3853 );
3854 assert!(matches!(v, Value::Int(42)));
3857 }
3858
3859 #[test]
3860 fn require_refer_imports_unqualified_names() {
3861 let v = run_with_modules(
3862 &[(
3863 "lib/math",
3864 "(define square (lambda (x) (* x x)))
3865 (define cube (lambda (x) (* x x x)))
3866 (provide square cube)",
3867 )],
3868 "(require \"lib/math\" :refer (square))
3869 (square 6)",
3870 );
3871 assert!(matches!(v, Value::Int(36)));
3872 }
3873
3874 #[test]
3875 fn require_does_not_import_non_provided() {
3876 let err = run_with_modules_err(
3879 &[(
3880 "lib/secret",
3881 "(define public 1)
3882 (define private 2)
3883 (provide public)",
3884 )],
3885 "(require \"lib/secret\" :as s)
3886 s/private",
3887 );
3888 match err {
3889 EvalError::UnboundSymbol { name, .. } => assert_eq!(&*name, "s/private"),
3890 other => panic!("{other:?}"),
3891 }
3892 }
3893
3894 #[test]
3895 fn require_chain_a_imports_b() {
3896 let v = run_with_modules(
3897 &[
3898 (
3899 "lib/util",
3900 "(define inc1 (lambda (n) (+ n 1)))
3901 (provide inc1)",
3902 ),
3903 (
3904 "lib/wrapper",
3905 "(require \"lib/util\" :as u)
3906 (define inc2 (lambda (n) (u/inc1 (u/inc1 n))))
3907 (provide inc2)",
3908 ),
3909 ],
3910 "(require \"lib/wrapper\" :as w)
3911 (w/inc2 10)",
3912 );
3913 assert!(matches!(v, Value::Int(12)));
3914 }
3915
3916 #[test]
3917 fn require_module_not_found() {
3918 let err = run_with_modules_err(&[], "(require \"missing/module\")");
3919 match err {
3921 EvalError::User { value, .. } => match value {
3922 Value::Error(e) => {
3923 assert_eq!(&*e.tag, "module-not-found");
3924 assert!(e.message.contains("missing/module"));
3925 }
3926 other => panic!("{other:?}"),
3927 },
3928 other => panic!("{other:?}"),
3929 }
3930 }
3931
3932 #[test]
3933 fn circular_require_detected() {
3934 let err = run_with_modules_err(
3935 &[
3936 ("a", "(require \"b\") (provide x) (define x 1)"),
3937 ("b", "(require \"a\") (provide y) (define y 2)"),
3938 ],
3939 "(require \"a\")",
3940 );
3941 match err {
3942 EvalError::User { value, .. } => match value {
3943 Value::Error(e) => assert_eq!(&*e.tag, "circular-require"),
3944 other => panic!("{other:?}"),
3945 },
3946 other => panic!("{other:?}"),
3947 }
3948 }
3949
3950 #[test]
3951 fn provide_at_top_level_errors() {
3952 let mut i: Interpreter<NoHost> = Interpreter::new();
3954 install_full_stdlib_with(&mut i, &mut NoHost);
3955 let forms = read_spanned("(provide x)").unwrap();
3956 let err = i.eval_program(&forms, &mut NoHost).unwrap_err();
3957 assert!(matches!(err, EvalError::BadSpecialForm { form, .. } if &*form == "provide"));
3958 }
3959
3960 #[test]
3961 fn require_refer_unknown_name_errors() {
3962 let err = run_with_modules_err(
3963 &[(
3964 "lib/math",
3965 "(define square (lambda (x) (* x x))) (provide square)",
3966 )],
3967 "(require \"lib/math\" :refer (square cube))",
3968 );
3969 match err {
3970 EvalError::User { value, .. } => match value {
3971 Value::Error(e) => {
3972 assert!(matches!(&*e.tag, "not-defined" | "not-exported"));
3973 }
3974 other => panic!("{other:?}"),
3975 },
3976 other => panic!("{other:?}"),
3977 }
3978 }
3979
3980 #[test]
3981 fn require_caches_module_load_once() {
3982 let v = run_with_modules(
3983 &[("lib/foo", "(define x 42) (provide x)")],
3984 "(require \"lib/foo\" :as a)
3985 (require \"lib/foo\" :as b)
3986 (+ a/x b/x)",
3987 );
3988 assert!(matches!(v, Value::Int(84)));
3990 }
3991
3992 #[test]
4001 fn macro_body_cannot_set_a_global() {
4002 let mut interp = Interpreter::new();
4003 install_primitives(&mut interp);
4004 let src = "(define *g* 0) (defmacro leak () (set! *g* 99)) (leak)";
4005 let forms = tatara_lisp::read_spanned(src).expect("parse");
4006 let err = interp
4007 .eval_program(&forms, &mut ())
4008 .expect_err("a macro must not be able to set! a global");
4009 let msg = format!("{err}");
4010 assert!(
4011 msg.contains("sealed") || msg.contains("cannot `set!`"),
4012 "expected a sealed-write diagnostic, got: {msg}"
4013 );
4014 }
4015
4016 #[test]
4017 fn the_global_is_actually_unchanged_after_a_refused_macro_set() {
4018 let mut interp = Interpreter::new();
4019 install_primitives(&mut interp);
4020 let forms = tatara_lisp::read_spanned("(define *g* 0) (defmacro leak () (set! *g* 99))")
4021 .expect("parse");
4022 interp.eval_program(&forms, &mut ()).expect("setup");
4023 let call = tatara_lisp::read_spanned("(leak)").expect("parse");
4025 let _ = interp.eval_program(&call, &mut ());
4026 let read = tatara_lisp::read_spanned("*g*").expect("parse");
4027 let v = interp.eval_program(&read, &mut ()).expect("read *g*");
4028 assert!(
4029 matches!(v, Value::Int(0)),
4030 "global was mutated by a macro body despite the seal: {v:?}"
4031 );
4032 }
4033
4034 #[test]
4037 fn ordinary_set_still_works_at_runtime() {
4038 let mut interp = Interpreter::new();
4039 install_primitives(&mut interp);
4040 let forms = tatara_lisp::read_spanned("(define x 1) (set! x 42) x").expect("parse");
4041 let v = interp.eval_program(&forms, &mut ()).expect("runtime set!");
4042 assert!(matches!(v, Value::Int(42)), "got {v:?}");
4043 }
4044
4045 #[test]
4048 fn macro_body_can_mutate_its_own_locals() {
4049 let mut interp = Interpreter::new();
4050 install_primitives(&mut interp);
4051 let src = "(defmacro m () (begin (define n 1) (set! n 2) n)) (m)";
4052 let forms = tatara_lisp::read_spanned(src).expect("parse");
4053 let v = interp
4054 .eval_program(&forms, &mut ())
4055 .expect("a macro must be able to mutate its own locals");
4056 assert!(matches!(v, Value::Int(2)), "got {v:?}");
4057 }
4058}