From 9265d66f58e2a24f0a89aed1f6d907e38f44b385 Mon Sep 17 00:00:00 2001 From: bakaq Date: Sun, 8 Dec 2024 19:47:18 -0300 Subject: [PATCH] Handle errors in QueryState --- src/machine/lib_machine/lib_machine_tests.rs | 61 ++++++++++++++++++-- src/machine/lib_machine/mod.rs | 39 +++++-------- 2 files changed, 73 insertions(+), 27 deletions(-) diff --git a/src/machine/lib_machine/lib_machine_tests.rs b/src/machine/lib_machine/lib_machine_tests.rs index c05fccf6..5b89d67d 100644 --- a/src/machine/lib_machine/lib_machine_tests.rs +++ b/src/machine/lib_machine/lib_machine_tests.rs @@ -44,10 +44,21 @@ fn failing_query() { let mut machine = MachineBuilder::default().build(); let query = r#"triple("a",P,"b")."#; let complete_answer: Result, _> = machine.run_query(query).collect(); + assert_eq!( complete_answer, - Err(String::from( - "error existence_error procedure / triple 3 / triple 3" + Err(Term::compound( + "error", + [ + Term::compound( + "existence_error", + [ + Term::atom("procedure"), + Term::compound("/", [Term::atom("triple"), Term::integer(3)]), + ] + ), + Term::compound("/", [Term::atom("triple"), Term::integer(3)]), + ], )) ); } @@ -349,8 +360,24 @@ fn non_existent_predicate_should_not_cause_panic_when_other_predicates_are_defin assert_eq!( complete_answer, - Err(String::from( - "error existence_error procedure / non_existent_predicate 3 / non_existent_predicate 3" + Err(Term::compound( + "error", + [ + Term::compound( + "existence_error", + [ + Term::atom("procedure"), + Term::compound( + "/", + [Term::atom("non_existent_predicate"), Term::integer(3)], + ), + ], + ), + Term::compound( + "/", + [Term::atom("non_existent_predicate"), Term::integer(3)] + ), + ], )) ); } @@ -555,3 +582,29 @@ fn order_of_variables_in_binding() { ])] ); } + +#[test] +#[cfg_attr(miri, ignore)] +fn errors_and_exceptions() { + let mut machine = MachineBuilder::default().build(); + + let complete_answer: Vec<_> = machine.run_query("functor(_,_,_).").collect(); + + assert_eq!( + complete_answer, + [Err(Term::compound( + "error", + [ + Term::atom("instantiation_error"), + Term::compound("/", [Term::atom("functor"), Term::integer(3)]), + ], + ))] + ); + + let complete_answer: Vec<_> = machine.run_query("throw(a).").collect(); + + assert_eq!( + complete_answer, + [Ok(LeafAnswer::Exception(Term::atom("a")))] + ); +} diff --git a/src/machine/lib_machine/mod.rs b/src/machine/lib_machine/mod.rs index 55b6817b..68560323 100644 --- a/src/machine/lib_machine/mod.rs +++ b/src/machine/lib_machine/mod.rs @@ -426,7 +426,7 @@ impl Drop for QueryState<'_> { } impl Iterator for QueryState<'_> { - type Item = Result; + type Item = Result; fn next(&mut self) -> Option { let var_names = &mut self.var_names; @@ -448,30 +448,23 @@ impl Iterator for QueryState<'_> { // this should halt the search for solutions as it // does in the Scryer top-level. the exception term is // contained in self.machine_st.ball. - let error_string = self - .machine + let h = machine.machine_st.heap.len(); + machine .machine_st - .ball - .stub - .iter() - .filter(|h| { - matches!( - h.get_tag(), - HeapCellValueTag::Atom | HeapCellValueTag::Fixnum - ) - }) - .map(|h| match h.get_tag() { - HeapCellValueTag::Atom => { - let (name, _) = cell_as_atom_cell!(h).get_name_and_arity(); - name.as_str().to_string() - } - HeapCellValueTag::Fixnum => h.get_value().clone().to_string(), - _ => unreachable!(), - }) - .collect::>() - .join(" "); + .heap + .extend(machine.machine_st.ball.stub.clone()); + let exception_term = + Term::from_heapcell(machine, machine.machine_st.heap[h], &mut var_names.clone()); + + if let Term::Compound(functor, args) = &exception_term { + if functor == "error" && args.len() == 2 { + // We have an error + return Some(Err(exception_term)); + } + } - return Some(Err(error_string)); + // We have an exception that is not an error + return Some(Ok(LeafAnswer::Exception(exception_term))); } if machine.machine_st.p == LIB_QUERY_SUCCESS { -- 2.54.0