From 9aac3cb08682b7a2df91914426eff372d1577311 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Wed, 21 Feb 2018 23:21:18 -0700 Subject: [PATCH] add compare predicate. --- README.md | 3 +- src/prolog/ast.rs | 10 +++- src/prolog/builtins.rs | 6 +- src/prolog/codegen.rs | 4 ++ src/prolog/io.rs | 4 ++ src/prolog/iterators.rs | 6 +- src/prolog/machine/machine_state_impl.rs | 36 ++++++++++- src/prolog/macros.rs | 6 ++ src/prolog/parser | 2 +- src/tests.rs | 76 ++++++++++++++++++++++++ 10 files changed, 146 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 49fd9db9..8c537b14 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ Extend rusty-wam to include the following, among other features: * Built-in control operators (`,`, `;`, `->`, etc.) (_done_). * Built-in predicates for list processing and top-level declarative control (`setup_call_control/3`, `call_with_inference_limit/3`, - etc.) (_in progress_). + etc.) (_done_). * Add a rudimentary module system. * Attributed variables using the SICStus Prolog interface and semantics. Adding coroutines like `dif/2`, `freeze/2`, etc. @@ -98,6 +98,7 @@ The following predicates are built-in to rusty-wam. * `call/1..63` * `call_with_inference_limit/3` * `catch/3` +* `compare/3` * `compound/1` * `display/1` * `duplicate_term/2` diff --git a/src/prolog/ast.rs b/src/prolog/ast.rs index 86ea088d..019a9714 100644 --- a/src/prolog/ast.rs +++ b/src/prolog/ast.rs @@ -421,6 +421,7 @@ pub enum QueryTerm { CallN(Vec>), CallWithInferenceLimit(Vec>), Catch(Vec>), + Compare(Vec>), CompareTerm(CompareTermQT, Vec>), Cut, Display(Vec>), @@ -442,6 +443,7 @@ impl QueryTerm { match self { &QueryTerm::Arg(_) => 3, &QueryTerm::Catch(_) => 3, + &QueryTerm::Compare(_) => 3, &QueryTerm::CompareTerm(..) => 2, &QueryTerm::Display(_) => 1, &QueryTerm::Throw(_) => 1, @@ -473,6 +475,7 @@ pub enum ClauseType<'a> { CallN, CallWithInferenceLimit, Catch, + Compare, CompareNumber(CompareNumberQT), CompareTerm(CompareTermQT), Deep(Level, &'a Cell, &'a TabledRc, Option), @@ -495,6 +498,7 @@ impl<'a> ClauseType<'a> { &ClauseType::CallN => "call", &ClauseType::CallWithInferenceLimit => "call_with_inference_limit", &ClauseType::Catch => "catch", + &ClauseType::Compare => "compare", &ClauseType::CompareNumber(qt) => qt.name(), &ClauseType::CompareTerm(qt) => qt.name(), &ClauseType::Display => "display", @@ -921,7 +925,9 @@ pub enum ControlInstruction { CallN(usize), // arity. CatchCall, CatchExecute, - CheckCpExecute, + CheckCpExecute, + CompareCall, + CompareExecute, CompareTermCall(CompareTermQT), CompareTermExecute(CompareTermQT), DisplayCall, @@ -987,6 +993,8 @@ impl ControlInstruction { &ControlInstruction::IsExecute(..) => true, &ControlInstruction::JmpByCall(..) => true, &ControlInstruction::JmpByExecute(..) => true, + &ControlInstruction::CompareCall => true, + &ControlInstruction::CompareExecute => true, _ => false } } diff --git a/src/prolog/builtins.rs b/src/prolog/builtins.rs index 32d28dcd..1bc5593c 100644 --- a/src/prolog/builtins.rs +++ b/src/prolog/builtins.rs @@ -632,7 +632,8 @@ fn get_builtins(atom_tbl: TabledData) -> Code { install_inference_counter!(temp_v!(1), temp_v!(2), temp_v!(4)), query![put_value!(temp_v!(3), 1)], reset_block!(), - fail!() + fail!(), + compare_execute!() // compare/3, 454. ] } @@ -748,6 +749,7 @@ pub fn build_code_dir(atom_tbl: TabledData) -> (Code, CodeDir, OpDir) code_dir.insert((tabled_rc!("@<", atom_tbl), 2), (PredicateKeyType::BuiltIn, 390)); code_dir.insert((tabled_rc!("=@=", atom_tbl), 2), (PredicateKeyType::BuiltIn, 391)); code_dir.insert((tabled_rc!("\\=@=", atom_tbl), 2), (PredicateKeyType::BuiltIn, 392)); - + code_dir.insert((tabled_rc!("compare", atom_tbl), 3), (PredicateKeyType::BuiltIn, 454)); + (builtin_code, code_dir, op_dir) } diff --git a/src/prolog/codegen.rs b/src/prolog/codegen.rs index 73c7c97e..9d3b61c0 100644 --- a/src/prolog/codegen.rs +++ b/src/prolog/codegen.rs @@ -259,6 +259,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker> }, &QueryTerm::Catch(_) => code.push(Line::Control(ControlInstruction::CatchCall)), + &QueryTerm::Compare(_) => + code.push(Line::Control(ControlInstruction::CompareCall)), &QueryTerm::CompareTerm(qt, _) => code.push(Line::Control(ControlInstruction::CompareTermCall(qt))), &QueryTerm::Display(_) => @@ -307,6 +309,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker> *ctrl = ControlInstruction::Execute(name, arity), ControlInstruction::CallN(arity) => *ctrl = ControlInstruction::ExecuteN(arity), + ControlInstruction::CompareCall => + *ctrl = ControlInstruction::CompareExecute, ControlInstruction::CompareTermCall(qt) => *ctrl = ControlInstruction::CompareTermExecute(qt), ControlInstruction::DisplayCall => diff --git a/src/prolog/io.rs b/src/prolog/io.rs index 3a0a083f..c9453201 100644 --- a/src/prolog/io.rs +++ b/src/prolog/io.rs @@ -129,6 +129,10 @@ impl fmt::Display for ControlInstruction { write!(f, "catch_execute"), &ControlInstruction::CheckCpExecute => write!(f, "check_cp_execute"), + &ControlInstruction::CompareCall => + write!(f, "compare_call"), + &ControlInstruction::CompareExecute => + write!(f, "compare_execute"), &ControlInstruction::CompareTermCall(qt) => write!(f, "compare_term_call {}", qt), &ControlInstruction::CompareTermExecute(qt) => diff --git a/src/prolog/iterators.rs b/src/prolog/iterators.rs index 3bb8fd61..600ed116 100644 --- a/src/prolog/iterators.rs +++ b/src/prolog/iterators.rs @@ -78,6 +78,10 @@ impl<'a> QueryIterator<'a> { let state = TermIterState::Clause(0, ClauseType::CompareNumber(qt), terms); QueryIterator { state_stack: vec![state] } }, + &QueryTerm::Compare(ref terms) => { + let state = TermIterState::Clause(0, ClauseType::Compare, terms); + QueryIterator { state_stack: vec![state] } + }, &QueryTerm::CompareTerm(qt, ref terms) => { let state = TermIterState::Clause(0, ClauseType::CompareTerm(qt), terms); QueryIterator { state_stack: vec![state] } @@ -329,7 +333,7 @@ impl<'a> ChunkedIterator<'a> break; } }, - &QueryTerm::SetupCallCleanup(_) => { + &QueryTerm::SetupCallCleanup(_) | &QueryTerm::Compare(_) => { result.push(term); arity = 3; break; diff --git a/src/prolog/machine/machine_state_impl.rs b/src/prolog/machine/machine_state_impl.rs index 56416a9c..02cdc8d0 100644 --- a/src/prolog/machine/machine_state_impl.rs +++ b/src/prolog/machine/machine_state_impl.rs @@ -1020,7 +1020,11 @@ impl MachineState { } pub(super) fn copy_and_align_ball_to_heap(&mut self) { - let diff = self.ball.0 - self.heap.h; + let diff = if self.ball.0 > self.heap.h { + self.ball.0 - self.heap.h + } else { + self.heap.h - self.ball.0 + }; for heap_value in self.ball.1.iter().cloned() { self.heap.push(match heap_value { @@ -1830,6 +1834,36 @@ impl MachineState { } }; }, + &ControlInstruction::CompareCall => { + let a1 = self[temp_v!(1)].clone(); + let a2 = self[temp_v!(2)].clone(); + let a3 = self[temp_v!(3)].clone(); + + let c = Addr::Con(match self.compare_term_test(a2, a3) { + Ordering::Greater => atom!(">", self.atom_tbl), + Ordering::Equal => atom!("=", self.atom_tbl), + Ordering::Less => atom!("<", self.atom_tbl) + }); + + self.unify(a1, c); + + self.p += 1; + }, + &ControlInstruction::CompareExecute => { + let a1 = self[temp_v!(1)].clone(); + let a2 = self[temp_v!(2)].clone(); + let a3 = self[temp_v!(3)].clone(); + + let c = Addr::Con(match self.compare_term_test(a2, a3) { + Ordering::Greater => atom!(">", self.atom_tbl), + Ordering::Equal => atom!("=", self.atom_tbl), + Ordering::Less => atom!("<", self.atom_tbl) + }); + + self.unify(a1, c); + + self.p = self.cp; + }, &ControlInstruction::CompareTermCall(qt) => { match qt { CompareTermQT::Equal => diff --git a/src/prolog/macros.rs b/src/prolog/macros.rs index 4886b13f..4fe21042 100644 --- a/src/prolog/macros.rs +++ b/src/prolog/macros.rs @@ -658,3 +658,9 @@ macro_rules! remove_call_policy_check { Line::BuiltIn(BuiltInInstruction::RemoveCallPolicyCheck) ) } + +macro_rules! compare_execute { + () => ( + Line::Control(ControlInstruction::CompareExecute) + ) +} diff --git a/src/prolog/parser b/src/prolog/parser index 74bb1031..cd115d7a 160000 --- a/src/prolog/parser +++ b/src/prolog/parser @@ -1 +1 @@ -Subproject commit 74bb1031f54631bae14aee7d8814c33573e7171d +Subproject commit cd115d7a6781a59003f0d52451319ae68988e785 diff --git a/src/tests.rs b/src/tests.rs index d80e7f4f..f1be2761 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1443,3 +1443,79 @@ fn test_queries_on_setup_call_cleanup() assert_prolog_success!(&mut wam, "?- catch(( setup_call_cleanup(true,(G=1;G=2),throw(cl)), throw(cont)), Pat, true).", [["Pat = cont", "G = _1"]]); } + +#[test] +fn test_queries_on_call_with_inference_limit() +{ + let mut wam = Machine::new(); + + // inference_limit_exceeded thrown on 0 limit. + assert_prolog_success!(&mut wam, "?- call_with_inference_limit(throw(error), 0, R).", + [["R = inference_limit_exceeded"]]); + assert_prolog_success!(&mut wam, "?- catch(call_with_inference_limit(throw(error), 1, R), + error, + true)."); + + assert_prolog_failure!(&mut wam, "?- call_with_inference_limit(g(X), 5, R)."); + + submit(&mut wam, "g(1). g(2). g(3). g(4). g(5)."); + + assert_prolog_success!(&mut wam, "?- call_with_inference_limit(g(X), 5, R).", + [["R = true", "X = 1"], + ["R = true", "X = 2"], + ["R = true", "X = 3"], + ["R = true", "X = 4"], + ["R = !", "X = 5"]]); + assert_prolog_success!(&mut wam, "?- call_with_inference_limit(g(X), 2, R).", + [["R = true", "X = 1"], + ["R = true", "X = 2"], + ["R = inference_limit_exceeded", "X = _1"]]); + + submit(&mut wam, "f(X) :- call_with_inference_limit(g(X), 5, _)."); + + assert_prolog_success!(&mut wam, "?- call_with_inference_limit(f(X), 6, R).", + [["R = true", "X = 1"], + ["R = true", "X = 2"], + ["R = true", "X = 3"], + ["R = true", "X = 4"], + ["R = !", "X = 5"]]); + assert_prolog_success!(&mut wam, "?- call_with_inference_limit(f(X), 5, R).", + [["R = true", "X = 1"], + ["R = true", "X = 2"], + ["R = true", "X = 3"], + ["R = true", "X = 4"], + ["R = inference_limit_exceeded", "X = _1"]]); + assert_prolog_success!(&mut wam, "?- call_with_inference_limit(f(X), 3, R).", + [["R = true", "X = 1"], + ["R = true", "X = 2"], + ["R = inference_limit_exceeded", "X = _1"]]); + assert_prolog_success!(&mut wam, "?- call_with_inference_limit(f(X), 2, R).", + [["R = true", "X = 1"], + ["R = inference_limit_exceeded", "X = _1"]]); + assert_prolog_success!(&mut wam, "?- call_with_inference_limit(f(X), 1, R).", + [["R = inference_limit_exceeded", "X = _1"]]); + + submit(&mut wam, "e(X) :- call_with_inference_limit(f(X), 10, _)."); + + assert_prolog_success!(&mut wam, "?- call_with_inference_limit(e(X), 7, R).", + [["R = true", "X = 1"], + ["R = true", "X = 2"], + ["R = true", "X = 3"], + ["R = true", "X = 4"], + ["R = !", "X = 5"]]); + assert_prolog_success!(&mut wam, "?- call_with_inference_limit(e(X), 6, R).", + [["R = true", "X = 1"], + ["R = true", "X = 2"], + ["R = true", "X = 3"], + ["R = true", "X = 4"], + ["R = inference_limit_exceeded", "X = _1"]]); + assert_prolog_success!(&mut wam, "?- call_with_inference_limit(e(X), 4, R).", + [["R = true", "X = 1"], + ["R = true", "X = 2"], + ["R = inference_limit_exceeded", "X = _1"]]); + assert_prolog_success!(&mut wam, "?- call_with_inference_limit(e(X), 3, R).", + [["R = true", "X = 1"], + ["R = inference_limit_exceeded", "X = _1"]]); + assert_prolog_success!(&mut wam, "?- call_with_inference_limit(e(X), 2, R).", + [["R = inference_limit_exceeded", "X = _1"]]); +} -- 2.54.0