scryer_prolog/machine/
mock_wam.rs

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
15// a mini-WAM for test purposes.
16
17pub struct MockWAM {
18    pub machine_st: MachineState,
19    pub op_dir: OpDir,
20    //pub flags: MachineFlags,
21}
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    /// For use in tests.
252    #[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    /// For use in tests.
264    #[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"); // 0
415
416            let h = section.cell_len();
417            assert_eq!(h, 3);
418
419            section.push_cell(heap_loc_as_cell!(h)); // 3
420            section.push_pstr("this is a string"); // 4
421
422            let h = section.cell_len();
423            assert_eq!(h + 1, 8);
424
425            section.push_cell(pstr_loc_as_cell!(heap_index!(h + 1))); // 7
426            section.push_pstr("this is a string"); // 8
427
428            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        // clear the heap of resource error data etc
574        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            // [1,2,3]
662            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            // [1,2]
671            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}