]> Repositorios git - scryer-prolog.git/commitdiff
bug fixes, tests
authorMark Thom <[email protected]>
Sun, 26 Feb 2017 03:53:33 +0000 (20:53 -0700)
committerMark Thom <[email protected]>
Sun, 26 Feb 2017 03:53:33 +0000 (20:53 -0700)
src/l2/codegen.rs
src/l2/machine.rs
src/main.rs

index e17a4900dc7a0a5c0be5ec78602260e191c57cf0..456f834a091f1ff0580550bea3d60e62839725df 100644 (file)
@@ -2,6 +2,7 @@ use l2::ast::*;
 use l2::iterators::{FactIterator, QueryIterator};
 
 use std::cell::Cell;
+use std::cmp::max;
 use std::collections::HashMap;
 use std::fmt;
 use std::vec::Vec;
@@ -236,6 +237,21 @@ impl<'a> TermMarker<'a> {
         reg
     }
 
+    fn advance_at_header(&mut self, term: &'a Term) {
+        self.arg_c = 1;
+        self.temp_c = max(term.subterms() + 1,
+                          self.bindings.values()
+                          .filter_map(|vr| {
+                              match vr {
+                                  &VarReg::Norm(RegType::Temp(reg)) |
+                                  &VarReg::ArgAndNorm(RegType::Temp(reg), _) =>
+                                      Some(reg),
+                                  _ => None
+                              }
+                          })
+                          .max().unwrap_or(0));
+    }
+
     fn advance(&mut self, term: &'a Term) {
         self.arg_c = 1;
         self.temp_c = term.subterms() + 1;
@@ -396,6 +412,21 @@ impl<'a> CodeGenerator<'a> {
         vfs
     }
 
+    //TODO: remove this if it proves to be unnecessary.
+    fn add_conditional_call(compiled_query: &mut Code, term: &Term) {
+        match term {
+            &Term::Atom(_, ref atom) => {
+                let call = ControlInstruction::Call(atom.clone(), 0);
+                compiled_query.push(Line::Control(call));
+            },
+            &Term::Clause(_, ref atom, ref terms) => {
+                let call = ControlInstruction::Call(atom.clone(), terms.len());
+                compiled_query.push(Line::Control(call));
+            },
+            _ => {}
+        }
+    }
+
     pub fn compile_rule(&mut self, rule: &'a Rule) -> Code {
         let vfs = Self::mark_perm_vars(&rule);
         let &Rule { head: (ref p0, ref p1), ref clauses } = rule;
@@ -409,18 +440,17 @@ impl<'a> CodeGenerator<'a> {
 
         let mut body = Vec::new();
 
-        self.marker.advance(p0);
-        
         body.push(Line::Control(ControlInstruction::Allocate(perm_vars)));
+
+        self.marker.advance(p0);
         body.push(Line::Fact(self.compile_target(p0)));
 
-        body.append(&mut self.compile_query(p1));
+        self.marker.advance_at_header(p1);
+        body.push(Line::Query(self.compile_target(p1)));
+        Self::add_conditional_call(&mut body, p1);
 
         body = clauses.iter()
-            .map(|ref term| {
-                self.marker.advance(term);
-                self.compile_query(term)
-            })
+            .map(|ref term| self.compile_query(term))
             .fold(body, |mut body, ref mut cqs| {
                 body.append(cqs);
                 body
@@ -433,7 +463,7 @@ impl<'a> CodeGenerator<'a> {
 
     pub fn compile_fact(&mut self, term: &'a Term) -> Code {
         self.marker.advance(term);
-        
+
         let mut compiled_fact = vec![Line::Fact(self.compile_target(term))];
         let proceed = Line::Control(ControlInstruction::Proceed);
 
@@ -443,20 +473,9 @@ impl<'a> CodeGenerator<'a> {
 
     pub fn compile_query(&mut self, term: &'a Term) -> Code {
         self.marker.advance(term);
-        
-        let mut compiled_query = vec![Line::Query(self.compile_target(term))];
 
-        match term {
-            &Term::Atom(_, ref atom) => {
-                let call = ControlInstruction::Call(atom.clone(), 0);
-                compiled_query.push(Line::Control(call));
-            },
-            &Term::Clause(_, ref atom, ref terms) => {
-                let call = ControlInstruction::Call(atom.clone(), terms.len());
-                compiled_query.push(Line::Control(call));
-            },
-            _ => {}
-        }
+        let mut compiled_query = vec![Line::Query(self.compile_target(term))];
+        Self::add_conditional_call(&mut compiled_query, term);
 
         compiled_query
     }
index c1f1f269fbee3e5161407814d1b5a3b2fecb59ee..869950d6956947665646a62f508b3957df5c84bd 100644 (file)
@@ -41,7 +41,7 @@ impl Machine {
         }
     }
 
-    fn failed(&self) -> bool {
+    pub fn failed(&self) -> bool {
         self.ms.fail
     }
 
@@ -173,13 +173,15 @@ impl Machine {
         
         if succeeded {
             let result = Some(self.heap_view(heap_locs));
-            self.ms.reset();
             result
         } else {
-            self.ms.reset();
             None
         }   
     }
+
+    pub fn reset(&mut self) {
+        self.ms.reset();
+    }
 }
 
 impl MachineState {
index 1d8ed6598317874462f3bc654ab4f86883ee0932..f1d55bbd0f60aff1955cf6cce2e09a675b737830 100644 (file)
@@ -6,6 +6,130 @@ use l2::machine::*;
 
 use std::io::{self, Write};
 
+fn submit(wam: &mut Machine, buffer: String) -> bool {
+    let result = l2::l2_parser::parse_TopLevel(&*buffer);
+
+    let mut cg = CodeGenerator::new();
+
+    match &result {
+        &Ok(TopLevel::Fact(ref fact)) => {
+            let compiled_fact = cg.compile_fact(&fact);
+            wam.add_fact(fact, compiled_fact);
+        },
+        &Ok(TopLevel::Rule(ref rule)) => {
+            let compiled_rule = cg.compile_rule(&rule);
+            wam.add_rule(rule, compiled_rule);
+        },
+        &Ok(TopLevel::Query(ref query)) => {
+            let compiled_query = cg.compile_query(&query);
+            let output = wam.run_query(compiled_query, &cg);
+
+            match output {
+                Some(result) => {
+                    println!("yes");
+
+                    if result != "" {
+                        println!("{}", result);
+                    }
+                },
+                None => println!("no")
+            }
+        },
+        &Err(_) => println!("Grammatical error of some kind!"),
+    };
+
+    let result = wam.failed();
+    wam.reset();
+    result
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[inline]
+    fn submit_ss(wam: &mut Machine, buffer: &'static str) -> bool {
+        submit(wam, String::from(buffer))
+    }
+
+    #[test]
+    fn test_queries_on_facts() {
+        let mut wam = Machine::new();
+
+        submit_ss(&mut wam, "p(Z, Z).");
+        submit_ss(&mut wam, "clouds(are, nice).");
+
+        // submit_ss returns true on failure, false on success.
+        assert_eq!(submit_ss(&mut wam, "?- p(Z, Z)."), false);
+        assert_eq!(submit_ss(&mut wam, "?- p(Z, z)."), false);
+        assert_eq!(submit_ss(&mut wam, "?- p(Z, w)."), false);
+        assert_eq!(submit_ss(&mut wam, "?- p(z, w)."), true);
+        assert_eq!(submit_ss(&mut wam, "?- p(w, w)."), false);
+        assert_eq!(submit_ss(&mut wam, "?- clouds(Z, Z)."), true);
+        assert_eq!(submit_ss(&mut wam, "?- clouds(are, Z)."), false);
+        assert_eq!(submit_ss(&mut wam, "?- clouds(Z, nice)."), false);
+
+        assert_eq!(submit_ss(&mut wam, "?- p(Z, h(Z, W), f(W))."), true);
+
+        submit_ss(&mut wam, "p(Z, h(Z, W), f(W)).");
+
+        assert_eq!(submit_ss(&mut wam, "?- p(z, h(z, z), f(w))."), true);
+        assert_eq!(submit_ss(&mut wam, "?- p(z, h(z, w), f(w))."), false);
+        assert_eq!(submit_ss(&mut wam, "?- p(z, h(z, W), f(w))."), false);
+        assert_eq!(submit_ss(&mut wam, "?- p(Z, h(Z, w), f(Z))."), false);
+        assert_eq!(submit_ss(&mut wam, "?- p(z, h(Z, w), f(Z))."), true);
+
+        submit_ss(&mut wam, "p(f(X), h(Y, f(a)), Y).");
+
+        assert_eq!(submit_ss(&mut wam, "?- p(Z, h(Z, W), f(W))."), false);
+    }
+
+    #[test]
+    fn test_queries_on_rules() {
+        let mut wam = Machine::new();
+
+        submit_ss(&mut wam, "p(X, Y) :- q(X, Z), r(Z, Y).");
+        submit_ss(&mut wam, "q(q, s).");
+        submit_ss(&mut wam, "r(s, t).");
+
+        assert_eq!(submit_ss(&mut wam, "?- p(X, Y)."), false);
+        assert_eq!(submit_ss(&mut wam, "?- p(q, t)."), false);
+        assert_eq!(submit_ss(&mut wam, "?- p(t, q)."), true);
+        assert_eq!(submit_ss(&mut wam, "?- p(q, T)."), false);
+        assert_eq!(submit_ss(&mut wam, "?- p(Q, t)."), false);
+        assert_eq!(submit_ss(&mut wam, "?- p(t, t)."), true);
+
+        submit_ss(&mut wam, "p(X, Y) :- q(f(f(X)), R), r(S, T).");
+        submit_ss(&mut wam, "q(f(f(X)), r).");
+
+        assert_eq!(submit_ss(&mut wam, "?- p(X, Y)."), false);
+
+        submit_ss(&mut wam, "q(f(f(x)), r).");
+
+        assert_eq!(submit_ss(&mut wam, "?- p(X, Y)."), false);
+
+        submit_ss(&mut wam, "p(X, Y) :- q(X, Y), r(X, Y).");
+        submit_ss(&mut wam, "q(s, t).");
+        submit_ss(&mut wam, "r(X, Y) :- r(a).");
+        submit_ss(&mut wam, "r(a).");
+
+        assert_eq!(submit_ss(&mut wam, "?- p(X, Y)."), false);
+        assert_eq!(submit_ss(&mut wam, "?- p(t, S)."), true);
+        assert_eq!(submit_ss(&mut wam, "?- p(t, s)."), true);
+        assert_eq!(submit_ss(&mut wam, "?- p(s, T)."), false);
+        assert_eq!(submit_ss(&mut wam, "?- p(S, t)."), false);
+
+        submit_ss(&mut wam, "p(f(f(a), g(b), X), g(b), h) :- q(X, Y).");
+        submit_ss(&mut wam, "q(X, Y).");
+
+        assert_eq!(submit_ss(&mut wam, "?- p(f(X, Y, Z), g(b), h)."), false);
+        assert_eq!(submit_ss(&mut wam, "?- p(f(X, g(Y), Z), g(Z), X)."), true);
+        assert_eq!(submit_ss(&mut wam, "?- p(f(X, g(Y), Z), g(Z), h)."), false);
+        assert_eq!(submit_ss(&mut wam, "?- p(Z, Y, X)."), false);
+        assert_eq!(submit_ss(&mut wam, "?- p(f(X, Y, Z), Y, h)."), false);
+    }
+}
+
 fn l2_repl() {
     let mut wam = Machine::new();
 
@@ -17,8 +141,6 @@ fn l2_repl() {
 
         io::stdin().read_line(&mut buffer).unwrap();
 
-        let result = l2::l2_parser::parse_TopLevel(&*buffer);
-
         if &*buffer == "quit\n" {
             break;
         } else if &*buffer == "clear\n" {
@@ -26,34 +148,7 @@ fn l2_repl() {
             continue;
         }
 
-        let mut cg = CodeGenerator::new();
-
-        match &result {
-            &Ok(TopLevel::Fact(ref fact)) => {
-                let compiled_fact = cg.compile_fact(&fact);
-                wam.add_fact(fact, compiled_fact);
-            },
-            &Ok(TopLevel::Rule(ref rule)) => {
-                let compiled_rule = cg.compile_rule(&rule);
-                wam.add_rule(rule, compiled_rule);
-            },
-            &Ok(TopLevel::Query(ref query)) => {
-                let compiled_query = cg.compile_query(&query);
-                let output = wam.run_query(compiled_query, &cg);
-
-                match output {
-                    Some(result) => {
-                        println!("yes");
-
-                        if result != "" {
-                            println!("{}", result);
-                        }
-                    },
-                    None => println!("no")
-                }
-            },
-            &Err(_) => println!("Grammatical error of some kind!"),
-        };
+        submit(&mut wam, buffer);
     }
 }