summaryrefslogtreecommitdiff
path: root/src/machine/mock_wam.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/machine/mock_wam.rs')
-rw-r--r--src/machine/mock_wam.rs851
1 files changed, 851 insertions, 0 deletions
diff --git a/src/machine/mock_wam.rs b/src/machine/mock_wam.rs
new file mode 100644
index 00000000..0b4923da
--- /dev/null
+++ b/src/machine/mock_wam.rs
@@ -0,0 +1,851 @@
+pub use crate::arena::*;
+pub use crate::atom_table::*;
+use crate::heap_print::*;
+pub use crate::machine::heap::*;
+pub use crate::machine::*;
+pub use crate::machine::machine_state::*;
+pub use crate::machine::stack::*;
+pub use crate::machine::streams::*;
+pub use crate::macros::*;
+pub use crate::parser::ast::*;
+use crate::read::*;
+pub use crate::types::*;
+
+#[cfg(test)]
+use crate::machine::copier::CopierTarget;
+
+#[cfg(test)]
+use std::ops::{Deref, DerefMut, Index, IndexMut};
+
+// a mini-WAM for test purposes.
+
+pub struct MockWAM {
+ pub machine_st: MachineState,
+ pub op_dir: OpDir,
+ pub flags: MachineFlags,
+}
+
+impl MockWAM {
+ pub fn new() -> Self {
+ let op_dir = default_op_dir();
+
+ Self {
+ machine_st: MachineState::new(),
+ op_dir,
+ flags: MachineFlags::default(),
+ }
+ }
+
+ pub fn write_parsed_term_to_heap(
+ &mut self,
+ input_stream: Stream,
+ ) -> Result<TermWriteResult, ParserError> {
+ self.machine_st.read(input_stream, &self.op_dir)
+ }
+
+ pub fn parse_and_write_parsed_term_to_heap(
+ &mut self,
+ term_string: &'static str,
+ ) -> Result<TermWriteResult, ParserError> {
+ let stream = Stream::from_static_string(term_string, &mut self.machine_st.arena);
+ self.write_parsed_term_to_heap(stream)
+ }
+
+ pub fn parse_and_print_term(
+ &mut self,
+ term_string: &'static str,
+ ) -> Result<String, ParserError> {
+ let term_write_result = self.parse_and_write_parsed_term_to_heap(term_string)?;
+
+ print_heap_terms(self.machine_st.heap.iter(), term_write_result.heap_loc);
+
+ let mut printer = HCPrinter::new(
+ &mut self.machine_st.heap,
+ &mut self.machine_st.arena,
+ &self.op_dir,
+ PrinterOutputter::new(),
+ heap_loc_as_cell!(term_write_result.heap_loc),
+ );
+
+ printer.var_names = term_write_result
+ .var_dict
+ .into_iter()
+ .map(|(var, cell)| (cell, var))
+ .collect();
+
+ Ok(printer.print().result())
+ }
+}
+
+#[cfg(test)]
+pub struct TermCopyingMockWAM<'a> {
+ pub wam: &'a mut MockWAM,
+}
+
+#[cfg(test)]
+impl<'a> Index<usize> for TermCopyingMockWAM<'a> {
+ type Output = HeapCellValue;
+
+ fn index(&self, index: usize) -> &HeapCellValue {
+ &self.wam.machine_st.heap[index]
+ }
+}
+
+#[cfg(test)]
+impl<'a> IndexMut<usize> for TermCopyingMockWAM<'a> {
+ #[inline]
+ fn index_mut(&mut self, index: usize) -> &mut HeapCellValue {
+ &mut self.wam.machine_st.heap[index]
+ }
+}
+
+#[cfg(test)]
+impl<'a> Deref for TermCopyingMockWAM<'a> {
+ type Target = MockWAM;
+
+ fn deref(&self) -> &Self::Target {
+ &self.wam
+ }
+}
+
+#[cfg(test)]
+impl<'a> DerefMut for TermCopyingMockWAM<'a> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.wam
+ }
+}
+
+#[cfg(test)]
+impl<'a> CopierTarget for TermCopyingMockWAM<'a> {
+ fn store(&self, val: HeapCellValue) -> HeapCellValue {
+ read_heap_cell!(val,
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
+ self.wam.machine_st.heap[h]
+ }
+ (HeapCellValueTag::StackVar, s) => {
+ self.wam.machine_st.stack[s]
+ }
+ _ => {
+ val
+ }
+ )
+ }
+
+ fn deref(&self, mut val: HeapCellValue) -> HeapCellValue {
+ loop {
+ let value = self.store(val);
+
+ if value.is_var() && value != val {
+ val = value;
+ continue;
+ }
+
+ return val;
+ }
+ }
+
+ fn push(&mut self, val: HeapCellValue) {
+ self.wam.machine_st.heap.push(val);
+ }
+
+ fn stack(&mut self) -> &mut Stack {
+ &mut self.wam.machine_st.stack
+ }
+
+ fn threshold(&self) -> usize {
+ self.wam.machine_st.heap.len()
+ }
+}
+
+#[cfg(test)]
+pub fn all_cells_marked_and_unforwarded(heap: &[HeapCellValue]) {
+ for (idx, cell) in heap.iter().enumerate() {
+ assert_eq!(
+ cell.get_mark_bit(),
+ true,
+ "cell {:?} at index {} is not marked",
+ cell,
+ idx
+ );
+ assert!(
+ cell.get_forwarding_bit() != Some(true),
+ "cell {:?} at index {} is forwarded",
+ cell,
+ idx
+ );
+ }
+}
+
+#[cfg(test)]
+pub fn all_cells_unmarked(heap: &Heap) {
+ for (idx, cell) in heap.iter().enumerate() {
+ assert!(
+ !cell.get_mark_bit(),
+ "cell {:?} at index {} is still marked",
+ cell,
+ idx
+ );
+
+ assert!(
+ cell.get_forwarding_bit() != Some(true),
+ "cell {:?} at index {} is still forwarded",
+ cell,
+ idx
+ );
+ }
+}
+
+#[cfg(test)]
+pub(crate) fn write_parsed_term_to_heap(
+ machine_st: &mut MachineState,
+ input_stream: Stream,
+ op_dir: &OpDir,
+) -> Result<TermWriteResult, ParserError> {
+ machine_st.read(input_stream, op_dir)
+}
+
+#[cfg(test)]
+pub(crate) fn parse_and_write_parsed_term_to_heap(
+ machine_st: &mut MachineState,
+ term_string: &'static str,
+ op_dir: &OpDir,
+) -> Result<TermWriteResult, ParserError> {
+ let stream = Stream::from_static_string(term_string, &mut machine_st.arena);
+ write_parsed_term_to_heap(machine_st, stream, op_dir)
+}
+
+impl Machine {
+ pub fn with_test_streams() -> Self {
+ use ref_thread_local::RefThreadLocal;
+
+ let mut machine_st = MachineState::new();
+
+ let user_input = Stream::Null(StreamOptions::default());
+ let user_output = Stream::from_owned_string("".to_owned(), &mut machine_st.arena);
+ let user_error = Stream::stderr(&mut machine_st.arena);
+
+ let mut wam = Machine {
+ machine_st,
+ indices: IndexStore::new(),
+ code: Code::new(),
+ user_input,
+ user_output,
+ user_error,
+ load_contexts: vec![],
+ };
+
+ let mut lib_path = current_dir();
+
+ lib_path.pop();
+ lib_path.push("lib");
+
+ wam.add_impls_to_indices();
+
+ bootstrapping_compile(
+ Stream::from_static_string(
+ LIBRARIES.borrow()["ops_and_meta_predicates"],
+ &mut wam.machine_st.arena,
+ ),
+ &mut wam,
+ ListingSource::from_file_and_path(
+ atom!("ops_and_meta_predicates.pl"),
+ lib_path.clone(),
+ ),
+ )
+ .unwrap();
+
+ bootstrapping_compile(
+ Stream::from_static_string(
+ LIBRARIES.borrow()["builtins"],
+ &mut wam.machine_st.arena,
+ ),
+ &mut wam,
+ ListingSource::from_file_and_path(atom!("builtins.pl"), lib_path.clone()),
+ )
+ .unwrap();
+
+ if let Some(ref mut builtins) = wam.indices.modules.get_mut(&atom!("builtins")) {
+ load_module(
+ &mut wam.indices.code_dir,
+ &mut wam.indices.op_dir,
+ &mut wam.indices.meta_predicates,
+ &CompilationTarget::User,
+ builtins,
+ );
+
+ import_builtin_impls(&wam.indices.code_dir, builtins);
+ } else {
+ unreachable!()
+ }
+
+ lib_path.pop(); // remove the "lib" at the end
+
+ bootstrapping_compile(
+ Stream::from_static_string(include_str!("../loader.pl"), &mut wam.machine_st.arena),
+ &mut wam,
+ ListingSource::from_file_and_path(atom!("loader.pl"), lib_path.clone()),
+ )
+ .unwrap();
+
+ wam.configure_modules();
+
+ if let Some(loader) = wam.indices.modules.get(&atom!("loader")) {
+ load_module(
+ &mut wam.indices.code_dir,
+ &mut wam.indices.op_dir,
+ &mut wam.indices.meta_predicates,
+ &CompilationTarget::User,
+ loader,
+ );
+ } else {
+ unreachable!()
+ }
+
+ wam.load_special_forms();
+ wam.load_top_level();
+ wam.configure_streams();
+
+ wam
+ }
+
+ pub fn test_load_file(&mut self, file: &str) -> Vec<u8> {
+ use std::io::Read;
+
+ let stream = Stream::from_owned_string(
+ std::fs::read_to_string(AsRef::<std::path::Path>::as_ref(file)).unwrap(),
+ &mut self.machine_st.arena,
+ );
+
+ self.load_file(file.into(), stream);
+ self.user_output.bytes().map(|b| b.unwrap()).collect()
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn unify_tests() {
+ let mut wam = MachineState::new();
+ let mut op_dir = default_op_dir();
+
+ op_dir.insert(
+ (atom!("+"), Fixity::In),
+ OpDesc::build_with(500, YFX as u8),
+ );
+ op_dir.insert(
+ (atom!("-"), Fixity::In),
+ OpDesc::build_with(500, YFX as u8),
+ );
+ op_dir.insert(
+ (atom!("*"), Fixity::In),
+ OpDesc::build_with(500, YFX as u8),
+ );
+ op_dir.insert(
+ (atom!("/"), Fixity::In),
+ OpDesc::build_with(400, YFX as u8),
+ );
+ op_dir.insert(
+ (atom!("="), Fixity::In),
+ OpDesc::build_with(700, XFX as u8),
+ );
+
+ {
+ parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
+
+ let term_write_result_2 =
+ parse_and_write_parsed_term_to_heap(&mut wam, "f(b,a).", &op_dir).unwrap();
+
+ unify!(
+ wam,
+ str_loc_as_cell!(0),
+ str_loc_as_cell!(term_write_result_2.heap_loc)
+ );
+
+ assert!(wam.fail);
+ }
+
+ all_cells_unmarked(&wam.heap);
+
+ wam.fail = false;
+ wam.heap.clear();
+
+ {
+ parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
+
+ let term_write_result_2 =
+ parse_and_write_parsed_term_to_heap(&mut wam, "f(b,b).", &op_dir).unwrap();
+
+ unify!(
+ wam,
+ str_loc_as_cell!(1),
+ heap_loc_as_cell!(term_write_result_2.heap_loc)
+ );
+
+ assert!(!wam.fail);
+ }
+
+ all_cells_unmarked(&wam.heap);
+
+ wam.fail = false;
+ wam.heap.clear();
+
+ {
+ parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
+
+ let term_write_result_2 =
+ parse_and_write_parsed_term_to_heap(&mut wam, "f(f(A),Y).", &op_dir).unwrap();
+
+ unify!(
+ wam,
+ heap_loc_as_cell!(0),
+ heap_loc_as_cell!(term_write_result_2.heap_loc)
+ );
+
+ assert!(!wam.fail);
+ }
+
+ all_cells_unmarked(&wam.heap);
+
+ wam.fail = false;
+ wam.heap.clear();
+
+ {
+ parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
+
+ let term_write_result_2 =
+ parse_and_write_parsed_term_to_heap(&mut wam, "f(f(A),Y).", &op_dir).unwrap();
+
+ unify!(
+ wam,
+ heap_loc_as_cell!(0),
+ heap_loc_as_cell!(term_write_result_2.heap_loc)
+ );
+
+ assert!(!wam.fail);
+ }
+
+ all_cells_unmarked(&wam.heap);
+
+ wam.fail = false;
+ wam.heap.clear();
+
+ {
+ parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
+
+ let term_write_result_2 =
+ parse_and_write_parsed_term_to_heap(&mut wam, "f(f(A),A).", &op_dir).unwrap();
+
+ unify!(
+ wam,
+ heap_loc_as_cell!(0),
+ heap_loc_as_cell!(term_write_result_2.heap_loc)
+ );
+
+ assert!(!wam.fail);
+ }
+
+ all_cells_unmarked(&wam.heap);
+
+ wam.fail = false;
+ wam.heap.clear();
+
+ {
+ parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
+
+ let term_write_result_2 =
+ parse_and_write_parsed_term_to_heap(&mut wam, "f(A,f(A)).", &op_dir).unwrap();
+
+ all_cells_unmarked(&wam.heap);
+
+ unify!(
+ wam,
+ heap_loc_as_cell!(0),
+ heap_loc_as_cell!(term_write_result_2.heap_loc)
+ );
+
+ assert!(!wam.fail);
+ }
+
+ all_cells_unmarked(&wam.heap);
+
+ wam.heap.clear();
+
+ wam.heap.push(pstr_as_cell!(atom!("this is a string")));
+ wam.heap.push(heap_loc_as_cell!(1));
+
+ wam.heap.push(pstr_as_cell!(atom!("this is a string")));
+ wam.heap.push(pstr_loc_as_cell!(4));
+
+ wam.heap.push(pstr_offset_as_cell!(0));
+ wam.heap.push(fixnum_as_cell!(Fixnum::build_with(6)));
+
+ unify!(wam, pstr_loc_as_cell!(0), pstr_loc_as_cell!(2));
+
+ assert!(!wam.fail);
+
+ assert_eq!(wam.heap[1], pstr_loc_as_cell!(4));
+
+ all_cells_unmarked(&wam.heap);
+
+ wam.heap.clear();
+
+ wam.heap.push(list_loc_as_cell!(1));
+ wam.heap.push(atom_as_cell!(atom!("a")));
+ wam.heap.push(list_loc_as_cell!(3));
+ wam.heap.push(atom_as_cell!(atom!("b")));
+ wam.heap.push(heap_loc_as_cell!(0));
+
+ wam.heap.push(list_loc_as_cell!(6));
+ wam.heap.push(atom_as_cell!(atom!("a")));
+ wam.heap.push(list_loc_as_cell!(8));
+ wam.heap.push(atom_as_cell!(atom!("b")));
+ wam.heap.push(heap_loc_as_cell!(5));
+
+ unify!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(5));
+
+ assert!(!wam.fail);
+
+ all_cells_unmarked(&wam.heap);
+
+ wam.heap.clear();
+
+ wam.heap.push(list_loc_as_cell!(1));
+ wam.heap.push(atom_as_cell!(atom!("a")));
+ wam.heap.push(list_loc_as_cell!(3));
+ wam.heap.push(atom_as_cell!(atom!("b")));
+ wam.heap.push(heap_loc_as_cell!(0));
+
+ wam.heap.push(list_loc_as_cell!(6));
+ wam.heap.push(atom_as_cell!(atom!("a")));
+ wam.heap.push(list_loc_as_cell!(8));
+ wam.heap.push(atom_as_cell!(atom!("c")));
+ wam.heap.push(heap_loc_as_cell!(5));
+
+ unify!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(5));
+
+ assert!(wam.fail);
+
+ wam.fail = false;
+ all_cells_unmarked(&wam.heap);
+ wam.heap.clear();
+
+ wam.heap.push(list_loc_as_cell!(1));
+ wam.heap.push(atom_as_cell!(atom!("a")));
+ wam.heap.push(list_loc_as_cell!(3));
+ wam.heap.push(atom_as_cell!(atom!("b")));
+ wam.heap.push(heap_loc_as_cell!(5));
+
+ wam.heap.push(list_loc_as_cell!(6));
+ wam.heap.push(atom_as_cell!(atom!("a")));
+ wam.heap.push(list_loc_as_cell!(8));
+ wam.heap.push(atom_as_cell!(atom!("b")));
+ wam.heap.push(heap_loc_as_cell!(0));
+
+ unify!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(5));
+
+ assert!(!wam.fail);
+ all_cells_unmarked(&wam.heap);
+ wam.heap.clear();
+
+ {
+ let term_write_result_1 =
+ parse_and_write_parsed_term_to_heap(&mut wam, "X = g(X,y).", &op_dir).unwrap();
+
+ print_heap_terms(wam.heap.iter(), term_write_result_1.heap_loc);
+
+ unify!(wam, heap_loc_as_cell!(2), str_loc_as_cell!(4));
+
+ assert_eq!(wam.heap[2], str_loc_as_cell!(4));
+ }
+ }
+
+ #[test]
+ fn test_unify_with_occurs_check() {
+ let mut wam = MachineState::new();
+ let mut op_dir = default_op_dir();
+
+ op_dir.insert(
+ (atom!("+"), Fixity::In),
+ OpDesc::build_with(500, YFX as u8),
+ );
+ op_dir.insert(
+ (atom!("-"), Fixity::In),
+ OpDesc::build_with(500, YFX as u8),
+ );
+ op_dir.insert(
+ (atom!("*"), Fixity::In),
+ OpDesc::build_with(400, YFX as u8),
+ );
+ op_dir.insert(
+ (atom!("/"), Fixity::In),
+ OpDesc::build_with(400, YFX as u8),
+ );
+
+ {
+ parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
+
+ let term_write_result_2 =
+ parse_and_write_parsed_term_to_heap(&mut wam, "f(A,f(A)).", &op_dir).unwrap();
+
+ all_cells_unmarked(&wam.heap);
+
+ unify_with_occurs_check!(
+ wam,
+ str_loc_as_cell!(0),
+ str_loc_as_cell!(term_write_result_2.heap_loc)
+ );
+
+ assert!(wam.fail);
+ }
+ }
+
+ #[test]
+ fn test_term_compare() {
+ use ordered_float::OrderedFloat;
+ use std::cmp::Ordering;
+
+ let mut wam = MachineState::new();
+
+ wam.heap.push(heap_loc_as_cell!(0));
+ wam.heap.push(heap_loc_as_cell!(1));
+
+ assert_eq!(
+ compare_term_test!(wam, wam.heap[0], wam.heap[1]),
+ Some(Ordering::Less)
+ );
+
+ assert_eq!(
+ compare_term_test!(wam, wam.heap[1], wam.heap[0]),
+ Some(Ordering::Greater)
+ );
+
+ assert_eq!(
+ compare_term_test!(wam, wam.heap[0], wam.heap[0]),
+ Some(Ordering::Equal)
+ );
+
+ assert_eq!(
+ compare_term_test!(wam, wam.heap[1], wam.heap[1]),
+ Some(Ordering::Equal)
+ );
+
+ assert_eq!(
+ compare_term_test!(
+ wam,
+ atom_as_cell!(atom!("atom")),
+ atom_as_cstr_cell!(atom!("string"))
+ ),
+ Some(Ordering::Less)
+ );
+
+ assert_eq!(
+ compare_term_test!(
+ wam,
+ atom_as_cell!(atom!("atom")),
+ atom_as_cell!(atom!("atom"))
+ ),
+ Some(Ordering::Equal)
+ );
+
+ assert_eq!(
+ compare_term_test!(
+ wam,
+ atom_as_cell!(atom!("atom")),
+ atom_as_cell!(atom!("aaa"))
+ ),
+ Some(Ordering::Greater)
+ );
+
+ assert_eq!(
+ compare_term_test!(
+ wam,
+ fixnum_as_cell!(Fixnum::build_with(6)),
+ heap_loc_as_cell!(1)
+ ),
+ Some(Ordering::Greater)
+ );
+
+ wam.heap.clear();
+
+ wam.heap.push(atom_as_cell!(atom!("f"), 1));
+ wam.heap.push(heap_loc_as_cell!(1));
+
+ assert_eq!(
+ compare_term_test!(
+ wam,
+ heap_loc_as_cell!(0),
+ heap_loc_as_cell!(0)
+ ),
+ Some(Ordering::Equal)
+ );
+
+ assert_eq!(
+ compare_term_test!(
+ wam,
+ heap_loc_as_cell!(0),
+ atom_as_cell!(atom!("a"))
+ ),
+ Some(Ordering::Greater)
+ );
+
+ wam.heap.clear();
+
+ // [1,2,3]
+ wam.heap.push(list_loc_as_cell!(1));
+ wam.heap.push(fixnum_as_cell!(Fixnum::build_with(1)));
+ wam.heap.push(list_loc_as_cell!(3));
+ wam.heap.push(fixnum_as_cell!(Fixnum::build_with(2)));
+ wam.heap.push(list_loc_as_cell!(5));
+ wam.heap.push(fixnum_as_cell!(Fixnum::build_with(3)));
+ wam.heap.push(empty_list_as_cell!());
+
+ // [1,2]
+ wam.heap.push(list_loc_as_cell!(8));
+ wam.heap.push(fixnum_as_cell!(Fixnum::build_with(1)));
+ wam.heap.push(list_loc_as_cell!(10));
+ wam.heap.push(fixnum_as_cell!(Fixnum::build_with(2)));
+ wam.heap.push(empty_list_as_cell!());
+
+ assert_eq!(
+ compare_term_test!(
+ wam,
+ heap_loc_as_cell!(7),
+ heap_loc_as_cell!(7)
+ ),
+ Some(Ordering::Equal)
+ );
+
+ assert_eq!(
+ compare_term_test!(
+ wam,
+ heap_loc_as_cell!(0),
+ heap_loc_as_cell!(7)
+ ),
+ Some(Ordering::Greater)
+ );
+
+ assert_eq!(
+ compare_term_test!(
+ wam,
+ empty_list_as_cell!(),
+ heap_loc_as_cell!(7)
+ ),
+ Some(Ordering::Less)
+ );
+
+ assert_eq!(
+ compare_term_test!(
+ wam,
+ empty_list_as_cell!(),
+ fixnum_as_cell!(Fixnum::build_with(1))
+ ),
+ Some(Ordering::Greater)
+ );
+
+ assert_eq!(
+ compare_term_test!(
+ wam,
+ empty_list_as_cell!(),
+ atom_as_cstr_cell!(atom!("string"))
+ ),
+ Some(Ordering::Less)
+ );
+
+ assert_eq!(
+ compare_term_test!(
+ wam,
+ empty_list_as_cell!(),
+ atom_as_cell!(atom!("atom"))
+ ),
+ Some(Ordering::Less)
+ );
+
+ assert_eq!(
+ compare_term_test!(
+ wam,
+ atom_as_cell!(atom!("atom")),
+ empty_list_as_cell!()
+ ),
+ Some(Ordering::Greater)
+ );
+
+ let one_p_one = typed_arena_ptr_as_cell!(
+ arena_alloc!(OrderedFloat(1.1), &mut wam.arena)
+ );
+
+ assert_eq!(
+ compare_term_test!(
+ wam,
+ one_p_one,
+ fixnum_as_cell!(Fixnum::build_with(1))
+ ),
+ Some(Ordering::Less)
+ );
+
+ assert_eq!(
+ compare_term_test!(
+ wam,
+ fixnum_as_cell!(Fixnum::build_with(1)),
+ one_p_one
+ ),
+ Some(Ordering::Greater)
+ );
+ }
+
+ #[test]
+ fn is_cyclic_term_tests() {
+ let mut wam = MachineState::new();
+
+ assert!(!wam.is_cyclic_term(atom_as_cell!(atom!("f"))));
+ assert!(!wam.is_cyclic_term(fixnum_as_cell!(Fixnum::build_with(555))));
+
+ wam.heap.push(heap_loc_as_cell!(0));
+
+ assert!(!wam.is_cyclic_term(heap_loc_as_cell!(0)));
+
+ all_cells_unmarked(&wam.heap);
+ wam.heap.clear();
+
+ wam.heap.extend(functor!(atom!("f"), [atom(atom!("a")), atom(atom!("b"))]));
+
+ assert!(!wam.is_cyclic_term(str_loc_as_cell!(0)));
+
+ all_cells_unmarked(&wam.heap);
+
+ assert!(!wam.is_cyclic_term(heap_loc_as_cell!(1)));
+
+ all_cells_unmarked(&wam.heap);
+
+ assert!(!wam.is_cyclic_term(heap_loc_as_cell!(2)));
+
+ all_cells_unmarked(&wam.heap);
+
+ wam.heap[2] = str_loc_as_cell!(0);
+
+ print_heap_terms(wam.heap.iter(), 0);
+
+ assert!(wam.is_cyclic_term(str_loc_as_cell!(0)));
+
+ all_cells_unmarked(&wam.heap);
+
+ wam.heap[2] = atom_as_cell!(atom!("b"));
+ wam.heap[1] = str_loc_as_cell!(0);
+
+ assert!(wam.is_cyclic_term(str_loc_as_cell!(0)));
+
+ all_cells_unmarked(&wam.heap);
+
+ assert!(wam.is_cyclic_term(heap_loc_as_cell!(1)));
+
+ all_cells_unmarked(&wam.heap);
+
+ wam.heap.clear();
+
+ wam.heap.push(pstr_as_cell!(atom!("a string")));
+ wam.heap.push(empty_list_as_cell!());
+
+ assert!(!wam.is_cyclic_term(pstr_loc_as_cell!(0)));
+ }
+}