1use crate::heap_print::*;
2pub use crate::machine::heap::*;
3pub use crate::machine::machine_state::*;
4pub use crate::machine::streams::*;
5pub use crate::machine::*;
6pub use crate::parser::ast::*;
7
8#[cfg(test)]
9use crate::machine::copier::CopierTarget;
10use crate::read::TermWriteResult;
11
12#[cfg(test)]
13use std::ops::{Deref, DerefMut, Index, IndexMut, Range};
14
15pub struct MockWAM {
18 pub machine_st: MachineState,
19 pub op_dir: OpDir,
20 }
22
23#[allow(dead_code)]
24impl MockWAM {
25 pub fn new() -> Self {
26 let op_dir = default_op_dir();
27
28 Self {
29 machine_st: MachineState::new(),
30 op_dir,
31 }
32 }
33
34 pub fn write_parsed_term_to_heap(
35 &mut self,
36 input_stream: Stream,
37 ) -> Result<TermWriteResult, CompilationError> {
38 self.machine_st.read(input_stream, &self.op_dir)
39 }
40
41 pub fn parse_and_write_parsed_term_to_heap(
42 &mut self,
43 term_string: &'static str,
44 ) -> Result<TermWriteResult, CompilationError> {
45 let stream = Stream::from_static_string(term_string, &mut self.machine_st.arena);
46 self.write_parsed_term_to_heap(stream)
47 }
48
49 pub fn parse_and_print_term(
50 &mut self,
51 term_string: &'static str,
52 ) -> Result<String, CompilationError> {
53 let term_write_result = self.parse_and_write_parsed_term_to_heap(term_string)?;
54 print_heap_terms(&self.machine_st.heap, term_write_result.heap_loc);
55
56 let mut printer = HCPrinter::new(
57 &mut self.machine_st.heap,
58 &mut self.machine_st.stack,
59 &self.machine_st.arena,
60 &self.op_dir,
61 PrinterOutputter::new(),
62 term_write_result.heap_loc,
63 );
64
65 printer.var_names = term_write_result
66 .var_dict
67 .into_iter()
68 .map(|(var, cell)| match var {
69 VarKey::VarPtr(var) => (cell, var.clone()),
70 VarKey::AnonVar(_) => (cell, VarPtr::from(var.to_string())),
71 })
72 .collect();
73
74 Ok(printer.print().result())
75 }
76}
77
78impl Default for MockWAM {
79 fn default() -> Self {
80 Self::new()
81 }
82}
83
84#[cfg(test)]
85pub struct TermCopyingMockWAM<'a> {
86 pub wam: &'a mut MockWAM,
87}
88
89#[cfg(test)]
90impl<'a> Index<usize> for TermCopyingMockWAM<'a> {
91 type Output = HeapCellValue;
92
93 #[inline]
94 fn index(&self, index: usize) -> &HeapCellValue {
95 &self.wam.machine_st.heap[index]
96 }
97}
98
99#[cfg(test)]
100impl<'a> IndexMut<usize> for TermCopyingMockWAM<'a> {
101 #[inline]
102 fn index_mut(&mut self, index: usize) -> &mut HeapCellValue {
103 &mut self.wam.machine_st.heap[index]
104 }
105}
106
107#[cfg(test)]
108impl<'a> Deref for TermCopyingMockWAM<'a> {
109 type Target = MockWAM;
110
111 #[inline]
112 fn deref(&self) -> &Self::Target {
113 self.wam
114 }
115}
116
117#[cfg(test)]
118impl<'a> DerefMut for TermCopyingMockWAM<'a> {
119 #[inline]
120 fn deref_mut(&mut self) -> &mut Self::Target {
121 self.wam
122 }
123}
124
125#[cfg(test)]
126impl<'a> CopierTarget for TermCopyingMockWAM<'a> {
127 fn store(&self, val: HeapCellValue) -> HeapCellValue {
128 read_heap_cell!(val,
129 (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
130 self.wam.machine_st.heap[h]
131 }
132 (HeapCellValueTag::StackVar, s) => {
133 self.wam.machine_st.stack[s]
134 }
135 _ => {
136 val
137 }
138 )
139 }
140
141 fn deref(&self, mut val: HeapCellValue) -> HeapCellValue {
142 loop {
143 let value = self.store(val);
144
145 if value.is_var() && value != val {
146 val = value;
147 continue;
148 }
149
150 return val;
151 }
152 }
153
154 fn push_attr_var_queue(&mut self, attr_var_loc: usize) {
155 self.wam
156 .machine_st
157 .attr_var_init
158 .attr_var_queue
159 .push(attr_var_loc);
160 }
161
162 fn stack(&mut self) -> &mut Stack {
163 &mut self.wam.machine_st.stack
164 }
165
166 fn threshold(&self) -> usize {
167 self.wam.machine_st.heap.cell_len()
168 }
169
170 #[inline(always)]
171 fn copy_pstr_to_threshold(&mut self, pstr_loc: usize) -> Result<usize, usize> {
172 self.wam.machine_st.heap.copy_pstr_within(pstr_loc)
173 }
174
175 #[inline(always)]
176 fn as_slice_from<'b>(&'b self, from: usize) -> Box<dyn Iterator<Item = u8> + 'b> {
177 Box::new(self.wam.machine_st.heap.as_slice()[from..].iter().cloned())
178 }
179
180 #[inline(always)]
181 fn reserve(&mut self, num_cells: usize) -> Result<HeapWriter<'_>, usize> {
182 self.wam.machine_st.heap.reserve(num_cells)
183 }
184
185 #[inline(always)]
186 fn copy_slice_to_end(&mut self, bounds: Range<usize>) -> Result<(), usize> {
187 self.wam.machine_st.heap.copy_slice_to_end(bounds)
188 }
189}
190
191#[cfg(test)]
192pub fn all_cells_marked_and_unforwarded(heap: &Heap, offset: usize) {
193 for curr_idx in offset..heap.cell_len() {
194 let cell = heap[curr_idx];
195
196 assert!(
197 cell.get_mark_bit(),
198 "cell {cell:?} at index {curr_idx} is not marked"
199 );
200 assert!(
201 !cell.get_forwarding_bit(),
202 "cell {cell:?} at index {curr_idx} is forwarded"
203 );
204 }
205}
206
207#[cfg(test)]
208pub fn unmark_all_cells(heap: &mut Heap, offset: usize) {
209 for idx in offset..heap.cell_len() {
210 heap[idx].set_mark_bit(false);
211 }
212}
213
214#[cfg(test)]
215pub fn all_cells_unmarked(iter: &impl SizedHeap) {
216 let mut idx = 0;
217 let cell_len = iter.cell_len();
218
219 while idx < cell_len {
220 let curr_idx = idx;
221 idx += 1;
222 let cell = iter[curr_idx];
223
224 assert!(
225 !cell.get_mark_bit(),
226 "cell {cell:?} at index {curr_idx} is still marked"
227 );
228 }
229}
230
231#[cfg(test)]
232pub(crate) fn write_parsed_term_to_heap(
233 machine_st: &mut MachineState,
234 input_stream: Stream,
235 op_dir: &OpDir,
236) -> Result<TermWriteResult, CompilationError> {
237 machine_st.read(input_stream, op_dir)
238}
239
240#[cfg(test)]
241pub(crate) fn parse_and_write_parsed_term_to_heap(
242 machine_st: &mut MachineState,
243 term_string: &'static str,
244 op_dir: &OpDir,
245) -> Result<TermWriteResult, CompilationError> {
246 let stream = Stream::from_static_string(term_string, &mut machine_st.arena);
247 write_parsed_term_to_heap(machine_st, stream, op_dir)
248}
249
250impl Machine {
251 #[allow(clippy::unbuffered_bytes)]
253 pub fn test_load_file(&mut self, file: &str) -> Vec<u8> {
254 let stream = Stream::from_owned_string(
255 std::fs::read_to_string(AsRef::<std::path::Path>::as_ref(file)).unwrap(),
256 &mut self.machine_st.arena,
257 );
258
259 self.load_file(file, stream);
260 self.user_output.bytes().map(|b| b.unwrap()).collect()
261 }
262
263 #[allow(clippy::unbuffered_bytes)]
265 pub fn test_load_string(&mut self, code: &str) -> Vec<u8> {
266 let stream = Stream::from_owned_string(code.to_owned(), &mut self.machine_st.arena);
267
268 self.load_file("<stdin>", stream);
269 self.user_output.bytes().map(|b| b.unwrap()).collect()
270 }
271}
272
273#[cfg(test)]
274mod tests {
275 use super::*;
276
277 use crate::functor_macro::FunctorElement;
278
279 #[test]
280 fn unify_tests() {
281 let mut wam = MachineState::new();
282 let mut op_dir = default_op_dir();
283
284 op_dir.insert((atom!("+"), Fixity::In), OpDesc::build_with(500, YFX));
285 op_dir.insert((atom!("-"), Fixity::In), OpDesc::build_with(500, YFX));
286 op_dir.insert((atom!("*"), Fixity::In), OpDesc::build_with(500, YFX));
287 op_dir.insert((atom!("/"), Fixity::In), OpDesc::build_with(400, YFX));
288 op_dir.insert((atom!("="), Fixity::In), OpDesc::build_with(700, XFX));
289
290 {
291 parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
292
293 let term_write_result_2 =
294 parse_and_write_parsed_term_to_heap(&mut wam, "f(b,a).", &op_dir).unwrap();
295
296 unify!(
297 wam,
298 str_loc_as_cell!(0),
299 str_loc_as_cell!(term_write_result_2.heap_loc)
300 );
301
302 assert!(wam.fail);
303 }
304
305 all_cells_unmarked(&wam.heap);
306
307 wam.fail = false;
308 wam.heap.clear();
309
310 {
311 parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
312
313 let term_write_result_2 =
314 parse_and_write_parsed_term_to_heap(&mut wam, "f(b,b).", &op_dir).unwrap();
315
316 unify!(
317 wam,
318 str_loc_as_cell!(1),
319 heap_loc_as_cell!(term_write_result_2.heap_loc)
320 );
321
322 assert!(!wam.fail);
323 }
324
325 all_cells_unmarked(&wam.heap);
326
327 wam.fail = false;
328 wam.heap.clear();
329
330 {
331 parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
332
333 let term_write_result_2 =
334 parse_and_write_parsed_term_to_heap(&mut wam, "f(f(A),Y).", &op_dir).unwrap();
335
336 unify!(
337 wam,
338 heap_loc_as_cell!(0),
339 heap_loc_as_cell!(term_write_result_2.heap_loc)
340 );
341
342 assert!(!wam.fail);
343 }
344
345 all_cells_unmarked(&wam.heap);
346
347 wam.fail = false;
348 wam.heap.clear();
349
350 {
351 parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
352
353 let term_write_result_2 =
354 parse_and_write_parsed_term_to_heap(&mut wam, "f(f(A),Y).", &op_dir).unwrap();
355
356 unify!(
357 wam,
358 heap_loc_as_cell!(0),
359 heap_loc_as_cell!(term_write_result_2.heap_loc)
360 );
361
362 assert!(!wam.fail);
363 }
364
365 all_cells_unmarked(&wam.heap);
366
367 wam.fail = false;
368 wam.heap.clear();
369
370 {
371 parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
372
373 let term_write_result_2 =
374 parse_and_write_parsed_term_to_heap(&mut wam, "f(f(A),A).", &op_dir).unwrap();
375
376 unify!(
377 wam,
378 heap_loc_as_cell!(0),
379 heap_loc_as_cell!(term_write_result_2.heap_loc)
380 );
381
382 assert!(!wam.fail);
383 }
384
385 all_cells_unmarked(&wam.heap);
386
387 wam.fail = false;
388 wam.heap.clear();
389
390 {
391 parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
392
393 let term_write_result_2 =
394 parse_and_write_parsed_term_to_heap(&mut wam, "f(A,f(A)).", &op_dir).unwrap();
395
396 all_cells_unmarked(&wam.heap);
397
398 unify!(
399 wam,
400 heap_loc_as_cell!(0),
401 heap_loc_as_cell!(term_write_result_2.heap_loc)
402 );
403
404 assert!(!wam.fail);
405 }
406
407 all_cells_unmarked(&wam.heap);
408
409 wam.heap.clear();
410
411 let mut writer = wam.heap.reserve(96).unwrap();
412
413 writer.write_with(|section| {
414 section.push_pstr("this is a string"); let h = section.cell_len();
417 assert_eq!(h, 3);
418
419 section.push_cell(heap_loc_as_cell!(h)); section.push_pstr("this is a string"); let h = section.cell_len();
423 assert_eq!(h + 1, 8);
424
425 section.push_cell(pstr_loc_as_cell!(heap_index!(h + 1))); section.push_pstr("this is a string"); section.push_cell(pstr_loc_as_cell!(heap_index!(h + 1)));
429 });
430
431 unify!(wam, pstr_loc_as_cell!(0), pstr_loc_as_cell!(heap_index!(4)));
432
433 assert!(!wam.fail);
434
435 assert_eq!(
436 wam.heap
437 .slice_to_str(heap_index!(0), "this is a string".len()),
438 "this is a string"
439 );
440 assert_eq!(wam.heap[3], pstr_loc_as_cell!(heap_index!(8)));
441 assert_eq!(
442 wam.heap
443 .slice_to_str(heap_index!(4), "this is a string".len()),
444 "this is a string"
445 );
446 assert_eq!(wam.heap[7], pstr_loc_as_cell!(heap_index!(8)));
447 assert_eq!(
448 wam.heap
449 .slice_to_str(heap_index!(8), "this is a string".len()),
450 "this is a string"
451 );
452 assert_eq!(wam.heap[11], pstr_loc_as_cell!(heap_index!(8)));
453
454 wam.heap.clear();
455
456 let mut writer = wam.heap.reserve(96).unwrap();
457
458 writer.write_with(|section| {
459 section.push_cell(list_loc_as_cell!(1));
460 section.push_cell(atom_as_cell!(atom!("a")));
461 section.push_cell(list_loc_as_cell!(3));
462 section.push_cell(atom_as_cell!(atom!("b")));
463 section.push_cell(heap_loc_as_cell!(0));
464
465 section.push_cell(list_loc_as_cell!(6));
466 section.push_cell(atom_as_cell!(atom!("a")));
467 section.push_cell(list_loc_as_cell!(8));
468 section.push_cell(atom_as_cell!(atom!("b")));
469 section.push_cell(heap_loc_as_cell!(5));
470 });
471
472 unify!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(5));
473
474 assert!(!wam.fail);
475
476 all_cells_unmarked(&wam.heap);
477
478 wam.heap.clear();
479
480 let mut writer = wam.heap.reserve(96).unwrap();
481
482 writer.write_with(|section| {
483 section.push_cell(list_loc_as_cell!(1));
484 section.push_cell(atom_as_cell!(atom!("a")));
485 section.push_cell(list_loc_as_cell!(3));
486 section.push_cell(atom_as_cell!(atom!("b")));
487 section.push_cell(heap_loc_as_cell!(0));
488
489 section.push_cell(list_loc_as_cell!(6));
490 section.push_cell(atom_as_cell!(atom!("a")));
491 section.push_cell(list_loc_as_cell!(8));
492 section.push_cell(atom_as_cell!(atom!("c")));
493 section.push_cell(heap_loc_as_cell!(5));
494 });
495
496 unify!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(5));
497
498 assert!(wam.fail);
499
500 wam.fail = false;
501 all_cells_unmarked(&wam.heap);
502
503 wam.heap.clear();
504
505 let mut writer = wam.heap.reserve(96).unwrap();
506
507 writer.write_with(|section| {
508 section.push_cell(list_loc_as_cell!(1));
509 section.push_cell(atom_as_cell!(atom!("a")));
510 section.push_cell(list_loc_as_cell!(3));
511 section.push_cell(atom_as_cell!(atom!("b")));
512 section.push_cell(heap_loc_as_cell!(5));
513
514 section.push_cell(list_loc_as_cell!(6));
515 section.push_cell(atom_as_cell!(atom!("a")));
516 section.push_cell(list_loc_as_cell!(8));
517 section.push_cell(atom_as_cell!(atom!("b")));
518 section.push_cell(heap_loc_as_cell!(0));
519 });
520
521 unify!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(5));
522
523 assert!(!wam.fail);
524 all_cells_unmarked(&wam.heap);
525 wam.heap.clear();
526
527 {
528 let term_write_result_1 =
529 parse_and_write_parsed_term_to_heap(&mut wam, "X = g(X,y).", &op_dir).unwrap();
530
531 print_heap_terms(&wam.heap, term_write_result_1.heap_loc);
532
533 unify!(wam, heap_loc_as_cell!(2), str_loc_as_cell!(4));
534
535 assert_eq!(wam.heap[2], str_loc_as_cell!(4));
536 }
537 }
538
539 #[test]
540 fn test_unify_with_occurs_check() {
541 let mut wam = MachineState::new();
542 let mut op_dir = default_op_dir();
543
544 op_dir.insert((atom!("+"), Fixity::In), OpDesc::build_with(500, YFX));
545 op_dir.insert((atom!("-"), Fixity::In), OpDesc::build_with(500, YFX));
546 op_dir.insert((atom!("*"), Fixity::In), OpDesc::build_with(400, YFX));
547 op_dir.insert((atom!("/"), Fixity::In), OpDesc::build_with(400, YFX));
548
549 {
550 parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
551
552 let term_write_result_2 =
553 parse_and_write_parsed_term_to_heap(&mut wam, "f(A,f(A)).", &op_dir).unwrap();
554
555 all_cells_unmarked(&wam.heap);
556
557 unify_with_occurs_check!(
558 wam,
559 str_loc_as_cell!(0),
560 str_loc_as_cell!(term_write_result_2.heap_loc)
561 );
562
563 assert!(wam.fail);
564 }
565 }
566
567 #[test]
568 fn test_term_compare() {
569 use std::cmp::Ordering;
570
571 let mut wam = MachineState::new();
572
573 wam.heap.clear();
575
576 let mut writer = wam.heap.reserve(96).unwrap();
577
578 writer.write_with(|section| {
579 section.push_cell(heap_loc_as_cell!(0));
580 section.push_cell(heap_loc_as_cell!(1));
581 });
582
583 assert_eq!(
584 compare_term_test!(wam, wam.heap[0], wam.heap[1]),
585 Some(Ordering::Less)
586 );
587
588 assert_eq!(
589 compare_term_test!(wam, wam.heap[1], wam.heap[0]),
590 Some(Ordering::Greater)
591 );
592
593 assert_eq!(
594 compare_term_test!(wam, wam.heap[0], wam.heap[0]),
595 Some(Ordering::Equal)
596 );
597
598 assert_eq!(
599 compare_term_test!(wam, wam.heap[1], wam.heap[1]),
600 Some(Ordering::Equal)
601 );
602
603 let cstr_cell = wam.heap.allocate_cstr("string").unwrap();
604
605 assert_eq!(
606 compare_term_test!(wam, atom_as_cell!(atom!("atom")), cstr_cell),
607 Some(Ordering::Less)
608 );
609
610 assert_eq!(
611 compare_term_test!(
612 wam,
613 atom_as_cell!(atom!("atom")),
614 atom_as_cell!(atom!("atom"))
615 ),
616 Some(Ordering::Equal)
617 );
618
619 assert_eq!(
620 compare_term_test!(
621 wam,
622 atom_as_cell!(atom!("atom")),
623 atom_as_cell!(atom!("aaa"))
624 ),
625 Some(Ordering::Greater)
626 );
627
628 assert_eq!(
629 compare_term_test!(
630 wam,
631 fixnum_as_cell!(Fixnum::build_with(6)),
632 heap_loc_as_cell!(1)
633 ),
634 Some(Ordering::Greater)
635 );
636
637 wam.heap.clear();
638
639 let mut writer = wam.heap.reserve(96).unwrap();
640
641 writer.write_with(|section| {
642 section.push_cell(atom_as_cell!(atom!("f"), 1));
643 section.push_cell(heap_loc_as_cell!(1));
644 });
645
646 assert_eq!(
647 compare_term_test!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(0)),
648 Some(Ordering::Equal)
649 );
650
651 assert_eq!(
652 compare_term_test!(wam, heap_loc_as_cell!(0), atom_as_cell!(atom!("a"))),
653 Some(Ordering::Greater)
654 );
655
656 wam.heap.clear();
657
658 let mut writer = wam.heap.reserve(96).unwrap();
659
660 writer.write_with(|section| {
661 section.push_cell(list_loc_as_cell!(1));
663 section.push_cell(fixnum_as_cell!(Fixnum::build_with(1)));
664 section.push_cell(list_loc_as_cell!(3));
665 section.push_cell(fixnum_as_cell!(Fixnum::build_with(2)));
666 section.push_cell(list_loc_as_cell!(5));
667 section.push_cell(fixnum_as_cell!(Fixnum::build_with(3)));
668 section.push_cell(empty_list_as_cell!());
669
670 section.push_cell(list_loc_as_cell!(8));
672 section.push_cell(fixnum_as_cell!(Fixnum::build_with(1)));
673 section.push_cell(list_loc_as_cell!(10));
674 section.push_cell(fixnum_as_cell!(Fixnum::build_with(2)));
675 section.push_cell(empty_list_as_cell!());
676 });
677
678 assert_eq!(
679 compare_term_test!(wam, heap_loc_as_cell!(7), heap_loc_as_cell!(7)),
680 Some(Ordering::Equal)
681 );
682
683 assert_eq!(
684 compare_term_test!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(7)),
685 Some(Ordering::Greater)
686 );
687
688 assert_eq!(
689 compare_term_test!(wam, empty_list_as_cell!(), heap_loc_as_cell!(7)),
690 Some(Ordering::Less)
691 );
692
693 assert_eq!(
694 compare_term_test!(
695 wam,
696 empty_list_as_cell!(),
697 fixnum_as_cell!(Fixnum::build_with(1))
698 ),
699 Some(Ordering::Greater)
700 );
701
702 let cstr_cell = wam.heap.allocate_cstr("string").unwrap();
703
704 assert_eq!(
705 compare_term_test!(wam, empty_list_as_cell!(), cstr_cell),
706 Some(Ordering::Less)
707 );
708
709 assert_eq!(
710 compare_term_test!(wam, empty_list_as_cell!(), atom_as_cell!(atom!("atom"))),
711 Some(Ordering::Less)
712 );
713
714 assert_eq!(
715 compare_term_test!(wam, atom_as_cell!(atom!("atom")), empty_list_as_cell!()),
716 Some(Ordering::Greater)
717 );
718
719 let one_p_one = HeapCellValue::from(float_alloc!(1.1, &mut wam.arena));
720
721 assert_eq!(
722 compare_term_test!(wam, one_p_one, fixnum_as_cell!(Fixnum::build_with(1))),
723 Some(Ordering::Less)
724 );
725
726 assert_eq!(
727 compare_term_test!(wam, fixnum_as_cell!(Fixnum::build_with(1)), one_p_one),
728 Some(Ordering::Greater)
729 );
730 }
731
732 #[test]
733 fn is_cyclic_term_tests() {
734 let mut wam = MachineState::new();
735
736 let mut writer = wam.heap.reserve(96).unwrap();
737
738 writer.write_with(|section| {
739 section.push_cell(atom_as_cell!(atom!("f")));
740 section.push_cell(fixnum_as_cell!(Fixnum::build_with(555)));
741 section.push_cell(heap_loc_as_cell!(0));
742 });
743
744 assert!(!wam.is_cyclic_term(0));
745 assert!(!wam.is_cyclic_term(1));
746 assert!(!wam.is_cyclic_term(2));
747
748 all_cells_unmarked(&wam.heap);
749 wam.heap.clear();
750
751 let mut functor_writer = Heap::functor_writer(functor!(
752 atom!("f"),
753 [atom_as_cell((atom!("a"))), atom_as_cell((atom!("b")))]
754 ));
755
756 functor_writer(&mut wam.heap).unwrap();
757
758 let h = wam.heap.cell_len();
759 wam.heap.push_cell(str_loc_as_cell!(0)).unwrap();
760
761 assert!(!wam.is_cyclic_term(h));
762
763 all_cells_unmarked(&wam.heap);
764
765 assert!(!wam.is_cyclic_term(1));
766
767 all_cells_unmarked(&wam.heap);
768
769 assert!(!wam.is_cyclic_term(2));
770
771 all_cells_unmarked(&wam.heap);
772
773 wam.heap[2] = str_loc_as_cell!(0);
774
775 print_heap_terms(&wam.heap, 0);
776
777 assert!(wam.is_cyclic_term(2));
778
779 all_cells_unmarked(&wam.heap);
780
781 wam.heap[2] = atom_as_cell!(atom!("b"));
782 wam.heap[1] = str_loc_as_cell!(0);
783
784 assert!(wam.is_cyclic_term(1));
785
786 all_cells_unmarked(&wam.heap);
787
788 wam.heap.clear();
789
790 let h = wam.heap.cell_len();
791 wam.heap.allocate_cstr("a string").unwrap();
792
793 assert!(!wam.is_cyclic_term(h));
794 }
795}