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