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