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 - 1 {
165 values[M - 1 - 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, value) in self.pop_many::<M>()?.into_iter().enumerate() {
176 numbers[index] = value.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 pub fn operate_binary(&mut self, operate: fn(Number, Number) -> Number) -> Result<(), Error> {
423 let [x, y] = self.pop_numbers()?;
424
425 self.push(operate(x, y).into())?;
426
427 Ok(())
428 }
429
430 pub fn collect_garbages(&mut self, cons: Option<&mut Cons>) -> Result<(), Error> {
434 self.allocation_index = 0;
435 self.space = !self.space;
436
437 self.code = self.copy_cons(self.code)?;
438 self.stack = self.copy_cons(self.stack)?;
439 self.r#false = self.copy_cons(self.r#false)?;
440 self.register = self.copy_cons(self.register)?;
441
442 if let Some(cons) = cons {
443 *cons = self.copy_cons(*cons)?;
444 }
445
446 let mut index = self.allocation_start();
447
448 while index < self.allocation_end() {
449 let value = self.copy_value(self.get::<false>(index)?)?;
450 self.set::<false>(index, value)?;
451 index += 1;
452 }
453
454 self.refresh_singletons()?;
455
456 Ok(())
457 }
458
459 fn copy_value(&mut self, value: Value) -> Result<Value, Error> {
460 Ok(if let Some(cons) = value.to_cons() {
461 self.copy_cons(cons)?.into()
462 } else {
463 value
464 })
465 }
466
467 fn copy_cons(&mut self, cons: Cons) -> Result<Cons, Error> {
468 if cons == NEVER {
469 return Ok(NEVER);
470 }
471
472 let car = self.garbage_car(cons)?;
473
474 Ok(if car == NEVER.into() {
475 self.garbage_cdr(cons)?.assume_cons()
477 } else {
478 let copy = self.allocate_unchecked(car, self.garbage_cdr(cons)?)?;
479
480 self.set_garbage_car(cons, NEVER.into())?;
482 self.set_garbage_cdr(cons, copy.into())?;
483
484 copy
485 }
486 .set_tag(cons.tag()))
487 }
488}
489
490impl<H: Heap> Write for Memory<H> {
491 fn write_str(&mut self, string: &str) -> fmt::Result {
492 (|| -> Result<(), Error> {
493 let mut list = self.null()?;
494 self.build_intermediate_string(string, &mut list)?;
495
496 if self.register() == self.null()? {
497 self.set_register(list);
498 } else {
499 let mut head = self.register();
500
501 while self.cdr(head)? != self.null()?.into() {
502 head = self.cdr(head)?.assume_cons();
503 }
504
505 self.set_cdr(head, list.into())?;
506 }
507
508 Ok(())
509 })()
510 .map_err(|_| fmt::Error)
511 }
512}
513
514impl<H: Heap> Display for Memory<H> {
515 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
516 writeln!(formatter, "code: {}", self.code)?;
517 writeln!(formatter, "stack: {}", self.stack)?;
518
519 for index in 0..self.allocation_index / 2 {
520 let index = self.allocation_start() + 2 * index;
521 let cons = Cons::new(index as u64);
522
523 write!(
524 formatter,
525 "{:02x}: {} {}",
526 index,
527 self.car(cons).map_err(|_| fmt::Error)?,
528 self.cdr(cons).map_err(|_| fmt::Error)?
529 )?;
530
531 for (cons, name) in [
532 (self.code, "code"),
533 (self.register, "register"),
534 (self.stack, "stack"),
535 ] {
536 if index == cons.index() && cons != NEVER {
537 write!(formatter, " <- {name}")?;
538 }
539 }
540
541 writeln!(formatter)?;
542 }
543
544 Ok(())
545 }
546}
547
548#[cfg(test)]
549mod tests {
550 use super::*;
551
552 const HEAP_SIZE: usize = 1 << 9;
553
554 fn create_heap() -> [Value; HEAP_SIZE] {
555 [Default::default(); HEAP_SIZE]
556 }
557
558 macro_rules! assert_snapshot {
559 ($memory:expr) => {
560 #[cfg(not(feature = "gc_always"))]
561 insta::assert_snapshot!($memory);
562
563 let _ = $memory;
564 };
565 }
566
567 #[test]
568 fn create() {
569 let memory = Memory::new(create_heap()).unwrap();
570
571 assert_snapshot!(memory);
572 }
573
574 #[test]
575 fn create_list() {
576 let mut memory = Memory::new(create_heap()).unwrap();
577
578 let list = memory
579 .cons(Number::from_i64(1).into(), memory.null().unwrap())
580 .unwrap();
581
582 assert_eq!(memory.cdr(list).unwrap().tag(), Type::Pair as Tag);
583 assert_snapshot!(memory);
584
585 let list = memory.cons(Number::from_i64(2).into(), list).unwrap();
586
587 assert_eq!(memory.cdr(list).unwrap().tag(), Type::Pair as Tag);
588 assert_snapshot!(memory);
589
590 let list = memory.cons(Number::from_i64(3).into(), list).unwrap();
591
592 assert_eq!(memory.cdr(list).unwrap().tag(), Type::Pair as Tag);
593 assert_snapshot!(memory);
594 }
595
596 #[test]
597 fn convert_false() {
598 let memory = Memory::new(create_heap()).unwrap();
599
600 assert_eq!(
601 Value::from(memory.boolean(false).unwrap())
602 .to_cons()
603 .unwrap(),
604 memory.boolean(false).unwrap()
605 );
606 }
607
608 #[test]
609 fn convert_true() {
610 let memory = Memory::new(create_heap()).unwrap();
611
612 assert_eq!(
613 Value::from(memory.boolean(true).unwrap())
614 .to_cons()
615 .unwrap(),
616 memory.boolean(true).unwrap()
617 );
618 }
619
620 #[test]
621 fn convert_null() {
622 let memory = Memory::new(create_heap()).unwrap();
623
624 assert_eq!(
625 Value::from(memory.null().unwrap()).to_cons().unwrap(),
626 memory.null().unwrap()
627 );
628 }
629
630 fn assert_raw_string<H: Heap>(memory: &Memory<H>, mut cons: Cons, string: &str) {
631 for character in string.chars() {
632 assert_eq!(
633 memory.car(cons).unwrap().assume_number().to_i64(),
634 character as _
635 );
636 cons = memory.cdr(cons).unwrap().assume_cons();
637 }
638
639 assert_eq!(cons, memory.null().unwrap());
640 }
641
642 #[test]
643 fn build_string() {
644 let mut memory = Memory::new(create_heap()).unwrap();
645
646 let string = memory.build_string("foo").unwrap();
647
648 assert_eq!(memory.car(string).unwrap(), Number::from_i64(3).into());
649 assert_eq!(memory.cdr(string).unwrap().tag(), Type::String as _);
650 assert_raw_string(&memory, memory.cdr(string).unwrap().assume_cons(), "foo");
651 }
652
653 #[test]
654 fn format_string() {
655 let mut memory = Memory::new(create_heap()).unwrap();
656
657 memory.set_register(memory.null().unwrap());
658
659 memory.write_str("foo").unwrap();
660
661 assert_raw_string(&memory, memory.register(), "foo");
662 }
663
664 #[test]
665 fn format_two_strings() {
666 let mut memory = Memory::new(create_heap()).unwrap();
667
668 memory.set_register(memory.null().unwrap());
669
670 memory.write_str("foo").unwrap();
671 memory.write_str("bar").unwrap();
672
673 assert_raw_string(&memory, memory.register(), "foobar");
674 }
675
676 #[test]
677 fn format_templated_string() {
678 const FOO: usize = 42;
679
680 let mut memory = Memory::new(create_heap()).unwrap();
681
682 memory.set_register(memory.null().unwrap());
683
684 write!(&mut memory, "foo{FOO}bar").unwrap();
685
686 assert_raw_string(&memory, memory.register(), "foo42bar");
687 }
688
689 mod stack {
690 use super::*;
691
692 #[test]
693 fn push_and_pop() {
694 let mut memory = Memory::new(create_heap()).unwrap();
695
696 memory.stack = memory.null().unwrap();
697 memory.push(Number::from_i64(42).into()).unwrap();
698
699 assert_eq!(memory.pop().unwrap(), Number::from_i64(42).into());
700 }
701
702 #[test]
703 fn push_and_pop_twice() {
704 let mut memory = Memory::new(create_heap()).unwrap();
705
706 memory.stack = memory.null().unwrap();
707 memory.push(Number::from_i64(1).into()).unwrap();
708 memory.push(Number::from_i64(2).into()).unwrap();
709
710 assert_eq!(memory.pop().unwrap(), Number::from_i64(2).into());
711 assert_eq!(memory.pop().unwrap(), Number::from_i64(1).into());
712 }
713 }
714
715 mod garbage_collection {
716 use super::*;
717
718 #[test]
719 fn collect_cons() {
720 let mut memory = Memory::new(create_heap()).unwrap();
721
722 memory
723 .allocate(Number::default().into(), Number::default().into())
724 .unwrap();
725 memory.collect_garbages(None).unwrap();
726
727 assert_snapshot!(memory);
728 }
729
730 #[test]
731 fn collect_stack() {
732 let mut memory = Memory::new(create_heap()).unwrap();
733
734 memory.stack = memory.null().unwrap();
735 memory.push(Number::from_i64(42).into()).unwrap();
736 memory.collect_garbages(None).unwrap();
737
738 assert_snapshot!(memory);
739 }
740
741 #[test]
742 fn collect_deep_stack() {
743 let mut memory = Memory::new(create_heap()).unwrap();
744
745 memory.stack = memory.null().unwrap();
746 memory.push(Number::from_i64(1).into()).unwrap();
747 memory.push(Number::from_i64(2).into()).unwrap();
748 memory.collect_garbages(None).unwrap();
749
750 assert_snapshot!(memory);
751 }
752
753 #[test]
754 fn collect_cycle() {
755 let mut memory = Memory::new(create_heap()).unwrap();
756
757 let cons = memory
758 .allocate(Number::default().into(), Number::default().into())
759 .unwrap();
760 memory.set_cdr(cons, cons.into()).unwrap();
761
762 memory.collect_garbages(None).unwrap();
763
764 assert_snapshot!(memory);
765 }
766 }
767}