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