Skip to content

Commit

Permalink
Handle errors in QueryState
Browse files Browse the repository at this point in the history
  • Loading branch information
bakaq committed Dec 8, 2024
1 parent 3d3baee commit 9265d66
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 27 deletions.
61 changes: 57 additions & 4 deletions src/machine/lib_machine/lib_machine_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,21 @@ fn failing_query() {
let mut machine = MachineBuilder::default().build();
let query = r#"triple("a",P,"b")."#;
let complete_answer: Result<Vec<_>, _> = 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)]),
],
))
);
}
Expand Down Expand Up @@ -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)]
),
],
))
);
}
Expand Down Expand Up @@ -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")))]
);
}
39 changes: 16 additions & 23 deletions src/machine/lib_machine/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ impl Drop for QueryState<'_> {
}

impl Iterator for QueryState<'_> {
type Item = Result<LeafAnswer, String>;
type Item = Result<LeafAnswer, Term>;

fn next(&mut self) -> Option<Self::Item> {
let var_names = &mut self.var_names;
Expand All @@ -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::<Vec<String>>()
.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 {
Expand Down

0 comments on commit 9265d66

Please sign in to comment.