use l2::iterators::{FactIterator, QueryIterator};
use std::cell::Cell;
+use std::cmp::max;
use std::collections::HashMap;
use std::fmt;
use std::vec::Vec;
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;
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;
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
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);
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
}
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();
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" {
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);
}
}