From: Mark Thom Date: Sun, 26 Feb 2017 03:53:33 +0000 (-0700) Subject: bug fixes, tests X-Git-Tag: v0.8.110~767 X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=e3e3f346e547bac4a2bd5061ddeb78c9535b5192;p=scryer-prolog.git bug fixes, tests --- diff --git a/src/l2/codegen.rs b/src/l2/codegen.rs index e17a4900..456f834a 100644 --- a/src/l2/codegen.rs +++ b/src/l2/codegen.rs @@ -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 } diff --git a/src/l2/machine.rs b/src/l2/machine.rs index c1f1f269..869950d6 100644 --- a/src/l2/machine.rs +++ b/src/l2/machine.rs @@ -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 { diff --git a/src/main.rs b/src/main.rs index 1d8ed659..f1d55bbd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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); } }