add support for conjunctive queries.

This commit is contained in:
Mark Thom
2017-05-07 15:26:36 -06:00
parent 9687878219
commit f155b5b2c2
17 changed files with 2109 additions and 1475 deletions

2
Cargo.lock generated
View File

@@ -1,6 +1,6 @@
[root] [root]
name = "rusty-wam" name = "rusty-wam"
version = "0.6.0" version = "0.6.1"
dependencies = [ dependencies = [
"lalrpop 0.12.5 (registry+https://github.com/rust-lang/crates.io-index)", "lalrpop 0.12.5 (registry+https://github.com/rust-lang/crates.io-index)",
"lalrpop-util 0.12.5 (registry+https://github.com/rust-lang/crates.io-index)", "lalrpop-util 0.12.5 (registry+https://github.com/rust-lang/crates.io-index)",

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "rusty-wam" name = "rusty-wam"
version = "0.6.0" version = "0.6.1"
authors = ["Mark Thom"] authors = ["Mark Thom"]
build = "build.rs" build = "build.rs"

View File

@@ -8,11 +8,11 @@ pure Prolog.
## Progress ## Progress
Prolog is implemented as a simple REPL. It is without without meta- or Prolog is implemented as a simple REPL. It is without meta- or
extra-logical operators, or side effects of any kind, with the lone extra-logical operators, or side effects of any kind, with the lone
exception of cut. In terms of the tutorial pacing, the work covers in exception of cut. In terms of the tutorial pacing, the work covers in
some form all of the WAM book, including lists, cuts, Debray some form all of the WAM book, including lists, cuts, Debray
allocation, and indexing. allocation, indexing, and conjunctive queries.
## Tutorial ## Tutorial
To enter a multi-clause predicate, the brackets ":{" and "}:" are used To enter a multi-clause predicate, the brackets ":{" and "}:" are used
@@ -76,6 +76,29 @@ Press ; to continue or . to abort.
; ;
no no
``` ```
and so do conjunctive queries:
```
prolog> ?- member([X,X],[a,b,c,[d,d],[e,d]]), member(X, [a,b,c,d,e,f,g]), member(Y, [X, a, b, c, d]).
yes
Y = d
X = d
Press ; to continue or . to abort.
Y = a
X = d
Press ; to continue or . to abort.
Y = b
X = d
Press ; to continue or . to abort.
Y = c
X = d
Press ; to continue or . to abort.
Y = d
X = d
Press ; to continue or . to abort.
no
prolog>
```
Note that the values of variables belonging to successful queries are Note that the values of variables belonging to successful queries are
printed out, on one line each. Uninstantiated variables are denoted by printed out, on one line each. Uninstantiated variables are denoted by

View File

@@ -3,16 +3,27 @@ mod prolog;
use prolog::io::*; use prolog::io::*;
use prolog::machine::*; use prolog::machine::*;
use prolog::prolog_parser::*;
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use prolog::ast::*; use prolog::codegen::*;
fn submit(wam: &mut Machine, buffer: &str) -> EvalResult { fn submit(wam: &mut Machine, buffer: &str) -> bool {
let result = eval(wam, buffer);
wam.reset(); wam.reset();
result
match parse_TopLevel(buffer.trim()) {
Ok(tl) =>
match eval(wam, &tl) {
EvalResult::InitialQuerySuccess(_, _) |
EvalResult::EntrySuccess |
EvalResult::SubsequentQuerySuccess =>
true,
_ => false
},
Err(_) => panic!("Bad parse in test case!")
}
} }
#[test] #[test]
@@ -23,28 +34,28 @@ mod tests {
submit(&mut wam, "clouds(are, nice)."); submit(&mut wam, "clouds(are, nice).");
// submit returns true on failure, false on success. // submit returns true on failure, false on success.
assert_eq!(submit(&mut wam, "?- p(Z, Z).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(Z, Z)."), true);
assert_eq!(submit(&mut wam, "?- p(Z, z).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(Z, z)."), true);
assert_eq!(submit(&mut wam, "?- p(Z, w).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(Z, w)."), true);
assert_eq!(submit(&mut wam, "?- p(z, w).").failed_query(), true); assert_eq!(submit(&mut wam, "?- p(z, w)."), false);
assert_eq!(submit(&mut wam, "?- p(w, w).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(w, w)."), true);
assert_eq!(submit(&mut wam, "?- clouds(Z, Z).").failed_query(), true); assert_eq!(submit(&mut wam, "?- clouds(Z, Z)."), false);
assert_eq!(submit(&mut wam, "?- clouds(are, Z).").failed_query(), false); assert_eq!(submit(&mut wam, "?- clouds(are, Z)."), true);
assert_eq!(submit(&mut wam, "?- clouds(Z, nice).").failed_query(), false); assert_eq!(submit(&mut wam, "?- clouds(Z, nice)."), true);
assert_eq!(submit(&mut wam, "?- p(Z, h(Z, W), f(W)).").failed_query(), true); assert_eq!(submit(&mut wam, "?- p(Z, h(Z, W), f(W))."), false);
submit(&mut wam, "p(Z, h(Z, W), f(W))."); submit(&mut wam, "p(Z, h(Z, W), f(W)).");
assert_eq!(submit(&mut wam, "?- p(z, h(z, z), f(w)).").failed_query(), true); assert_eq!(submit(&mut wam, "?- p(z, h(z, z), f(w))."), false);
assert_eq!(submit(&mut wam, "?- p(z, h(z, w), f(w)).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(z, h(z, w), f(w))."), true);
assert_eq!(submit(&mut wam, "?- p(z, h(z, W), f(w)).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(z, h(z, W), f(w))."), true);
assert_eq!(submit(&mut wam, "?- p(Z, h(Z, w), f(Z)).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(Z, h(Z, w), f(Z))."), true);
assert_eq!(submit(&mut wam, "?- p(z, h(Z, w), f(Z)).").failed_query(), true); assert_eq!(submit(&mut wam, "?- p(z, h(Z, w), f(Z))."), false);
submit(&mut wam, "p(f(X), h(Y, f(a)), Y)."); submit(&mut wam, "p(f(X), h(Y, f(a)), Y).");
assert_eq!(submit(&mut wam, "?- p(Z, h(Z, W), f(W)).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(Z, h(Z, W), f(W))."), true);
} }
#[test] #[test]
@@ -55,48 +66,48 @@ mod tests {
submit(&mut wam, "q(q, s)."); submit(&mut wam, "q(q, s).");
submit(&mut wam, "r(s, t)."); submit(&mut wam, "r(s, t).");
assert_eq!(submit(&mut wam, "?- p(X, Y).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(X, Y)."), true);
assert_eq!(submit(&mut wam, "?- p(q, t).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(q, t)."), true);
assert_eq!(submit(&mut wam, "?- p(t, q).").failed_query(), true); assert_eq!(submit(&mut wam, "?- p(t, q)."), false);
assert_eq!(submit(&mut wam, "?- p(q, T).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(q, T)."), true);
assert_eq!(submit(&mut wam, "?- p(Q, t).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(Q, t)."), true);
assert_eq!(submit(&mut wam, "?- p(t, t).").failed_query(), true); assert_eq!(submit(&mut wam, "?- p(t, t)."), false);
submit(&mut wam, "p(X, Y) :- q(f(f(X)), R), r(S, T)."); submit(&mut wam, "p(X, Y) :- q(f(f(X)), R), r(S, T).");
submit(&mut wam, "q(f(f(X)), r)."); submit(&mut wam, "q(f(f(X)), r).");
assert_eq!(submit(&mut wam, "?- p(X, Y).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(X, Y)."), true);
submit(&mut wam, "q(f(f(x)), r)."); submit(&mut wam, "q(f(f(x)), r).");
assert_eq!(submit(&mut wam, "?- p(X, Y).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(X, Y)."), true);
submit(&mut wam, "p(X, Y) :- q(X, Y), r(X, Y)."); submit(&mut wam, "p(X, Y) :- q(X, Y), r(X, Y).");
submit(&mut wam, "q(s, t)."); submit(&mut wam, "q(s, t).");
submit(&mut wam, "r(X, Y) :- r(a)."); submit(&mut wam, "r(X, Y) :- r(a).");
submit(&mut wam, "r(a)."); submit(&mut wam, "r(a).");
assert_eq!(submit(&mut wam, "?- p(X, Y).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(X, Y)."), true);
assert_eq!(submit(&mut wam, "?- p(t, S).").failed_query(), true); assert_eq!(submit(&mut wam, "?- p(t, S)."), false);
assert_eq!(submit(&mut wam, "?- p(t, s).").failed_query(), true); assert_eq!(submit(&mut wam, "?- p(t, s)."), false);
assert_eq!(submit(&mut wam, "?- p(s, T).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(s, T)."), true);
assert_eq!(submit(&mut wam, "?- p(S, t).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(S, t)."), true);
submit(&mut wam, "p(f(f(a), g(b), X), g(b), h) :- q(X, Y)."); submit(&mut wam, "p(f(f(a), g(b), X), g(b), h) :- q(X, Y).");
submit(&mut wam, "q(X, Y)."); submit(&mut wam, "q(X, Y).");
assert_eq!(submit(&mut wam, "?- p(f(X, Y, Z), g(b), h).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(f(X, Y, Z), g(b), h)."), true);
assert_eq!(submit(&mut wam, "?- p(f(X, g(Y), Z), g(Z), X).").failed_query(), true); assert_eq!(submit(&mut wam, "?- p(f(X, g(Y), Z), g(Z), X)."), false);
assert_eq!(submit(&mut wam, "?- p(f(X, g(Y), Z), g(Z), h).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(f(X, g(Y), Z), g(Z), h)."), true);
assert_eq!(submit(&mut wam, "?- p(Z, Y, X).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(Z, Y, X)."), true);
assert_eq!(submit(&mut wam, "?- p(f(X, Y, Z), Y, h).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(f(X, Y, Z), Y, h)."), true);
submit(&mut wam, "p(_, f(_, Y, _)) :- h(Y)."); submit(&mut wam, "p(_, f(_, Y, _)) :- h(Y).");
submit(&mut wam, "h(y)."); submit(&mut wam, "h(y).");
assert_eq!(submit(&mut wam, "?- p(_, f(_, Y, _)).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(_, f(_, Y, _))."), true);
assert_eq!(submit(&mut wam, "?- p(_, f(_, y, _)).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(_, f(_, y, _))."), true);
assert_eq!(submit(&mut wam, "?- p(_, f(_, z, _)).").failed_query(), true); assert_eq!(submit(&mut wam, "?- p(_, f(_, z, _))."), false);
} }
#[test] #[test]
@@ -105,44 +116,44 @@ mod tests {
submit(&mut wam, "p(X, a). p(b, X)."); submit(&mut wam, "p(X, a). p(b, X).");
assert_eq!(submit(&mut wam, "?- p(x, Y).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(x, Y)."), true);
assert_eq!(submit(&mut wam, "?- p(X, a).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(X, a)."), true);
assert_eq!(submit(&mut wam, "?- p(b, X).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(b, X)."), true);
assert_eq!(submit(&mut wam, "?- p(X, X).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(X, X)."), true);
assert_eq!(submit(&mut wam, "?- p(b, a).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(b, a)."), true);
assert_eq!(submit(&mut wam, "?- p(a, b).").failed_query(), true); assert_eq!(submit(&mut wam, "?- p(a, b)."), false);
submit(&mut wam, "p(X, Y, a). p(X, a, Y). p(X, Y, a)."); submit(&mut wam, "p(X, Y, a). p(X, a, Y). p(X, Y, a).");
assert_eq!(submit(&mut wam, "?- p(c, d, X).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(c, d, X)."), true);
assert_eq!(submit(&mut wam, "?- p(a, a, a).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(a, a, a)."), true);
assert_eq!(submit(&mut wam, "?- p(b, c, d).").failed_query(), true); assert_eq!(submit(&mut wam, "?- p(b, c, d)."), false);
submit(&mut wam, "p(X, a). p(X, Y) :- q(Z), p(X, X)."); submit(&mut wam, "p(X, a). p(X, Y) :- q(Z), p(X, X).");
assert_eq!(submit(&mut wam, "?- p(X, Y).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(X, Y)."), true);
assert_eq!(submit(&mut wam, "?- p(x, a).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(x, a)."), true);
assert_eq!(submit(&mut wam, "?- p(X, a).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(X, a)."), true);
assert_eq!(submit(&mut wam, "?- p(X, b).").failed_query(), true); assert_eq!(submit(&mut wam, "?- p(X, b)."), false);
submit(&mut wam, "q(z)."); submit(&mut wam, "q(z).");
assert_eq!(submit(&mut wam, "?- p(X, b).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(X, b)."), true);
assert_eq!(submit(&mut wam, "?- p(x, a).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(x, a)."), true);
assert_eq!(submit(&mut wam, "?- p(X, Y).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(X, Y)."), true);
submit(&mut wam, "p(X, a). p(X, Y) :- q(Y), p(X, X)."); submit(&mut wam, "p(X, a). p(X, Y) :- q(Y), p(X, X).");
assert_eq!(submit(&mut wam, "?- p(X, Y).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(X, Y)."), true);
assert_eq!(submit(&mut wam, "?- p(X, b).").failed_query(), true); assert_eq!(submit(&mut wam, "?- p(X, b)."), false);
submit(&mut wam, "p(a, z). p(X, Y) :- q(Y), p(X, Y)."); submit(&mut wam, "p(a, z). p(X, Y) :- q(Y), p(X, Y).");
assert_eq!(submit(&mut wam, "?- p(X, Y).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(X, Y)."), true);
assert_eq!(submit(&mut wam, "?- p(X, z).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(X, z)."), true);
assert_eq!(submit(&mut wam, "?- p(a, z).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(a, z)."), true);
assert_eq!(submit(&mut wam, "?- p(a, X).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(a, X)."), true);
assert_eq!(submit(&mut wam, "?- p(b, a).").failed_query(), true); assert_eq!(submit(&mut wam, "?- p(b, a)."), false);
submit(&mut wam, "p(X, Y, Z) :- q(X), r(Y), s(Z). submit(&mut wam, "p(X, Y, Z) :- q(X), r(Y), s(Z).
p(a, b, Z) :- q(Z)."); p(a, b, Z) :- q(Z).");
@@ -151,9 +162,9 @@ mod tests {
submit(&mut wam, "r(y)."); submit(&mut wam, "r(y).");
submit(&mut wam, "s(z)."); submit(&mut wam, "s(z).");
assert_eq!(submit(&mut wam, "?- p(X, Y, Z).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(X, Y, Z)."), true);
assert_eq!(submit(&mut wam, "?- p(a, b, c).").failed_query(), true); assert_eq!(submit(&mut wam, "?- p(a, b, c)."), false);
assert_eq!(submit(&mut wam, "?- p(a, b, C).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(a, b, C)."), true);
submit(&mut wam, "p(X) :- q(X). p(X) :- r(X)."); submit(&mut wam, "p(X) :- q(X). p(X) :- r(X).");
submit(&mut wam, "q(X) :- a."); submit(&mut wam, "q(X) :- a.");
@@ -162,10 +173,10 @@ mod tests {
submit(&mut wam, "s(x, t)."); submit(&mut wam, "s(x, t).");
submit(&mut wam, "t(y, u)."); submit(&mut wam, "t(y, u).");
assert_eq!(submit(&mut wam, "?- p(X).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(X)."), true);
assert_eq!(submit(&mut wam, "?- p(x).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(x)."), true);
assert_eq!(submit(&mut wam, "?- p(y).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(y)."), true);
assert_eq!(submit(&mut wam, "?- p(z).").failed_query(), true); assert_eq!(submit(&mut wam, "?- p(z)."), false);
submit(&mut wam, "p(f(f(X)), h(W), Y) :- g(W), h(W), f(X). submit(&mut wam, "p(f(f(X)), h(W), Y) :- g(W), h(W), f(X).
p(X, Y, Z) :- h(Y), g(W), z(Z)."); p(X, Y, Z) :- h(Y), g(W), z(Z).");
@@ -174,24 +185,24 @@ mod tests {
submit(&mut wam, "f(s)."); submit(&mut wam, "f(s).");
submit(&mut wam, "z(Z)."); submit(&mut wam, "z(Z).");
assert_eq!(submit(&mut wam, "?- p(X, Y, Z).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(X, Y, Z)."), true);
assert_eq!(submit(&mut wam, "?- p(X, X, Z).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(X, X, Z)."), true);
assert_eq!(submit(&mut wam, "?- p(f(f(Z)), Y, Z).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(f(f(Z)), Y, Z)."), true);
assert_eq!(submit(&mut wam, "?- p(X, X, X).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(X, X, X)."), true);
assert_eq!(submit(&mut wam, "?- p(X, Y, X).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(X, Y, X)."), true);
assert_eq!(submit(&mut wam, "?- p(f(f(X)), h(f(X)), Y).").failed_query(), true); assert_eq!(submit(&mut wam, "?- p(f(f(X)), h(f(X)), Y)."), false);
submit(&mut wam, "p(X) :- f(Y), g(Y), i(X, Y)."); submit(&mut wam, "p(X) :- f(Y), g(Y), i(X, Y).");
submit(&mut wam, "g(f(a)). g(f(b)). g(f(c))."); submit(&mut wam, "g(f(a)). g(f(b)). g(f(c)).");
submit(&mut wam, "f(f(a)). f(f(b)). f(f(c))."); submit(&mut wam, "f(f(a)). f(f(b)). f(f(c)).");
submit(&mut wam, "i(X, X)."); submit(&mut wam, "i(X, X).");
assert_eq!(submit(&mut wam, "?- p(X).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(X)."), true);
submit(&mut wam, "p(X) :- f(f(Y)), g(Y, f(Y)), i(X, f(Y))."); submit(&mut wam, "p(X) :- f(f(Y)), g(Y, f(Y)), i(X, f(Y)).");
submit(&mut wam, "g(Y, f(Y)) :- g(f(Y))."); submit(&mut wam, "g(Y, f(Y)) :- g(f(Y)).");
assert_eq!(submit(&mut wam, "?- p(X).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(X)."), true);
} }
#[test] #[test]
@@ -202,77 +213,77 @@ mod tests {
submit(&mut wam, "memberchk(X, [X|_]) :- !. submit(&mut wam, "memberchk(X, [X|_]) :- !.
memberchk(X, [_|Xs]) :- memberchk(X, Xs)."); memberchk(X, [_|Xs]) :- memberchk(X, Xs).");
assert_eq!(submit(&mut wam, "?- memberchk(X, [a,b,c]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- memberchk(X, [a,b,c])."), true);
assert_eq!(submit(&mut wam, "?- memberchk([X,X], [a,b,c,[d,e],[d,d]]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- memberchk([X,X], [a,b,c,[d,e],[d,d]])."), true);
assert_eq!(submit(&mut wam, "?- memberchk([X,X], [a,b,c,[D,d],[e,e]]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- memberchk([X,X], [a,b,c,[D,d],[e,e]])."), true);
assert_eq!(submit(&mut wam, "?- memberchk([X,X], [a,b,c,[e,d],[f,e]]).").failed_query(), true); assert_eq!(submit(&mut wam, "?- memberchk([X,X], [a,b,c,[e,d],[f,e]])."), false);
assert_eq!(submit(&mut wam, "?- memberchk([X,X,Y], [a,b,c,[e,d],[f,e]]).").failed_query(), true); assert_eq!(submit(&mut wam, "?- memberchk([X,X,Y], [a,b,c,[e,d],[f,e]])."), false);
assert_eq!(submit(&mut wam, "?- memberchk([X,X,Y], [a,b,c,[e,e,d],[f,e]]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- memberchk([X,X,Y], [a,b,c,[e,e,d],[f,e]])."), true);
// test deep cuts. // test deep cuts.
submit(&mut wam, "commit :- a, !."); submit(&mut wam, "commit :- a, !.");
assert_eq!(submit(&mut wam, "?- commit.").failed_query(), true); assert_eq!(submit(&mut wam, "?- commit."), false);
submit(&mut wam, "a."); submit(&mut wam, "a.");
assert_eq!(submit(&mut wam, "?- commit.").failed_query(), false); assert_eq!(submit(&mut wam, "?- commit."), true);
submit(&mut wam, "commit(X) :- a(X), !."); submit(&mut wam, "commit(X) :- a(X), !.");
assert_eq!(submit(&mut wam, "?- commit(X).").failed_query(), true); assert_eq!(submit(&mut wam, "?- commit(X)."), false);
submit(&mut wam, "a(x)."); submit(&mut wam, "a(x).");
assert_eq!(submit(&mut wam, "?- commit(X).").failed_query(), false); assert_eq!(submit(&mut wam, "?- commit(X)."), true);
submit(&mut wam, "a :- b, !, c. a :- d."); submit(&mut wam, "a :- b, !, c. a :- d.");
assert_eq!(submit(&mut wam, "?- a.").failed_query(), true); assert_eq!(submit(&mut wam, "?- a."), false);
submit(&mut wam, "b."); submit(&mut wam, "b.");
assert_eq!(submit(&mut wam, "?- a.").failed_query(), true); assert_eq!(submit(&mut wam, "?- a."), false);
submit(&mut wam, "d."); submit(&mut wam, "d.");
// we've committed to the first clause since the query on b // we've committed to the first clause since the query on b
// succeeds, so we expect failure here. // succeeds, so we expect failure here.
assert_eq!(submit(&mut wam, "?- a.").failed_query(), true); assert_eq!(submit(&mut wam, "?- a."), false);
submit(&mut wam, "c."); submit(&mut wam, "c.");
assert_eq!(submit(&mut wam, "?- a.").failed_query(), false); assert_eq!(submit(&mut wam, "?- a."), true);
submit(&mut wam, "a(X) :- b, !, c(X). a(X) :- d(X)."); submit(&mut wam, "a(X) :- b, !, c(X). a(X) :- d(X).");
assert_eq!(submit(&mut wam, "?- a(X).").failed_query(), true); assert_eq!(submit(&mut wam, "?- a(X)."), false);
submit(&mut wam, "c(c)."); submit(&mut wam, "c(c).");
submit(&mut wam, "d(d)."); submit(&mut wam, "d(d).");
assert_eq!(submit(&mut wam, "?- a(X).").failed_query(), false); assert_eq!(submit(&mut wam, "?- a(X)."), true);
submit(&mut wam, "b."); submit(&mut wam, "b.");
assert_eq!(submit(&mut wam, "?- a(X).").failed_query(), false); assert_eq!(submit(&mut wam, "?- a(X)."), true);
wam.clear(); wam.clear();
assert_eq!(submit(&mut wam, "?- c(X).").failed_query(), true); assert_eq!(submit(&mut wam, "?- c(X)."), false);
submit(&mut wam, "a(X) :- b, c(X), !. a(X) :- d(X)."); submit(&mut wam, "a(X) :- b, c(X), !. a(X) :- d(X).");
submit(&mut wam, "b."); submit(&mut wam, "b.");
assert_eq!(submit(&mut wam, "?- a(X).").failed_query(), true); assert_eq!(submit(&mut wam, "?- a(X)."), false);
submit(&mut wam, "d(d)."); submit(&mut wam, "d(d).");
assert_eq!(submit(&mut wam, "?- a(X).").failed_query(), false); assert_eq!(submit(&mut wam, "?- a(X)."), true);
submit(&mut wam, "c(c)."); submit(&mut wam, "c(c).");
assert_eq!(submit(&mut wam, "?- a(X).").failed_query(), false); assert_eq!(submit(&mut wam, "?- a(X)."), true);
} }
#[test] #[test]
@@ -281,44 +292,44 @@ mod tests {
submit(&mut wam, "p([Z, W])."); submit(&mut wam, "p([Z, W]).");
assert_eq!(submit(&mut wam, "?- p([Z, Z]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p([Z, Z])."), true);
assert_eq!(submit(&mut wam, "?- p([Z, W, Y]).").failed_query(), true); assert_eq!(submit(&mut wam, "?- p([Z, W, Y])."), false);
assert_eq!(submit(&mut wam, "?- p([Z | W]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p([Z | W])."), true);
assert_eq!(submit(&mut wam, "?- p([Z | [Z]]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p([Z | [Z]])."), true);
assert_eq!(submit(&mut wam, "?- p([Z | [W]]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p([Z | [W]])."), true);
assert_eq!(submit(&mut wam, "?- p([Z | []]).").failed_query(), true); assert_eq!(submit(&mut wam, "?- p([Z | []])."), false);
submit(&mut wam, "p([Z, Z])."); submit(&mut wam, "p([Z, Z]).");
assert_eq!(submit(&mut wam, "?- p([Z, Z]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p([Z, Z])."), true);
assert_eq!(submit(&mut wam, "?- p([Z, W, Y]).").failed_query(), true); assert_eq!(submit(&mut wam, "?- p([Z, W, Y])."), false);
assert_eq!(submit(&mut wam, "?- p([Z | W]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p([Z | W])."), true);
assert_eq!(submit(&mut wam, "?- p([Z | [Z]]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p([Z | [Z]])."), true);
assert_eq!(submit(&mut wam, "?- p([Z | [W]]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p([Z | [W]])."), true);
assert_eq!(submit(&mut wam, "?- p([Z | []]).").failed_query(), true); assert_eq!(submit(&mut wam, "?- p([Z | []])."), false);
submit(&mut wam, "p([Z])."); submit(&mut wam, "p([Z]).");
assert_eq!(submit(&mut wam, "?- p([Z, Z]).").failed_query(), true); assert_eq!(submit(&mut wam, "?- p([Z, Z])."), false);
assert_eq!(submit(&mut wam, "?- p([Z, W, Y]).").failed_query(), true); assert_eq!(submit(&mut wam, "?- p([Z, W, Y])."), false);
assert_eq!(submit(&mut wam, "?- p([Z | W]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p([Z | W])."), true);
assert_eq!(submit(&mut wam, "?- p([Z | [Z]]).").failed_query(), true); assert_eq!(submit(&mut wam, "?- p([Z | [Z]])."), false);
assert_eq!(submit(&mut wam, "?- p([Z | [W]]).").failed_query(), true); assert_eq!(submit(&mut wam, "?- p([Z | [W]])."), false);
assert_eq!(submit(&mut wam, "?- p([Z | []]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p([Z | []])."), true);
submit(&mut wam, "member(X, [X|Xs]). submit(&mut wam, "member(X, [X|Xs]).
member(X, [Y|Xs]) :- member(X, Xs)."); member(X, [Y|Xs]) :- member(X, Xs).");
assert_eq!(submit(&mut wam, "?- member(a, [c, [X, Y]]).").failed_query(), true); assert_eq!(submit(&mut wam, "?- member(a, [c, [X, Y]])."), false);
assert_eq!(submit(&mut wam, "?- member(c, [a, [X, Y]]).").failed_query(), true); assert_eq!(submit(&mut wam, "?- member(c, [a, [X, Y]])."), false);
assert_eq!(submit(&mut wam, "?- member(a, [a, [X, Y]]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- member(a, [a, [X, Y]])."), true);
assert_eq!(submit(&mut wam, "?- member(a, [X, Y, Z]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- member(a, [X, Y, Z])."), true);
assert_eq!(submit(&mut wam, "?- member([X, X], [a, [X, Y]]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- member([X, X], [a, [X, Y]])."), true);
assert_eq!(submit(&mut wam, "?- member([X, X], [a, [b, c], [b, b], [Z, x], [d, f]]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- member([X, X], [a, [b, c], [b, b], [Z, x], [d, f]])."), true);
assert_eq!(submit(&mut wam, "?- member([X, X], [a, [b, c], [b, d], [foo, x], [d, f]]).").failed_query(), true); assert_eq!(submit(&mut wam, "?- member([X, X], [a, [b, c], [b, d], [foo, x], [d, f]])."), false);
assert_eq!(submit(&mut wam, "?- member([X, Y], [a, [b, c], [b, b], [Z, x], [d, f]]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- member([X, Y], [a, [b, c], [b, b], [Z, x], [d, f]])."), true);
assert_eq!(submit(&mut wam, "?- member([X, Y, Y], [a, [b, c], [b, b], [Z, x], [d, f]]).").failed_query(), true); assert_eq!(submit(&mut wam, "?- member([X, Y, Y], [a, [b, c], [b, b], [Z, x], [d, f]])."), false);
assert_eq!(submit(&mut wam, "?- member([X, Y, Z], [a, [b, c], [b, b], [Z, x], [d, f]]).").failed_query(), true); assert_eq!(submit(&mut wam, "?- member([X, Y, Z], [a, [b, c], [b, b], [Z, x], [d, f]])."), false);
} }
#[test] #[test]
@@ -336,92 +347,92 @@ mod tests {
p(X) :- x. p(X) :- x.
p([c, d, e])."); p([c, d, e]).");
assert_eq!(submit(&mut wam, "?- p(a).").failed_query(), true); assert_eq!(submit(&mut wam, "?- p(a)."), false);
assert_eq!(submit(&mut wam, "?- p(b).").failed_query(), true); assert_eq!(submit(&mut wam, "?- p(b)."), false);
assert_eq!(submit(&mut wam, "?- p(c).").failed_query(), true); assert_eq!(submit(&mut wam, "?- p(c)."), false);
assert_eq!(submit(&mut wam, "?- p(f(a)).").failed_query(), true); assert_eq!(submit(&mut wam, "?- p(f(a))."), false);
assert_eq!(submit(&mut wam, "?- p(g(b, X)).").failed_query(), true); assert_eq!(submit(&mut wam, "?- p(g(b, X))."), false);
assert_eq!(submit(&mut wam, "?- p(g(Y, X)).").failed_query(), true); assert_eq!(submit(&mut wam, "?- p(g(Y, X))."), false);
assert_eq!(submit(&mut wam, "?- p(g(Y, c)).").failed_query(), true); assert_eq!(submit(&mut wam, "?- p(g(Y, c))."), false);
assert_eq!(submit(&mut wam, "?- p(g(b)).").failed_query(), true); assert_eq!(submit(&mut wam, "?- p(g(b))."), false);
assert_eq!(submit(&mut wam, "?- p([]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p([])."), true);
assert_eq!(submit(&mut wam, "?- p([c, d, e]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p([c, d, e])."), true);
assert_eq!(submit(&mut wam, "?- p([c, d | X]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p([c, d | X])."), true);
assert_eq!(submit(&mut wam, "?- p([c|X]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p([c|X])."), true);
assert_eq!(submit(&mut wam, "?- p([Y|X]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p([Y|X])."), true);
assert_eq!(submit(&mut wam, "?- p([Y|[d|Xs]]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p([Y|[d|Xs]])."), true);
submit(&mut wam, "a."); submit(&mut wam, "a.");
assert_eq!(submit(&mut wam, "?- p(a).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(a)."), true);
assert_eq!(submit(&mut wam, "?- p(b).").failed_query(), true); assert_eq!(submit(&mut wam, "?- p(b)."), false);
assert_eq!(submit(&mut wam, "?- p(c).").failed_query(), true); assert_eq!(submit(&mut wam, "?- p(c)."), false);
assert_eq!(submit(&mut wam, "?- p(f(a)).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(f(a))."), true);
assert_eq!(submit(&mut wam, "?- p(g(b, X)).").failed_query(), true); assert_eq!(submit(&mut wam, "?- p(g(b, X))."), false);
assert_eq!(submit(&mut wam, "?- p(g(Y, X)).").failed_query(), true); assert_eq!(submit(&mut wam, "?- p(g(Y, X))."), false);
assert_eq!(submit(&mut wam, "?- p(g(Y, c)).").failed_query(), true); assert_eq!(submit(&mut wam, "?- p(g(Y, c))."), false);
assert_eq!(submit(&mut wam, "?- p(g(b)).").failed_query(), true); assert_eq!(submit(&mut wam, "?- p(g(b))."), false);
assert_eq!(submit(&mut wam, "?- p([]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p([])."), true);
assert_eq!(submit(&mut wam, "?- p([c, d, e]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p([c, d, e])."), true);
assert_eq!(submit(&mut wam, "?- p([c, d | X]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p([c, d | X])."), true);
assert_eq!(submit(&mut wam, "?- p([c|X]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p([c|X])."), true);
assert_eq!(submit(&mut wam, "?- p([Y|X]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p([Y|X])."), true);
assert_eq!(submit(&mut wam, "?- p([Y|[d|Xs]]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p([Y|[d|Xs]])."), true);
submit(&mut wam, "b."); submit(&mut wam, "b.");
submit(&mut wam, "f(x)."); submit(&mut wam, "f(x).");
assert_eq!(submit(&mut wam, "?- p(a).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(a)."), true);
assert_eq!(submit(&mut wam, "?- p(b).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(b)."), true);
assert_eq!(submit(&mut wam, "?- p(c).").failed_query(), true); assert_eq!(submit(&mut wam, "?- p(c)."), false);
assert_eq!(submit(&mut wam, "?- p(f(a)).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(f(a))."), true);
assert_eq!(submit(&mut wam, "?- p(g(b, X)).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(g(b, X))."), true);
assert_eq!(submit(&mut wam, "?- p(g(Y, X)).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(g(Y, X))."), true);
assert_eq!(submit(&mut wam, "?- p(g(Y, c)).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(g(Y, c))."), true);
assert_eq!(submit(&mut wam, "?- p(g(b)).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(g(b))."), true);
assert_eq!(submit(&mut wam, "?- p([]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p([])."), true);
assert_eq!(submit(&mut wam, "?- p([c, d, e]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p([c, d, e])."), true);
assert_eq!(submit(&mut wam, "?- p([c, d | X]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p([c, d | X])."), true);
assert_eq!(submit(&mut wam, "?- p([c|X]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p([c|X])."), true);
assert_eq!(submit(&mut wam, "?- p([Y|X]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p([Y|X])."), true);
assert_eq!(submit(&mut wam, "?- p([Y|[d|Xs]]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p([Y|[d|Xs]])."), true);
submit(&mut wam, "c."); submit(&mut wam, "c.");
submit(&mut wam, "g(X)."); submit(&mut wam, "g(X).");
assert_eq!(submit(&mut wam, "?- p(a).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(a)."), true);
assert_eq!(submit(&mut wam, "?- p(b).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(b)."), true);
assert_eq!(submit(&mut wam, "?- p(c).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(c)."), true);
assert_eq!(submit(&mut wam, "?- p(f(a)).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(f(a))."), true);
assert_eq!(submit(&mut wam, "?- p(g(b, X)).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(g(b, X))."), true);
assert_eq!(submit(&mut wam, "?- p(g(Y, X)).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(g(Y, X))."), true);
assert_eq!(submit(&mut wam, "?- p(g(Y, c)).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(g(Y, c))."), true);
assert_eq!(submit(&mut wam, "?- p(g(b)).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(g(b))."), true);
assert_eq!(submit(&mut wam, "?- p([]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p([])."), true);
assert_eq!(submit(&mut wam, "?- p([c, d, e]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p([c, d, e])."), true);
assert_eq!(submit(&mut wam, "?- p([c, d | X]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p([c, d | X])."), true);
assert_eq!(submit(&mut wam, "?- p([c|X]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p([c|X])."), true);
assert_eq!(submit(&mut wam, "?- p([Y|X]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p([Y|X])."), true);
assert_eq!(submit(&mut wam, "?- p([Y|[d|Xs]]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p([Y|[d|Xs]])."), true);
assert_eq!(submit(&mut wam, "?- p(blah).").failed_query(), true); assert_eq!(submit(&mut wam, "?- p(blah)."), false);
submit(&mut wam, "x."); submit(&mut wam, "x.");
assert_eq!(submit(&mut wam, "?- p(a).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(a)."), true);
assert_eq!(submit(&mut wam, "?- p(b).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(b)."), true);
assert_eq!(submit(&mut wam, "?- p(c).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(c)."), true);
assert_eq!(submit(&mut wam, "?- p(f(a)).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(true(a))."), true);
assert_eq!(submit(&mut wam, "?- p(g(b, X)).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(g(b, X))."), true);
assert_eq!(submit(&mut wam, "?- p(g(Y, X)).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(g(Y, X))."), true);
assert_eq!(submit(&mut wam, "?- p(g(Y, c)).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(g(Y, c))."), true);
assert_eq!(submit(&mut wam, "?- p(g(b)).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(g(b))."), true);
assert_eq!(submit(&mut wam, "?- p([]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p([])."), true);
assert_eq!(submit(&mut wam, "?- p([c, d, e]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p([c, d, e])."), true);
assert_eq!(submit(&mut wam, "?- p([c, d | X]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p([c, d | X])."), true);
assert_eq!(submit(&mut wam, "?- p([c|X]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p([c|X])."), true);
assert_eq!(submit(&mut wam, "?- p([Y|X]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p([Y|X])."), true);
assert_eq!(submit(&mut wam, "?- p([Y|[d|Xs]]).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p([Y|[d|Xs]])."), true);
assert_eq!(submit(&mut wam, "?- p(blah).").failed_query(), false); assert_eq!(submit(&mut wam, "?- p(blah)."), true);
submit(&mut wam, "call(or(X, Y)) :- call(X). submit(&mut wam, "call(or(X, Y)) :- call(X).
call(trace) :- trace. call(trace) :- trace.
@@ -433,41 +444,116 @@ mod tests {
call(call(X)) :- call(X). call(call(X)) :- call(X).
call(repeat). call(repeat).
call(repeat) :- call(repeat). call(repeat) :- call(repeat).
call(true)."); call(false).");
assert_eq!(submit(&mut wam, "?- call(repeat).").failed_query(), false); assert_eq!(submit(&mut wam, "?- call(repeat)."), true);
assert_eq!(submit(&mut wam, "?- call(true).").failed_query(), false); assert_eq!(submit(&mut wam, "?- call(false)."), true);
assert_eq!(submit(&mut wam, "?- call(call(repeat)).").failed_query(), false); assert_eq!(submit(&mut wam, "?- call(call(repeat))."), true);
assert_eq!(submit(&mut wam, "?- call(call(true)).").failed_query(), false); assert_eq!(submit(&mut wam, "?- call(call(false))."), true);
assert_eq!(submit(&mut wam, "?- call(notrace).").failed_query(), true); assert_eq!(submit(&mut wam, "?- call(notrace)."), false);
assert_eq!(submit(&mut wam, "?- call(nl).").failed_query(), true); assert_eq!(submit(&mut wam, "?- call(nl)."), false);
assert_eq!(submit(&mut wam, "?- call(builtin(X)).").failed_query(), true); assert_eq!(submit(&mut wam, "?- call(builtin(X))."), false);
assert_eq!(submit(&mut wam, "?- call(extern(X)).").failed_query(), true); assert_eq!(submit(&mut wam, "?- call(extern(X))."), false);
submit(&mut wam, "notrace."); submit(&mut wam, "notrace.");
submit(&mut wam, "nl."); submit(&mut wam, "nl.");
assert_eq!(submit(&mut wam, "?- call(repeat).").failed_query(), false); assert_eq!(submit(&mut wam, "?- call(repeat)."), true);
assert_eq!(submit(&mut wam, "?- call(true).").failed_query(), false); assert_eq!(submit(&mut wam, "?- call(false)."), true);
assert_eq!(submit(&mut wam, "?- call(call(repeat)).").failed_query(), false); assert_eq!(submit(&mut wam, "?- call(call(repeat))."), true);
assert_eq!(submit(&mut wam, "?- call(call(true)).").failed_query(), false); assert_eq!(submit(&mut wam, "?- call(call(false))."), true);
assert_eq!(submit(&mut wam, "?- call(notrace).").failed_query(), false); assert_eq!(submit(&mut wam, "?- call(notrace)."), true);
assert_eq!(submit(&mut wam, "?- call(nl).").failed_query(), false); assert_eq!(submit(&mut wam, "?- call(nl)."), true);
assert_eq!(submit(&mut wam, "?- call(builtin(X)).").failed_query(), true); assert_eq!(submit(&mut wam, "?- call(builtin(X))."), false);
assert_eq!(submit(&mut wam, "?- call(extern(X)).").failed_query(), true); assert_eq!(submit(&mut wam, "?- call(extern(X))."), false);
submit(&mut wam, "builtin(X)."); submit(&mut wam, "builtin(X).");
submit(&mut wam, "extern(x)."); submit(&mut wam, "extern(x).");
assert_eq!(submit(&mut wam, "?- call(repeat).").failed_query(), false); assert_eq!(submit(&mut wam, "?- call(repeat)."), true);
assert_eq!(submit(&mut wam, "?- call(true).").failed_query(), false); assert_eq!(submit(&mut wam, "?- call(false)."), true);
assert_eq!(submit(&mut wam, "?- call(call(repeat)).").failed_query(), false); assert_eq!(submit(&mut wam, "?- call(call(repeat))."), true);
assert_eq!(submit(&mut wam, "?- call(call(true)).").failed_query(), false); assert_eq!(submit(&mut wam, "?- call(call(false))."), true);
assert_eq!(submit(&mut wam, "?- call(notrace).").failed_query(), false); assert_eq!(submit(&mut wam, "?- call(notrace)."), true);
assert_eq!(submit(&mut wam, "?- call(nl).").failed_query(), false); assert_eq!(submit(&mut wam, "?- call(nl)."), true);
assert_eq!(submit(&mut wam, "?- call(builtin(X)).").failed_query(), false); assert_eq!(submit(&mut wam, "?- call(builtin(X))."), true);
assert_eq!(submit(&mut wam, "?- call(extern(X)).").failed_query(), false); assert_eq!(submit(&mut wam, "?- call(extern(X))."), true);
} }
#[test]
fn test_queries_on_conjuctive_queries() {
let mut wam = Machine::new();
submit(&mut wam, "p(a, b).");
submit(&mut wam, "q(b, c).");
assert_eq!(submit(&mut wam, "?- p(X, Y), q(Y, Z)."), true);
assert_eq!(submit(&mut wam, "?- p(X, Y), q(Y, X)."), false);
submit(&mut wam, "p(a, [f(g(X))]).");
submit(&mut wam, "q(Y, c).");
assert_eq!(submit(&mut wam, "?- p(X, Y), q(Y, Z)."), true);
assert_eq!(submit(&mut wam, "?- p(X, Y), q(Y, X)."), false);
submit(&mut wam, "member(X, [X|_]).
member(X, [_|Xs]) :- member(X, Xs).");
assert_eq!(submit(&mut wam, "?- member(X, [a,b,c]), member(X, [a,b,c])."), true);
assert_eq!(submit(&mut wam, "?- member(X, [a,b,c]), member(X, [b,c])."), true);
assert_eq!(submit(&mut wam, "?- member(X, [a,c]), member(X, [b,c])."), true);
assert_eq!(submit(&mut wam, "?- member(X, [a,b,c,d]), !, member(X, [a,d])."), true);
assert_eq!(submit(&mut wam, "?- member(X, [a,b,c,d]), !, member(X, [e])."), false);
assert_eq!(submit(&mut wam, "?- member([X,X],[a,b,c,[d,d],[e,d]]),
member(X, [a,b,c,d,e,f,g]),
member(Y, [X, a, b, c, d])."),
true);
assert_eq!(submit(&mut wam, "?- member([X,X],[a,b,c,[d,d],[e,d]]),
member(X, [a,b,c,d,e,f,g]),
!,
member(Y, [X, a, b, c, d])."),
true);
submit(&mut wam, "p(a, [f(g(X))]).");
submit(&mut wam, "q(Y, c).");
assert_eq!(submit(&mut wam, "?- p(X, Y), q(Y, Z)."), true);
assert_eq!(submit(&mut wam, "?- p(X, Y), q(Y, X)."), false);
submit(&mut wam, "p(a, [f(g(X))]). p(X, c) :- c.");
submit(&mut wam, "c.");
submit(&mut wam, "q(Y, c).");
assert_eq!(submit(&mut wam, "?- p(X, Y), q(Y, Z)."), true);
assert_eq!(submit(&mut wam, "?- p(X, Y), !, q(Y, Z)."), true);
submit(&mut wam, "q([f(g(x))], Z). q([f(g(y))], Y). q([f(g(z))], a).");
assert_eq!(submit(&mut wam, "?- p(X, Y), q(Y, Z)."), true);
assert_eq!(submit(&mut wam, "?- p(X, Y), !, q(Y, Z)."), true);
assert_eq!(submit(&mut wam, "?- p(X, Y), !, q(Y, X)."), true);
submit(&mut wam, "p(X, [f(g(x))]). p(X, [f(g(y))]). p(X, [f(g(z))]).");
assert_eq!(submit(&mut wam, "?- q(f(X), Y), p(X, Y)."), false);
assert_eq!(submit(&mut wam, "?- q(X, Y), p(X, Y)."), true);
assert_eq!(submit(&mut wam, "?- p(X, Y), q(X, Y)."), true);
assert_eq!(submit(&mut wam, "?- p(X, Y), q(Y, X)."), true);
assert_eq!(submit(&mut wam, "?- q(X, Y), p(Y, X)."), true);
}
}
fn process_buffer(wam: &mut Machine, buffer: &str)
{
match parse_TopLevel(buffer.trim()) {
Ok(tl) => {
let result = eval(wam, &tl);
print(wam, result);
},
Err(_) => {
println!("Grammatical error of some kind!");
}
};
} }
fn prolog_repl() { fn prolog_repl() {
@@ -481,13 +567,11 @@ fn prolog_repl() {
if buffer == "quit\n" { if buffer == "quit\n" {
break; break;
} else if buffer == "clear\n" { } else if buffer == "clear\n" {
wam = Machine::new(); wam.clear();
continue; continue;
} }
let result = eval(&mut wam, buffer.trim()); process_buffer(&mut wam, buffer.trim());
print(&mut wam, result);
wam.reset(); wam.reset();
} }
} }

