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