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