bug fixes, tests
This commit is contained in:
@@ -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
|
||||
@@ -445,18 +475,7 @@ impl<'a> CodeGenerator<'a> {
|
||||
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));
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
Self::add_conditional_call(&mut compiled_query, term);
|
||||
|
||||
compiled_query
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
155
src/main.rs
155
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user