1use crate::{
2 Error,
3 cons::{Cons, NEVER, Tag},
4 number::Number,
5 r#type::Type,
6 value::Value,
7};
8use core::fmt::{self, Display, Formatter, Write};
9
10const CONS_FIELD_COUNT: usize = 2;
11
12macro_rules! assert_heap_index {
13 ($self:expr, $index:expr, $garbage:expr) => {
14 let (start, end) = if $garbage {
15 let start = if $self.space { 0 } else { $self.space_size() };
16
17 (start, start + $self.space_size())
18 } else {
19 ($self.allocation_start(), $self.allocation_end())
20 };
21
22 debug_assert!(start <= $index);
23 debug_assert!($index < end);
24 };
25}
26
27macro_rules! assert_heap_cons {
28 ($self:expr, $cons:expr) => {
29 if $cons != NEVER {
30 assert_heap_index!($self, $cons.index(), false);
31 }
32 };
33}
34
35macro_rules! assert_heap_value {
36 ($self:expr, $cons:expr) => {
37 if let Some(cons) = $cons.to_cons() {
38 assert_heap_cons!($self, cons);
39 }
40 };
41}
42
43pub struct Memory<H> {
45 code: Cons,
46 stack: Cons,
47 r#false: Cons,
48 register: Cons,
49 allocation_index: usize,
50 space: bool,
51 heap: H,
52}
53
54impl<H: Heap> Memory<H> {
55 pub fn new(heap: H) -> Result<Self, Error> {
57 let mut memory = Self {
58 code: NEVER,
59 stack: NEVER,
60 r#false: NEVER,
61 register: NEVER,
62 allocation_index: 0,
63 space: false,
64 heap,
65 };
66
67 let cons = memory.allocate_unchecked(Default::default(), Default::default())?;
69 memory.r#false = memory.allocate_unchecked(cons.into(), cons.into())?;
70
71 Ok(memory)
72 }
73
74 fn heap(&self) -> &[Value] {
75 self.heap.as_ref()
76 }
77
78 fn heap_mut(&mut self) -> &mut [Value] {
79 self.heap.as_mut()
80 }
81
82 #[inline]
84 pub const fn code(&self) -> Cons {
85 self.code
86 }
87
88 #[inline]
90 pub const fn set_code(&mut self, value: Cons) {
91 self.code = value;
92 }
93
94 #[inline]
96 pub const fn register(&self) -> Cons {
97 self.register
98 }
99
100 #[inline]
102 pub const fn set_register(&mut self, value: Cons) {
103 self.register = value;
104 }
105
106 #[inline]
108 pub const fn stack(&self) -> Cons {
109 self.stack
110 }
111
112 #[inline]
114 pub const fn set_stack(&mut self, value: Cons) {
115 self.stack = value;
116 }
117
118 #[inline]
120 pub fn boolean(&self, value: bool) -> Result<Cons, Error> {
121 Ok(if value {
122 self.cdr(self.r#false)?.assume_cons()
123 } else {
124 self.r#false
125 })
126 }
127
128 #[inline]
130 pub fn null(&self) -> Result<Cons, Error> {
131 Ok(self.car(self.r#false)?.assume_cons())
132 }
133
134 #[inline]
136 pub(crate) const fn set_false(&mut self, cons: Cons) {
137 self.r#false = cons;
138 }
139
140 #[inline(always)]
142 pub fn push(&mut self, value: Value) -> Result<(), Error> {
143 self.stack = self.cons(value, self.stack)?;
144
145 Ok(())
146 }
147
148 #[inline]
150 pub fn pop(&mut self) -> Result<Value, Error> {
151 debug_assert_ne!(self.stack, self.null()?);
152
153 let value = self.car(self.stack)?;
154 self.stack = self.cdr(self.stack)?.assume_cons();
155 Ok(value)
156 }
157
158 pub fn pop_many<const M: usize>(&mut self) -> Result<[Value; M], Error> {
160 let mut values = [Default::default(); M];
161
162 for index in 0..=M - 1 {
163 values[M - 1 - index] = self.pop()?;
164 }
165
166 Ok(values)
167 }
168
169 pub fn pop_numbers<const M: usize>(&mut self) -> Result<[Number; M], Error> {
171 let mut numbers = [Default::default(); M];
172
173 for (index, value) in self.pop_many::<M>()?.into_iter().enumerate() {
174 numbers[index] = value.assume_number();
175 }
176
177 Ok(numbers)
178 }
179
180 #[inline]
182 pub fn top(&self) -> Result<Value, Error> {
183 debug_assert_ne!(self.stack, self.null()?);
184
185 self.car(self.stack)
186 }
187
188 #[inline]
190 pub fn set_top(&mut self, value: Value) -> Result<(), Error> {
191 self.set_car(self.stack, value)
192 }
193
194 #[inline]
196 pub fn cons(&mut self, car: Value, cdr: Cons) -> Result<Cons, Error> {
197 self.allocate(car, cdr.set_tag(Type::Pair as Tag).into())
198 }
199
200 #[inline]
202 pub fn allocate(&mut self, car: Value, cdr: Value) -> Result<Cons, Error> {
203 let mut cons = self.allocate_unchecked(car, cdr)?;
204
205 debug_assert_eq!(cons.tag(), Type::default() as Tag);
206 assert_heap_cons!(self, cons);
207 assert_heap_value!(self, car);
208 assert_heap_value!(self, cdr);
209
210 if self.is_out_of_memory() || cfg!(feature = "gc_always") {
211 self.collect_garbages(Some(&mut cons))?;
212 }
213
214 Ok(cons)
215 }
216
217 #[inline]
218 fn allocate_unchecked(&mut self, car: Value, cdr: Value) -> Result<Cons, Error> {
219 if self.is_out_of_memory() {
220 return Err(Error::OutOfMemory);
221 }
222
223 let cons = Cons::new(self.allocation_end() as u64);
224 self.allocation_index += CONS_FIELD_COUNT;
225
226 assert_heap_cons!(self, cons);
227
228 self.set_car(cons, car)?;
229 self.set_raw_cdr(cons, cdr)?;
230
231 debug_assert!(self.allocation_index <= self.space_size());
232
233 Ok(cons)
234 }
235
236 #[inline]
237 fn is_out_of_memory(&self) -> bool {
238 self.allocation_index >= self.space_size()
239 }
240
241 #[inline]
243 pub fn size(&self) -> usize {
244 self.heap().len()
245 }
246
247 #[inline]
248 fn space_size(&self) -> usize {
249 self.size() / 2
250 }
251
252 #[inline]
254 pub const fn allocation_index(&self) -> usize {
255 self.allocation_index
256 }
257
258 #[inline]
260 pub fn allocation_start(&self) -> usize {
261 if self.space { self.space_size() } else { 0 }
262 }
263
264 #[inline]
266 pub fn allocation_end(&self) -> usize {
267 self.allocation_start() + self.allocation_index
268 }
269
270 #[inline]
271 fn get<const G: bool>(&self, index: usize) -> Result<Value, Error> {
272 assert_heap_index!(self, index, G);
273
274 self.heap()
275 .get(index)
276 .copied()
277 .ok_or(Error::InvalidMemoryAccess)
278 }
279
280 #[inline]
281 fn set<const G: bool>(&mut self, index: usize, value: Value) -> Result<(), Error> {
282 assert_heap_index!(self, index, G);
283
284 *self
285 .heap_mut()
286 .get_mut(index)
287 .ok_or(Error::InvalidMemoryAccess)? = value;
288
289 Ok(())
290 }
291
292 #[inline]
294 pub fn car(&self, cons: Cons) -> Result<Value, Error> {
295 self.get::<false>(cons.index())
296 }
297
298 #[inline]
300 pub fn cdr(&self, cons: Cons) -> Result<Value, Error> {
301 self.get::<false>(cons.index() + 1)
302 }
303
304 #[inline]
305 fn garbage_car(&self, cons: Cons) -> Result<Value, Error> {
306 self.get::<true>(cons.index())
307 }
308
309 #[inline]
310 fn garbage_cdr(&self, cons: Cons) -> Result<Value, Error> {
311 self.get::<true>(cons.index() + 1)
312 }
313
314 #[inline]
316 pub fn car_value(&self, cons: Value) -> Result<Value, Error> {
317 self.car(cons.assume_cons())
318 }
319
320 #[inline]
322 pub fn cdr_value(&self, cons: Value) -> Result<Value, Error> {
323 self.cdr(cons.assume_cons())
324 }
325
326 #[inline]
327 fn set_field<const G: bool>(
328 &mut self,
329 cons: Cons,
330 index: usize,
331 value: Value,
332 ) -> Result<(), Error> {
333 self.set::<G>(cons.index() + index, value)
334 }
335
336 #[inline]
338 pub fn set_car(&mut self, cons: Cons, value: Value) -> Result<(), Error> {
339 self.set_field::<false>(cons, 0, value)
340 }
341
342 #[inline]
344 pub fn set_cdr(&mut self, cons: Cons, value: Value) -> Result<(), Error> {
345 self.set_field::<false>(
347 cons,
348 1,
349 value.set_tag(self.get::<false>(cons.index() + 1)?.tag()),
350 )
351 }
352
353 #[inline]
355 pub fn set_raw_cdr(&mut self, cons: Cons, value: Value) -> Result<(), Error> {
356 self.set_field::<false>(cons, 1, value)
357 }
358
359 #[inline]
360 fn set_garbage_car(&mut self, cons: Cons, value: Value) -> Result<(), Error> {
361 self.set_field::<true>(cons, 0, value)
362 }
363
364 #[inline]
365 fn set_garbage_cdr(&mut self, cons: Cons, value: Value) -> Result<(), Error> {
366 self.set_field::<true>(cons, 1, value)
367 }
368
369 #[inline(always)]
371 pub fn set_car_value(&mut self, cons: Value, value: Value) -> Result<(), Error> {
372 self.set_car(cons.assume_cons(), value)
373 }
374
375 #[inline(always)]
377 pub fn set_cdr_value(&mut self, cons: Value, value: Value) -> Result<(), Error> {
378 self.set_cdr(cons.assume_cons(), value)
379 }
380
381 #[inline(always)]
383 pub fn tail(&self, mut list: Cons, mut index: usize) -> Result<Cons, Error> {
384 while index > 0 {
385 list = self.cdr(list)?.assume_cons();
386 index -= 1;
387 }
388
389 Ok(list)
390 }
391
392 pub fn build_string(&mut self, string: &str) -> Result<Cons, Error> {
394 let string = self.build_raw_string(string)?;
395 let length = Number::from_i64(self.list_length(string)? as _).into();
396 self.allocate(length, string.set_tag(Type::String as _).into())
397 }
398
399 pub fn build_raw_string(&mut self, string: &str) -> Result<Cons, Error> {
401 let mut list = self.null()?;
402 self.build_intermediate_string(string, &mut list)?;
403 Ok(list)
404 }
405
406 fn build_intermediate_string(&mut self, string: &str, list: &mut Cons) -> Result<(), Error> {
407 for character in string.chars().rev() {
408 *list = self.cons(Number::from_i64(character as _).into(), *list)?;
409 }
410
411 Ok(())
412 }
413
414 pub fn operate_top(
416 &mut self,
417 operate: impl Fn(&Self, Value) -> Result<Value, Error>,
418 ) -> Result<(), Error> {
419 let value = self.pop()?;
420 self.push(operate(self, value)?)?;
421 Ok(())
422 }
423
424 pub fn list_length(&self, mut list: Cons) -> Result<usize, Error> {
426 let mut length = 0;
427
428 while list != self.null()? {
429 length += 1;
430 list = self.cdr(list)?.assume_cons();
431 }
432
433 Ok(length)
434 }
435
436 pub fn operate_unary(&mut self, operate: impl Fn(Number) -> Number) -> Result<(), Error> {
438 let [x] = self.pop_numbers()?;
439
440 self.push(operate(x).into())?;
441
442 Ok(())
443 }
444
445 pub fn operate_binary(&mut self, operate: fn(Number, Number) -> Number) -> Result<(), Error> {
447 let [x, y] = self.pop_numbers()?;
448
449 self.push(operate(x, y).into())?;
450
451 Ok(())
452 }
453
454 pub fn collect_garbages(&mut self, cons: Option<&mut Cons>) -> Result<(), Error> {
458 self.allocation_index = 0;
459 self.space = !self.space;
460
461 self.code = self.copy_cons(self.code)?;
462 self.stack = self.copy_cons(self.stack)?;
463 self.r#false = self.copy_cons(self.r#false)?;
464 self.register = self.copy_cons(self.register)?;
465
466 if let Some(cons) = cons {
467 *cons = self.copy_cons(*cons)?;
468 }
469
470 let mut index = self.allocation_start();
471
472 while index < self.allocation_end() {
473 let value = self.copy_value(self.get::<false>(index)?)?;
474 self.set::<false>(index, value)?;
475 index += 1;
476 }
477
478 Ok(())
479 }
480
481 fn copy_value(&mut self, value: Value) -> Result<Value, Error> {
482 Ok(if let Some(cons) = value.to_cons() {
483 self.copy_cons(cons)?.into()
484 } else {
485 value
486 })
487 }
488
489 fn copy_cons(&mut self, cons: Cons) -> Result<Cons, Error> {
490 Ok(if cons == NEVER {
491 NEVER
492 } else if self.garbage_car(cons)? == NEVER.into() {
493 self.garbage_cdr(cons)?.assume_cons()
495 } else {
496 let copy = self.allocate_unchecked(self.garbage_car(cons)?, self.garbage_cdr(cons)?)?;
497
498 self.set_garbage_car(cons, NEVER.into())?;
500 self.set_garbage_cdr(cons, copy.into())?;
501
502 copy
503 }
504 .set_tag(cons.tag()))
505 }
506}
507
508impl<H: Heap> Write for Memory<H> {
509 fn write_str(&mut self, string: &str) -> fmt::Result {
510 (|| -> Result<(), Error> {
511 let mut list = self.null()?;
512 self.build_intermediate_string(string, &mut list)?;
513
514 if self.register() == self.null()? {
515 self.set_register(list);
516 } else {
517 let mut head = self.register();
518
519 while self.cdr(head)? != self.null()?.into() {
520 head = self.cdr(head)?.assume_cons();
521 }
522
523 self.set_cdr(head, list.into())?;
524 }
525
526 Ok(())
527 })()
528 .map_err(|_| fmt::Error)
529 }
530}
531
532impl<H: Heap> Display for Memory<H> {
533 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
534 writeln!(formatter, "code: {}", self.code)?;
535 writeln!(formatter, "stack: {}", self.stack)?;
536
537 for index in 0..self.allocation_index / 2 {
538 let index = self.allocation_start() + 2 * index;
539 let cons = Cons::new(index as u64);
540
541 write!(
542 formatter,
543 "{:02x}: {} {}",
544 index,
545 self.car(cons).map_err(|_| fmt::Error)?,
546 self.cdr(cons).map_err(|_| fmt::Error)?
547 )?;
548
549 for (cons, name) in [
550 (self.code, "code"),
551 (self.register, "register"),
552 (self.stack, "stack"),
553 ] {
554 if index == cons.index() && cons != NEVER {
555 write!(formatter, " <- {name}")?;
556 }
557 }
558
559 writeln!(formatter)?;
560 }
561
562 Ok(())
563 }
564}
565
566pub trait Heap: AsRef<[Value]> + AsMut<[Value]> {}
568
569impl Heap for &mut [Value] {}
570
571impl<const N: usize> Heap for [Value; N] {}
572
573#[cfg(feature = "alloc")]
574impl Heap for alloc::vec::Vec<Value> {}
575
576#[cfg(test)]
577mod tests {
578 use super::*;
579
580 const HEAP_SIZE: usize = 1 << 9;
581
582 fn create_heap() -> [Value; HEAP_SIZE] {
583 [Default::default(); HEAP_SIZE]
584 }
585
586 macro_rules! assert_snapshot {
587 ($memory:expr) => {
588 #[cfg(not(feature = "gc_always"))]
589 insta::assert_snapshot!($memory);
590
591 let _ = $memory;
592 };
593 }
594
595 #[test]
596 fn create() {
597 let memory = Memory::new(create_heap()).unwrap();
598
599 assert_snapshot!(memory);
600 }
601
602 #[test]
603 fn create_list() {
604 let mut memory = Memory::new(create_heap()).unwrap();
605
606 let list = memory
607 .cons(Number::from_i64(1).into(), memory.null().unwrap())
608 .unwrap();
609
610 assert_eq!(memory.cdr(list).unwrap().tag(), Type::Pair as Tag);
611 assert_snapshot!(memory);
612
613 let list = memory.cons(Number::from_i64(2).into(), list).unwrap();
614
615 assert_eq!(memory.cdr(list).unwrap().tag(), Type::Pair as Tag);
616 assert_snapshot!(memory);
617
618 let list = memory.cons(Number::from_i64(3).into(), list).unwrap();
619
620 assert_eq!(memory.cdr(list).unwrap().tag(), Type::Pair as Tag);
621 assert_snapshot!(memory);
622 }
623
624 #[test]
625 fn convert_false() {
626 let memory = Memory::new(create_heap()).unwrap();
627
628 assert_eq!(
629 Value::from(memory.boolean(false).unwrap())
630 .to_cons()
631 .unwrap(),
632 memory.boolean(false).unwrap()
633 );
634 }
635
636 #[test]
637 fn convert_true() {
638 let memory = Memory::new(create_heap()).unwrap();
639
640 assert_eq!(
641 Value::from(memory.boolean(true).unwrap())
642 .to_cons()
643 .unwrap(),
644 memory.boolean(true).unwrap()
645 );
646 }
647
648 #[test]
649 fn convert_null() {
650 let memory = Memory::new(create_heap()).unwrap();
651
652 assert_eq!(
653 Value::from(memory.null().unwrap()).to_cons().unwrap(),
654 memory.null().unwrap()
655 );
656 }
657
658 fn assert_raw_string<H: Heap>(memory: &Memory<H>, mut cons: Cons, string: &str) {
659 for character in string.chars() {
660 assert_eq!(
661 memory.car(cons).unwrap().assume_number().to_i64(),
662 character as _
663 );
664 cons = memory.cdr(cons).unwrap().assume_cons();
665 }
666
667 assert_eq!(cons, memory.null().unwrap());
668 }
669
670 #[test]
671 fn build_string() {
672 let mut memory = Memory::new(create_heap()).unwrap();
673
674 let string = memory.build_string("foo").unwrap();
675
676 assert_eq!(memory.car(string).unwrap(), Number::from_i64(3).into());
677 assert_eq!(memory.cdr(string).unwrap().tag(), Type::String as _);
678 assert_raw_string(&memory, memory.cdr(string).unwrap().assume_cons(), "foo");
679 }
680
681 #[test]
682 fn format_string() {
683 let mut memory = Memory::new(create_heap()).unwrap();
684
685 memory.set_register(memory.null().unwrap());
686
687 memory.write_str("foo").unwrap();
688
689 assert_raw_string(&memory, memory.register(), "foo");
690 }
691
692 #[test]
693 fn format_two_strings() {
694 let mut memory = Memory::new(create_heap()).unwrap();
695
696 memory.set_register(memory.null().unwrap());
697
698 memory.write_str("foo").unwrap();
699 memory.write_str("bar").unwrap();
700
701 assert_raw_string(&memory, memory.register(), "foobar");
702 }
703
704 #[test]
705 fn format_templated_string() {
706 const FOO: usize = 42;
707
708 let mut memory = Memory::new(create_heap()).unwrap();
709
710 memory.set_register(memory.null().unwrap());
711
712 write!(&mut memory, "foo{FOO}bar").unwrap();
713
714 assert_raw_string(&memory, memory.register(), "foo42bar");
715 }
716
717 mod stack {
718 use super::*;
719
720 #[test]
721 fn push_and_pop() {
722 let mut memory = Memory::new(create_heap()).unwrap();
723
724 memory.stack = memory.null().unwrap();
725 memory.push(Number::from_i64(42).into()).unwrap();
726
727 assert_eq!(memory.pop().unwrap(), Number::from_i64(42).into());
728 }
729
730 #[test]
731 fn push_and_pop_twice() {
732 let mut memory = Memory::new(create_heap()).unwrap();
733
734 memory.stack = memory.null().unwrap();
735 memory.push(Number::from_i64(1).into()).unwrap();
736 memory.push(Number::from_i64(2).into()).unwrap();
737
738 assert_eq!(memory.pop().unwrap(), Number::from_i64(2).into());
739 assert_eq!(memory.pop().unwrap(), Number::from_i64(1).into());
740 }
741 }
742
743 mod garbage_collection {
744 use super::*;
745
746 #[test]
747 fn collect_cons() {
748 let mut memory = Memory::new(create_heap()).unwrap();
749
750 memory
751 .allocate(Number::default().into(), Number::default().into())
752 .unwrap();
753 memory.collect_garbages(None).unwrap();
754
755 assert_snapshot!(memory);
756 }
757
758 #[test]
759 fn collect_stack() {
760 let mut memory = Memory::new(create_heap()).unwrap();
761
762 memory.stack = memory.null().unwrap();
763 memory.push(Number::from_i64(42).into()).unwrap();
764 memory.collect_garbages(None).unwrap();
765
766 assert_snapshot!(memory);
767 }
768
769 #[test]
770 fn collect_deep_stack() {
771 let mut memory = Memory::new(create_heap()).unwrap();
772
773 memory.stack = memory.null().unwrap();
774 memory.push(Number::from_i64(1).into()).unwrap();
775 memory.push(Number::from_i64(2).into()).unwrap();
776 memory.collect_garbages(None).unwrap();
777
778 assert_snapshot!(memory);
779 }
780
781 #[test]
782 fn collect_cycle() {
783 let mut memory = Memory::new(create_heap()).unwrap();
784
785 let cons = memory
786 .allocate(Number::default().into(), Number::default().into())
787 .unwrap();
788 memory.set_cdr(cons, cons.into()).unwrap();
789
790 memory.collect_garbages(None).unwrap();
791
792 assert_snapshot!(memory);
793 }
794 }
795}