1use std::{collections::HashMap, sync::atomic::AtomicU16};
2
3use bumpalo::Bump;
4use gc::{is_garbage_collected, MemoryManager};
5use log::*;
6
7use compiler::Compiler;
8use error::{BacktraceError, VmError, VmResult};
9pub use settings::Settings;
10use stack_frame::StackFrame;
11use val::{
12 custom::CustomVal, ByteCode, CustomType, Instruction, NativeFunction, NativeFunctionContext,
13 ProtectedVal, Symbol, UnsafeVal, Val, ValId,
14};
15
16mod builtins;
17mod compiler;
18pub mod error;
19mod gc;
20pub mod parser;
21pub mod repl;
22mod settings;
23mod stack_frame;
24pub mod val;
25
26type BumpVec<'a, T> = bumpalo::collections::Vec<'a, T>;
27
28pub const ISSUE_LINK: &str = "https://github.com/wmedrano/spore/issues";
30
31#[derive(Debug)]
46pub struct Vm {
47 stack: Vec<UnsafeVal>,
49 values: HashMap<Symbol, UnsafeVal>,
51 stack_frame: StackFrame,
53 previous_stack_frames: Vec<StackFrame>,
55 pub(crate) objects: MemoryManager,
57 settings: Settings,
59 tmp_arena: Option<Bump>,
61}
62
63impl Default for Vm {
64 fn default() -> Vm {
66 Vm::new(Settings::default())
67 }
68}
69
70static VM_ID: AtomicU16 = AtomicU16::new(1);
73
74impl Vm {
75 pub fn new(settings: Settings) -> Vm {
77 let start_t = std::time::Instant::now();
78 let vm_id = VM_ID.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
79 let mut vm = Vm {
80 stack: Vec::with_capacity(4096),
83 values: HashMap::new(),
84 previous_stack_frames: Vec::with_capacity(64),
86 stack_frame: StackFrame::default(),
87 objects: MemoryManager::new(vm_id),
88 settings,
89 tmp_arena: Some(Bump::new()),
90 };
91 for (name, func) in builtins::BUILTINS {
92 vm = vm.with_native_function(name, *func);
93 }
94 info!(
95 "Initialized Spore VM in {elapsed:?} with {settings:?}",
96 elapsed = start_t.elapsed()
97 );
98 vm
99 }
100
101 pub fn with_native_function(mut self, name: &str, func: NativeFunction) -> Self {
103 let func: UnsafeVal = func.into();
104 assert!(!is_garbage_collected(func));
105 unsafe { self.register_value(name, func) };
107 self
108 }
109
110 pub fn with_custom_value(mut self, name: &str, val: impl CustomType) -> Self {
131 let id = self.objects.insert_custom(CustomVal::new(val));
132 unsafe { self.register_value(name, id) };
134 self
135 }
136
137 pub fn with(self, f: impl Fn(Vm) -> Vm) -> Self {
139 f(self)
140 }
141
142 unsafe fn register_value(&mut self, name: &str, val: impl Into<UnsafeVal>) {
147 let val = val.into();
148 info!(
149 "Registering {name:?} to a(n) {tp} value.",
150 tp = val.type_name()
151 );
152 let interned_sym = self.get_or_create_symbol(name);
153 self.values.insert(interned_sym, val);
154 }
155}
156
157impl Vm {
158 pub fn val_by_name(&self, name: &str) -> Option<Val> {
160 let interned_name = self.get_symbol(name)?;
161 self.values
162 .get(&interned_name)
163 .copied()
164 .map(|v| unsafe { Val::from_unsafe_val(v) })
166 }
167
168 pub fn eval_str(&mut self, source: &str) -> VmResult<ProtectedVal> {
175 let mut arena = self.tmp_arena.take().unwrap_or_else(|| {
176 warn!("Arena was unexpectedly unavailable. Please file an issue at {ISSUE_LINK} with proper context.");
177 Bump::new()
178 });
179 let bytecode = Compiler::compile(self, source, &arena)?;
180 arena.reset();
181 self.tmp_arena = Some(arena);
182 let bytecode_id = self.objects.insert_bytecode(bytecode);
183 self.eval_bytecode(bytecode_id, std::iter::empty())
184 }
185
186 pub fn eval_function_by_name(
199 &mut self,
200 name: &str,
201 args: impl ExactSizeIterator<Item = Val<'static>>,
202 ) -> VmResult<ProtectedVal> {
203 let interned_name = self.get_or_create_symbol(name);
204 let function_val =
205 *self
206 .values
207 .get(&interned_name)
208 .ok_or_else(|| VmError::SymbolNotDefined {
209 src: None,
210 symbol: name.to_string(),
211 })?;
212 let bytecode_id = match function_val {
213 UnsafeVal::ByteCodeFunction(bc) => bc,
214 UnsafeVal::NativeFunction(f) => self
215 .objects
216 .insert_bytecode(ByteCode::new_native_function_call(name, f, args.len())),
217 v => {
218 return Err(VmError::TypeError {
219 src: None,
220 context: "eval-function-by-name",
221 expected: UnsafeVal::FUNCTION_TYPE_NAME,
222 actual: v.type_name(),
223 value: v.formatted(self).to_string(),
224 })
225 }
226 };
227 let args = args.map(|arg| unsafe { arg.as_unsafe_val() });
229 self.eval_bytecode(bytecode_id, args)
230 }
231
232 fn eval_bytecode(
234 &mut self,
235 bytecode_id: ValId<ByteCode>,
236 args: impl Iterator<Item = UnsafeVal>,
237 ) -> VmResult<ProtectedVal> {
238 let bytecode = self.objects.get_bytecode(bytecode_id).unwrap();
239 self.previous_stack_frames.clear();
240 self.stack.clear();
241 self.stack.extend(args);
242 self.stack
243 .extend(std::iter::repeat(UnsafeVal::Void).take(bytecode.local_bindings));
244 self.stack_frame = StackFrame::new(bytecode_id, bytecode, 0);
245 unsafe { self.run_gc() };
247 loop {
248 if let Some(v) = self.run_next().map_err(|err| self.annotate_src(err))? {
249 let v = unsafe { Val::from_unsafe_val(v) };
251 return Ok(ProtectedVal::new(self, v));
252 }
253 }
254 }
255
256 fn annotate_src(&self, error: VmError) -> VmError {
257 match self.stack_frame.previous_instruction_source(self) {
258 Some(src) => error.with_src(src),
259 None => error,
260 }
261 }
262
263 fn run_next(&mut self) -> VmResult<Option<UnsafeVal>> {
268 let maybe_instruction = self
269 .stack_frame
270 .instructions
271 .as_ref()
272 .get(self.stack_frame.instruction_idx);
273 let instruction = maybe_instruction.unwrap_or(&Instruction::Return);
274 self.stack_frame.instruction_idx += 1;
275 match instruction {
276 Instruction::PushConst(c) => self.stack.push(*c),
277 Instruction::PushCurrentFunction => {
278 let f = UnsafeVal::ByteCodeFunction(self.stack_frame.bytecode_id);
279 self.stack.push(f);
280 }
281 Instruction::Pop(n) => {
282 let start = self.stack.len() - n;
283 self.stack.drain(start..);
284 }
285 Instruction::GetArg(n) => {
286 let val = self.stack[self.stack_frame.stack_start + *n];
287 self.stack.push(val);
288 }
289 Instruction::BindArg(n) => {
290 let val = self.stack.pop().unwrap();
291 self.stack[self.stack_frame.stack_start + *n] = val;
292 }
293 Instruction::Deref(symbol) => {
294 let v = match self.values.get(symbol) {
295 Some(v) => *v,
296 None => {
297 return Err(VmError::SymbolNotDefined {
298 src: None,
299 symbol: self
300 .symbol_to_str(*symbol)
301 .unwrap_or("*symbol-not-registered*")
302 .to_string(),
303 });
304 }
305 };
306 self.stack.push(v);
307 }
308 Instruction::Define(symbol) => {
309 let v = self.stack.pop().ok_or_else(BacktraceError::capture)?;
310 self.values.insert(*symbol, v);
311 }
312 Instruction::Eval(n) => {
313 self.execute_eval(*n)?;
314 }
315 Instruction::EvalNative { func, arg_count } => {
316 self.execute_eval_native(*func, *arg_count)?;
317 }
318 Instruction::JumpIf(n) => {
319 if self.stack.pop().unwrap().is_truthy() {
320 self.stack_frame.instruction_idx += *n;
321 }
322 }
323 Instruction::Jump(n) => {
324 self.stack_frame.instruction_idx += *n;
325 }
326 Instruction::Return => return Ok(self.execute_return()),
327 }
328 Ok(None)
329 }
330
331 fn execute_eval_native(&mut self, func: NativeFunction, arg_count: usize) -> VmResult<()> {
332 let stack_start = self.stack.len() - arg_count;
333 let args = unsafe {
334 let slice = std::slice::from_raw_parts(self.stack.as_ptr().add(stack_start), arg_count);
335 Val::from_unsafe_val_slice(slice)
336 };
337 let builder = func(NativeFunctionContext::new(self), args)?;
338 let v = unsafe { builder.build() };
340 match arg_count {
341 0 => {
342 self.stack.push(v);
343 }
344 _ => {
345 self.stack.truncate(stack_start + 1);
346 self.stack[stack_start] = v;
347 }
348 };
349 Ok(())
350 }
351
352 fn execute_eval(&mut self, n: usize) -> VmResult<()> {
356 if n == 0 {
357 Err(BacktraceError::capture())?;
358 }
359 let function_idx = self
360 .stack
361 .len()
362 .checked_sub(n)
363 .ok_or_else(BacktraceError::capture)?;
364 let stack_start = function_idx + 1;
365 let func_val = self.stack[function_idx];
366 match func_val {
367 UnsafeVal::NativeFunction(func) => {
368 let args = unsafe {
369 let slice =
370 std::slice::from_raw_parts(self.stack.as_ptr().add(stack_start), n - 1);
371 Val::from_unsafe_val_slice(slice)
372 };
373 let builder = func(NativeFunctionContext::new(self), args)?;
374 let v = unsafe { builder.build() };
376 self.stack[function_idx] = v;
377 self.stack.truncate(stack_start);
378 Ok(())
379 }
380 UnsafeVal::ByteCodeFunction(bytecode_id) => {
381 let bytecode = {
382 let bytecode = self.objects.get_bytecode(bytecode_id).unwrap();
383 let arg_count = n - 1;
384 if bytecode.arg_count != arg_count {
385 return Err(VmError::ArityError {
386 function: bytecode.name.clone(),
387 expected: bytecode.arg_count,
388 actual: arg_count,
389 });
390 }
391 if self.previous_stack_frames.capacity() == self.previous_stack_frames.len() {
392 return Err(self.execute_call_stack_limit_reached());
393 }
394 bytecode
395 };
396 self.stack
397 .extend(std::iter::repeat(UnsafeVal::Void).take(bytecode.local_bindings));
398 let previous_stack_frame = std::mem::replace(
399 &mut self.stack_frame,
400 StackFrame::new(bytecode_id, bytecode, stack_start),
401 );
402 self.previous_stack_frames.push(previous_stack_frame);
403 Ok(())
404 }
405 _ => Err(VmError::TypeError {
406 src: None,
407 context: "function invocation",
408 expected: UnsafeVal::FUNCTION_TYPE_NAME,
409 actual: func_val.type_name(),
410 value: func_val.formatted(self).to_string(),
411 }),
412 }
413 }
414
415 fn execute_call_stack_limit_reached(&mut self) -> VmError {
416 let mut call_stack = Vec::with_capacity(1 + self.previous_stack_frames.len());
417 call_stack.push(self.stack_frame.bytecode(self).name.clone());
418 call_stack.extend(
419 self.previous_stack_frames
420 .iter()
421 .rev()
422 .map(|sf| sf.bytecode(self).name.clone()),
423 );
424 VmError::MaximumFunctionCallDepth {
425 call_stack,
426 max_depth: self.previous_stack_frames.len(),
427 }
428 }
429
430 fn execute_return(&mut self) -> Option<UnsafeVal> {
432 let ret_val: UnsafeVal = if self.stack_frame.stack_start < self.stack.len() {
434 self.stack.pop().unwrap()
436 } else {
437 ().into()
438 };
439 match self.previous_stack_frames.pop() {
441 Some(c) => {
443 self.stack.truncate(self.stack_frame.stack_start);
444 match self.stack.last_mut() {
445 Some(v) => *v = ret_val,
446 None => unreachable!(),
447 }
448 self.stack_frame = c;
449 None
450 }
451 None => {
453 std::mem::take(&mut self.stack_frame);
454 self.stack.clear();
455 Some(ret_val)
456 }
457 }
458 }
459}
460
461impl Vm {
462 pub unsafe fn run_gc(&mut self) {
470 let is_gc = |v: &UnsafeVal| is_garbage_collected(*v);
471 let mut arena = self.tmp_arena.take().unwrap_or_else(|| {
472 warn!("Arena was unexpectedly unavailable. Please file an issue at {ISSUE_LINK} with proper context.");
473 Bump::new()
474 });
475 {
476 let mut bytecodes: BumpVec<(ValId<_>, ByteCode)> = BumpVec::new_in(&arena);
477 bytecodes.push((
478 self.stack_frame.bytecode_id,
479 self.stack_frame.bytecode(self).clone(),
480 ));
481 for previous_frame in self.previous_stack_frames.iter() {
482 bytecodes.push((
483 previous_frame.bytecode_id,
484 previous_frame.bytecode(self).clone(),
485 ));
486 }
487 let vals = self
488 .stack
489 .iter()
490 .copied()
491 .filter(is_gc)
492 .chain(self.values.values().copied().filter(is_gc))
493 .chain(bytecodes.iter().flat_map(|(id, bytecode)| {
494 bytecode
495 .values()
496 .filter(is_gc)
497 .chain(std::iter::once((*id).into()))
498 }));
499 self.objects.run_gc(&arena, vals);
500 }
501 arena.reset();
502 self.tmp_arena = Some(arena);
503 }
504}
505
506impl Vm {
507 pub fn get_symbol(&self, s: &str) -> Option<Symbol> {
509 self.objects.get_symbol(s)
510 }
511
512 pub fn get_or_create_symbol(&mut self, s: &str) -> Symbol {
514 self.objects.get_or_create_symbol(s)
515 }
516
517 pub fn symbol_to_str(&self, s: Symbol) -> Option<&str> {
519 self.objects.symbol_to_str(s)
520 }
521}
522
523impl Drop for Vm {
524 fn drop(&mut self) {
525 info!("Dropping Spore VM.");
526 }
527}
528
529#[cfg(test)]
530mod tests {
531 use error::CompileError;
532 use parser::span::Span;
533
534 use super::*;
535
536 #[test]
537 fn constant_expression_evaluates_to_constant() {
538 let mut vm = Vm::default();
539 let actual = vm.eval_str("42").unwrap();
540 assert_eq!(actual.try_int().unwrap(), 42);
541 }
542
543 #[test]
544 fn expression_can_evaluate() {
545 let mut vm = Vm::default();
546 let actual = vm.eval_str("(+ 1 2 3 4.0)").unwrap();
547 assert_eq!(actual.try_float().unwrap(), 10.0);
548 }
549
550 #[test]
551 fn list_function_returns_list() {
552 let mut vm = Vm::default();
553 let actual = vm.eval_str("(list 1 2.3 \"three\")").unwrap();
554 assert_eq!(actual.to_string(), "(1 2.3 \"three\")");
555 }
556
557 #[test]
558 fn vm_error_is_reported() {
559 let mut vm = Vm::default();
560 let src = "(+ true false)";
561 let actual = vm.eval_str(src).unwrap_err();
562 assert_eq!(
563 actual,
564 VmError::TypeError {
565 src: Some(Span::new(0, 14).with_src(src.into())),
566 context: "+",
567 expected: "int or float",
568 actual: UnsafeVal::BOOL_TYPE_NAME,
569 value: "true".to_string(),
570 }
571 );
572 }
573
574 #[test]
575 fn compile_error_is_reported() {
576 let mut vm = Vm::default();
577 let actual = vm.eval_str("((define x 12))").unwrap_err();
578 assert_eq!(
579 actual,
580 VmError::CompileError(CompileError::DefineNotAllowed)
581 );
582 }
583
584 #[test]
585 fn defined_variable_can_be_referenced() {
586 let mut vm = Vm::default();
587 assert_eq!(
588 vm.eval_str("(define x 12) (+ x x)")
589 .unwrap()
590 .try_int()
591 .unwrap(),
592 24
593 );
594 assert_eq!(vm.eval_str("(+ x 10)").unwrap().try_int().unwrap(), 22);
595 }
596
597 #[test]
598 fn if_statement_can_return_any_of() {
599 let mut vm = Vm::default();
600 assert_eq!(
601 vm.eval_str("(if true (+ 1 2))").unwrap().try_int().unwrap(),
602 3
603 );
604 assert_eq!(
605 vm.eval_str("(if true (+ 1 2) (+ 3 4))")
606 .unwrap()
607 .try_int()
608 .unwrap(),
609 3
610 );
611 assert_eq!(
612 vm.eval_str("(if false (+ 1 2) (+ 3 4))")
613 .unwrap()
614 .try_int()
615 .unwrap(),
616 7
617 );
618 let got = vm.eval_str("(if false (+ 1 2))").unwrap();
619 assert!(got.is_void(), "{got}");
620 }
621
622 #[test]
623 fn if_statement_with_truthy_predicate_true_branch() {
624 let mut vm = Vm::default();
625 assert_eq!(
626 vm.eval_str("(if 1 (+ 1 2) (+ 3 4))")
627 .unwrap()
628 .try_int()
629 .unwrap(),
630 3
631 );
632 assert_eq!(vm.eval_str("(if 1 (+ 1 2))").unwrap().try_int().unwrap(), 3);
633 }
634
635 #[test]
636 fn lambda_can_be_evaluated() {
637 let mut vm = Vm::default();
638 assert_eq!(
639 vm.eval_str("((lambda () 7))").unwrap().try_int().unwrap(),
640 7
641 );
642 assert_eq!(
643 vm.eval_str("((lambda () (+ 1 2 3)))")
644 .unwrap()
645 .try_int()
646 .unwrap(),
647 6
648 );
649 }
650
651 #[test]
652 fn lambda_with_args_can_be_evaluated() {
653 let mut vm = Vm::default();
654 assert_eq!(
655 vm.eval_str("((lambda (a b) 4) 1 2)")
656 .unwrap()
657 .try_int()
658 .unwrap(),
659 4,
660 );
661 assert_eq!(
662 vm.eval_str("((lambda (a b) (+ a b)) 1 2)")
663 .unwrap()
664 .try_int()
665 .unwrap(),
666 3
667 );
668 }
669
670 #[test]
671 fn function_called_with_wrong_number_of_args_produces_error() {
672 let mut vm = Vm::default();
673 assert_eq!(
674 vm.eval_str("((lambda () 10) 1)").unwrap_err(),
675 VmError::ArityError {
676 function: "".into(),
677 expected: 0,
678 actual: 1
679 },
680 );
681 assert_eq!(
682 vm.eval_str("((lambda (a) a))").unwrap_err(),
683 VmError::ArityError {
684 function: "".into(),
685 expected: 1,
686 actual: 0
687 },
688 );
689 let mut got = vm
690 .eval_str("(define (takes-two-args arg1 arg2) (+ arg1 arg2))")
691 .unwrap();
692 assert!(got.is_void(), "{got}");
693 let (vm, _) = got.split();
694 assert_eq!(
695 vm.eval_str("(takes-two-args 1)").unwrap_err(),
696 VmError::ArityError {
697 function: "takes-two-args".into(),
698 expected: 2,
699 actual: 1,
700 },
701 );
702 }
703
704 #[test]
705 fn can_get_val_by_name() {
706 let mut vm = Vm::default();
707 vm.eval_str("(define one 1) (define two 2)").unwrap();
708 assert_eq!(vm.val_by_name("one").unwrap().try_int().unwrap(), 1);
709 assert_eq!(vm.val_by_name("two").unwrap().try_int().unwrap(), 2);
710 }
711
712 #[test]
713 fn getting_val_that_does_not_exist_returns_err() {
714 let mut vm = Vm::default();
715 vm.eval_str("(define one 1) (define two 2)").unwrap();
716 assert!(vm.val_by_name("three").is_none());
717 }
718
719 #[test]
720 fn can_eval_by_function_with_native_function() {
721 let mut vm = Vm::default();
722 let ans = vm
723 .eval_function_by_name("+", [10.into(), 5.into()].into_iter())
724 .unwrap()
725 .try_int()
726 .unwrap();
727 assert_eq!(ans, 15);
728 }
729
730 #[test]
731 fn eval_function_that_does_not_exist_produces_error() {
732 let mut vm = Vm::default();
733 vm.eval_str("(define (foo) 1)").unwrap();
734 assert_eq!(
735 vm.eval_function_by_name("bar", std::iter::empty())
736 .unwrap_err(),
737 VmError::SymbolNotDefined {
738 src: None,
739 symbol: "bar".into()
740 },
741 );
742 }
743
744 #[test]
745 fn eval_function_that_is_not_function_produces_error() {
746 let mut vm = Vm::default();
747 vm.eval_str("(define foo 100)").unwrap();
748 assert_eq!(
749 vm.eval_function_by_name("foo", std::iter::empty())
750 .unwrap_err(),
751 VmError::TypeError {
752 src: None,
753 context: "eval-function-by-name",
754 expected: UnsafeVal::FUNCTION_TYPE_NAME,
755 actual: UnsafeVal::INT_TYPE_NAME,
756 value: "100".into(),
757 }
758 );
759 }
760
761 #[test]
762 fn can_call_function_recursively() {
763 let mut vm = Vm::default();
764 vm.eval_str("(define (fib n) (if (< n 2) n (+ (fib (+ n -1)) (fib (+ n -2)))))")
765 .unwrap();
766 let ans = vm
767 .eval_function_by_name("fib", std::iter::once(10.into()))
768 .unwrap()
769 .try_int()
770 .unwrap();
771 assert_eq!(ans, 55);
772 }
773
774 #[test]
775 fn infinite_recursion_halts() {
776 let mut vm = Vm::default();
777 assert!(vm
778 .eval_str("(define (recurse) (recurse))")
779 .unwrap()
780 .is_void());
781 assert_eq!(
782 vm.eval_str("(recurse)").unwrap_err(),
783 VmError::MaximumFunctionCallDepth {
784 max_depth: 64,
785 call_stack: std::iter::repeat("recurse")
786 .take(64)
787 .chain(std::iter::once(""))
788 .map(Into::into)
789 .collect(),
790 }
791 );
792 }
793
794 #[test]
795 fn aggressive_inline_produces_same_results_when_there_are_no_redefinitions() {
796 let mut aggressive_inline_vm = Vm::new(Settings {
797 enable_aggressive_inline: true,
798 enable_source_maps: false,
799 });
800 let mut default_vm = Vm::new(Settings {
801 enable_aggressive_inline: false,
802 enable_source_maps: true,
803 });
804 let srcs = ["(define x 12)", "x", "(+ x x)"];
805 for src in srcs {
806 assert_eq!(
807 aggressive_inline_vm.eval_str(src).unwrap().to_string(),
808 default_vm.eval_str(src).unwrap().to_string(),
809 )
810 }
811 }
812
813 #[test]
814 fn let_statement() {
815 let mut vm = Vm::default();
816 assert_eq!(
817 vm.eval_str("(let ([x 10] [y 20] [z (+ x y)]) (+ x y z))")
818 .unwrap()
819 .try_int()
820 .unwrap(),
821 60
822 );
823 }
824
825 #[test]
826 fn when_multiple_bindings_exist_last_one_is_used() {
827 let mut vm = Vm::default();
828 let src = r#"
829(let ([x 1])
830 (let ([x 2]
831 [x (+ x x)])
832 x))
833"#;
834 assert_eq!(vm.eval_str(src).unwrap().try_int().unwrap(), 4);
835 }
836
837 #[test]
838 fn multiple_bindings_dont_affect_previous_binding_when_out_of_scope() {
839 let mut vm = Vm::default();
840 let src = r#"
841(let ([x 1])
842 (let ([x 2]
843 [x (+ x x)])
844 x)
845x)
846"#;
847 assert_eq!(vm.eval_str(src).unwrap().try_int().unwrap(), 1);
848 }
849
850 #[test]
851 fn local_bindings_take_precedence_over_arguments() {
852 let mut vm = Vm::default();
853 let src = r#"
854(define (foo x)
855 (let ([old-x x]
856 [x 10])
857 (+ old-x x)))
858
859(foo 100)
860"#;
861 assert_eq!(vm.eval_str(src).unwrap().try_int().unwrap(), 110);
862 }
863
864 #[test]
865 fn empty_or_returns_false() {
866 let mut vm = Vm::default();
867 let src = "(or)";
868 assert!(!vm.eval_str(src).unwrap().try_bool().unwrap());
869 }
870
871 #[test]
872 fn or_with_true_returns_true() {
873 let mut vm = Vm::default();
874 let src = "(or false false true false)";
875 assert!(vm.eval_str(src).unwrap().try_bool().unwrap());
876 }
877
878 #[test]
879 fn or_with_truthy_values_returns_first_truthy_value() {
880 let mut vm = Vm::default();
881 let src = "(or false false 5 4 3 2)";
882 assert_eq!(vm.eval_str(src).unwrap().try_int().unwrap(), 5);
883 }
884
885 #[test]
886 fn or_with_all_false_or_void_returns_last_arg() {
887 let mut vm = Vm::default();
888 assert!(vm
889 .eval_str("(or void false void false void)")
890 .unwrap()
891 .is_void());
892 assert!(!vm
893 .eval_str("(or void false void false void false)")
894 .unwrap()
895 .try_bool()
896 .unwrap());
897 }
898
899 #[test]
900 fn and_with_no_args_returns_true() {
901 let mut vm = Vm::default();
902 let src = "(and)";
903 assert!(vm.eval_str(src).unwrap().try_bool().unwrap());
904 }
905
906 #[test]
907 fn and_with_all_truthy_args_returns_last_arg() {
908 let mut vm = Vm::default();
909 let src = "(and 1 2 3 4)";
910 assert_eq!(vm.eval_str(src).unwrap().try_int().unwrap(), 4);
911 }
912
913 #[test]
914 fn and_with_false_arg_returns_first_false_arg() {
915 let mut vm = Vm::default();
916 assert!(!vm
917 .eval_str("(and 1 2 false 3 4)")
918 .unwrap()
919 .try_bool()
920 .unwrap());
921 assert!(vm.eval_str("(and 1 2 void 3 4)").unwrap().is_void());
922 }
923}