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