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