]> Repositorios git - scryer-prolog.git/commitdiff
add compare predicate.
authorMark Thom <[email protected]>
Thu, 22 Feb 2018 06:21:18 +0000 (23:21 -0700)
committerMark Thom <[email protected]>
Thu, 22 Feb 2018 06:21:18 +0000 (23:21 -0700)
README.md
src/prolog/ast.rs
src/prolog/builtins.rs
src/prolog/codegen.rs
src/prolog/io.rs
src/prolog/iterators.rs
src/prolog/machine/machine_state_impl.rs
src/prolog/macros.rs
src/prolog/parser
src/tests.rs

index 49fd9db9de53dbfae43eda5a01124f4529616c43..8c537b14aac68a72169344b91065bc33c3875dcb 100644 (file)
--- 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`
index 86ea088de33901da444d47043ed2e45cde496533..019a97142d8849168689cd7b0d8fbebe7aa7d305 100644 (file)
@@ -421,6 +421,7 @@ pub enum QueryTerm {
     CallN(Vec<Box<Term>>),
     CallWithInferenceLimit(Vec<Box<Term>>),
     Catch(Vec<Box<Term>>),
+    Compare(Vec<Box<Term>>),
     CompareTerm(CompareTermQT, Vec<Box<Term>>),
     Cut,
     Display(Vec<Box<Term>>),
@@ -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<RegType>, &'a TabledRc<Atom>, Option<Fixity>),
@@ -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
         }
     }
index 32d28dcddf84926b8d0bbbfbd916940c5e48d3f3..1bc5593ca5878b7f8b84d76cfa432884523bea04 100644 (file)
@@ -632,7 +632,8 @@ fn get_builtins(atom_tbl: TabledData<Atom>) -> 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<Atom>) -> (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)
 }
index 73c7c97ee43a1caa179d074c43b71b3733d483b4..9d3b61c0524d747452c9a1ac2ef039520a1eaeed 100644 (file)
@@ -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 =>
index 3a0a083f9c80ad34b45570f3dc3c2808fb1a4e75..c94532011f78c52a85b364cb5d67aa68e9315514 100644 (file)
@@ -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) =>
index 3bb8fd610a6c59702e03b9263d65d3ce0a4509fd..600ed11646d7ed3ec55c4b34055d1cfd302d6fce 100644 (file)
@@ -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;
index 56416a9c61c7d89aa1f081633ee1ea4b60654551..02cdc8d012d72b3f9bf2863d82c7c3ec66848bd0 100644 (file)
@@ -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 =>
index 4886b13f616d16c3659cf57832cf0cdb75647273..4fe210425637a7f93e44acb86938d55cdd20862a 100644 (file)
@@ -658,3 +658,9 @@ macro_rules! remove_call_policy_check {
         Line::BuiltIn(BuiltInInstruction::RemoveCallPolicyCheck)
     )
 }
+
+macro_rules! compare_execute {
+    () => (
+        Line::Control(ControlInstruction::CompareExecute)
+    )
+}
index 74bb1031f54631bae14aee7d8814c33573e7171d..cd115d7a6781a59003f0d52451319ae68988e785 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 74bb1031f54631bae14aee7d8814c33573e7171d
+Subproject commit cd115d7a6781a59003f0d52451319ae68988e785
index d80e7f4f9b8a9663e318cc6bb17dfef10ec79779..f1be2761c4390937f3526a32600842f68a7e77f7 100644 (file)
@@ -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"]]);
+}