add support for conjunctive queries.
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -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)",
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
27
README.md
27
README.md
@@ -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
|
||||||
|
|||||||
564
src/main.rs
564
src/main.rs
@@ -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,55 +116,55 @@ 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).");
|
||||||
|
|
||||||
submit(&mut wam, "q(x).");
|
submit(&mut wam, "q(x).");
|
||||||
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,123 +213,123 @@ 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."), false);
|
||||||
|
|
||||||
assert_eq!(submit(&mut wam, "?- commit.").failed_query(), true);
|
|
||||||
|
|
||||||
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]
|
||||||
fn test_queries_on_lists() {
|
fn test_queries_on_lists() {
|
||||||
let mut wam = Machine::new();
|
let mut wam = Machine::new();
|
||||||
|
|
||||||
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)."), true);
|
||||||
|
assert_eq!(submit(&mut wam, "?- call(false)."), true);
|
||||||
|
assert_eq!(submit(&mut wam, "?- call(call(repeat))."), true);
|
||||||
|
assert_eq!(submit(&mut wam, "?- call(call(false))."), true);
|
||||||
|
assert_eq!(submit(&mut wam, "?- call(notrace)."), false);
|
||||||
|
assert_eq!(submit(&mut wam, "?- call(nl)."), false);
|
||||||
|
assert_eq!(submit(&mut wam, "?- call(builtin(X))."), false);
|
||||||
|
assert_eq!(submit(&mut wam, "?- call(extern(X))."), false);
|
||||||
|
|
||||||
assert_eq!(submit(&mut wam, "?- call(repeat).").failed_query(), false);
|
|
||||||
assert_eq!(submit(&mut wam, "?- call(true).").failed_query(), false);
|
|
||||||
assert_eq!(submit(&mut wam, "?- call(call(repeat)).").failed_query(), false);
|
|
||||||
assert_eq!(submit(&mut wam, "?- call(call(true)).").failed_query(), false);
|
|
||||||
assert_eq!(submit(&mut wam, "?- call(notrace).").failed_query(), true);
|
|
||||||
assert_eq!(submit(&mut wam, "?- call(nl).").failed_query(), true);
|
|
||||||
assert_eq!(submit(&mut wam, "?- call(builtin(X)).").failed_query(), true);
|
|
||||||
assert_eq!(submit(&mut wam, "?- call(extern(X)).").failed_query(), true);
|
|
||||||
|
|
||||||
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
58
src/prolog/allocator.rs
Normal 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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,7 +71,7 @@ impl RegType {
|
|||||||
RegType::Perm(reg_num) | RegType::Temp(reg_num) => reg_num
|
RegType::Perm(reg_num) | RegType::Temp(reg_num) => reg_num
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_perm(self) -> bool {
|
pub fn is_perm(self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
RegType::Perm(_) => true,
|
RegType::Perm(_) => true,
|
||||||
@@ -90,7 +91,7 @@ impl VarReg {
|
|||||||
match self {
|
match self {
|
||||||
VarReg::ArgAndNorm(reg, _) | VarReg::Norm(reg) => reg
|
VarReg::ArgAndNorm(reg, _) | VarReg::Norm(reg) => reg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for VarReg {
|
impl Default for VarReg {
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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,21 +9,40 @@ 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)
|
||||||
where Iter : Iterator<Item=TermRef<'a>>
|
where Iter : Iterator<Item=TermRef<'a>>
|
||||||
{
|
{
|
||||||
@@ -98,7 +117,7 @@ impl<'a> CodeGenerator<'a> {
|
|||||||
|
|
||||||
fn add_or_increment_void_instr<Target>(target: &mut Vec<Target>)
|
fn add_or_increment_void_instr<Target>(target: &mut Vec<Target>)
|
||||||
where Target: CompilationTarget<'a>
|
where Target: CompilationTarget<'a>
|
||||||
{
|
{
|
||||||
if let Some(ref mut instr) = target.last_mut() {
|
if let Some(ref mut instr) = target.last_mut() {
|
||||||
if Target::is_void_instr(&*instr) {
|
if Target::is_void_instr(&*instr) {
|
||||||
Target::incr_void_instr(instr);
|
Target::incr_void_instr(instr);
|
||||||
@@ -232,76 +251,30 @@ 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() {
|
||||||
*ctrl = ControlInstruction::Execute(name.clone(), last_arity);
|
*ctrl = ControlInstruction::Execute(name.clone(), last_arity);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => dealloc_index = body.len()
|
_ => dealloc_index = body.len()
|
||||||
};
|
};
|
||||||
|
|
||||||
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,23 +484,39 @@ 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 {
|
||||||
|
|||||||
@@ -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,11 +174,51 @@ 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
|
||||||
lvl: Level,
|
{
|
||||||
term_loc: GenContext,
|
match term_loc {
|
||||||
cell: &Cell<RegType>,
|
GenContext::Head if !r.is_perm() => r.reg_num() == k,
|
||||||
target: &mut Vec<Target>)
|
_ => 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,
|
||||||
|
term_loc: GenContext,
|
||||||
|
cell: &Cell<RegType>,
|
||||||
|
target: &mut Vec<Target>)
|
||||||
where Target: CompilationTarget<'a>
|
where Target: CompilationTarget<'a>
|
||||||
{
|
{
|
||||||
let r = cell.get();
|
let r = cell.get();
|
||||||
@@ -262,12 +242,12 @@ 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>,
|
||||||
term_loc: GenContext,
|
term_loc: GenContext,
|
||||||
target: &mut Vec<Target>)
|
target: &mut Vec<Target>)
|
||||||
where Target: CompilationTarget<'a>
|
where Target: CompilationTarget<'a>
|
||||||
{
|
{
|
||||||
let (r, is_new_var) = match self.get(var) {
|
let (r, is_new_var) = match self.get(var) {
|
||||||
@@ -311,7 +291,7 @@ impl<'a> TermMarker<'a> {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
target.push(Target::subterm_to_variable(r));
|
target.push(Target::subterm_to_variable(r));
|
||||||
},
|
},
|
||||||
Level::Deep =>
|
Level::Deep =>
|
||||||
target.push(Target::subterm_to_value(r))
|
target.push(Target::subterm_to_value(r))
|
||||||
};
|
};
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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) =>
|
||||||
@@ -262,7 +247,7 @@ impl<'a> VariableFixtures<'a>
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
&mut QueryInstruction::SetVariable(reg)
|
&mut QueryInstruction::SetVariable(reg)
|
||||||
| &mut QueryInstruction::PutVariable(reg, _) =>
|
| &mut QueryInstruction::PutVariable(reg, _) =>
|
||||||
if let Some(found) = unsafe_vars.get_mut(®) {
|
if let Some(found) = unsafe_vars.get_mut(®) {
|
||||||
*found = true;
|
*found = true;
|
||||||
},
|
},
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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) =>
|
||||||
|
|||||||
@@ -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();
|
||||||
wam.add_fact(fact, compiled_fact);
|
|
||||||
|
let compiled_fact = cg.compile_fact(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();
|
||||||
wam.add_rule(rule, compiled_rule);
|
|
||||||
|
let compiled_rule = cg.compile_rule(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();
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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,105 +103,239 @@ 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),
|
&Line::Cut(ref cut_instr) =>
|
||||||
&Line::Cut(ref cut_instr) =>
|
self.ms.execute_cut_instr(cut_instr),
|
||||||
self.ms.execute_cut_instr(cut_instr),
|
&Line::Control(ref control_instr) =>
|
||||||
&Line::Control(ref control_instr) =>
|
self.ms.execute_ctrl_instr(&self.code_dir, control_instr),
|
||||||
self.ms.execute_ctrl_instr(&self.code_dir, control_instr),
|
&Line::Fact(ref fact) => {
|
||||||
&Line::Fact(ref fact) => {
|
for fact_instr in fact {
|
||||||
for fact_instr in fact {
|
if self.failed() {
|
||||||
if self.failed() {
|
break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.ms.execute_fact_instr(&fact_instr);
|
|
||||||
}
|
}
|
||||||
self.ms.p += 1;
|
|
||||||
},
|
|
||||||
&Line::Indexing(ref indexing_instr) =>
|
|
||||||
self.ms.execute_indexing_instr(&indexing_instr),
|
|
||||||
&Line::IndexedChoice(ref choice_instr) =>
|
|
||||||
self.ms.execute_indexed_choice_instr(choice_instr),
|
|
||||||
&Line::Query(ref query) => {
|
|
||||||
for query_instr in query {
|
|
||||||
if self.failed() {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.ms.execute_query_instr(&query_instr);
|
self.ms.execute_fact_instr(&fact_instr);
|
||||||
}
|
|
||||||
self.ms.p += 1;
|
|
||||||
}
|
}
|
||||||
|
self.ms.p += 1;
|
||||||
|
},
|
||||||
|
&Line::Indexing(ref indexing_instr) =>
|
||||||
|
self.ms.execute_indexing_instr(&indexing_instr),
|
||||||
|
&Line::IndexedChoice(ref choice_instr) =>
|
||||||
|
self.ms.execute_indexed_choice_instr(choice_instr),
|
||||||
|
&Line::Query(ref query) => {
|
||||||
|
for query_instr in query {
|
||||||
|
if self.failed() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.ms.execute_query_instr(&query_instr);
|
||||||
|
}
|
||||||
|
self.ms.p += 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn backtrack(&mut self)
|
||||||
|
{
|
||||||
|
let b0 = self.ms
|
||||||
|
.or_stack
|
||||||
|
.top()
|
||||||
|
.map(|fr| fr.b0)
|
||||||
|
.unwrap_or(0);
|
||||||
|
|
||||||
|
let p = if self.ms.b > 0 {
|
||||||
|
let b = self.ms.b - 1;
|
||||||
|
self.ms.or_stack[b].bp
|
||||||
|
} else {
|
||||||
|
self.ms.p = CodePtr::TopLevel(0, 0, 0);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
self.ms.p = p;
|
||||||
|
|
||||||
|
if let CodePtr::TopLevel(_, _, p) = p {
|
||||||
|
self.ms.fail = p == 0;
|
||||||
|
self.ms.b0 = b0;
|
||||||
|
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
self.ms.fail = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn query_stepper<'a>(&mut self, mut ptr: CodePtr)
|
||||||
|
{
|
||||||
|
loop
|
||||||
|
{
|
||||||
|
self.execute_instr(ptr);
|
||||||
|
|
||||||
if self.failed() {
|
if self.failed() {
|
||||||
let b0 = self.ms
|
self.backtrack();
|
||||||
.or_stack
|
|
||||||
.top()
|
|
||||||
.map(|fr| fr.b0)
|
|
||||||
.unwrap_or(0);
|
|
||||||
|
|
||||||
let p = if self.ms.b > 0 {
|
|
||||||
let b = self.ms.b - 1;
|
|
||||||
self.ms.or_stack[b].bp
|
|
||||||
} else {
|
|
||||||
CodePtr::TopLevel
|
|
||||||
};
|
|
||||||
|
|
||||||
if let CodePtr::TopLevel = p {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
self.ms.fail = false;
|
|
||||||
self.ms.p = p;
|
|
||||||
self.ms.b0 = b0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
true
|
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,75 +394,16 @@ 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();
|
||||||
self.code_dir.clear();
|
self.code_dir.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reset(&mut self) {
|
pub fn reset(&mut self) {
|
||||||
self.ms.reset();
|
self.ms.reset();
|
||||||
}
|
}
|
||||||
@@ -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,
|
||||||
@@ -815,7 +909,7 @@ impl MachineState {
|
|||||||
match norm {
|
match norm {
|
||||||
RegType::Perm(n) => {
|
RegType::Perm(n) => {
|
||||||
let e = self.e;
|
let e = self.e;
|
||||||
|
|
||||||
self[norm] = Addr::StackCell(e, n);
|
self[norm] = Addr::StackCell(e, n);
|
||||||
self.registers[arg] = self[norm].clone();
|
self.registers[arg] = self[norm].clone();
|
||||||
},
|
},
|
||||||
@@ -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;
|
||||||
}
|
}
|
||||||
@@ -1132,9 +1226,9 @@ impl MachineState {
|
|||||||
self.b = b0;
|
self.b = b0;
|
||||||
self.tidy_trail();
|
self.tidy_trail();
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
@@ -1161,5 +1255,5 @@ impl MachineState {
|
|||||||
self.and_stack.clear();
|
self.and_stack.clear();
|
||||||
self.or_stack.clear();
|
self.or_stack.clear();
|
||||||
self.registers = vec![Addr::HeapCell(0); 64];
|
self.registers = vec![Addr::HeapCell(0); 64];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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 = {
|
||||||
|
let temp = self.temp_c;
|
||||||
|
self.temp_c += 1;
|
||||||
|
RegType::Temp(temp)
|
||||||
|
};
|
||||||
|
|
||||||
for (var, (var_status, cells)) in vs.into_iter() {
|
match lvl {
|
||||||
match var_status {
|
Level::Deep => target.push(Target::subterm_to_variable(r)),
|
||||||
VarStatus::Temp(chunk_num, tvd) => {
|
Level::Shallow => {
|
||||||
self.bindings.insert(var, VarData::Temp(chunk_num, 0, tvd));
|
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)
|
||||||
},
|
},
|
||||||
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;
|
let temp = self.temp_c;
|
||||||
self.temp_c += 1;
|
self.temp_c += 1;
|
||||||
cell.set(RegType::Temp(temp));
|
|
||||||
},
|
RegType::Temp(temp)
|
||||||
Level::Shallow if !reg_type.is_perm() => {
|
}
|
||||||
let arg = self.arg_c;
|
|
||||||
self.arg_c += 1;
|
|
||||||
cell.set(RegType::Temp(arg));
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
cell.set(r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mark_old_var(&mut self, lvl: Level, var: &'a Var) -> VarReg
|
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 inner_reg = self.get(var);
|
let (r, is_new_var) = match self.get(var) {
|
||||||
|
RegType::Temp(0) => {
|
||||||
match lvl {
|
let o = self.temp_c;
|
||||||
Level::Deep => VarReg::Norm(inner_reg),
|
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 => {
|
Level::Shallow => {
|
||||||
let reg = VarReg::ArgAndNorm(inner_reg, self.arg_c);
|
let k = self.arg_c;
|
||||||
self.arg_c += 1;
|
self.arg_c += 1;
|
||||||
reg
|
|
||||||
|
cell.set(VarReg::ArgAndNorm(r, k));
|
||||||
|
|
||||||
|
if is_new_var {
|
||||||
|
target.push(Target::argument_to_variable(r, k));
|
||||||
|
} else {
|
||||||
|
target.push(Target::argument_to_value(r, k));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Level::Deep => {
|
||||||
|
cell.set(VarReg::Norm(r));
|
||||||
|
|
||||||
|
if is_new_var {
|
||||||
|
target.push(Target::subterm_to_variable(r));
|
||||||
|
} else {
|
||||||
|
target.push(Target::subterm_to_value(r));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if !r.is_perm() {
|
||||||
|
self.record_register(var, r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mark_new_var(&mut self, lvl: Level, var: &'a Var, reg: RegType) -> VarReg
|
fn reset(&mut self) {
|
||||||
{
|
self.bindings.clear();
|
||||||
let inner_reg = if !reg.is_perm() {
|
}
|
||||||
let temp = self.temp_c;
|
|
||||||
self.temp_c += 1;
|
fn advance(&mut self, term_loc: GenContext, term: &'a Term) {
|
||||||
RegType::Temp(temp)
|
if let GenContext::Head = term_loc {
|
||||||
|
self.arg_c = 1;
|
||||||
|
self.temp_c = max(term.subterms() + 1, self.temp_c);
|
||||||
} else {
|
} else {
|
||||||
reg
|
self.arg_c = 1;
|
||||||
};
|
self.temp_c = term.subterms() + 1;
|
||||||
|
|
||||||
let reg = match lvl {
|
|
||||||
Level::Deep => VarReg::Norm(inner_reg),
|
|
||||||
Level::Shallow => {
|
|
||||||
let reg = VarReg::ArgAndNorm(inner_reg, self.arg_c);
|
|
||||||
self.arg_c += 1;
|
|
||||||
reg
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.record_register(var, inner_reg);
|
|
||||||
reg
|
|
||||||
}
|
|
||||||
|
|
||||||
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 advance_arg(&mut self) {
|
||||||
self.arg_c += 1;
|
self.arg_c += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn advance_at_head(&mut self, term: &'a Term) {
|
fn bindings(&self) -> &AllocVarDict<'a> {
|
||||||
self.arg_c = 1;
|
&self.bindings
|
||||||
self.temp_c = max(term.subterms() + 1, self.temp_c);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn advance(&mut self, term: &'a Term) {
|
fn bindings_mut(&mut self) -> &mut AllocVarDict<'a> {
|
||||||
self.arg_c = 1;
|
&mut self.bindings
|
||||||
self.temp_c = term.subterms() + 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reset(&mut self) {
|
fn take_bindings(self) -> AllocVarDict<'a> {
|
||||||
self.bindings.clear();
|
self.bindings
|
||||||
self.contents.clear();
|
|
||||||
self.in_use.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reset_contents(&mut self) {
|
|
||||||
self.contents.clear();
|
|
||||||
self.in_use.clear();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
Reference in New Issue
Block a user