58
src/prolog/allocator.rs Normal file
View File

@@ -0,0 +1,58 @@
use prolog::ast::*;
use prolog::fixtures::*;
use prolog::targets::*;
use std::cell::Cell;
pub trait Allocator<'a>
{
fn new() -> Self;
fn mark_anon_var<Target>(&mut self, Level, &mut Vec<Target>)
where Target: CompilationTarget<'a>;
fn mark_non_var<Target>(&mut self, Level, GenContext, &'a Cell<RegType>, &mut Vec<Target>)
where Target: CompilationTarget<'a>;
fn mark_var<Target>(&mut self, &'a Var, Level, &'a Cell<VarReg>, GenContext, &mut Vec<Target>)
where Target: CompilationTarget<'a>;
fn reset(&mut self);
fn reset_contents(&mut self) {}
fn advance(&mut self, GenContext, &'a Term);
fn advance_arg(&mut self);
fn bindings(&self) -> &AllocVarDict<'a>;
fn bindings_mut(&mut self) -> &mut AllocVarDict<'a>;
fn take_bindings(self) -> AllocVarDict<'a>;
fn drain_var_data(&mut self, vs: VariableFixtures<'a>) -> VariableFixtures<'a>
{
let mut perm_vs = VariableFixtures::new();
for (var, (var_status, cells)) in vs.into_iter() {
match var_status {
VarStatus::Temp(chunk_num, tvd) => {
self.bindings_mut().insert(var, VarData::Temp(chunk_num, 0, tvd));
},
VarStatus::Perm(_) => {
self.bindings_mut().insert(var, VarData::Perm(0));
perm_vs.insert(var, (var_status, cells));
}
};
}
perm_vs
}
fn get(&self, var: &'a Var) -> RegType {
self.bindings().get(var).unwrap().as_reg_type()
}
fn record_register(&mut self, var: &'a Var, r: RegType) {
match self.bindings_mut().get_mut(var).unwrap() {
&mut VarData::Temp(_, ref mut s, _) => *s = r.reg_num(),
&mut VarData::Perm(ref mut s) => *s = r.reg_num()
}
}
}

View File

@@ -1,4 +1,5 @@
use std::cell::Cell; use std::cell::Cell;
use std::cmp::Ordering;
use std::collections::{HashMap, VecDeque}; use std::collections::{HashMap, VecDeque};
use std::ops::{Add, AddAssign}; use std::ops::{Add, AddAssign};
use std::vec::Vec; use std::vec::Vec;
@@ -43,7 +44,7 @@ impl PredicateClause {
pub enum TopLevel { pub enum TopLevel {
Fact(Term), Fact(Term),
Predicate(Vec<PredicateClause>), Predicate(Vec<PredicateClause>),
Query(Term), Query(Vec<TermOrCut>),
Rule(Rule) Rule(Rule)
} }
@@ -266,17 +267,6 @@ pub enum Line {
Query(CompiledQuery) Query(CompiledQuery)
} }
pub enum LineOrCodeOffset<'a> {
Instruction(&'a Line),
Offset(usize)
}
impl<'a> From<&'a Line> for LineOrCodeOffset<'a> {
fn from(line: &'a Line) -> Self {
LineOrCodeOffset::Instruction(line)
}
}
pub type ThirdLevelIndex = Vec<IndexedChoiceInstruction>; pub type ThirdLevelIndex = Vec<IndexedChoiceInstruction>;
pub type Code = Vec<Line>; pub type Code = Vec<Line>;
@@ -369,15 +359,29 @@ impl HeapCellValue {
} }
} }
#[derive(Clone, Copy)] #[derive(Clone, Copy, PartialEq)]
pub enum CodePtr { pub enum CodePtr {
DirEntry(usize), DirEntry(usize),
TopLevel TopLevel(usize, usize, usize) // chunk_num, e, offset.
}
impl PartialOrd<CodePtr> for CodePtr {
fn partial_cmp(&self, other: &CodePtr) -> Option<Ordering> {
match (self, other) {
(&CodePtr::DirEntry(p1), &CodePtr::DirEntry(ref p2)) =>
p1.partial_cmp(p2),
(&CodePtr::DirEntry(_), &CodePtr::TopLevel(_, _, _)) =>
Some(Ordering::Less),
(&CodePtr::TopLevel(_, _, p1), &CodePtr::TopLevel(_, _, ref p2)) =>
p1.partial_cmp(p2),
_ => Some(Ordering::Greater)
}
}
} }
impl Default for CodePtr { impl Default for CodePtr {
fn default() -> Self { fn default() -> Self {
CodePtr::TopLevel CodePtr::TopLevel(0, 0, 0)
} }
} }
@@ -387,7 +391,7 @@ impl Add<usize> for CodePtr {
fn add(self, rhs: usize) -> Self::Output { fn add(self, rhs: usize) -> Self::Output {
match self { match self {
CodePtr::DirEntry(p) => CodePtr::DirEntry(p + rhs), CodePtr::DirEntry(p) => CodePtr::DirEntry(p + rhs),
CodePtr::TopLevel => CodePtr::TopLevel CodePtr::TopLevel(cn, e, p) => CodePtr::TopLevel(cn, e, p + rhs)
} }
} }
} }
@@ -395,8 +399,8 @@ impl Add<usize> for CodePtr {
impl AddAssign<usize> for CodePtr { impl AddAssign<usize> for CodePtr {
fn add_assign(&mut self, rhs: usize) { fn add_assign(&mut self, rhs: usize) {
match self { match self {
&mut CodePtr::DirEntry(ref mut p) => *p += rhs, &mut CodePtr::DirEntry(ref mut p) |
_ => {} &mut CodePtr::TopLevel(_, _, ref mut p) => *p += rhs
} }
} }
} }
@@ -430,6 +434,13 @@ impl Term {
} }
} }
pub fn subterms(&self) -> usize {
match self {
&Term::Clause(_, _, ref terms) => terms.len(),
_ => 1
}
}
pub fn name(&self) -> Option<&Atom> { pub fn name(&self) -> Option<&Atom> {
match self { match self {
&Term::Constant(_, Constant::Atom(ref atom)) &Term::Constant(_, Constant::Atom(ref atom))
@@ -445,24 +456,3 @@ impl Term {
} }
} }
} }
pub type HeapVarDict = HashMap<Var, Addr>;
pub enum EvalResult {
EntryFailure,
EntrySuccess,
InitialQuerySuccess(HeapVarDict),
QueryFailure,
SubsequentQuerySuccess,
}
impl EvalResult {
#[allow(dead_code)]
pub fn failed_query(&self) -> bool {
if let &EvalResult::QueryFailure = self {
true
} else {
false
}
}
}

