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