View File

@@ -1,5 +1,5 @@
use prolog::allocator::*;
use prolog::ast::*; use prolog::ast::*;
use prolog::debray_allocator::*;
use prolog::fixtures::*; use prolog::fixtures::*;
use prolog::indexing::*; use prolog::indexing::*;
use prolog::iterators::*; use prolog::iterators::*;
@@ -9,19 +9,38 @@ use std::cell::Cell;
use std::collections::HashMap; use std::collections::HashMap;
use std::vec::Vec; use std::vec::Vec;
pub struct CodeGenerator<'a> { pub struct CodeGenerator<'a, TermMarker> {
marker: TermMarker<'a>, marker: TermMarker,
var_count: HashMap<&'a Var, usize> var_count: HashMap<&'a Var, usize>
} }
impl<'a> CodeGenerator<'a> { pub enum EvalResult<'a> {
EntryFailure,
EntrySuccess,
InitialQuerySuccess(AllocVarDict<'a>, HeapVarDict<'a>),
QueryFailure,
SubsequentQuerySuccess,
}
impl<'a> EvalResult<'a> {
#[allow(dead_code)]
pub fn failed_query(&self) -> bool {
if let &EvalResult::QueryFailure = self {
true
} else {
false
}
}
}
impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker> {
pub fn new() -> Self { pub fn new() -> Self {
CodeGenerator { marker: TermMarker::new(), CodeGenerator { marker: Allocator::new(),
var_count: HashMap::new() } var_count: HashMap::new() }
} }
pub fn vars(&self) -> &HashMap<&Var, VarData> { pub fn take_vars(self) -> AllocVarDict<'a> {
&self.marker.bindings self.marker.take_bindings()
} }
fn update_var_count<Iter>(&mut self, iter: Iter) fn update_var_count<Iter>(&mut self, iter: Iter)
@@ -232,12 +251,12 @@ impl<'a> CodeGenerator<'a> {
} }
} }
fn lco(body: &mut Code, rule: &'a Rule) -> usize fn lco(body: &mut Code, toc: &TermOrCut) -> usize
{ {
let last_arity = rule.last_clause().arity(); let last_arity = toc.arity();
let mut dealloc_index = body.len() - 1; let mut dealloc_index = body.len() - 1;
match rule.last_clause() { match toc {
&TermOrCut::Term(Term::Clause(_, ref name, _)) &TermOrCut::Term(Term::Clause(_, ref name, _))
| &TermOrCut::Term(Term::Constant(_, Constant::Atom(ref name))) => { | &TermOrCut::Term(Term::Constant(_, Constant::Atom(ref name))) => {
if let &mut Line::Control(ref mut ctrl) = body.last_mut().unwrap() { if let &mut Line::Control(ref mut ctrl) = body.last_mut().unwrap() {
@@ -250,58 +269,12 @@ impl<'a> CodeGenerator<'a> {
dealloc_index dealloc_index
} }
pub fn compile_rule(&mut self, rule: &'a Rule) -> Code fn compile_seq(&mut self,
clauses: &'a [TermOrCut],
vs: &VariableFixtures<'a>,
body: &mut Code,
is_exposed: bool)
{ {
let iter = ChunkedIterator::from_rule(rule);
let (mut vs, deep_cuts) = self.collect_var_data(iter);
vs = self.marker.drain_var_data(vs);
let &Rule { head: (ref p0, ref p1), ref clauses } = rule;
self.marker.advance(p0);
let perm_vars = vs.vars_above_threshold(0) + deep_cuts as usize;
let mut body = Vec::new();
if clauses.len() > 0 {
body.push(Line::Control(ControlInstruction::Allocate(perm_vars)));
if deep_cuts {
body.push(Line::Cut(CutInstruction::GetLevel));
}
}
if p0.is_clause() {
body.push(Line::Fact(self.compile_target(p0, GenContext::Head, false)));
}
match p1 {
&TermOrCut::Cut => {
let term = if clauses.is_empty() {
Terminal::Terminal
} else {
Terminal::Non
};
body.push(Line::Cut(CutInstruction::NeckCut(term)));
},
&TermOrCut::Term(ref p1) => {
self.marker.advance(p1);
if p1.is_clause() {
let term_loc = if p1.is_callable() {
GenContext::Last(0)
} else {
GenContext::Mid(0)
};
body.push(Line::Query(self.compile_target(p1, term_loc, false)));
}
Self::add_conditional_call(&mut body, p1, perm_vars);
}
};
let iter = ChunkedIterator::from_term_sequence(clauses); let iter = ChunkedIterator::from_term_sequence(clauses);
for (chunk_num, (_, terms)) in iter.enumerate() { for (chunk_num, (_, terms)) in iter.enumerate() {
@@ -315,17 +288,114 @@ impl<'a> CodeGenerator<'a> {
vec![Line::Cut(CutInstruction::Cut(Terminal::Terminal))], vec![Line::Cut(CutInstruction::Cut(Terminal::Terminal))],
&TermOrCutRef::Term(term) if i + 1 < terms.len() => { &TermOrCutRef::Term(term) if i + 1 < terms.len() => {
let num_vars = vs.vars_above_threshold(i + 1); let num_vars = vs.vars_above_threshold(i + 1);
self.compile_internal_query(term, GenContext::Mid(chunk_num), num_vars) self.compile_internal_query(term,
GenContext::Mid(chunk_num),
num_vars,
is_exposed)
}, },
&TermOrCutRef::Term(term) => { &TermOrCutRef::Term(term) => {
let num_vars = vs.vars_above_threshold(i + 1); let num_vars = vs.vars_above_threshold(i + 1);
self.compile_internal_query(term, GenContext::Last(chunk_num), num_vars) self.compile_internal_query(term,
GenContext::Last(chunk_num),
num_vars,
is_exposed)
} }
}; };
body.append(&mut body_appendage); body.append(&mut body_appendage);
} }
} }
}
fn compile_seq_prelude(&mut self,
num_clauses: usize,
vs: &VariableFixtures<'a>,
deep_cuts: bool,
body: &mut Code)
-> usize
{
let perm_vars = vs.vars_above_threshold(0) + deep_cuts as usize;
if num_clauses > 0 {
body.push(Line::Control(ControlInstruction::Allocate(perm_vars)));
if deep_cuts {
body.push(Line::Cut(CutInstruction::GetLevel));
}
}
perm_vars
}
fn compile_neck_cut_or(&mut self,
p1: &'a TermOrCut,
clauses: &'a [TermOrCut],
body: &mut Code,
perm_vars: usize,
is_exposed: bool)
{
match p1 {
&TermOrCut::Cut => {
let term = if clauses.is_empty() {
Terminal::Terminal
} else {
Terminal::Non
};
body.push(Line::Cut(CutInstruction::NeckCut(term)));
},
&TermOrCut::Term(ref p1) => {
self.marker.advance(GenContext::Head, p1);
if p1.is_clause() {
let term_loc = if p1.is_callable() {
GenContext::Last(0)
} else {
GenContext::Mid(0)
};
body.push(Line::Query(self.compile_target(p1, term_loc, is_exposed)));
}
Self::add_conditional_call(body, p1, perm_vars);
}
};
}
fn compile_cleanup(body: &mut Code, num_clauses: usize, toc: &TermOrCut)
{
let dealloc_index = Self::lco(body, toc);
if num_clauses > 0 {
body.insert(dealloc_index, Line::Control(ControlInstruction::Deallocate));
}
}
pub fn compile_rule<'b: 'a>(&mut self, rule: &'b Rule) -> Code
{
let iter = ChunkedIterator::from_rule(rule);
let (mut vs, deep_cuts) = self.collect_var_data(iter);
vs = self.marker.drain_var_data(vs);
let &Rule { head: (ref p0, ref p1), ref clauses } = rule;
let mut body = Vec::new();
self.marker.advance(GenContext::Head, p0);
let perm_vars = self.compile_seq_prelude(clauses.len(), &vs, deep_cuts, &mut body);
if p0.is_clause() {
body.push(Line::Fact(self.compile_target(p0, GenContext::Head, false)));
}
let clauses_slice = if clauses.len() > 1 {
&clauses[1 .. ]
} else {
&[]
};
self.compile_neck_cut_or(p1, clauses_slice, &mut body, perm_vars, false);
self.compile_seq(clauses, &vs, &mut body, false);
if clauses.len() > 0 { if clauses.len() > 0 {
let mut index = body.len() - 1; let mut index = body.len() - 1;
@@ -335,15 +405,11 @@ impl<'a> CodeGenerator<'a> {
} }
if let &mut Line::Query(ref mut query) = &mut body[index] { if let &mut Line::Query(ref mut query) = &mut body[index] {
vs.mark_unsafe_query_vars(p0, query); vs.mark_unsafe_vars_in_rule(p0, query);
} }
} }
let dealloc_index = Self::lco(&mut body, &rule); Self::compile_cleanup(&mut body, clauses.len(), rule.last_clause());
if clauses.len() > 0 {
body.insert(dealloc_index, Line::Control(ControlInstruction::Deallocate));
}
body body
} }
@@ -352,7 +418,7 @@ impl<'a> CodeGenerator<'a> {
{ {
let mut unsafe_vars = HashMap::new(); let mut unsafe_vars = HashMap::new();
for var_status in self.marker.bindings.values() { for var_status in self.marker.bindings().values() {
unsafe_vars.insert(var_status.as_reg_type(), false); unsafe_vars.insert(var_status.as_reg_type(), false);
} }
@@ -375,13 +441,13 @@ impl<'a> CodeGenerator<'a> {
} }
} }
pub fn compile_fact(&mut self, term: &'a Term) -> Code pub fn compile_fact<'b: 'a>(&mut self, term: &'b Term) -> Code
{ {
let iter = ChunkedIterator::from_term(term, true); let iter = ChunkedIterator::from_term(term, true);
let (vs, _) = self.collect_var_data(iter); let (vs, _) = self.collect_var_data(iter);
self.marker.drain_var_data(vs); self.marker.drain_var_data(vs);
self.marker.advance(term); self.marker.advance(GenContext::Head, term);
let mut code = Vec::new(); let mut code = Vec::new();
@@ -397,14 +463,19 @@ impl<'a> CodeGenerator<'a> {
code code
} }
fn compile_internal_query(&mut self, term: &'a Term, term_loc: GenContext, index: usize) -> Code fn compile_internal_query(&mut self,
term: &'a Term,
term_loc: GenContext,
index: usize,
is_exposed: bool)
-> Code
{ {
self.marker.advance(term); self.marker.advance(term_loc, term);
let mut code = Vec::new(); let mut code = Vec::new();
if term.is_clause() { if term.is_clause() {
let compiled_query = Line::Query(self.compile_target(term, term_loc, false)); let compiled_query = Line::Query(self.compile_target(term, term_loc, is_exposed));
code.push(compiled_query); code.push(compiled_query);
} }
@@ -413,22 +484,38 @@ impl<'a> CodeGenerator<'a> {
code code
} }
pub fn compile_query(&mut self, term: &'a Term) -> Code pub fn compile_query(&mut self, query: &'a Vec<TermOrCut>) -> Code
{ {
let iter = ChunkedIterator::from_term(term, true); let iter = ChunkedIterator::from_term_sequence(query);
let (vs, _) = self.collect_var_data(iter); let (mut vs, deep_cuts) = self.collect_var_data(iter);
let p1 = query.first().unwrap();
self.marker.drain_var_data(vs); vs = self.marker.drain_var_data(vs);
self.marker.advance(term);
let mut code = Vec::new(); let mut code = Vec::new();
let perm_vars = self.compile_seq_prelude(query.len() - 1,
&vs,
deep_cuts,
&mut code);
if term.is_clause() { let query_slice = if query.len() > 1 {
let compiled_query = self.compile_target(term, GenContext::Last(0), true); &query[1 .. ]
code.push(Line::Query(compiled_query)); } else {
&[]
};
self.compile_neck_cut_or(p1, query_slice, &mut code, perm_vars, true);
self.compile_seq(query_slice, &vs, &mut code, true);
for line in code.iter_mut() {
match line {
&mut Line::Query(ref mut query) =>
vs.mark_unsafe_vars_in_query(query),
_ => {}
};
} }
Self::add_conditional_call(&mut code, term, 0); Self::compile_cleanup(&mut code, query.len() - 1, query.last().unwrap());
code code
} }
@@ -456,12 +543,12 @@ impl<'a> CodeGenerator<'a> {
subseqs subseqs
} }
fn compile_pred_subseq(&mut self, clauses: &'a [PredicateClause]) -> Code fn compile_pred_subseq<'b: 'a>(&mut self, clauses: &'b [PredicateClause]) -> Code
{ {
let mut code_body = Vec::new(); let mut code_body = Vec::new();
let mut code_offsets = CodeOffsets::new(); let mut code_offsets = CodeOffsets::new();
let multi_clause = clauses.len() > 1; let num_clauses = clauses.len();
for (i, clause) in clauses.iter().enumerate() { for (i, clause) in clauses.iter().enumerate() {
self.marker.reset(); self.marker.reset();
@@ -473,10 +560,10 @@ impl<'a> CodeGenerator<'a> {
self.compile_rule(rule) self.compile_rule(rule)
}; };
if multi_clause { if num_clauses > 1 {
let choice = match i { let choice = match i {
0 => ChoiceInstruction::TryMeElse(clause_code.len() + 1), 0 => ChoiceInstruction::TryMeElse(clause_code.len() + 1),
_ if i == clauses.len() - 1 => ChoiceInstruction::TrustMe, _ if i == num_clauses - 1 => ChoiceInstruction::TrustMe,
_ => ChoiceInstruction::RetryMeElse(clause_code.len() + 1) _ => ChoiceInstruction::RetryMeElse(clause_code.len() + 1)
}; };
@@ -497,10 +584,10 @@ impl<'a> CodeGenerator<'a> {
code code
} }
pub fn compile_predicate(&mut self, clauses: &'a Vec<PredicateClause>) -> Code pub fn compile_predicate<'b: 'a>(&mut self, clauses: &'b Vec<PredicateClause>) -> Code
{ {
let mut code = Vec::new(); let mut code = Vec::new();
let split_pred = Self::split_predicate(clauses); let split_pred = Self::split_predicate(&clauses);
let multi_seq = split_pred.len() > 1; let multi_seq = split_pred.len() > 1;
for (l, r) in split_pred { for (l, r) in split_pred {

View File

@@ -1,3 +1,4 @@
use prolog::allocator::*;
use prolog::ast::*; use prolog::ast::*;
use prolog::fixtures::*; use prolog::fixtures::*;
use prolog::targets::*; use prolog::targets::*;
@@ -5,25 +6,15 @@ use prolog::targets::*;
use std::cell::Cell; use std::cell::Cell;
use std::collections::{BTreeSet, HashMap}; use std::collections::{BTreeSet, HashMap};
pub struct TermMarker<'a> { pub struct DebrayAllocator<'a> {
pub bindings: HashMap<&'a Var, VarData>, bindings: HashMap<&'a Var, VarData>,
arg_c: usize, arg_c: usize,
temp_lb: usize, temp_lb: usize,
contents: HashMap<usize, &'a Var>, contents: HashMap<usize, &'a Var>,
in_use: BTreeSet<usize>, in_use: BTreeSet<usize>,
} }
impl<'a> TermMarker<'a> { impl<'a> DebrayAllocator<'a> {
pub fn new() -> TermMarker<'a> {
TermMarker {
arg_c: 1,
temp_lb: 1,
bindings: HashMap::new(),
contents: HashMap::new(),
in_use: BTreeSet::new()
}
}
fn occurs_shallowly_in_head(&self, var: &'a Var, r: usize) -> bool fn occurs_shallowly_in_head(&self, var: &'a Var, r: usize) -> bool
{ {
match self.bindings.get(var).unwrap() { match self.bindings.get(var).unwrap() {
@@ -33,25 +24,6 @@ impl<'a> TermMarker<'a> {
} }
} }
pub fn drain_var_data(&mut self, vs: VariableFixtures<'a>) -> VariableFixtures<'a>
{
let mut perm_vs = VariableFixtures::new();
for (var, (var_status, cells)) in vs.into_iter() {
match var_status {
VarStatus::Temp(chunk_num, tvd) => {
self.bindings.insert(var, VarData::Temp(chunk_num, 0, tvd));
},
VarStatus::Perm(_) => {
self.bindings.insert(var, VarData::Perm(0));
perm_vs.insert(var, (var_status, cells));
}
};
}
perm_vs
}
fn alloc_with_cr(&self, var: &'a Var) -> usize fn alloc_with_cr(&self, var: &'a Var) -> usize
{ {
match self.bindings.get(var) { match self.bindings.get(var) {
@@ -186,38 +158,6 @@ impl<'a> TermMarker<'a> {
} }
} }
fn get(&self, var: &'a Var) -> RegType {
self.bindings.get(var).unwrap().as_reg_type()
}
fn in_place(&self, var: &'a Var, term_loc: GenContext, r: RegType, k: usize) -> bool
{
match term_loc {
GenContext::Head if !r.is_perm() => r.reg_num() == k,
_ => match self.bindings.get(var).unwrap() {
&VarData::Temp(_, o, _) if r.reg_num() == k => o == k,
_ => false
}
}
}
pub fn mark_anon_var<Target>(&mut self, lvl: Level, target: &mut Vec<Target>)
where Target: CompilationTarget<'a>
{
let r = RegType::Temp(self.alloc_reg_to_non_var());
match lvl {
Level::Shallow => {
let k = self.arg_c;
self.arg_c += 1;
target.push(Target::argument_to_variable(r, k));
},
Level::Deep =>
target.push(Target::subterm_to_variable(r))
};
}
fn alloc_reg_to_non_var(&mut self) -> usize fn alloc_reg_to_non_var(&mut self) -> usize
{ {
let mut final_index = 0; let mut final_index = 0;
@@ -234,7 +174,47 @@ impl<'a> TermMarker<'a> {
final_index final_index
} }
pub fn mark_non_var<Target>(&mut self, fn in_place(&self, var: &'a Var, term_loc: GenContext, r: RegType, k: usize) -> bool
{
match term_loc {
GenContext::Head if !r.is_perm() => r.reg_num() == k,
_ => match self.bindings().get(var).unwrap() {
&VarData::Temp(_, o, _) if r.reg_num() == k => o == k,
_ => false
}
}
}
}
impl<'a> Allocator<'a> for DebrayAllocator<'a>
{
fn new() -> DebrayAllocator<'a> {
DebrayAllocator {
arg_c: 1,
temp_lb: 1,
bindings: HashMap::new(),
contents: HashMap::new(),
in_use: BTreeSet::new()
}
}
fn mark_anon_var<Target>(&mut self, lvl: Level, target: &mut Vec<Target>)
where Target: CompilationTarget<'a>
{
let r = RegType::Temp(self.alloc_reg_to_non_var());
match lvl {
Level::Deep => target.push(Target::subterm_to_variable(r)),
Level::Shallow => {
let k = self.arg_c;
self.arg_c += 1;
target.push(Target::argument_to_variable(r, k));
}
};
}
fn mark_non_var<Target>(&mut self,
lvl: Level, lvl: Level,
term_loc: GenContext, term_loc: GenContext,
cell: &Cell<RegType>, cell: &Cell<RegType>,
@@ -262,7 +242,7 @@ impl<'a> TermMarker<'a> {
} }
} }
pub fn mark_var<Target>(&mut self, fn mark_var<Target>(&mut self,
var: &'a Var, var: &'a Var,
lvl: Level, lvl: Level,
cell: &'a Cell<VarReg>, cell: &'a Cell<VarReg>,
@@ -325,30 +305,35 @@ impl<'a> TermMarker<'a> {
} }
} }
fn record_register(&mut self, var: &'a Var, r: RegType) { fn reset(&mut self) {
match self.bindings.get_mut(var).unwrap() {
&mut VarData::Temp(_, ref mut s, _) => *s = r.reg_num(),
&mut VarData::Perm(ref mut s) => *s = r.reg_num()
}
}
pub fn advance_arg(&mut self) {
self.arg_c += 1;
}
pub fn advance(&mut self, term: &'a Term) {
self.arg_c = 1;
self.temp_lb = term.arity() + 1;
}
pub fn reset(&mut self) {
self.bindings.clear(); self.bindings.clear();
self.contents.clear(); self.contents.clear();
self.in_use.clear(); self.in_use.clear();
} }
pub fn reset_contents(&mut self) { fn reset_contents(&mut self) {
self.contents.clear(); self.contents.clear();
self.in_use.clear(); self.in_use.clear();
} }
fn advance_arg(&mut self) {
self.arg_c += 1;
}
fn bindings(&self) -> &AllocVarDict<'a> {
&self.bindings
}
fn bindings_mut(&mut self) -> &mut AllocVarDict<'a> {
&mut self.bindings
}
fn take_bindings(self) -> AllocVarDict<'a> {
self.bindings
}
fn advance(&mut self, _: GenContext, term: &'a Term) {
self.arg_c = 1;
self.temp_lb = term.arity() + 1;
}
} }

View File

@@ -8,6 +8,9 @@ use std::vec::Vec;
pub type OccurrenceSet = BTreeSet<(GenContext, usize)>; pub type OccurrenceSet = BTreeSet<(GenContext, usize)>;
pub type HeapVarDict<'a> = HashMap<&'a Var, Addr>;
pub type AllocVarDict<'a> = HashMap<&'a Var, VarData>;
pub struct TempVarData { pub struct TempVarData {
last_term_arity: usize, last_term_arity: usize,
pub use_set: OccurrenceSet, pub use_set: OccurrenceSet,
@@ -232,26 +235,8 @@ impl<'a> VariableFixtures<'a>
} }
} }
pub fn mark_unsafe_query_vars(&self, head: &Term, query: &mut CompiledQuery) fn mark_unsafe_vars(&self, unsafe_vars: &mut HashMap<RegType, bool>, query: &mut CompiledQuery)
{ {
let mut unsafe_vars = HashMap::new();
for &(_, ref cb) in self.values() {
if !cb.is_empty() {
let index = cb.first().unwrap().get().norm();
unsafe_vars.insert(index, false);
}
}
for term_ref in head.breadth_first_iter() {
match term_ref {
TermRef::Var(_, cell, _) => {
unsafe_vars.remove(&cell.get().norm());
},
_ => {}
};
}
for query_instr in query.iter_mut() { for query_instr in query.iter_mut() {
match query_instr { match query_instr {
&mut QueryInstruction::PutValue(RegType::Perm(i), arg) => &mut QueryInstruction::PutValue(RegType::Perm(i), arg) =>
@@ -277,4 +262,43 @@ impl<'a> VariableFixtures<'a>
}; };
} }
} }
fn record_unsafe_vars(&self, unsafe_vars: &mut HashMap<RegType, bool>) {
for &(_, ref cb) in self.values() {
match cb.first() {
Some(index) => {
unsafe_vars.insert(index.get().norm(), false);
},
None => {}
};
}
}
fn mark_head_vars_as_safe(&self, head: &Term, unsafe_vars: &mut HashMap<RegType, bool>)
{
for term_ref in head.breadth_first_iter() {
match term_ref {
TermRef::Var(_, cell, _) => {
unsafe_vars.remove(&cell.get().norm());
},
_ => {}
};
}
}
pub fn mark_unsafe_vars_in_query(&self, query: &mut CompiledQuery) {
let mut unsafe_vars = HashMap::new();
self.record_unsafe_vars(&mut unsafe_vars);
self.mark_unsafe_vars(&mut unsafe_vars, query);
}
pub fn mark_unsafe_vars_in_rule(&self, head: &Term, query: &mut CompiledQuery)
{
let mut unsafe_vars = HashMap::new();
self.record_unsafe_vars(&mut unsafe_vars);
self.mark_head_vars_as_safe(head, &mut unsafe_vars);
self.mark_unsafe_vars(&mut unsafe_vars, query);
}
} }

View File

@@ -30,6 +30,7 @@ impl TToken {
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
enum CellRef<'a> { enum CellRef<'a> {
Lis(usize),
View(CellView<'a>), View(CellView<'a>),
Redirect(usize), Redirect(usize),
TToken(TToken) TToken(TToken)
@@ -56,7 +57,9 @@ impl<'a> HeapCellViewer<'a> {
match focus { match focus {
&Addr::Con(ref c) => &Addr::Con(ref c) =>
return CellRef::View(CellView::Con(c)), return CellRef::View(CellView::Con(c)),
&Addr::Lis(hc) | &Addr::HeapCell(hc) | &Addr::Str(hc) => &Addr::Lis(hc) =>
return CellRef::Lis(hc),
&Addr::HeapCell(hc) | &Addr::Str(hc) =>
return CellRef::Redirect(hc), return CellRef::Redirect(hc),
&Addr::StackCell(fr, sc) => { &Addr::StackCell(fr, sc) => {
match &self.and_stack[fr][sc] { match &self.and_stack[fr][sc] {
@@ -108,22 +111,25 @@ impl<'a> HeapCellViewer<'a> {
} }
} }
fn handle_list(&mut self, focus: usize) -> CellView<'a> {
self.state_stack.push(CellRef::TToken(TToken::RSBracket));
self.state_stack.push(CellRef::Redirect(focus + 1));
self.state_stack.push(CellRef::TToken(TToken::Bar));
self.state_stack.push(CellRef::Redirect(focus));
let len = self.state_stack.len() - 4;
return CellView::TToken(TToken::LSBracket(len));
}
fn from_heap(&mut self, mut focus: usize) -> CellView<'a> { fn from_heap(&mut self, mut focus: usize) -> CellView<'a> {
loop { loop {
match &self.heap[focus] { match &self.heap[focus] {
&HeapCellValue::Con(ref c) => &HeapCellValue::Con(ref c) =>
return CellView::Con(c), return CellView::Con(c),
&HeapCellValue::Lis(a) => { &HeapCellValue::Lis(a) =>
self.state_stack.push(CellRef::TToken(TToken::RSBracket)); return self.handle_list(a),
self.state_stack.push(CellRef::Redirect(a + 1));
self.state_stack.push(CellRef::TToken(TToken::Bar));
self.state_stack.push(CellRef::Redirect(a));
let len = self.state_stack.len() - 4;
return CellView::TToken(TToken::LSBracket(len));
},
&HeapCellValue::NamedStr(arity, ref name) => { &HeapCellValue::NamedStr(arity, ref name) => {
self.state_stack.push(CellRef::TToken(TToken::RRBracket)); self.state_stack.push(CellRef::TToken(TToken::RRBracket));
@@ -146,6 +152,7 @@ impl<'a> HeapCellViewer<'a> {
}, },
&HeapCellValue::Ref(Ref::StackCell(fr, sc)) => { &HeapCellValue::Ref(Ref::StackCell(fr, sc)) => {
match self.cell_ref_from_addr(&self.and_stack[fr][sc]) { match self.cell_ref_from_addr(&self.and_stack[fr][sc]) {
CellRef::Lis(hc) => return self.handle_list(hc),
CellRef::View(cell_view) => return cell_view, CellRef::View(cell_view) => return cell_view,
CellRef::Redirect(hc) => focus = hc, CellRef::Redirect(hc) => focus = hc,
CellRef::TToken(token) => return CellView::TToken(token) CellRef::TToken(token) => return CellView::TToken(token)
@@ -160,6 +167,8 @@ impl<'a> HeapCellViewer<'a> {
fn follow(&mut self, cell_ref: CellRef<'a>) -> CellView<'a> fn follow(&mut self, cell_ref: CellRef<'a>) -> CellView<'a>
{ {
match cell_ref { match cell_ref {
CellRef::Lis(hc) =>
self.handle_list(hc),
CellRef::Redirect(hc) => CellRef::Redirect(hc) =>
self.from_heap(hc), self.from_heap(hc),
CellRef::View(cell_view) => CellRef::View(cell_view) =>

View File

@@ -1,6 +1,6 @@
use prolog::ast::*; use prolog::ast::*;
use prolog::codegen::*; use prolog::codegen::*;
use prolog::prolog_parser::*; use prolog::debray_allocator::*;
use prolog::machine::*; use prolog::machine::*;
use termion::raw::IntoRawMode; use termion::raw::IntoRawMode;
@@ -257,13 +257,12 @@ pub fn read() -> String {
result result
} }
pub fn eval(wam: &mut Machine, buffer: &str) -> EvalResult pub fn eval<'a, 'b: 'a>(wam: &'a mut Machine, tl: &'b TopLevel) -> EvalResult<'b>
{ {
let result = parse_TopLevel(buffer); match tl {
let mut cg = CodeGenerator::new(); &TopLevel::Predicate(ref clauses) => {
let mut cg = CodeGenerator::<DebrayAllocator>::new();
match &result {
&Ok(TopLevel::Predicate(ref clauses)) => {
if is_consistent(clauses) { if is_consistent(clauses) {
let compiled_pred = cg.compile_predicate(clauses); let compiled_pred = cg.compile_predicate(clauses);
wam.add_predicate(clauses, compiled_pred); wam.add_predicate(clauses, compiled_pred);
@@ -277,30 +276,34 @@ Each predicate must have the same name and arity.";
EvalResult::EntryFailure EvalResult::EntryFailure
} }
}, },
&Ok(TopLevel::Fact(ref fact)) => { &TopLevel::Fact(ref fact) => {
let compiled_fact = cg.compile_fact(&fact); let mut cg = CodeGenerator::<DebrayAllocator>::new();
let compiled_fact = cg.compile_fact(fact);
wam.add_fact(fact, compiled_fact); wam.add_fact(fact, compiled_fact);
EvalResult::EntrySuccess EvalResult::EntrySuccess
}, },
&Ok(TopLevel::Rule(ref rule)) => { &TopLevel::Rule(ref rule) => {
let compiled_rule = cg.compile_rule(&rule); let mut cg = CodeGenerator::<DebrayAllocator>::new();
let compiled_rule = cg.compile_rule(rule);
wam.add_rule(rule, compiled_rule); wam.add_rule(rule, compiled_rule);
EvalResult::EntrySuccess EvalResult::EntrySuccess
}, },
&Ok(TopLevel::Query(ref query)) => { &TopLevel::Query(ref query) => {
let compiled_query = cg.compile_query(&query); let mut cg = CodeGenerator::<DebrayAllocator>::new();
wam.run_query(compiled_query, &cg)
}, let compiled_query = cg.compile_query(query);
&Err(_) => { wam.submit_query(compiled_query, cg.take_vars())
println!("Grammatical error of some kind!");
EvalResult::EntryFailure
} }
} }
} }
pub fn print(wam: &mut Machine, result: EvalResult) { pub fn print(wam: &mut Machine, result: EvalResult) {
match result { match result {
EvalResult::InitialQuerySuccess(heap_locs) => { EvalResult::InitialQuerySuccess(alloc_locs, mut heap_locs) => {
println!("yes"); println!("yes");
if heap_locs.is_empty() { if heap_locs.is_empty() {
@@ -324,14 +327,14 @@ pub fn print(wam: &mut Machine, result: EvalResult) {
for c in stdin.keys() { for c in stdin.keys() {
match c.unwrap() { match c.unwrap() {
Key::Char(';') => { Key::Char(';') => {
result = wam.continue_query(); result = wam.continue_query(&alloc_locs, &mut heap_locs);
break; break;
}, },
Key::Char('.') => Key::Char('.') =>
break 'outer, break 'outer,
_ => {} _ => {}
} }
}; }
if let &EvalResult::QueryFailure = &result { if let &EvalResult::QueryFailure = &result {
write!(stdout, "no\n\r").unwrap(); write!(stdout, "no\n\r").unwrap();

View File

@@ -230,7 +230,7 @@ impl<'a> ChunkedIterator<'a>
} }
} }
pub fn from_term_sequence(terms: &'a Vec<TermOrCut>) -> Self pub fn from_term_sequence(terms: &'a [TermOrCut]) -> Self
{ {
let iter = terms.iter().map(|c| { let iter = terms.iter().map(|c| {
match c { match c {

View File

@@ -3,6 +3,7 @@ use prolog::codegen::*;
use prolog::heapview::*; use prolog::heapview::*;
use prolog::and_stack::*; use prolog::and_stack::*;
use prolog::or_stack::*; use prolog::or_stack::*;
use prolog::fixtures::*;
use std::collections::HashMap; use std::collections::HashMap;
use std::ops::{Index, IndexMut}; use std::ops::{Index, IndexMut};
@@ -31,7 +32,7 @@ struct MachineState {
registers: Registers, registers: Registers,
trail: Vec<Ref>, trail: Vec<Ref>,
tr: usize, tr: usize,
hb: usize hb: usize,
} }
type CodeDir = HashMap<(Atom, usize), usize>; type CodeDir = HashMap<(Atom, usize), usize>;
@@ -39,7 +40,8 @@ type CodeDir = HashMap<(Atom, usize), usize>;
pub struct Machine { pub struct Machine {
ms: MachineState, ms: MachineState,
code: Code, code: Code,
code_dir: CodeDir code_dir: CodeDir,
cached_query: Option<Code>
} }
impl Index<RegType> for MachineState { impl Index<RegType> for MachineState {
@@ -68,12 +70,29 @@ impl IndexMut<RegType> for MachineState {
} }
} }
impl Index<CodePtr> for Machine {
type Output = Line;
fn index(&self, ptr: CodePtr) -> &Self::Output {
match ptr {
CodePtr::TopLevel(_, _, p) => {
match &self.cached_query {
&Some(ref cq) => &cq[p],
&None => panic!("Out-of-bounds top level index.")
}
},
CodePtr::DirEntry(p) => &self.code[p]
}
}
}
impl Machine { impl Machine {
pub fn new() -> Self { pub fn new() -> Self {
Machine { Machine {
ms: MachineState::new(), ms: MachineState::new(),
code: Vec::new(), code: Vec::new(),
code_dir: HashMap::new() code_dir: HashMap::new(),
cached_query: None
} }
} }
@@ -84,41 +103,60 @@ impl Machine {
pub fn add_fact(&mut self, fact: &Term, mut code: Code) { pub fn add_fact(&mut self, fact: &Term, mut code: Code) {
if let Some(name) = fact.name() { if let Some(name) = fact.name() {
let p = self.code.len(); let p = self.code.len();
let name = name.clone();
let arity = fact.arity(); let arity = fact.arity();
self.code.append(&mut code); self.code.append(&mut code);
self.code_dir.insert((name.clone(), arity), p); self.code_dir.insert((name, arity), p);
} }
} }
pub fn add_rule(&mut self, rule: &Rule, mut code: Code) { pub fn add_rule(&mut self, rule: &Rule, mut code: Code) {
if let Some(name) = rule.head.0.name() { if let Some(name) = rule.head.0.name() {
let p = self.code.len(); let p = self.code.len();
let name = name.clone();
let arity = rule.head.0.arity(); let arity = rule.head.0.arity();
self.code.append(&mut code); self.code.append(&mut code);
self.code_dir.insert((name.clone(), arity), p); self.code_dir.insert((name, arity), p);
} }
} }
pub fn add_predicate(&mut self, pred: &Vec<PredicateClause>, mut code: Code) pub fn add_predicate(&mut self, clauses: &Vec<PredicateClause>, mut code: Code)
{ {
let p = self.code.len(); let p = self.code.len();
let name = pred.first().unwrap().name().clone();
let arity = pred.first().unwrap().arity(); let arity = clauses.first().unwrap().arity();
let name = clauses.first().unwrap().name().clone();
self.code.append(&mut code); self.code.append(&mut code);
self.code_dir.insert((name, arity), p); self.code_dir.insert((name, arity), p);
} }
fn execute_instr<'a>(&mut self, instr_src: LineOrCodeOffset<'a>) -> bool fn cached_query_size(&self) -> usize {
match &self.cached_query {
&Some(ref query) => query.len(),
_ => 0
}
}
fn execute_instr(&mut self, ptr: CodePtr)
{ {
let mut instr = match instr_src { // can't use self[ptr] or self.index(ptr) to set the value of
LineOrCodeOffset::Instruction(instr) => instr, // instr! instr is then typed as Line, not &Line. WHY????
LineOrCodeOffset::Offset(p) => &self.code[p] // This is a compiler bug. Has to be.
let instr = match ptr {
CodePtr::TopLevel(_, _, p) => {
match &self.cached_query {
&Some(ref cq) => &cq[p],
&None => return
}
},
CodePtr::DirEntry(p) => &self.code[p]
}; };
loop {
match instr { match instr {
&Line::Choice(ref choice_instr) => &Line::Choice(ref choice_instr) =>
self.ms.execute_choice_instr(choice_instr), self.ms.execute_choice_instr(choice_instr),
@@ -151,8 +189,10 @@ impl Machine {
self.ms.p += 1; self.ms.p += 1;
} }
} }
}
if self.failed() { fn backtrack(&mut self)
{
let b0 = self.ms let b0 = self.ms
.or_stack .or_stack
.top() .top()
@@ -163,26 +203,139 @@ impl Machine {
let b = self.ms.b - 1; let b = self.ms.b - 1;
self.ms.or_stack[b].bp self.ms.or_stack[b].bp
} else { } else {
CodePtr::TopLevel self.ms.p = CodePtr::TopLevel(0, 0, 0);
return;
}; };
if let CodePtr::TopLevel = p { self.ms.p = p;
return false;
if let CodePtr::TopLevel(_, _, p) = p {
self.ms.fail = p == 0;
self.ms.b0 = b0;
return;
} else { } else {
self.ms.fail = false; self.ms.fail = false;
self.ms.p = p;
self.ms.b0 = b0;
} }
} }
fn query_stepper<'a>(&mut self, mut ptr: CodePtr)
{
loop
{
self.execute_instr(ptr);
if self.failed() {
self.backtrack();
}
match self.ms.p { match self.ms.p {
CodePtr::DirEntry(p) if p < self.code.len() => CodePtr::DirEntry(p) if p < self.code.len() =>
instr = &self.code[p], ptr = self.ms.p,
_ => break _ => break
};
} }
} }
true fn record_var_places<'a>(&self,
chunk_num: usize,
e: usize,
alloc_locs: &AllocVarDict<'a>,
heap_locs: &mut HeapVarDict<'a>)
{
for (var, var_data) in alloc_locs {
match var_data {
&VarData::Perm(_) => {
let r = var_data.as_reg_type().reg_num();
let addr = self.ms.and_stack[e][r].clone();
heap_locs.insert(var, addr);
},
&VarData::Temp(cn, _, _) if cn == chunk_num => {
let r = var_data.as_reg_type();
let addr = self.ms[r].clone();
heap_locs.insert(var, addr);
},
_ => {}
}
}
}
fn run_query<'a>(&mut self, alloc_locs: &AllocVarDict<'a>, heap_locs: &mut HeapVarDict<'a>)
{
let end_ptr = CodePtr::TopLevel(0, 0, self.cached_query_size());
let mut tl_ptr = self.ms.p;
while tl_ptr < end_ptr {
self.query_stepper(tl_ptr);
tl_ptr = self.ms.p;
if let &mut CodePtr::TopLevel(ref mut cn, ref mut e, p) = &mut tl_ptr {
if p == 0 {
break;
}
match &self[CodePtr::TopLevel(*cn, *e, p)] {
&Line::Control(ControlInstruction::Call(_, _, _))
| &Line::Control(ControlInstruction::Execute(_, _)) => {
self.record_var_places(*cn, *e, alloc_locs, heap_locs);
*cn += 1;
},
&Line::Control(ControlInstruction::Allocate(_)) =>
*e = self.ms.e,
_ => {}
};
self.ms.p = CodePtr::TopLevel(*cn, *e, p);
} else {
break;
}
}
}
pub fn submit_query<'a>(&mut self, code: Code, alloc_locs: AllocVarDict<'a>) -> EvalResult<'a>
{
let mut heap_locs = HashMap::new();
self.cached_query = Some(code);
self.run_query(&alloc_locs, &mut heap_locs);
if self.failed() {
EvalResult::QueryFailure
} else {
EvalResult::InitialQuerySuccess(alloc_locs, heap_locs)
}
}
pub fn continue_query<'a>(&mut self,
alloc_locs: &AllocVarDict<'a>,
heap_locs: &mut HeapVarDict<'a>)
-> EvalResult
{
if !self.or_stack_is_empty() {
if self.ms.b == 0 {
return EvalResult::QueryFailure;
}
let b = self.ms.b - 1;
self.ms.p = self.ms.or_stack[b].bp;
if let CodePtr::TopLevel(_, _, 0) = self.ms.p {
return EvalResult::QueryFailure
}
self.run_query(alloc_locs, heap_locs);
if self.failed() {
EvalResult::QueryFailure
} else {
EvalResult::SubsequentQuerySuccess
}
} else {
EvalResult::QueryFailure
}
} }
pub fn heap_view(&self, var_dir: &HeapVarDict) -> String { pub fn heap_view(&self, var_dir: &HeapVarDict) -> String {
@@ -241,69 +394,10 @@ impl Machine {
result result
} }
pub fn run_query(&mut self, code: Code, cg: &CodeGenerator) -> EvalResult
{
let mut succeeded = true;
let mut heap_locs = HashMap::new();
for instr in code.iter().take(1) {
succeeded = self.execute_instr(LineOrCodeOffset::from(instr));
}
if succeeded {
for (var, var_data) in cg.vars() {
let r = var_data.as_reg_type();
let addr = self.ms[r].clone();
heap_locs.insert((*var).clone(), addr);
}
for instr in code.iter().skip(1) {
succeeded = self.execute_instr(LineOrCodeOffset::from(instr));
if !succeeded {
break;
}
}
}
if succeeded {
EvalResult::InitialQuerySuccess(heap_locs)
} else {
EvalResult::QueryFailure
}
}
pub fn or_stack_is_empty(&self) -> bool { pub fn or_stack_is_empty(&self) -> bool {
self.ms.or_stack.is_empty() self.ms.or_stack.is_empty()
} }
pub fn continue_query(&mut self) -> EvalResult
{
if !self.or_stack_is_empty() {
if self.ms.b == 0 {
return EvalResult::QueryFailure;
}
let b = self.ms.b - 1;
self.ms.p = self.ms.or_stack[b].bp;
let succeeded = if let CodePtr::DirEntry(p) = self.ms.p {
self.execute_instr(LineOrCodeOffset::Offset(p))
} else {
false
};
if succeeded {
EvalResult::SubsequentQuerySuccess
} else {
EvalResult::QueryFailure
}
} else {
EvalResult::QueryFailure
}
}
#[allow(dead_code)]
pub fn clear(&mut self) { pub fn clear(&mut self) {
self.reset(); self.reset();
self.code.clear(); self.code.clear();
@@ -319,12 +413,12 @@ impl MachineState {
fn new() -> MachineState { fn new() -> MachineState {
MachineState { h: 0, MachineState { h: 0,
s: 0, s: 0,
p: CodePtr::TopLevel, p: CodePtr::default(),
b: 0, b: 0,
b0: 0, b0: 0,
e: 0, e: 0,
num_of_args: 0, num_of_args: 0,
cp: CodePtr::TopLevel, cp: CodePtr::default(),
fail: false, fail: false,
heap: Vec::with_capacity(256), heap: Vec::with_capacity(256),
mode: MachineMode::Write, mode: MachineMode::Write,
@@ -1112,7 +1206,7 @@ impl MachineState {
} }
if let &Terminal::Terminal = term { if let &Terminal::Terminal = term {
self.p = CodePtr::TopLevel; self.p = CodePtr::default();
} else { } else {
self.p += 1; self.p += 1;
} }
@@ -1134,7 +1228,7 @@ impl MachineState {
} }
if let &Terminal::Terminal = term { if let &Terminal::Terminal = term {
self.p = CodePtr::TopLevel; self.p = CodePtr::default();
} else { } else {
self.p += 1; self.p += 1;
} }
@@ -1150,8 +1244,8 @@ impl MachineState {
self.b0 = 0; self.b0 = 0;
self.s = 0; self.s = 0;
self.tr = 0; self.tr = 0;
self.p = CodePtr::TopLevel; self.p = CodePtr::default();
self.cp = CodePtr::TopLevel; self.cp = CodePtr::default();
self.num_of_args = 0; self.num_of_args = 0;
self.fail = false; self.fail = false;

View File

@@ -1,3 +1,4 @@
pub mod allocator;
pub mod and_stack; pub mod and_stack;
pub mod ast; pub mod ast;
pub mod codegen; pub mod codegen;
@@ -7,6 +8,7 @@ pub mod heapview;
pub mod indexing; pub mod indexing;
pub mod io; pub mod io;
pub mod iterators; pub mod iterators;
pub mod naive_allocator;
pub mod prolog_parser; pub mod prolog_parser;
pub mod machine; pub mod machine;
pub mod or_stack; pub mod or_stack;

View File

@@ -1,163 +1,157 @@
use prolog::allocator::*;
use prolog::ast::*; use prolog::ast::*;
use prolog::fixtures::*; use prolog::fixtures::*;
use prolog::targets::*;
use std::cell::Cell; use std::cell::Cell;
use std::cmp::max; use std::cmp::max;
use std::collections::{BTreeSet, HashMap}; use std::collections::HashMap;
pub struct TermMarker<'a> { pub struct NaiveAllocator<'a> {
pub bindings: HashMap<&'a Var, VarData>, bindings: AllocVarDict<'a>,
arg_c: usize, arg_c: usize,
temp_c: usize, temp_c: usize,
contents: HashMap<usize, &'a Var>,
in_use: BTreeSet<usize>,
} }
impl<'a> TermMarker<'a> { impl<'a> Allocator<'a> for NaiveAllocator<'a>
pub fn new() -> TermMarker<'a> { {
TermMarker { fn new() -> Self {
NaiveAllocator {
arg_c: 1, arg_c: 1,
temp_c: 1, temp_c: 1,
bindings: HashMap::new(), bindings: HashMap::new(),
contents: HashMap::new(),
in_use: BTreeSet::new()
} }
} }
pub fn drain_var_data(&mut self, vs: VariableFixtures<'a>) -> VariableFixtures<'a> fn mark_anon_var<Target>(&mut self, lvl: Level, target: &mut Vec<Target>)
where Target: CompilationTarget<'a>
{ {
let mut perm_vs = VariableFixtures::new(); let r = {
for (var, (var_status, cells)) in vs.into_iter() {
match var_status {
VarStatus::Temp(chunk_num, tvd) => {
self.bindings.insert(var, VarData::Temp(chunk_num, 0, tvd));
},
VarStatus::Perm(_) => {
self.bindings.insert(var, VarData::Perm(0));
perm_vs.insert(var, (var_status, cells));
}
};
}
perm_vs
}
fn get(&self, var: &'a Var) -> RegType {
self.bindings.get(var).unwrap().as_reg_type()
}
pub fn contains_var(&self, var: &'a Var) -> bool {
self.bindings.contains_key(var)
}
pub fn marked_var(&self, var: &'a Var) -> bool {
self.get(var).reg_num() != 0
}
fn record_register(&mut self, var: &'a Var, r: RegType) {
match self.bindings.get_mut(var).unwrap() {
&mut VarData::Temp(_, ref mut s, _) => *s = r.reg_num(),
&mut VarData::Perm(ref mut s) => *s = r.reg_num()
}
}
pub fn mark_non_var(&mut self, lvl: Level, cell: &Cell<RegType>) {
let reg_type = cell.get();
if reg_type.reg_num() == 0 {
match lvl {
Level::Deep if !reg_type.is_perm() => {
let temp = self.temp_c;
self.temp_c += 1;
cell.set(RegType::Temp(temp));
},
Level::Shallow if !reg_type.is_perm() => {
let arg = self.arg_c;
self.arg_c += 1;
cell.set(RegType::Temp(arg));
},
_ => {}
};
}
}
pub fn mark_old_var(&mut self, lvl: Level, var: &'a Var) -> VarReg
{
let inner_reg = self.get(var);
match lvl {
Level::Deep => VarReg::Norm(inner_reg),
Level::Shallow => {
let reg = VarReg::ArgAndNorm(inner_reg, self.arg_c);
self.arg_c += 1;
reg
}
}
}
pub fn mark_new_var(&mut self, lvl: Level, var: &'a Var, reg: RegType) -> VarReg
{
let inner_reg = if !reg.is_perm() {
let temp = self.temp_c; let temp = self.temp_c;
self.temp_c += 1; self.temp_c += 1;
RegType::Temp(temp) RegType::Temp(temp)
};
match lvl {
Level::Deep => target.push(Target::subterm_to_variable(r)),
Level::Shallow => {
let k = self.arg_c;
self.arg_c += 1;
target.push(Target::argument_to_variable(r, k));
}
}
}
fn mark_non_var<Target>(&mut self,
lvl: Level,
_: GenContext,
cell: &Cell<RegType>,
_: &mut Vec<Target>)
where Target: CompilationTarget<'a>
{
let r = cell.get();
if r.reg_num() == 0 {
let r = match lvl {
Level::Shallow => {
let k = self.arg_c;
self.arg_c += 1;
RegType::Temp(k)
},
_ => {
let temp = self.temp_c;
self.temp_c += 1;
RegType::Temp(temp)
}
};
cell.set(r);
}
}
fn mark_var<Target>(&mut self,
var: &'a Var,
lvl: Level,
cell: &'a Cell<VarReg>,
_: GenContext,
target: &mut Vec<Target>)
where Target: CompilationTarget<'a>
{
let (r, is_new_var) = match self.get(var) {
RegType::Temp(0) => {
let o = self.temp_c;
self.temp_c += 1;
(RegType::Temp(o), true)
},
RegType::Perm(0) => {
let pr = cell.get().norm();
self.record_register(var, pr);
(pr, true)
},
r => (r, false)
};
match lvl {
Level::Shallow => {
let k = self.arg_c;
self.arg_c += 1;
cell.set(VarReg::ArgAndNorm(r, k));
if is_new_var {
target.push(Target::argument_to_variable(r, k));
} else { } else {
reg target.push(Target::argument_to_value(r, k));
}; }
},
Level::Deep => {
cell.set(VarReg::Norm(r));
let reg = match lvl { if is_new_var {
Level::Deep => VarReg::Norm(inner_reg), target.push(Target::subterm_to_variable(r));
Level::Shallow => { } else {
let reg = VarReg::ArgAndNorm(inner_reg, self.arg_c); target.push(Target::subterm_to_value(r));
self.arg_c += 1; }
reg
} }
}; };
self.record_register(var, inner_reg); if !r.is_perm() {
reg self.record_register(var, r);
}
pub fn mark_anon_var(&mut self, lvl: Level) -> VarReg {
let inner_reg = {
let temp = self.temp_c;
self.temp_c += 1;
RegType::Temp(temp)
};
match lvl {
Level::Deep => VarReg::Norm(inner_reg),
Level::Shallow => {
let reg = VarReg::ArgAndNorm(inner_reg, self.arg_c);
self.arg_c += 1;
reg
}
} }
} }
pub fn advance_arg(&mut self) { fn reset(&mut self) {
self.arg_c += 1; self.bindings.clear();
} }
pub fn advance_at_head(&mut self, term: &'a Term) { fn advance(&mut self, term_loc: GenContext, term: &'a Term) {
if let GenContext::Head = term_loc {
self.arg_c = 1; self.arg_c = 1;
self.temp_c = max(term.subterms() + 1, self.temp_c); self.temp_c = max(term.subterms() + 1, self.temp_c);
} } else {
pub fn advance(&mut self, term: &'a Term) {
self.arg_c = 1; self.arg_c = 1;
self.temp_c = term.subterms() + 1; self.temp_c = term.subterms() + 1;
} }
pub fn reset(&mut self) {
self.bindings.clear();
self.contents.clear();
self.in_use.clear();
} }
pub fn reset_contents(&mut self) { fn advance_arg(&mut self) {
self.contents.clear(); self.arg_c += 1;
self.in_use.clear(); }
fn bindings(&self) -> &AllocVarDict<'a> {
&self.bindings
}
fn bindings_mut(&mut self) -> &mut AllocVarDict<'a> {
&mut self.bindings
}
fn take_bindings(self) -> AllocVarDict<'a> {
self.bindings
} }
} }

View File

@@ -5,7 +5,7 @@ use std::cell::Cell;
grammar; grammar;
pub TopLevel: TopLevel = { pub TopLevel: TopLevel = {
"?-" <t:Term> "." => TopLevel::Query(t), "?-" <q:Query> "." => TopLevel::Query(q),
<Predicate> => TopLevel::Predicate(<>), <Predicate> => TopLevel::Predicate(<>),
<Rule> "." => TopLevel::Rule(<>), <Rule> "." => TopLevel::Rule(<>),
<Term> "." => TopLevel::Fact(<>) <Term> "." => TopLevel::Fact(<>)
@@ -56,6 +56,14 @@ PredicateClause : PredicateClause = {
<Term> "." => PredicateClause::Fact(<>) <Term> "." => PredicateClause::Fact(<>)
}; };
Query : Vec<TermOrCut> = {
<tcs: (<TermOrCut> ",")*> <tc: TermOrCut> => {
let mut tcs = tcs;
tcs.push(tc);
tcs
}
};
Rule : Rule = { Rule : Rule = {
<c:Clause> ":-" <h:TermOrCut> <cs: ("," <TermOrCut>)*> => <c:Clause> ":-" <h:TermOrCut> <cs: ("," <TermOrCut>)*> =>
Rule { head: (c, h), clauses: cs }, Rule { head: (c, h), clauses: cs },

File diff suppressed because it is too large Load Diff