transition to prolog
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.4.0"
|
version = "0.5.0"
|
||||||
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.4.0"
|
version = "0.5.0"
|
||||||
authors = ["Mark Thom"]
|
authors = ["Mark Thom"]
|
||||||
|
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
|
|||||||
51
README.md
51
README.md
@@ -8,9 +8,11 @@ pure Prolog.
|
|||||||
|
|
||||||
## Progress
|
## Progress
|
||||||
|
|
||||||
The language L3 is implemented as a simple REPL. L3 is pure Prolog --
|
Pure Prolog is implemented as a simple REPL. "Pure Prolog" is Prolog
|
||||||
Prolog without cut, meta- or extra-logical operators, or side effects
|
without cut, meta- or extra-logical operators, or side effects of any
|
||||||
of any kind. No data types apart from atoms are currently supported.
|
kind. In terms of the tutorial pacing, the work has progressed to the
|
||||||
|
middle of section 5.2. Atoms and lists are the only two data types
|
||||||
|
currently supported.
|
||||||
|
|
||||||
## Tutorial
|
## Tutorial
|
||||||
To enter a multi-clause predicate, the brackets ":{" and "}:" are used
|
To enter a multi-clause predicate, the brackets ":{" and "}:" are used
|
||||||
@@ -18,11 +20,11 @@ as delimiters. They must be entirely contained with their own lines.
|
|||||||
|
|
||||||
For example,
|
For example,
|
||||||
```
|
```
|
||||||
l3> :{
|
prolog> :{
|
||||||
p(f(f(X)), h(W), Y) :- g(W), h(W), f(X).
|
p(f(f(X)), h(W), Y) :- g(W), h(W), f(X).
|
||||||
p(X, Y, Z) :- h(Y), z(Z).
|
p(X, Y, Z) :- h(Y), z(Z).
|
||||||
}:
|
}:
|
||||||
l3> :{
|
prolog> :{
|
||||||
h(x).
|
h(x).
|
||||||
h(y).
|
h(y).
|
||||||
h(z).
|
h(z).
|
||||||
@@ -31,28 +33,49 @@ h(z).
|
|||||||
|
|
||||||
Single clause predicates can be entered without brackets, as in
|
Single clause predicates can be entered without brackets, as in
|
||||||
```
|
```
|
||||||
l3> p(X) :- q(X).
|
prolog> p(X) :- q(X).
|
||||||
l3> f(s).
|
prolog> f(s).
|
||||||
l3> z(Z).
|
prolog> z(Z).
|
||||||
```
|
```
|
||||||
|
|
||||||
Queries are issued as
|
Queries are issued as
|
||||||
```
|
```
|
||||||
l3> ?- p(X, Y, Z).
|
prolog> ?- p(X, Y, Z).
|
||||||
```
|
```
|
||||||
|
|
||||||
Given the above work, the result of the query will be
|
Given the above work, the result of the query will be
|
||||||
```
|
```
|
||||||
l3> ?- p(X, Y, Z).
|
prolog> ?- p(X, Y, Z).
|
||||||
yes
|
yes
|
||||||
X = _0
|
X = _0
|
||||||
Y = x
|
Y = x
|
||||||
Z = _2
|
Z = _2
|
||||||
Press ; to continue or A to abort.
|
Press ; to continue or . to abort.
|
||||||
```
|
```
|
||||||
|
|
||||||
Pressing ; will backtrack through other possible answers, if any exist.
|
Pressing ; will backtrack through other possible answers, if any exist.
|
||||||
Pressing A will abort the search and return to the prompt.
|
Pressing . will abort the search and return to the prompt.
|
||||||
|
|
||||||
|
Wildcards work as well:
|
||||||
|
|
||||||
|
```
|
||||||
|
prolog> prolog> :{
|
||||||
|
member(X, [X|_]).
|
||||||
|
member(X, [_|Xs]) :- member(X, Xs).
|
||||||
|
}:
|
||||||
|
prolog> ?- member(X, [a, b, c]).
|
||||||
|
yes
|
||||||
|
X = a
|
||||||
|
Press ; to continue or . to abort.
|
||||||
|
;
|
||||||
|
X = b
|
||||||
|
Press ; to continue or . to abort.
|
||||||
|
;
|
||||||
|
X = c
|
||||||
|
Press ; to continue or . to abort.
|
||||||
|
;
|
||||||
|
no
|
||||||
|
```
|
||||||
|
|
||||||
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
|
||||||
@@ -66,8 +89,8 @@ unification on a cyclic term succeeds, and the attempt to write the
|
|||||||
term to a string results in an infinite loop, ie.
|
term to a string results in an infinite loop, ie.
|
||||||
|
|
||||||
```
|
```
|
||||||
l3> p(W, W).
|
prolog> p(W, W).
|
||||||
l3> ?- p(f(f(W)), W).
|
prolog> ?- p(f(f(W)), W).
|
||||||
yes
|
yes
|
||||||
*loops to infinity*
|
*loops to infinity*
|
||||||
```
|
```
|
||||||
60
src/main.rs
60
src/main.rs
@@ -1,13 +1,13 @@
|
|||||||
extern crate termion;
|
extern crate termion;
|
||||||
mod l3;
|
mod prolog;
|
||||||
|
|
||||||
use l3::io::*;
|
use prolog::io::*;
|
||||||
use l3::machine::*;
|
use prolog::machine::*;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use l3::ast::*;
|
use prolog::ast::*;
|
||||||
|
|
||||||
fn submit(wam: &mut Machine, buffer: &str) -> EvalResult {
|
fn submit(wam: &mut Machine, buffer: &str) -> EvalResult {
|
||||||
let result = eval(wam, buffer);
|
let result = eval(wam, buffer);
|
||||||
@@ -174,13 +174,59 @@ mod tests {
|
|||||||
assert_eq!(submit(&mut wam, "?- p(X, Y, X).").failed_query(), false);
|
assert_eq!(submit(&mut wam, "?- p(X, Y, X).").failed_query(), false);
|
||||||
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).").failed_query(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_queries_on_lists() {
|
||||||
|
let mut wam = Machine::new();
|
||||||
|
|
||||||
|
submit(&mut wam, "p([Z, W]).");
|
||||||
|
|
||||||
|
assert_eq!(submit(&mut wam, "?- p([Z, Z]).").failed_query(), false);
|
||||||
|
assert_eq!(submit(&mut wam, "?- p([Z, W, Y]).").failed_query(), true);
|
||||||
|
assert_eq!(submit(&mut wam, "?- p([Z | W]).").failed_query(), false);
|
||||||
|
assert_eq!(submit(&mut wam, "?- p([Z | [Z]]).").failed_query(), false);
|
||||||
|
assert_eq!(submit(&mut wam, "?- p([Z | [W]]).").failed_query(), false);
|
||||||
|
assert_eq!(submit(&mut wam, "?- p([Z | []]).").failed_query(), true);
|
||||||
|
|
||||||
|
submit(&mut wam, "p([Z, Z]).");
|
||||||
|
|
||||||
|
assert_eq!(submit(&mut wam, "?- p([Z, Z]).").failed_query(), false);
|
||||||
|
assert_eq!(submit(&mut wam, "?- p([Z, W, Y]).").failed_query(), true);
|
||||||
|
assert_eq!(submit(&mut wam, "?- p([Z | W]).").failed_query(), false);
|
||||||
|
assert_eq!(submit(&mut wam, "?- p([Z | [Z]]).").failed_query(), false);
|
||||||
|
assert_eq!(submit(&mut wam, "?- p([Z | [W]]).").failed_query(), false);
|
||||||
|
assert_eq!(submit(&mut wam, "?- p([Z | []]).").failed_query(), true);
|
||||||
|
|
||||||
|
submit(&mut wam, "p([Z]).");
|
||||||
|
|
||||||
|
assert_eq!(submit(&mut wam, "?- p([Z, Z]).").failed_query(), true);
|
||||||
|
assert_eq!(submit(&mut wam, "?- p([Z, W, Y]).").failed_query(), true);
|
||||||
|
assert_eq!(submit(&mut wam, "?- p([Z | W]).").failed_query(), false);
|
||||||
|
assert_eq!(submit(&mut wam, "?- p([Z | [Z]]).").failed_query(), true);
|
||||||
|
assert_eq!(submit(&mut wam, "?- p([Z | [W]]).").failed_query(), true);
|
||||||
|
assert_eq!(submit(&mut wam, "?- p([Z | []]).").failed_query(), false);
|
||||||
|
|
||||||
|
submit(&mut wam, "member(X, [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(c, [a, [X, Y]]).").failed_query(), true);
|
||||||
|
assert_eq!(submit(&mut wam, "?- member(a, [a, [X, Y]]).").failed_query(), false);
|
||||||
|
assert_eq!(submit(&mut wam, "?- member(a, [X, Y, Z]).").failed_query(), false);
|
||||||
|
assert_eq!(submit(&mut wam, "?- member([X, X], [a, [X, Y]]).").failed_query(), false);
|
||||||
|
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, d], [foo, x], [d, f]]).").failed_query(), true);
|
||||||
|
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, Y], [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]]).").failed_query(), true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn l3_repl() {
|
fn prolog_repl() {
|
||||||
let mut wam = Machine::new();
|
let mut wam = Machine::new();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
print!("l3> ");
|
print!("prolog> ");
|
||||||
|
|
||||||
let buffer = read();
|
let buffer = read();
|
||||||
|
|
||||||
@@ -199,5 +245,5 @@ fn l3_repl() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
l3_repl();
|
prolog_repl();
|
||||||
}
|
}
|
||||||
|
|||||||
80
src/prolog/and_stack.rs
Normal file
80
src/prolog/and_stack.rs
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
use prolog::ast::*;
|
||||||
|
|
||||||
|
use std::ops::{Index, IndexMut};
|
||||||
|
use std::vec::Vec;
|
||||||
|
|
||||||
|
pub struct Frame {
|
||||||
|
pub global_index: usize,
|
||||||
|
pub e: usize,
|
||||||
|
pub cp: CodePtr,
|
||||||
|
perms: Vec<Addr>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Frame {
|
||||||
|
fn new(global_index: usize, e: usize, cp: CodePtr, n: usize) -> Self {
|
||||||
|
Frame {
|
||||||
|
global_index: global_index,
|
||||||
|
e: e,
|
||||||
|
cp: cp,
|
||||||
|
perms: vec![Addr::HeapCell(0); n]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AndStack(Vec<Frame>);
|
||||||
|
|
||||||
|
impl AndStack {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
AndStack(Vec::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push(&mut self, global_index: usize, e: usize, cp: CodePtr, n: usize) {
|
||||||
|
self.0.push(Frame::new(global_index, e, cp, n));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn top(&self) -> Option<&Frame> {
|
||||||
|
self.0.last()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.0.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
self.0.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
// drop the last n frames.
|
||||||
|
pub fn drop_frames(&mut self, n: usize) {
|
||||||
|
let len = self.0.len();
|
||||||
|
self.0.truncate(len - n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Index<usize> for AndStack {
|
||||||
|
type Output = Frame;
|
||||||
|
|
||||||
|
fn index(&self, index: usize) -> &Self::Output {
|
||||||
|
self.0.index(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IndexMut<usize> for AndStack {
|
||||||
|
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
||||||
|
self.0.index_mut(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Index<usize> for Frame {
|
||||||
|
type Output = Addr;
|
||||||
|
|
||||||
|
fn index(&self, index: usize) -> &Self::Output {
|
||||||
|
self.perms.index(index - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IndexMut<usize> for Frame {
|
||||||
|
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
||||||
|
self.perms.index_mut(index - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
342
src/prolog/ast.rs
Normal file
342
src/prolog/ast.rs
Normal file
@@ -0,0 +1,342 @@
|
|||||||
|
use std::cell::Cell;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::ops::{Add, AddAssign};
|
||||||
|
use std::vec::Vec;
|
||||||
|
|
||||||
|
pub type Var = String;
|
||||||
|
|
||||||
|
pub type Atom = String;
|
||||||
|
|
||||||
|
pub enum PredicateClause {
|
||||||
|
Fact(Term),
|
||||||
|
Rule(Rule)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PredicateClause {
|
||||||
|
pub fn name(&self) -> &Atom {
|
||||||
|
match self {
|
||||||
|
&PredicateClause::Fact(ref t) => t.name().unwrap(),
|
||||||
|
&PredicateClause::Rule(ref rule) => rule.head.0.name().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn arity(&self) -> usize {
|
||||||
|
match self {
|
||||||
|
&PredicateClause::Fact(ref t) => t.arity(),
|
||||||
|
&PredicateClause::Rule(ref rule) => rule.head.0.arity()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum TopLevel {
|
||||||
|
Fact(Term),
|
||||||
|
Predicate(Vec<PredicateClause>),
|
||||||
|
Query(Term),
|
||||||
|
Rule(Rule)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum Level {
|
||||||
|
Deep, Shallow
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum RegType {
|
||||||
|
Perm(usize),
|
||||||
|
Temp(usize)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for RegType {
|
||||||
|
fn default() -> Self {
|
||||||
|
RegType::Temp(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RegType {
|
||||||
|
pub fn reg_num(self) -> usize {
|
||||||
|
match self {
|
||||||
|
RegType::Perm(reg_num) | RegType::Temp(reg_num) => reg_num
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_perm(self) -> bool {
|
||||||
|
match self {
|
||||||
|
RegType::Perm(_) => true,
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum VarReg {
|
||||||
|
ArgAndNorm(RegType, usize),
|
||||||
|
Norm(RegType)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VarReg {
|
||||||
|
pub fn norm(self) -> RegType {
|
||||||
|
match self {
|
||||||
|
VarReg::ArgAndNorm(reg, _) | VarReg::Norm(reg) => reg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn root_register(self) -> usize {
|
||||||
|
match self {
|
||||||
|
VarReg::ArgAndNorm(_, root) => root,
|
||||||
|
VarReg::Norm(root) => root.reg_num()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for VarReg {
|
||||||
|
fn default() -> Self {
|
||||||
|
VarReg::Norm(RegType::default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq)]
|
||||||
|
pub enum Constant {
|
||||||
|
Atom(Atom),
|
||||||
|
EmptyList
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Term {
|
||||||
|
AnonVar,
|
||||||
|
Clause(Cell<RegType>, Atom, Vec<Box<Term>>),
|
||||||
|
Cons(Cell<RegType>, Box<Term>, Box<Term>),
|
||||||
|
Constant(Cell<RegType>, Constant),
|
||||||
|
Var(Cell<VarReg>, Var)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Rule {
|
||||||
|
pub head: (Term, Term),
|
||||||
|
pub clauses: Vec<Term>
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum TermRef<'a> {
|
||||||
|
AnonVar(Level),
|
||||||
|
Cons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
|
||||||
|
Constant(Level, &'a Cell<RegType>, &'a Constant),
|
||||||
|
Clause(Level, &'a Cell<RegType>, &'a Atom, &'a Vec<Box<Term>>),
|
||||||
|
Var(Level, &'a Cell<VarReg>, &'a Var)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum FactInstruction {
|
||||||
|
GetConstant(Level, Constant, RegType),
|
||||||
|
GetList(Level, RegType),
|
||||||
|
GetStructure(Level, Atom, usize, RegType),
|
||||||
|
GetValue(RegType, usize),
|
||||||
|
GetVariable(RegType, usize),
|
||||||
|
UnifyConstant(Constant),
|
||||||
|
UnifyVariable(RegType),
|
||||||
|
UnifyValue(RegType)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum QueryInstruction {
|
||||||
|
PutConstant(Level, Constant, RegType),
|
||||||
|
PutList(Level, RegType),
|
||||||
|
PutStructure(Level, Atom, usize, RegType),
|
||||||
|
PutValue(RegType, usize),
|
||||||
|
PutVariable(RegType, usize),
|
||||||
|
SetConstant(Constant),
|
||||||
|
SetVariable(RegType),
|
||||||
|
SetValue(RegType)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum ChoiceInstruction {
|
||||||
|
RetryMeElse(usize),
|
||||||
|
TrustMe,
|
||||||
|
TryMeElse(usize)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum ControlInstruction {
|
||||||
|
Allocate(usize),
|
||||||
|
Call(Atom, usize),
|
||||||
|
Deallocate,
|
||||||
|
Proceed
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type CompiledFact = Vec<FactInstruction>;
|
||||||
|
|
||||||
|
pub type CompiledQuery = Vec<QueryInstruction>;
|
||||||
|
|
||||||
|
pub enum Line {
|
||||||
|
Choice(ChoiceInstruction),
|
||||||
|
Control(ControlInstruction),
|
||||||
|
Fact(CompiledFact),
|
||||||
|
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 Code = Vec<Line>;
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq)]
|
||||||
|
pub enum Addr {
|
||||||
|
Con(Constant),
|
||||||
|
Lis(usize),
|
||||||
|
HeapCell(usize),
|
||||||
|
StackCell(usize, usize),
|
||||||
|
Str(usize)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Addr {
|
||||||
|
pub fn is_ref(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
&Addr::HeapCell(_) | &Addr::StackCell(_, _) => true,
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_ref(&self) -> Option<Ref> {
|
||||||
|
match self {
|
||||||
|
&Addr::HeapCell(hc) => Some(Ref::HeapCell(hc)),
|
||||||
|
&Addr::StackCell(fr, sc) => Some(Ref::StackCell(fr, sc)),
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Ref> for Addr {
|
||||||
|
fn from(r: Ref) -> Self {
|
||||||
|
match r {
|
||||||
|
Ref::HeapCell(hc) => Addr::HeapCell(hc),
|
||||||
|
Ref::StackCell(fr, sc) => Addr::StackCell(fr, sc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq)]
|
||||||
|
pub enum Ref {
|
||||||
|
HeapCell(usize),
|
||||||
|
StackCell(usize, usize)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq)]
|
||||||
|
pub enum HeapCellValue {
|
||||||
|
Con(Constant),
|
||||||
|
Lis(usize),
|
||||||
|
NamedStr(usize, Atom),
|
||||||
|
Ref(Ref),
|
||||||
|
Str(usize)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Addr> for HeapCellValue {
|
||||||
|
fn from(addr: Addr) -> HeapCellValue {
|
||||||
|
match addr {
|
||||||
|
Addr::Con(constant) =>
|
||||||
|
HeapCellValue::Con(constant),
|
||||||
|
Addr::HeapCell(hc) =>
|
||||||
|
HeapCellValue::Ref(Ref::HeapCell(hc)),
|
||||||
|
Addr::Lis(a) =>
|
||||||
|
HeapCellValue::Lis(a),
|
||||||
|
Addr::StackCell(fr, sc) =>
|
||||||
|
HeapCellValue::Ref(Ref::StackCell(fr, sc)),
|
||||||
|
Addr::Str(hc) =>
|
||||||
|
HeapCellValue::Str(hc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HeapCellValue {
|
||||||
|
pub fn as_addr(&self, focus: usize) -> Addr {
|
||||||
|
match self {
|
||||||
|
&HeapCellValue::Con(ref c) => Addr::Con(c.clone()),
|
||||||
|
&HeapCellValue::Lis(a) => Addr::Lis(a),
|
||||||
|
&HeapCellValue::Ref(r) => Addr::from(r),
|
||||||
|
&HeapCellValue::Str(s) => Addr::Str(s),
|
||||||
|
&HeapCellValue::NamedStr(_, _) => Addr::Str(focus)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum CodePtr {
|
||||||
|
DirEntry(usize),
|
||||||
|
TopLevel
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for CodePtr {
|
||||||
|
fn default() -> Self {
|
||||||
|
CodePtr::TopLevel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add<usize> for CodePtr {
|
||||||
|
type Output = CodePtr;
|
||||||
|
|
||||||
|
fn add(self, rhs: usize) -> Self::Output {
|
||||||
|
match self {
|
||||||
|
CodePtr::DirEntry(p) => CodePtr::DirEntry(p + rhs),
|
||||||
|
CodePtr::TopLevel => CodePtr::TopLevel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AddAssign<usize> for CodePtr {
|
||||||
|
fn add_assign(&mut self, rhs: usize) {
|
||||||
|
match self {
|
||||||
|
&mut CodePtr::DirEntry(ref mut p) => *p += rhs,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type Heap = Vec<HeapCellValue>;
|
||||||
|
|
||||||
|
pub type Registers = Vec<Addr>;
|
||||||
|
|
||||||
|
impl Term {
|
||||||
|
pub fn subterms(&self) -> usize {
|
||||||
|
match self {
|
||||||
|
&Term::Clause(_, _, ref terms) => terms.len(),
|
||||||
|
_ => 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> Option<&Atom> {
|
||||||
|
match self {
|
||||||
|
&Term::Constant(_, Constant::Atom(ref atom))
|
||||||
|
| &Term::Var(_, ref atom)
|
||||||
|
| &Term::Clause(_, ref atom, _) => Some(atom),
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn arity(&self) -> usize {
|
||||||
|
match self {
|
||||||
|
&Term::Clause(_, _, ref child_terms) => child_terms.len(),
|
||||||
|
_ => 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
546
src/prolog/codegen.rs
Normal file
546
src/prolog/codegen.rs
Normal file
@@ -0,0 +1,546 @@
|
|||||||
|
use prolog::ast::*;
|
||||||
|
use prolog::iterators::{FactIterator, QueryIterator};
|
||||||
|
|
||||||
|
use std::cell::Cell;
|
||||||
|
use std::cmp::max;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::vec::Vec;
|
||||||
|
|
||||||
|
trait CompilationTarget<'a> {
|
||||||
|
type Iterator : Iterator<Item=TermRef<'a>>;
|
||||||
|
|
||||||
|
fn iter(&'a Term) -> Self::Iterator;
|
||||||
|
|
||||||
|
fn to_structure(Level, Atom, usize, RegType) -> Self;
|
||||||
|
fn to_constant(Level, Constant, RegType) -> Self;
|
||||||
|
fn to_list(Level, RegType) -> Self;
|
||||||
|
|
||||||
|
fn constant_subterm(Constant) -> Self;
|
||||||
|
|
||||||
|
fn argument_to_variable(RegType, usize) -> Self;
|
||||||
|
fn argument_to_value(RegType, usize) -> Self;
|
||||||
|
|
||||||
|
fn subterm_to_variable(RegType) -> Self;
|
||||||
|
fn subterm_to_value(RegType) -> Self;
|
||||||
|
|
||||||
|
fn clause_arg_to_instr(RegType) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> CompilationTarget<'a> for FactInstruction {
|
||||||
|
type Iterator = FactIterator<'a>;
|
||||||
|
|
||||||
|
fn iter(term: &'a Term) -> Self::Iterator {
|
||||||
|
term.breadth_first_iter()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_structure(lvl: Level, atom: Atom, arity: usize, reg: RegType) -> Self {
|
||||||
|
FactInstruction::GetStructure(lvl, atom, arity, reg)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_constant(lvl: Level, constant: Constant, reg: RegType) -> Self {
|
||||||
|
FactInstruction::GetConstant(lvl, constant, reg)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_list(lvl: Level, reg: RegType) -> Self {
|
||||||
|
FactInstruction::GetList(lvl, reg)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn constant_subterm(constant: Constant) -> Self {
|
||||||
|
FactInstruction::UnifyConstant(constant)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn argument_to_variable(arg: RegType, val: usize) -> Self {
|
||||||
|
FactInstruction::GetVariable(arg, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn argument_to_value(arg: RegType, val: usize) -> Self {
|
||||||
|
FactInstruction::GetValue(arg, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn subterm_to_variable(val: RegType) -> Self {
|
||||||
|
FactInstruction::UnifyVariable(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn subterm_to_value(val: RegType) -> Self {
|
||||||
|
FactInstruction::UnifyValue(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clause_arg_to_instr(val: RegType) -> Self {
|
||||||
|
FactInstruction::UnifyVariable(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> CompilationTarget<'a> for QueryInstruction {
|
||||||
|
type Iterator = QueryIterator<'a>;
|
||||||
|
|
||||||
|
fn iter(term: &'a Term) -> Self::Iterator {
|
||||||
|
term.post_order_iter()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_structure(lvl: Level, atom: Atom, arity: usize, reg: RegType) -> Self {
|
||||||
|
QueryInstruction::PutStructure(lvl, atom, arity, reg)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_constant(lvl: Level, constant: Constant, reg: RegType) -> Self {
|
||||||
|
QueryInstruction::PutConstant(lvl, constant, reg)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_list(lvl: Level, reg: RegType) -> Self {
|
||||||
|
QueryInstruction::PutList(lvl, reg)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn constant_subterm(constant: Constant) -> Self {
|
||||||
|
QueryInstruction::SetConstant(constant)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn argument_to_variable(arg: RegType, val: usize) -> Self {
|
||||||
|
QueryInstruction::PutVariable(arg, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn argument_to_value(arg: RegType, val: usize) -> Self {
|
||||||
|
QueryInstruction::PutValue(arg, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn subterm_to_variable(val: RegType) -> Self {
|
||||||
|
QueryInstruction::SetVariable(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn subterm_to_value(val: RegType) -> Self {
|
||||||
|
QueryInstruction::SetValue(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clause_arg_to_instr(val: RegType) -> Self {
|
||||||
|
QueryInstruction::SetValue(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TermMarker<'a> {
|
||||||
|
bindings: HashMap<&'a Var, VarReg>,
|
||||||
|
arg_c: usize,
|
||||||
|
perm_c: usize,
|
||||||
|
temp_c: usize
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> TermMarker<'a> {
|
||||||
|
fn new() -> TermMarker<'a> {
|
||||||
|
TermMarker { bindings: HashMap::new(),
|
||||||
|
arg_c: 1,
|
||||||
|
perm_c: 1,
|
||||||
|
temp_c: 1 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reset(&mut self) {
|
||||||
|
self.bindings.clear();
|
||||||
|
self.perm_c = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn contains_var(&self, var: &'a Var) -> bool {
|
||||||
|
self.bindings.contains_key(var)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get(&self, var: &'a Var) -> VarReg {
|
||||||
|
*self.bindings.get(var).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn insert(&mut self, var: &'a Var, r: VarReg) {
|
||||||
|
self.bindings.insert(var, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 perm = self.perm_c;
|
||||||
|
self.perm_c += 1;
|
||||||
|
cell.set(RegType::Perm(perm));
|
||||||
|
},
|
||||||
|
Level::Deep => {
|
||||||
|
let temp = self.temp_c;
|
||||||
|
self.temp_c += 1;
|
||||||
|
cell.set(RegType::Temp(temp));
|
||||||
|
},
|
||||||
|
Level::Shallow if reg_type.is_perm() => {
|
||||||
|
let arg = self.arg_c;
|
||||||
|
self.arg_c += 1;
|
||||||
|
cell.set(RegType::Perm(arg));
|
||||||
|
},
|
||||||
|
Level::Shallow => {
|
||||||
|
let arg = self.arg_c;
|
||||||
|
self.arg_c += 1;
|
||||||
|
cell.set(RegType::Temp(arg));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mark_old_var(&mut self, lvl: Level, var: &'a Var) -> VarReg
|
||||||
|
{
|
||||||
|
let reg = self.get(var);
|
||||||
|
|
||||||
|
match lvl {
|
||||||
|
Level::Deep => VarReg::Norm(reg.norm()),
|
||||||
|
Level::Shallow => {
|
||||||
|
let reg = VarReg::ArgAndNorm(reg.norm(), self.arg_c);
|
||||||
|
|
||||||
|
self.arg_c += 1;
|
||||||
|
self.insert(var, reg);
|
||||||
|
|
||||||
|
reg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mark_new_var(&mut self, lvl: Level, var: &'a Var, reg: RegType) -> VarReg
|
||||||
|
{
|
||||||
|
let inner_reg = if reg.is_perm() {
|
||||||
|
let perm = self.perm_c;
|
||||||
|
self.perm_c += 1;
|
||||||
|
RegType::Perm(perm)
|
||||||
|
} else {
|
||||||
|
let temp = self.temp_c;
|
||||||
|
self.temp_c += 1;
|
||||||
|
RegType::Temp(temp)
|
||||||
|
};
|
||||||
|
|
||||||
|
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.insert(var, reg);
|
||||||
|
reg
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn advance_at_head(&mut self, term: &'a Term) {
|
||||||
|
self.arg_c = 1;
|
||||||
|
self.temp_c = max(term.subterms(), self.temp_c) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn advance(&mut self, term: &'a Term) {
|
||||||
|
self.arg_c = 1;
|
||||||
|
self.temp_c = term.subterms() + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
enum TermStatus {
|
||||||
|
New, Old, Recurrent
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CodeGenerator<'a> {
|
||||||
|
marker: TermMarker<'a>
|
||||||
|
}
|
||||||
|
|
||||||
|
type VariableFixture<'a> = (TermStatus, Vec<&'a Cell<VarReg>>);
|
||||||
|
type VariableFixtures<'a> = HashMap<&'a Var, VariableFixture<'a>>;
|
||||||
|
|
||||||
|
impl<'a> CodeGenerator<'a> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
CodeGenerator { marker: TermMarker::new() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn vars(&self) -> &HashMap<&Var, VarReg> {
|
||||||
|
&self.marker.bindings
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_structure<Target>(&mut self,
|
||||||
|
lvl: Level,
|
||||||
|
cell: &'a Cell<RegType>,
|
||||||
|
name: &'a Atom,
|
||||||
|
arity: usize)
|
||||||
|
-> Target
|
||||||
|
where Target: CompilationTarget<'a>
|
||||||
|
{
|
||||||
|
self.marker.mark_non_var(lvl, cell);
|
||||||
|
Target::to_structure(lvl, name.clone(), arity, cell.get())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_constant<Target>(&mut self,
|
||||||
|
lvl: Level,
|
||||||
|
cell: &'a Cell<RegType>,
|
||||||
|
constant: &'a Constant)
|
||||||
|
-> Target
|
||||||
|
where Target: CompilationTarget<'a>
|
||||||
|
{
|
||||||
|
self.marker.mark_non_var(lvl, cell);
|
||||||
|
Target::to_constant(lvl, constant.clone(), cell.get())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_list<Target>(&mut self, lvl: Level, cell: &'a Cell<RegType>) -> Target
|
||||||
|
where Target: CompilationTarget<'a>
|
||||||
|
{
|
||||||
|
self.marker.mark_non_var(lvl, cell);
|
||||||
|
Target::to_list(lvl, cell.get())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn constant_subterm<Target>(&mut self,
|
||||||
|
cell: &'a Cell<RegType>,
|
||||||
|
constant: &'a Constant)
|
||||||
|
-> Target
|
||||||
|
where Target: CompilationTarget<'a>
|
||||||
|
{
|
||||||
|
self.marker.mark_non_var(Level::Deep, cell);
|
||||||
|
Target::constant_subterm(constant.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn anon_var_term<Target>(&mut self, lvl: Level) -> Target
|
||||||
|
where Target: CompilationTarget<'a>
|
||||||
|
{
|
||||||
|
let reg = self.marker.mark_anon_var(lvl);
|
||||||
|
|
||||||
|
match reg {
|
||||||
|
VarReg::ArgAndNorm(arg, norm) =>
|
||||||
|
Target::argument_to_variable(arg, norm),
|
||||||
|
VarReg::Norm(norm) =>
|
||||||
|
Target::subterm_to_variable(norm)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn var_term<Target>(&mut self,
|
||||||
|
lvl: Level,
|
||||||
|
cell: &'a Cell<VarReg>,
|
||||||
|
var: &'a Var)
|
||||||
|
-> Target
|
||||||
|
where Target: CompilationTarget<'a>
|
||||||
|
{
|
||||||
|
if !self.marker.contains_var(var) {
|
||||||
|
let reg = self.marker.mark_new_var(lvl, var, cell.get().norm());
|
||||||
|
cell.set(reg);
|
||||||
|
|
||||||
|
match reg {
|
||||||
|
VarReg::ArgAndNorm(arg, norm) =>
|
||||||
|
Target::argument_to_variable(arg, norm),
|
||||||
|
VarReg::Norm(norm) =>
|
||||||
|
Target::subterm_to_variable(norm)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let reg = self.marker.mark_old_var(lvl, var);
|
||||||
|
cell.set(reg);
|
||||||
|
|
||||||
|
match reg {
|
||||||
|
VarReg::ArgAndNorm(arg, norm) =>
|
||||||
|
Target::argument_to_value(arg, norm),
|
||||||
|
VarReg::Norm(norm) =>
|
||||||
|
Target::subterm_to_value(norm)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn non_var_subterm<Target>(&mut self, cell: &'a Cell<RegType>) -> Target
|
||||||
|
where Target: CompilationTarget<'a>
|
||||||
|
{
|
||||||
|
self.marker.mark_non_var(Level::Deep, cell);
|
||||||
|
Target::clause_arg_to_instr(cell.get())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn subterm_to_instr<Target>(&mut self, subterm: &'a Term) -> Target
|
||||||
|
where Target: CompilationTarget<'a>
|
||||||
|
{
|
||||||
|
match subterm {
|
||||||
|
&Term::AnonVar =>
|
||||||
|
self.anon_var_term(Level::Deep),
|
||||||
|
&Term::Cons(ref cell, _, _) | &Term::Clause(ref cell, _, _) =>
|
||||||
|
self.non_var_subterm(cell),
|
||||||
|
&Term::Constant(ref cell, ref constant) =>
|
||||||
|
self.constant_subterm(cell, constant),
|
||||||
|
&Term::Var(ref cell, ref var) =>
|
||||||
|
self.var_term(Level::Deep, cell, var)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compile_target<Target>(&mut self, term: &'a Term) -> Vec<Target>
|
||||||
|
where Target: CompilationTarget<'a>
|
||||||
|
{
|
||||||
|
let iter = Target::iter(term);
|
||||||
|
let mut target = Vec::new();
|
||||||
|
|
||||||
|
for term in iter {
|
||||||
|
match term {
|
||||||
|
TermRef::Clause(lvl, cell, atom, terms) => {
|
||||||
|
target.push(self.to_structure(lvl, cell, atom, terms.len()));
|
||||||
|
|
||||||
|
for subterm in terms {
|
||||||
|
target.push(self.subterm_to_instr(subterm.as_ref()));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
TermRef::Cons(lvl, cell, head, tail) => {
|
||||||
|
target.push(self.to_list(lvl, cell));
|
||||||
|
|
||||||
|
target.push(self.subterm_to_instr(head));
|
||||||
|
target.push(self.subterm_to_instr(tail));
|
||||||
|
},
|
||||||
|
TermRef::Constant(lvl @ Level::Shallow, cell, constant) =>
|
||||||
|
target.push(self.to_constant(lvl, cell, constant)),
|
||||||
|
TermRef::AnonVar(lvl @ Level::Shallow) =>
|
||||||
|
target.push(self.anon_var_term(lvl)),
|
||||||
|
TermRef::Var(lvl @ Level::Shallow, ref cell, ref var) =>
|
||||||
|
target.push(self.var_term(lvl, cell, var)),
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
target
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mark_vars_in_term<Iter>(iter: Iter, vs: &mut VariableFixtures<'a>)
|
||||||
|
where Iter : Iterator<Item=TermRef<'a>>
|
||||||
|
{
|
||||||
|
for term in iter {
|
||||||
|
if let TermRef::Var(_, reg_cell, var) = term {
|
||||||
|
let mut status = vs.entry(var)
|
||||||
|
.or_insert((TermStatus::New, Vec::new()));
|
||||||
|
|
||||||
|
status.1.push(reg_cell);
|
||||||
|
|
||||||
|
match status.0 {
|
||||||
|
TermStatus::Old => status.0 = TermStatus::Recurrent,
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for &mut (ref mut term_status, ref mut cb) in vs.values_mut() {
|
||||||
|
match *term_status {
|
||||||
|
TermStatus::New => *term_status = TermStatus::Old,
|
||||||
|
TermStatus::Recurrent => {
|
||||||
|
for cell_reg in cb.drain(0..) {
|
||||||
|
cell_reg.set(VarReg::Norm(RegType::Perm(0)));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mark_perm_vars(rule: &'a Rule) -> VariableFixtures {
|
||||||
|
let &Rule { head: (ref p0, ref p1), ref clauses } = rule;
|
||||||
|
let mut vfs = HashMap::new();
|
||||||
|
|
||||||
|
let iter = p0.breadth_first_iter().chain(p1.breadth_first_iter());
|
||||||
|
|
||||||
|
Self::mark_vars_in_term(iter, &mut vfs);
|
||||||
|
|
||||||
|
for term in clauses {
|
||||||
|
Self::mark_vars_in_term(term.breadth_first_iter(), &mut vfs);
|
||||||
|
}
|
||||||
|
|
||||||
|
vfs
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_conditional_call(compiled_query: &mut Code, term: &Term) {
|
||||||
|
match term {
|
||||||
|
&Term::Constant(_, Constant::Atom(ref atom)) => {
|
||||||
|
let call = ControlInstruction::Call(atom.clone(), 0);
|
||||||
|
compiled_query.push(Line::Control(call));
|
||||||
|
},
|
||||||
|
&Term::Clause(_, ref atom, ref terms) => {
|
||||||
|
let call = ControlInstruction::Call(atom.clone(), terms.len());
|
||||||
|
compiled_query.push(Line::Control(call));
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compile_rule(&mut self, rule: &'a Rule) -> Code {
|
||||||
|
let vfs = Self::mark_perm_vars(&rule);
|
||||||
|
let &Rule { head: (ref p0, ref p1), ref clauses } = rule;
|
||||||
|
let mut perm_vars = 0;
|
||||||
|
|
||||||
|
for &(term_status, _) in vfs.values() {
|
||||||
|
if let TermStatus::Recurrent = term_status {
|
||||||
|
perm_vars += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut body = Vec::new();
|
||||||
|
|
||||||
|
body.push(Line::Control(ControlInstruction::Allocate(perm_vars)));
|
||||||
|
|
||||||
|
self.marker.advance(p0);
|
||||||
|
body.push(Line::Fact(self.compile_target(p0)));
|
||||||
|
|
||||||
|
self.marker.advance_at_head(p1);
|
||||||
|
body.push(Line::Query(self.compile_target(p1)));
|
||||||
|
|
||||||
|
Self::add_conditional_call(&mut body, p1);
|
||||||
|
|
||||||
|
body = clauses.iter()
|
||||||
|
.map(|ref term| self.compile_query(term))
|
||||||
|
.fold(body, |mut body, ref mut cqs| {
|
||||||
|
body.append(cqs);
|
||||||
|
body
|
||||||
|
});
|
||||||
|
|
||||||
|
body.push(Line::Control(ControlInstruction::Deallocate));
|
||||||
|
body
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compile_fact(&mut self, term: &'a Term) -> Code {
|
||||||
|
self.marker.advance(term);
|
||||||
|
|
||||||
|
let mut compiled_fact = vec![Line::Fact(self.compile_target(term))];
|
||||||
|
let proceed = Line::Control(ControlInstruction::Proceed);
|
||||||
|
|
||||||
|
compiled_fact.push(proceed);
|
||||||
|
compiled_fact
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compile_query(&mut self, term: &'a Term) -> Code {
|
||||||
|
self.marker.advance(term);
|
||||||
|
|
||||||
|
let mut compiled_query = vec![Line::Query(self.compile_target(term))];
|
||||||
|
Self::add_conditional_call(&mut compiled_query, term);
|
||||||
|
|
||||||
|
compiled_query
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compile_predicate(&mut self, clauses: &'a Vec<PredicateClause>) -> Code
|
||||||
|
{
|
||||||
|
let mut code = Vec::new();
|
||||||
|
|
||||||
|
for (i, clause) in clauses.iter().enumerate() {
|
||||||
|
self.marker.reset();
|
||||||
|
|
||||||
|
let mut clause_code = match clause {
|
||||||
|
&PredicateClause::Fact(ref fact) =>
|
||||||
|
self.compile_fact(fact),
|
||||||
|
&PredicateClause::Rule(ref rule) =>
|
||||||
|
self.compile_rule(rule)
|
||||||
|
};
|
||||||
|
|
||||||
|
let choice = match i {
|
||||||
|
0 => ChoiceInstruction::TryMeElse(clause_code.len() + 1),
|
||||||
|
_ if i == clauses.len() - 1 => ChoiceInstruction::TrustMe,
|
||||||
|
_ => ChoiceInstruction::RetryMeElse(clause_code.len() + 1)
|
||||||
|
};
|
||||||
|
|
||||||
|
code.push(Line::Choice(choice));
|
||||||
|
code.append(&mut clause_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
code
|
||||||
|
}
|
||||||
|
}
|
||||||
184
src/prolog/heapview.rs
Normal file
184
src/prolog/heapview.rs
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
use prolog::and_stack::*;
|
||||||
|
use prolog::ast::*;
|
||||||
|
|
||||||
|
use std::vec::Vec;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum TToken {
|
||||||
|
Bar,
|
||||||
|
Comma,
|
||||||
|
LRBracket,
|
||||||
|
LSBracket(usize),
|
||||||
|
Nothing,
|
||||||
|
RRBracket,
|
||||||
|
RSBracket
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TToken {
|
||||||
|
pub fn as_str(self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
TToken::Bar => " | ",
|
||||||
|
TToken::Comma => ", ",
|
||||||
|
TToken::LRBracket => "(",
|
||||||
|
TToken::LSBracket(_) => "[",
|
||||||
|
TToken::Nothing => "",
|
||||||
|
TToken::RRBracket => ")",
|
||||||
|
TToken::RSBracket => "]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
enum CellRef<'a> {
|
||||||
|
View(CellView<'a>),
|
||||||
|
Redirect(usize),
|
||||||
|
TToken(TToken)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum CellView<'a> {
|
||||||
|
Con(&'a Constant),
|
||||||
|
HeapVar(usize),
|
||||||
|
StackVar(usize, usize),
|
||||||
|
Str(usize, &'a Atom),
|
||||||
|
TToken(TToken),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct HeapCellViewer<'a> {
|
||||||
|
and_stack: &'a AndStack,
|
||||||
|
heap: &'a Heap,
|
||||||
|
state_stack: Vec<CellRef<'a>>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> HeapCellViewer<'a> {
|
||||||
|
fn cell_ref_from_addr(&self, mut focus: &'a Addr) -> CellRef<'a> {
|
||||||
|
loop {
|
||||||
|
match focus {
|
||||||
|
&Addr::Con(ref c) =>
|
||||||
|
return CellRef::View(CellView::Con(c)),
|
||||||
|
&Addr::Lis(hc) | &Addr::HeapCell(hc) | &Addr::Str(hc) =>
|
||||||
|
return CellRef::Redirect(hc),
|
||||||
|
&Addr::StackCell(fr, sc) => {
|
||||||
|
match &self.and_stack[fr][sc] {
|
||||||
|
&Addr::StackCell(fr1, sc1) => {
|
||||||
|
if fr1 == fr && sc1 == sc {
|
||||||
|
return CellRef::View(CellView::StackVar(fr, sc));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => focus = &self.and_stack[fr][sc]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(heap: &'a Heap, and_stack: &'a AndStack, addr: &'a Addr) -> Self
|
||||||
|
{
|
||||||
|
let mut viewer = HeapCellViewer {
|
||||||
|
heap: heap,
|
||||||
|
and_stack: and_stack,
|
||||||
|
state_stack: vec![]
|
||||||
|
};
|
||||||
|
|
||||||
|
let cell_ref = viewer.cell_ref_from_addr(addr);
|
||||||
|
let view = viewer.follow(cell_ref);
|
||||||
|
|
||||||
|
viewer.state_stack.push(CellRef::View(view));
|
||||||
|
|
||||||
|
viewer
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove_token(&mut self, loc: usize) {
|
||||||
|
self.state_stack[loc] = CellRef::TToken(TToken::Nothing);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn peek(&mut self) -> Option<CellView<'a>> {
|
||||||
|
let len = self.state_stack.len();
|
||||||
|
|
||||||
|
if len > 0 {
|
||||||
|
let last_elt = self.state_stack.pop().unwrap();
|
||||||
|
let cell_view = self.follow(last_elt);
|
||||||
|
|
||||||
|
self.state_stack.truncate(len - 1);
|
||||||
|
self.state_stack.push(last_elt);
|
||||||
|
|
||||||
|
Some(cell_view)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_heap(&mut self, mut focus: usize) -> CellView<'a> {
|
||||||
|
loop {
|
||||||
|
match &self.heap[focus] {
|
||||||
|
&HeapCellValue::Con(ref c) =>
|
||||||
|
return CellView::Con(c),
|
||||||
|
&HeapCellValue::Lis(a) => {
|
||||||
|
self.state_stack.push(CellRef::TToken(TToken::RSBracket));
|
||||||
|
|
||||||
|
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) => {
|
||||||
|
self.state_stack.push(CellRef::TToken(TToken::RRBracket));
|
||||||
|
|
||||||
|
for i in (2 .. arity + 1).rev() {
|
||||||
|
self.state_stack.push(CellRef::Redirect(focus + i));
|
||||||
|
self.state_stack.push(CellRef::TToken(TToken::Comma));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.state_stack.push(CellRef::Redirect(focus + 1));
|
||||||
|
self.state_stack.push(CellRef::TToken(TToken::LRBracket));
|
||||||
|
|
||||||
|
return CellView::Str(arity, name);
|
||||||
|
},
|
||||||
|
&HeapCellValue::Ref(Ref::HeapCell(hc)) => {
|
||||||
|
if focus == hc {
|
||||||
|
return CellView::HeapVar(hc);
|
||||||
|
} else {
|
||||||
|
focus = hc;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
&HeapCellValue::Ref(Ref::StackCell(fr, sc)) => {
|
||||||
|
match self.cell_ref_from_addr(&self.and_stack[fr][sc]) {
|
||||||
|
CellRef::View(cell_view) => return cell_view,
|
||||||
|
CellRef::Redirect(hc) => focus = hc,
|
||||||
|
CellRef::TToken(token) => return CellView::TToken(token)
|
||||||
|
};
|
||||||
|
},
|
||||||
|
&HeapCellValue::Str(cell_num) =>
|
||||||
|
focus = cell_num,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn follow(&mut self, cell_ref: CellRef<'a>) -> CellView<'a>
|
||||||
|
{
|
||||||
|
match cell_ref {
|
||||||
|
CellRef::Redirect(hc) =>
|
||||||
|
self.from_heap(hc),
|
||||||
|
CellRef::View(cell_view) =>
|
||||||
|
cell_view,
|
||||||
|
CellRef::TToken(term_token) =>
|
||||||
|
CellView::TToken(term_token)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl<'a> Iterator for HeapCellViewer<'a> {
|
||||||
|
type Item = CellView<'a>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
if let Some(cell_ref) = self.state_stack.pop() {
|
||||||
|
Some(self.follow(cell_ref))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
290
src/prolog/io.rs
Normal file
290
src/prolog/io.rs
Normal file
@@ -0,0 +1,290 @@
|
|||||||
|
use prolog::ast::*;
|
||||||
|
use prolog::codegen::*;
|
||||||
|
use prolog::prolog_parser::*;
|
||||||
|
use prolog::machine::*;
|
||||||
|
|
||||||
|
use termion::raw::IntoRawMode;
|
||||||
|
use termion::input::TermRead;
|
||||||
|
use termion::event::Key;
|
||||||
|
|
||||||
|
use std::io::{Write, stdin, stdout};
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
impl fmt::Display for Constant {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
&Constant::Atom(ref atom) =>
|
||||||
|
write!(f, "{}", atom),
|
||||||
|
&Constant::EmptyList =>
|
||||||
|
write!(f, "[]")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for FactInstruction {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
&FactInstruction::GetConstant(Level::Shallow, ref constant, ref r) =>
|
||||||
|
write!(f, "get_constant {}, A{}", constant, r.reg_num()),
|
||||||
|
&FactInstruction::GetConstant(Level::Deep, ref constant, ref r) =>
|
||||||
|
write!(f, "get_constant {}, {}", constant, r),
|
||||||
|
&FactInstruction::GetList(Level::Shallow, ref r) =>
|
||||||
|
write!(f, "get_list A{}", r.reg_num()),
|
||||||
|
&FactInstruction::GetList(Level::Deep, ref r) =>
|
||||||
|
write!(f, "get_list {}", r),
|
||||||
|
&FactInstruction::GetStructure(Level::Deep, ref name, ref arity, ref r) =>
|
||||||
|
write!(f, "get_structure {}/{}, {}", name, arity, r),
|
||||||
|
&FactInstruction::GetStructure(Level::Shallow, ref name, ref arity, ref r) =>
|
||||||
|
write!(f, "get_structure {}/{}, A{}", name, arity, r.reg_num()),
|
||||||
|
&FactInstruction::GetValue(ref x, ref a) =>
|
||||||
|
write!(f, "get_value {}, A{}", x, a),
|
||||||
|
&FactInstruction::GetVariable(ref x, ref a) =>
|
||||||
|
write!(f, "get_variable {}, A{}", x, a),
|
||||||
|
&FactInstruction::UnifyConstant(ref constant) =>
|
||||||
|
write!(f, "unify_constant {}", constant),
|
||||||
|
&FactInstruction::UnifyVariable(ref r) =>
|
||||||
|
write!(f, "unify_variable {}", r),
|
||||||
|
&FactInstruction::UnifyValue(ref r) =>
|
||||||
|
write!(f, "unify_value {}", r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for QueryInstruction {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
&QueryInstruction::PutConstant(Level::Shallow, ref constant, ref r) =>
|
||||||
|
write!(f, "put_constant {}, A{}", constant, r.reg_num()),
|
||||||
|
&QueryInstruction::PutConstant(Level::Deep, ref constant, ref r) =>
|
||||||
|
write!(f, "put_constant {}, {}", constant, r),
|
||||||
|
&QueryInstruction::PutList(Level::Shallow, ref r) =>
|
||||||
|
write!(f, "put_list A{}", r.reg_num()),
|
||||||
|
&QueryInstruction::PutList(Level::Deep, ref r) =>
|
||||||
|
write!(f, "put_list {}", r),
|
||||||
|
&QueryInstruction::PutStructure(Level::Deep, ref name, ref arity, ref r) =>
|
||||||
|
write!(f, "put_structure {}/{}, {}", name, arity, r),
|
||||||
|
&QueryInstruction::PutStructure(Level::Shallow, ref name, ref arity, ref r) =>
|
||||||
|
write!(f, "put_structure {}/{}, A{}", name, arity, r.reg_num()),
|
||||||
|
&QueryInstruction::PutValue(ref x, ref a) =>
|
||||||
|
write!(f, "put_value {}, A{}", x, a),
|
||||||
|
&QueryInstruction::PutVariable(ref x, ref a) =>
|
||||||
|
write!(f, "put_variable {}, A{}", x, a),
|
||||||
|
&QueryInstruction::SetConstant(ref constant) =>
|
||||||
|
write!(f, "set_constant {}", constant),
|
||||||
|
&QueryInstruction::SetVariable(ref r) =>
|
||||||
|
write!(f, "set_variable {}", r),
|
||||||
|
&QueryInstruction::SetValue(ref r) =>
|
||||||
|
write!(f, "set_value {}", r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ControlInstruction {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
&ControlInstruction::Allocate(num_cells) =>
|
||||||
|
write!(f, "allocate {}", num_cells),
|
||||||
|
&ControlInstruction::Call(ref name, ref arity) =>
|
||||||
|
write!(f, "call {}/{}", name, arity),
|
||||||
|
&ControlInstruction::Deallocate =>
|
||||||
|
write!(f, "deallocate"),
|
||||||
|
&ControlInstruction::Proceed =>
|
||||||
|
write!(f, "proceed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ChoiceInstruction {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
&ChoiceInstruction::TryMeElse(offset) =>
|
||||||
|
write!(f, "try_me_else {}", offset),
|
||||||
|
&ChoiceInstruction::RetryMeElse(offset) =>
|
||||||
|
write!(f, "retry_me_else {}", offset),
|
||||||
|
&ChoiceInstruction::TrustMe =>
|
||||||
|
write!(f, "trust_me")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Level {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
&Level::Shallow => write!(f, "A"),
|
||||||
|
&Level::Deep => write!(f, "X")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for VarReg {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
&VarReg::Norm(RegType::Perm(reg)) => write!(f, "Y{}", reg),
|
||||||
|
&VarReg::Norm(RegType::Temp(reg)) => write!(f, "X{}", reg),
|
||||||
|
&VarReg::ArgAndNorm(RegType::Perm(reg), arg) =>
|
||||||
|
write!(f, "Y{} A{}", reg, arg),
|
||||||
|
&VarReg::ArgAndNorm(RegType::Temp(reg), arg) =>
|
||||||
|
write!(f, "X{} A{}", reg, arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for RegType {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
&RegType::Perm(val) => write!(f, "Y{}", val),
|
||||||
|
&RegType::Temp(val) => write!(f, "X{}", val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn is_consistent(predicate: &Vec<PredicateClause>) -> bool {
|
||||||
|
let name = predicate.first().unwrap().name();
|
||||||
|
let arity = predicate.first().unwrap().arity();
|
||||||
|
|
||||||
|
for clause in predicate.iter().skip(1) {
|
||||||
|
if !(name == clause.name() && arity == clause.arity()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn print_code(code: &Code) {
|
||||||
|
for clause in code {
|
||||||
|
match clause {
|
||||||
|
&Line::Fact(ref fact) =>
|
||||||
|
for fact_instr in fact {
|
||||||
|
println!("{}", fact_instr);
|
||||||
|
},
|
||||||
|
&Line::Choice(ref choice) =>
|
||||||
|
println!("{}", choice),
|
||||||
|
&Line::Control(ref control) =>
|
||||||
|
println!("{}", control),
|
||||||
|
&Line::Query(ref query) =>
|
||||||
|
for query_instr in query {
|
||||||
|
println!("{}", query_instr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read() -> String {
|
||||||
|
let _ = stdout().flush();
|
||||||
|
|
||||||
|
let mut buffer = String::new();
|
||||||
|
let mut result = String::new();
|
||||||
|
|
||||||
|
let stdin = stdin();
|
||||||
|
stdin.read_line(&mut buffer).unwrap();
|
||||||
|
|
||||||
|
if &*buffer.trim() == ":{" {
|
||||||
|
buffer.clear();
|
||||||
|
|
||||||
|
stdin.read_line(&mut buffer).unwrap();
|
||||||
|
|
||||||
|
while &*buffer.trim() != "}:" {
|
||||||
|
result += buffer.as_str();
|
||||||
|
buffer.clear();
|
||||||
|
stdin.read_line(&mut buffer).unwrap();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result = buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn eval(wam: &mut Machine, buffer: &str) -> EvalResult
|
||||||
|
{
|
||||||
|
let result = parse_TopLevel(buffer);
|
||||||
|
let mut cg = CodeGenerator::new();
|
||||||
|
|
||||||
|
match &result {
|
||||||
|
&Ok(TopLevel::Predicate(ref clauses)) => {
|
||||||
|
if is_consistent(clauses) {
|
||||||
|
let compiled_pred = cg.compile_predicate(clauses);
|
||||||
|
wam.add_predicate(clauses, compiled_pred);
|
||||||
|
|
||||||
|
EvalResult::EntrySuccess
|
||||||
|
} else {
|
||||||
|
let msg = r"Error: predicate is inconsistent.
|
||||||
|
Each predicate must have the same name and arity.";
|
||||||
|
|
||||||
|
println!("{}", msg);
|
||||||
|
EvalResult::EntryFailure
|
||||||
|
}
|
||||||
|
},
|
||||||
|
&Ok(TopLevel::Fact(ref fact)) => {
|
||||||
|
let compiled_fact = cg.compile_fact(&fact);
|
||||||
|
wam.add_fact(fact, compiled_fact);
|
||||||
|
EvalResult::EntrySuccess
|
||||||
|
},
|
||||||
|
&Ok(TopLevel::Rule(ref rule)) => {
|
||||||
|
let compiled_rule = cg.compile_rule(&rule);
|
||||||
|
wam.add_rule(rule, compiled_rule);
|
||||||
|
EvalResult::EntrySuccess
|
||||||
|
},
|
||||||
|
&Ok(TopLevel::Query(ref query)) => {
|
||||||
|
let compiled_query = cg.compile_query(&query);
|
||||||
|
wam.run_query(compiled_query, &cg)
|
||||||
|
},
|
||||||
|
&Err(_) => {
|
||||||
|
println!("Grammatical error of some kind!");
|
||||||
|
EvalResult::EntryFailure
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn print(wam: &mut Machine, result: EvalResult) {
|
||||||
|
match result {
|
||||||
|
EvalResult::InitialQuerySuccess(heap_locs) => {
|
||||||
|
println!("yes");
|
||||||
|
|
||||||
|
if heap_locs.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
'outer: loop {
|
||||||
|
let mut result = EvalResult::QueryFailure;
|
||||||
|
let bindings = wam.heap_view(&heap_locs);
|
||||||
|
|
||||||
|
let stdin = stdin();
|
||||||
|
let mut stdout = stdout().into_raw_mode().unwrap();
|
||||||
|
|
||||||
|
write!(stdout, "{}\n\r", bindings).unwrap();
|
||||||
|
stdout.flush().unwrap();
|
||||||
|
|
||||||
|
if !wam.or_stack_is_empty() {
|
||||||
|
write!(stdout, "Press ; to continue or . to abort.\n\r").unwrap();
|
||||||
|
stdout.flush().unwrap();
|
||||||
|
|
||||||
|
for c in stdin.keys() {
|
||||||
|
match c.unwrap() {
|
||||||
|
Key::Char(';') => {
|
||||||
|
result = wam.continue_query();
|
||||||
|
break;
|
||||||
|
},
|
||||||
|
Key::Char('.') =>
|
||||||
|
break 'outer,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if let &EvalResult::QueryFailure = &result {
|
||||||
|
write!(stdout, "no\n\r").unwrap();
|
||||||
|
stdout.flush().unwrap();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
EvalResult::QueryFailure => println!("no"),
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
}
|
||||||
209
src/prolog/iterators.rs
Normal file
209
src/prolog/iterators.rs
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
use prolog::ast::*;
|
||||||
|
|
||||||
|
use std::cell::Cell;
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
use std::vec::Vec;
|
||||||
|
|
||||||
|
enum IteratorState<'a> {
|
||||||
|
AnonVar(Level),
|
||||||
|
Clause(Level, usize, &'a Cell<RegType>, &'a Atom, &'a Vec<Box<Term>>),
|
||||||
|
Constant(Level, &'a Cell<RegType>, &'a Constant),
|
||||||
|
InitialCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
|
||||||
|
FinalCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
|
||||||
|
RootClause(usize, &'a Vec<Box<Term>>),
|
||||||
|
Var(Level, &'a Cell<VarReg>, &'a Var)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> IteratorState<'a> {
|
||||||
|
fn to_state(lvl: Level, term: &'a Term) -> IteratorState<'a> {
|
||||||
|
match term {
|
||||||
|
&Term::AnonVar =>
|
||||||
|
IteratorState::AnonVar(lvl),
|
||||||
|
&Term::Clause(ref cell, ref atom, ref child_terms) =>
|
||||||
|
IteratorState::Clause(lvl, 0, cell, atom, child_terms),
|
||||||
|
&Term::Cons(ref cell, ref head, ref tail) =>
|
||||||
|
IteratorState::InitialCons(lvl, cell, head.as_ref(), tail.as_ref()),
|
||||||
|
&Term::Constant(ref cell, ref constant) =>
|
||||||
|
IteratorState::Constant(lvl, cell, constant),
|
||||||
|
&Term::Var(ref cell, ref var) =>
|
||||||
|
IteratorState::Var(lvl, cell, var)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct QueryIterator<'a> {
|
||||||
|
state_stack: Vec<IteratorState<'a>>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> QueryIterator<'a> {
|
||||||
|
fn push_clause(&mut self,
|
||||||
|
lvl: Level,
|
||||||
|
child_num: usize,
|
||||||
|
cell: &'a Cell<RegType>,
|
||||||
|
name: &'a Atom,
|
||||||
|
child_terms: &'a Vec<Box<Term>>)
|
||||||
|
{
|
||||||
|
self.state_stack.push(IteratorState::Clause(lvl,
|
||||||
|
child_num,
|
||||||
|
cell,
|
||||||
|
name,
|
||||||
|
child_terms));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_root_clause(&mut self,
|
||||||
|
child_num: usize,
|
||||||
|
child_terms: &'a Vec<Box<Term>>)
|
||||||
|
{
|
||||||
|
self.state_stack.push(IteratorState::RootClause(child_num, child_terms));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
|
||||||
|
self.state_stack.push(IteratorState::to_state(lvl, term));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_final_cons(&mut self,
|
||||||
|
lvl: Level,
|
||||||
|
cell: &'a Cell<RegType>,
|
||||||
|
head: &'a Term,
|
||||||
|
tail: &'a Term)
|
||||||
|
{
|
||||||
|
self.state_stack.push(IteratorState::FinalCons(lvl, cell, head, tail));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new(term: &'a Term) -> QueryIterator<'a> {
|
||||||
|
let state = match term {
|
||||||
|
&Term::AnonVar =>
|
||||||
|
IteratorState::AnonVar(Level::Shallow),
|
||||||
|
&Term::Clause(_, _, ref terms) =>
|
||||||
|
IteratorState::RootClause(0, terms),
|
||||||
|
&Term::Cons(ref cell, ref head, ref tail) =>
|
||||||
|
IteratorState::InitialCons(Level::Shallow, cell, head.as_ref(), tail.as_ref()),
|
||||||
|
&Term::Constant(ref cell, ref constant) =>
|
||||||
|
IteratorState::Constant(Level::Shallow, cell, constant),
|
||||||
|
&Term::Var(ref cell, ref var) =>
|
||||||
|
IteratorState::Var(Level::Shallow, cell, var)
|
||||||
|
};
|
||||||
|
|
||||||
|
QueryIterator { state_stack: vec![state] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for QueryIterator<'a> {
|
||||||
|
type Item = TermRef<'a>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
while let Some(iter_state) = self.state_stack.pop() {
|
||||||
|
match iter_state {
|
||||||
|
IteratorState::AnonVar(lvl) =>
|
||||||
|
return Some(TermRef::AnonVar(lvl)),
|
||||||
|
IteratorState::Clause(lvl, child_num, cell, atom, child_terms) => {
|
||||||
|
if child_num == child_terms.len() {
|
||||||
|
return Some(TermRef::Clause(lvl, cell, atom, child_terms));
|
||||||
|
} else {
|
||||||
|
self.push_clause(lvl, child_num + 1, cell, atom, child_terms);
|
||||||
|
self.push_subterm(Level::Deep, child_terms[child_num].as_ref());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
IteratorState::InitialCons(lvl, cell, head, tail) => {
|
||||||
|
self.push_final_cons(lvl, cell, head, tail);
|
||||||
|
self.push_subterm(Level::Deep, head);
|
||||||
|
self.push_subterm(Level::Deep, tail);
|
||||||
|
},
|
||||||
|
IteratorState::FinalCons(lvl, cell, head, tail) =>
|
||||||
|
return Some(TermRef::Cons(lvl, cell, head, tail)),
|
||||||
|
IteratorState::Constant(lvl, cell, constant) =>
|
||||||
|
return Some(TermRef::Constant(lvl, cell, constant)),
|
||||||
|
IteratorState::RootClause(child_num, child_terms) => {
|
||||||
|
if child_num == child_terms.len() {
|
||||||
|
return None;
|
||||||
|
} else {
|
||||||
|
self.push_root_clause(child_num + 1, child_terms);
|
||||||
|
self.push_subterm(Level::Shallow, child_terms[child_num].as_ref());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
IteratorState::Var(lvl, cell, var) =>
|
||||||
|
return Some(TermRef::Var(lvl, cell, var))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct FactIterator<'a> {
|
||||||
|
state_queue: VecDeque<IteratorState<'a>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> FactIterator<'a> {
|
||||||
|
fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
|
||||||
|
self.state_queue.push_back(IteratorState::to_state(lvl, term));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new(term: &'a Term) -> FactIterator<'a> {
|
||||||
|
let states = match term {
|
||||||
|
&Term::AnonVar =>
|
||||||
|
vec![IteratorState::AnonVar(Level::Shallow)],
|
||||||
|
&Term::Clause(_, _, ref terms) =>
|
||||||
|
vec![IteratorState::RootClause(0, terms)],
|
||||||
|
&Term::Cons(ref cell, ref head, ref tail) =>
|
||||||
|
vec![IteratorState::InitialCons(Level::Shallow,
|
||||||
|
cell,
|
||||||
|
head.as_ref(),
|
||||||
|
tail.as_ref())],
|
||||||
|
&Term::Constant(ref cell, ref constant) =>
|
||||||
|
vec![IteratorState::Constant(Level::Shallow, cell, constant)],
|
||||||
|
&Term::Var(ref cell, ref var) =>
|
||||||
|
vec![IteratorState::Var(Level::Shallow, cell, var)]
|
||||||
|
};
|
||||||
|
|
||||||
|
FactIterator { state_queue: VecDeque::from(states) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for FactIterator<'a> {
|
||||||
|
type Item = TermRef<'a>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
while let Some(state) = self.state_queue.pop_front() {
|
||||||
|
match state {
|
||||||
|
IteratorState::AnonVar(lvl) =>
|
||||||
|
return Some(TermRef::AnonVar(lvl)),
|
||||||
|
IteratorState::Clause(lvl, _, cell, atom, child_terms) => {
|
||||||
|
for child_term in child_terms {
|
||||||
|
self.push_subterm(Level::Deep, child_term);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Some(TermRef::Clause(lvl, cell, atom, child_terms));
|
||||||
|
},
|
||||||
|
IteratorState::InitialCons(lvl, cell, head, tail) => {
|
||||||
|
self.push_subterm(Level::Deep, head);
|
||||||
|
self.push_subterm(Level::Deep, tail);
|
||||||
|
|
||||||
|
return Some(TermRef::Cons(lvl, cell, head, tail));
|
||||||
|
},
|
||||||
|
IteratorState::Constant(lvl, cell, constant) =>
|
||||||
|
return Some(TermRef::Constant(lvl, cell, constant)),
|
||||||
|
IteratorState::RootClause(_, child_terms) => {
|
||||||
|
for child_term in child_terms {
|
||||||
|
self.push_subterm(Level::Shallow, child_term);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
IteratorState::Var(lvl, cell, var) =>
|
||||||
|
return Some(TermRef::Var(lvl, cell, var)),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Term {
|
||||||
|
pub fn post_order_iter(&self) -> QueryIterator {
|
||||||
|
QueryIterator::new(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn breadth_first_iter(&self) -> FactIterator {
|
||||||
|
FactIterator::new(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
784
src/prolog/machine.rs
Normal file
784
src/prolog/machine.rs
Normal file
@@ -0,0 +1,784 @@
|
|||||||
|
use prolog::ast::*;
|
||||||
|
use prolog::codegen::*;
|
||||||
|
use prolog::heapview::*;
|
||||||
|
use prolog::and_stack::*;
|
||||||
|
use prolog::or_stack::*;
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::ops::{Index, IndexMut};
|
||||||
|
use std::vec::Vec;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
enum MachineMode {
|
||||||
|
Read,
|
||||||
|
Write
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MachineState {
|
||||||
|
h: usize,
|
||||||
|
s: usize,
|
||||||
|
p: CodePtr,
|
||||||
|
b: usize,
|
||||||
|
e: usize,
|
||||||
|
num_of_args: usize,
|
||||||
|
cp: CodePtr,
|
||||||
|
fail: bool,
|
||||||
|
heap: Heap,
|
||||||
|
mode: MachineMode,
|
||||||
|
and_stack: AndStack,
|
||||||
|
or_stack: OrStack,
|
||||||
|
registers: Registers,
|
||||||
|
trail: Vec<Ref>,
|
||||||
|
tr: usize,
|
||||||
|
hb: usize
|
||||||
|
}
|
||||||
|
|
||||||
|
type CodeDir = HashMap<(Atom, usize), usize>;
|
||||||
|
|
||||||
|
pub struct Machine {
|
||||||
|
ms: MachineState,
|
||||||
|
code: Code,
|
||||||
|
code_dir: CodeDir
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Index<RegType> for MachineState {
|
||||||
|
type Output = Addr;
|
||||||
|
|
||||||
|
fn index(&self, reg: RegType) -> &Self::Output {
|
||||||
|
match reg {
|
||||||
|
RegType::Temp(temp) => &self.registers[temp],
|
||||||
|
RegType::Perm(perm) => {
|
||||||
|
let e = self.e;
|
||||||
|
&self.and_stack[e][perm]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IndexMut<RegType> for MachineState {
|
||||||
|
fn index_mut(&mut self, reg: RegType) -> &mut Self::Output {
|
||||||
|
match reg {
|
||||||
|
RegType::Temp(temp) => &mut self.registers[temp],
|
||||||
|
RegType::Perm(perm) => {
|
||||||
|
let e = self.e;
|
||||||
|
&mut self.and_stack[e][perm]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Machine {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Machine {
|
||||||
|
ms: MachineState::new(),
|
||||||
|
code: Vec::new(),
|
||||||
|
code_dir: HashMap::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn failed(&self) -> bool {
|
||||||
|
self.ms.fail
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_fact(&mut self, fact: &Term, mut code: Code) {
|
||||||
|
if fact.name().is_some() {
|
||||||
|
let p = self.code.len();
|
||||||
|
let name = fact.name().unwrap().clone();
|
||||||
|
let arity = fact.arity();
|
||||||
|
|
||||||
|
self.code.append(&mut code);
|
||||||
|
self.code_dir.insert((name, arity), p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_rule(&mut self, rule: &Rule, mut code: Code) {
|
||||||
|
if rule.head.0.name().is_some() {
|
||||||
|
let p = self.code.len();
|
||||||
|
let name = rule.head.0.name().unwrap().clone();
|
||||||
|
let arity = rule.head.0.arity();
|
||||||
|
|
||||||
|
self.code.append(&mut code);
|
||||||
|
self.code_dir.insert((name, arity), p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_predicate(&mut self, pred: &Vec<PredicateClause>, mut code: Code)
|
||||||
|
{
|
||||||
|
let p = self.code.len();
|
||||||
|
let name = pred.first().unwrap().name().clone();
|
||||||
|
let arity = pred.first().unwrap().arity();
|
||||||
|
|
||||||
|
self.code.append(&mut code);
|
||||||
|
self.code_dir.insert((name, arity), p);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn execute_instr<'a>(&mut self, instr_src: LineOrCodeOffset<'a>) -> bool
|
||||||
|
{
|
||||||
|
let mut instr = match instr_src {
|
||||||
|
LineOrCodeOffset::Instruction(instr) => instr,
|
||||||
|
LineOrCodeOffset::Offset(p) => &self.code[p]
|
||||||
|
};
|
||||||
|
|
||||||
|
loop {
|
||||||
|
match instr {
|
||||||
|
&Line::Choice(ref choice_instr) =>
|
||||||
|
self.ms.execute_choice_instr(choice_instr),
|
||||||
|
&Line::Fact(ref fact) => {
|
||||||
|
for fact_instr in fact {
|
||||||
|
if self.failed() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.ms.execute_fact_instr(&fact_instr);
|
||||||
|
}
|
||||||
|
self.ms.p += 1;
|
||||||
|
},
|
||||||
|
&Line::Query(ref query) => {
|
||||||
|
for query_instr in query {
|
||||||
|
if self.failed() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.ms.execute_query_instr(&query_instr);
|
||||||
|
}
|
||||||
|
self.ms.p += 1;
|
||||||
|
},
|
||||||
|
&Line::Control(ref control_instr) =>
|
||||||
|
self.ms.execute_ctrl_instr(&self.code_dir, control_instr),
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.failed() {
|
||||||
|
let p = self.ms
|
||||||
|
.or_stack
|
||||||
|
.top()
|
||||||
|
.map(|fr| fr.bp)
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
if let CodePtr::TopLevel = p {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
self.ms.fail = false;
|
||||||
|
self.ms.p = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match self.ms.p {
|
||||||
|
CodePtr::DirEntry(p) if p < self.code.len() =>
|
||||||
|
instr = &self.code[p],
|
||||||
|
_ => break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn heap_view(&self, var_dir: &HeapVarDict) -> String {
|
||||||
|
let mut result = String::new();
|
||||||
|
|
||||||
|
for (var, addr) in var_dir {
|
||||||
|
let mut viewer = HeapCellViewer::new(&self.ms.heap,
|
||||||
|
&self.ms.and_stack,
|
||||||
|
addr);
|
||||||
|
|
||||||
|
if result != "" {
|
||||||
|
result += "\n\r";
|
||||||
|
}
|
||||||
|
|
||||||
|
result += var.as_str();
|
||||||
|
result += " = ";
|
||||||
|
|
||||||
|
while let Some(view) = viewer.next() {
|
||||||
|
match view {
|
||||||
|
CellView::Con(&Constant::EmptyList) =>
|
||||||
|
result += "[]",
|
||||||
|
CellView::Con(&Constant::Atom(ref atom)) =>
|
||||||
|
result += atom.as_str(),
|
||||||
|
CellView::HeapVar(cell_num) => {
|
||||||
|
result += "_";
|
||||||
|
result += cell_num.to_string().as_str();
|
||||||
|
},
|
||||||
|
CellView::StackVar(fr, sc) => {
|
||||||
|
result += "_";
|
||||||
|
result += fr.to_string().as_str();
|
||||||
|
result += "_";
|
||||||
|
result += sc.to_string().as_str();
|
||||||
|
},
|
||||||
|
CellView::Str(_, ref name) =>
|
||||||
|
result += name.as_str(),
|
||||||
|
CellView::TToken(TToken::Bar) => {
|
||||||
|
match viewer.peek() {
|
||||||
|
Some(CellView::Con(&Constant::EmptyList)) => {
|
||||||
|
viewer.next();
|
||||||
|
},
|
||||||
|
Some(CellView::TToken(TToken::LSBracket(loc))) => {
|
||||||
|
result += ", ";
|
||||||
|
|
||||||
|
viewer.next();
|
||||||
|
viewer.remove_token(loc);
|
||||||
|
},
|
||||||
|
_ => result += " | "
|
||||||
|
};
|
||||||
|
},
|
||||||
|
CellView::TToken(token) =>
|
||||||
|
result += token.as_str()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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, vr) in cg.vars() {
|
||||||
|
let addr = self.ms.registers[vr.root_register()].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 {
|
||||||
|
self.ms.or_stack.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn continue_query(&mut self) -> EvalResult
|
||||||
|
{
|
||||||
|
if !self.or_stack_is_empty() {
|
||||||
|
let b = self.ms.b;
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reset(&mut self) {
|
||||||
|
self.ms.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MachineState {
|
||||||
|
fn new() -> MachineState {
|
||||||
|
MachineState { h: 0,
|
||||||
|
s: 0,
|
||||||
|
p: CodePtr::TopLevel,
|
||||||
|
b: 0,
|
||||||
|
e: 0,
|
||||||
|
num_of_args: 0,
|
||||||
|
cp: CodePtr::TopLevel,
|
||||||
|
fail: false,
|
||||||
|
heap: Vec::with_capacity(256),
|
||||||
|
mode: MachineMode::Write,
|
||||||
|
and_stack: AndStack::new(),
|
||||||
|
or_stack: OrStack::new(),
|
||||||
|
registers: vec![Addr::HeapCell(0); 64],
|
||||||
|
trail: Vec::new(),
|
||||||
|
tr: 0,
|
||||||
|
hb: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn num_frames(&self) -> usize {
|
||||||
|
self.and_stack.len() + self.or_stack.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn store(&self, a: Addr) -> Addr {
|
||||||
|
match a {
|
||||||
|
Addr::HeapCell(r) => self.heap[r].as_addr(r),
|
||||||
|
Addr::StackCell(fr, sc) => self.and_stack[fr][sc].clone(),
|
||||||
|
addr => addr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deref(&self, a: Addr) -> Addr {
|
||||||
|
let mut a = a;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let value = self.store(a.clone());
|
||||||
|
|
||||||
|
if value.is_ref() && value != a {
|
||||||
|
a = value;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return a;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bind(&mut self, r1: Ref, a2: Addr) {
|
||||||
|
let t2 = self.store(a2);
|
||||||
|
|
||||||
|
match r1 {
|
||||||
|
Ref::StackCell(fr, sc) =>
|
||||||
|
self.and_stack[fr][sc] = t2,
|
||||||
|
Ref::HeapCell(hc) =>
|
||||||
|
self.heap[hc] = HeapCellValue::from(t2)
|
||||||
|
};
|
||||||
|
|
||||||
|
self.trail(r1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unify(&mut self, a1: Addr, a2: Addr) {
|
||||||
|
let mut pdl = vec![a1, a2];
|
||||||
|
|
||||||
|
self.fail = false;
|
||||||
|
|
||||||
|
while !(pdl.is_empty() || self.fail) {
|
||||||
|
let d1 = self.deref(pdl.pop().unwrap());
|
||||||
|
let d2 = self.deref(pdl.pop().unwrap());
|
||||||
|
|
||||||
|
if d1 != d2 {
|
||||||
|
match (self.store(d1.clone()), self.store(d2.clone())) {
|
||||||
|
(Addr::HeapCell(hc), _) =>
|
||||||
|
self.bind(Ref::HeapCell(hc), d2),
|
||||||
|
(_, Addr::HeapCell(hc)) =>
|
||||||
|
self.bind(Ref::HeapCell(hc), d1),
|
||||||
|
(Addr::StackCell(fr, sc), _) =>
|
||||||
|
self.bind(Ref::StackCell(fr, sc), d2),
|
||||||
|
(_, Addr::StackCell(fr, sc)) =>
|
||||||
|
self.bind(Ref::StackCell(fr, sc), d1),
|
||||||
|
(Addr::Lis(a1), Addr::Lis(a2)) => {
|
||||||
|
pdl.push(Addr::HeapCell(a1));
|
||||||
|
pdl.push(Addr::HeapCell(a2));
|
||||||
|
|
||||||
|
pdl.push(Addr::HeapCell(a1 + 1));
|
||||||
|
pdl.push(Addr::HeapCell(a2 + 1));
|
||||||
|
},
|
||||||
|
(Addr::Con(c1), Addr::Con(c2)) => {
|
||||||
|
if c1 != c2 {
|
||||||
|
self.fail = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(Addr::Str(a1), Addr::Str(a2)) => {
|
||||||
|
let r1 = &self.heap[a1];
|
||||||
|
let r2 = &self.heap[a2];
|
||||||
|
|
||||||
|
if let &HeapCellValue::NamedStr(n1, ref f1) = r1 {
|
||||||
|
if let &HeapCellValue::NamedStr(n2, ref f2) = r2 {
|
||||||
|
if n1 == n2 && *f1 == *f2 {
|
||||||
|
for i in 1 .. n1 + 1 {
|
||||||
|
pdl.push(Addr::HeapCell(a1 + i));
|
||||||
|
pdl.push(Addr::HeapCell(a2 + i));
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.fail = true;
|
||||||
|
},
|
||||||
|
_ => self.fail = true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn trail(&mut self, r: Ref) {
|
||||||
|
match r {
|
||||||
|
Ref::HeapCell(hc) => {
|
||||||
|
if hc < self.hb {
|
||||||
|
self.trail.push(r);
|
||||||
|
self.tr += 1;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Ref::StackCell(fr, _) => {
|
||||||
|
let fr_gi = self.and_stack[fr].global_index;
|
||||||
|
let b_gi = if !self.or_stack.is_empty() {
|
||||||
|
self.or_stack[self.b].global_index
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
if fr_gi < b_gi {
|
||||||
|
self.trail.push(r);
|
||||||
|
self.tr += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unwind_trail(&mut self, a1: usize, a2: usize) {
|
||||||
|
for i in a1 .. a2 {
|
||||||
|
match self.trail[i] {
|
||||||
|
Ref::HeapCell(r) =>
|
||||||
|
self.heap[r] = HeapCellValue::Ref(Ref::HeapCell(r)),
|
||||||
|
Ref::StackCell(fr, sc) =>
|
||||||
|
self.and_stack[fr][sc] = Addr::StackCell(fr, sc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn execute_fact_instr(&mut self, instr: &FactInstruction) {
|
||||||
|
match instr {
|
||||||
|
&FactInstruction::GetConstant(_, ref constant, reg) => {
|
||||||
|
let addr = self.deref(self[reg].clone());
|
||||||
|
|
||||||
|
match self.store(addr) {
|
||||||
|
Addr::HeapCell(hc) => {
|
||||||
|
self.heap[hc] = HeapCellValue::Con(constant.clone());
|
||||||
|
self.trail(Ref::HeapCell(hc));
|
||||||
|
},
|
||||||
|
Addr::StackCell(fr, sc) => {
|
||||||
|
self.and_stack[fr][sc] = Addr::Con(constant.clone());
|
||||||
|
self.trail(Ref::StackCell(fr, sc));
|
||||||
|
},
|
||||||
|
Addr::Con(c) => {
|
||||||
|
if c != *constant {
|
||||||
|
self.fail = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => self.fail = true
|
||||||
|
};
|
||||||
|
},
|
||||||
|
&FactInstruction::GetList(_, reg) => {
|
||||||
|
let addr = self.deref(self[reg].clone());
|
||||||
|
|
||||||
|
match self.store(addr.clone()) {
|
||||||
|
Addr::HeapCell(hc) => {
|
||||||
|
let h = self.h;
|
||||||
|
|
||||||
|
self.heap.push(HeapCellValue::Lis(h+1));
|
||||||
|
self.bind(Ref::HeapCell(hc), Addr::HeapCell(h));
|
||||||
|
|
||||||
|
self.h += 1;
|
||||||
|
self.mode = MachineMode::Write;
|
||||||
|
},
|
||||||
|
Addr::StackCell(fr, sc) => {
|
||||||
|
let h = self.h;
|
||||||
|
|
||||||
|
self.heap.push(HeapCellValue::Lis(h+1));
|
||||||
|
self.bind(Ref::StackCell(fr, sc), Addr::HeapCell(h));
|
||||||
|
|
||||||
|
self.h += 1;
|
||||||
|
self.mode = MachineMode::Write;
|
||||||
|
},
|
||||||
|
Addr::Lis(a) => {
|
||||||
|
self.s = a;
|
||||||
|
self.mode = MachineMode::Read;
|
||||||
|
},
|
||||||
|
_ => self.fail = true
|
||||||
|
};
|
||||||
|
},
|
||||||
|
&FactInstruction::GetStructure(_, ref name, arity, reg) => {
|
||||||
|
let addr = self.deref(self[reg].clone());
|
||||||
|
|
||||||
|
match self.store(addr.clone()) {
|
||||||
|
Addr::Str(a) => {
|
||||||
|
let result = &self.heap[a];
|
||||||
|
|
||||||
|
if let &HeapCellValue::NamedStr(narity, ref str) = result {
|
||||||
|
if narity == arity && *name == *str {
|
||||||
|
self.s = a + 1;
|
||||||
|
self.mode = MachineMode::Read;
|
||||||
|
} else {
|
||||||
|
self.fail = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Addr::HeapCell(_) | Addr::StackCell(_, _) => {
|
||||||
|
self.heap.push(HeapCellValue::Str(self.h + 1));
|
||||||
|
self.heap.push(HeapCellValue::NamedStr(arity, name.clone()));
|
||||||
|
|
||||||
|
let h = self.h;
|
||||||
|
|
||||||
|
self.bind(addr.as_ref().unwrap(), Addr::HeapCell(h));
|
||||||
|
|
||||||
|
self.h += 2;
|
||||||
|
self.mode = MachineMode::Write;
|
||||||
|
},
|
||||||
|
_ => self.fail = true
|
||||||
|
};
|
||||||
|
},
|
||||||
|
&FactInstruction::GetVariable(norm, arg) =>
|
||||||
|
self[norm] = self.registers[arg].clone(),
|
||||||
|
&FactInstruction::GetValue(norm, arg) => {
|
||||||
|
let norm_addr = self[norm].clone();
|
||||||
|
let reg_addr = self.registers[arg].clone();
|
||||||
|
|
||||||
|
self.unify(norm_addr, reg_addr);
|
||||||
|
},
|
||||||
|
&FactInstruction::UnifyConstant(ref c) => {
|
||||||
|
match self.mode {
|
||||||
|
MachineMode::Read => {
|
||||||
|
let addr = self.deref(Addr::HeapCell(self.s));
|
||||||
|
|
||||||
|
match self.store(addr) {
|
||||||
|
Addr::HeapCell(hc) =>
|
||||||
|
self.heap[hc] = HeapCellValue::Con(c.clone()),
|
||||||
|
Addr::StackCell(fr, sc) =>
|
||||||
|
self.and_stack[fr][sc] = Addr::Con(c.clone()),
|
||||||
|
Addr::Con(c1) => {
|
||||||
|
if c1 != *c {
|
||||||
|
self.fail = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => self.fail = true
|
||||||
|
};
|
||||||
|
},
|
||||||
|
MachineMode::Write => {
|
||||||
|
self.heap.push(HeapCellValue::Con(c.clone()));
|
||||||
|
self.h += 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
&FactInstruction::UnifyVariable(reg) => {
|
||||||
|
match self.mode {
|
||||||
|
MachineMode::Read =>
|
||||||
|
self[reg] = self.heap[self.s].as_addr(self.s),
|
||||||
|
MachineMode::Write => {
|
||||||
|
let h = self.h;
|
||||||
|
|
||||||
|
self.heap.push(HeapCellValue::Ref(Ref::HeapCell(h)));
|
||||||
|
self[reg] = Addr::HeapCell(self.h);
|
||||||
|
self.h += 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.s += 1;
|
||||||
|
},
|
||||||
|
&FactInstruction::UnifyValue(reg) => {
|
||||||
|
let s = self.s;
|
||||||
|
|
||||||
|
match self.mode {
|
||||||
|
MachineMode::Read => {
|
||||||
|
let reg_addr = self[reg].clone();
|
||||||
|
self.unify(reg_addr, Addr::HeapCell(s));
|
||||||
|
},
|
||||||
|
MachineMode::Write => {
|
||||||
|
let heap_val = self.store(self[reg].clone());
|
||||||
|
self.heap.push(HeapCellValue::from(heap_val));
|
||||||
|
self.h += 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.s += 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn execute_query_instr(&mut self, instr: &QueryInstruction) {
|
||||||
|
match instr {
|
||||||
|
&QueryInstruction::PutConstant(_, ref constant, reg) =>
|
||||||
|
self[reg] = Addr::Con(constant.clone()),
|
||||||
|
&QueryInstruction::PutList(_, reg) =>
|
||||||
|
self[reg] = Addr::Lis(self.h),
|
||||||
|
&QueryInstruction::PutStructure(_, ref name, arity, reg) => {
|
||||||
|
self.heap.push(HeapCellValue::NamedStr(arity, name.clone()));
|
||||||
|
self[reg] = Addr::Str(self.h);
|
||||||
|
self.h += 1;
|
||||||
|
},
|
||||||
|
&QueryInstruction::PutValue(norm, arg) =>
|
||||||
|
self.registers[arg] = self[norm].clone(),
|
||||||
|
&QueryInstruction::PutVariable(norm, arg) => {
|
||||||
|
let h = self.h;
|
||||||
|
self.heap.push(HeapCellValue::Ref(Ref::HeapCell(h)));
|
||||||
|
|
||||||
|
self[norm] = Addr::HeapCell(h);
|
||||||
|
self.registers[arg] = Addr::HeapCell(h);
|
||||||
|
|
||||||
|
self.h += 1;
|
||||||
|
},
|
||||||
|
&QueryInstruction::SetConstant(ref constant) => {
|
||||||
|
self.heap.push(HeapCellValue::Con(constant.clone()));
|
||||||
|
self.h += 1;
|
||||||
|
},
|
||||||
|
&QueryInstruction::SetVariable(reg) => {
|
||||||
|
let h = self.h;
|
||||||
|
self.heap.push(HeapCellValue::Ref(Ref::HeapCell(h)));
|
||||||
|
self[reg] = Addr::HeapCell(h);
|
||||||
|
|
||||||
|
self.h += 1;
|
||||||
|
},
|
||||||
|
&QueryInstruction::SetValue(reg) => {
|
||||||
|
let heap_val = self[reg].clone();
|
||||||
|
self.heap.push(HeapCellValue::from(heap_val));
|
||||||
|
|
||||||
|
self.h += 1;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn execute_ctrl_instr(&mut self, code_dir: &CodeDir, instr: &ControlInstruction)
|
||||||
|
{
|
||||||
|
match instr {
|
||||||
|
&ControlInstruction::Allocate(num_cells) => {
|
||||||
|
let num_frames = self.num_frames();
|
||||||
|
|
||||||
|
self.and_stack.push(num_frames + 1, self.e, self.cp, num_cells);
|
||||||
|
|
||||||
|
self.e = self.and_stack.len() - 1;
|
||||||
|
self.p += 1;
|
||||||
|
},
|
||||||
|
&ControlInstruction::Call(ref name, arity) => {
|
||||||
|
let compiled_tl_index = code_dir.get(&(name.clone(), arity))
|
||||||
|
.map(|index| *index);
|
||||||
|
|
||||||
|
match compiled_tl_index {
|
||||||
|
Some(compiled_tl_index) => {
|
||||||
|
self.cp = self.p + 1;
|
||||||
|
self.num_of_args = arity;
|
||||||
|
self.p = CodePtr::DirEntry(compiled_tl_index);
|
||||||
|
},
|
||||||
|
None => self.fail = true
|
||||||
|
};
|
||||||
|
},
|
||||||
|
&ControlInstruction::Deallocate => {
|
||||||
|
let e = self.e;
|
||||||
|
|
||||||
|
let num_frame_e = self.and_stack.top().unwrap().global_index;
|
||||||
|
let num_frame_b = self.or_stack
|
||||||
|
.top()
|
||||||
|
.map(|fr| fr.global_index)
|
||||||
|
.unwrap_or(0);
|
||||||
|
|
||||||
|
self.p = self.and_stack[e].cp;
|
||||||
|
self.e = self.and_stack[e].e;
|
||||||
|
|
||||||
|
if num_frame_e > num_frame_b {
|
||||||
|
let top_e = self.and_stack.top().unwrap().e;
|
||||||
|
self.and_stack.drop_frames(top_e - self.e + 1);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
&ControlInstruction::Proceed =>
|
||||||
|
self.p = self.cp,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn execute_choice_instr(&mut self, instr: &ChoiceInstruction)
|
||||||
|
{
|
||||||
|
match instr {
|
||||||
|
&ChoiceInstruction::TryMeElse(offset) => {
|
||||||
|
let n = self.num_of_args;
|
||||||
|
let num_frames = self.num_frames();
|
||||||
|
|
||||||
|
self.or_stack.push(num_frames + 1,
|
||||||
|
self.e,
|
||||||
|
self.cp,
|
||||||
|
self.b,
|
||||||
|
self.p + offset,
|
||||||
|
self.tr,
|
||||||
|
self.h,
|
||||||
|
self.num_of_args);
|
||||||
|
|
||||||
|
self.b = self.or_stack.len() - 1;
|
||||||
|
let b = self.b;
|
||||||
|
|
||||||
|
for i in 1 .. n + 1 {
|
||||||
|
self.or_stack[b][i] = self.registers[i].clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.hb = self.h;
|
||||||
|
self.p += 1;
|
||||||
|
},
|
||||||
|
&ChoiceInstruction::RetryMeElse(offset) => {
|
||||||
|
let b = self.b;
|
||||||
|
let n = self.or_stack[b].num_args();
|
||||||
|
|
||||||
|
for i in 1 .. n + 1 {
|
||||||
|
self.registers[i] = self.or_stack[b][i].clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.e = self.or_stack[b].e;
|
||||||
|
self.cp = self.or_stack[b].cp;
|
||||||
|
|
||||||
|
self.or_stack[b].bp = self.p + offset;
|
||||||
|
|
||||||
|
let old_tr = self.or_stack[b].tr;
|
||||||
|
let curr_tr = self.tr;
|
||||||
|
|
||||||
|
self.unwind_trail(old_tr, curr_tr);
|
||||||
|
self.tr = self.or_stack[b].tr;
|
||||||
|
|
||||||
|
self.trail.truncate(self.tr);
|
||||||
|
self.heap.truncate(self.or_stack[b].h);
|
||||||
|
|
||||||
|
self.h = self.or_stack[b].h;
|
||||||
|
self.hb = self.h;
|
||||||
|
|
||||||
|
self.p += 1;
|
||||||
|
},
|
||||||
|
&ChoiceInstruction::TrustMe => {
|
||||||
|
let b = self.b;
|
||||||
|
let n = self.or_stack[b].num_args();
|
||||||
|
|
||||||
|
for i in 1 .. n + 1 {
|
||||||
|
self.registers[i] = self.or_stack[b][i].clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.e = self.or_stack[b].e;
|
||||||
|
self.cp = self.or_stack[b].cp;
|
||||||
|
|
||||||
|
let old_tr = self.or_stack[b].tr;
|
||||||
|
let curr_tr = self.tr;
|
||||||
|
|
||||||
|
self.unwind_trail(old_tr, curr_tr);
|
||||||
|
|
||||||
|
self.tr = self.or_stack[b].tr;
|
||||||
|
self.trail.truncate(self.tr);
|
||||||
|
|
||||||
|
self.h = self.or_stack[b].h;
|
||||||
|
self.heap.truncate(self.h);
|
||||||
|
|
||||||
|
self.b = self.or_stack[b].b;
|
||||||
|
|
||||||
|
self.or_stack.pop();
|
||||||
|
|
||||||
|
self.hb = self.h;
|
||||||
|
self.p += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reset(&mut self) {
|
||||||
|
self.h = 0;
|
||||||
|
self.hb = 0;
|
||||||
|
self.e = 0;
|
||||||
|
self.b = 0;
|
||||||
|
self.s = 0;
|
||||||
|
self.tr = 0;
|
||||||
|
self.p = CodePtr::TopLevel;
|
||||||
|
self.cp = CodePtr::TopLevel;
|
||||||
|
self.num_of_args = 0;
|
||||||
|
|
||||||
|
self.fail = false;
|
||||||
|
self.trail.clear();
|
||||||
|
self.heap.clear();
|
||||||
|
self.mode = MachineMode::Write;
|
||||||
|
self.and_stack.clear();
|
||||||
|
self.or_stack.clear();
|
||||||
|
self.registers = vec![Addr::HeapCell(0); 64];
|
||||||
|
}
|
||||||
|
}
|
||||||
9
src/prolog/mod.rs
Normal file
9
src/prolog/mod.rs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
pub mod and_stack;
|
||||||
|
pub mod ast;
|
||||||
|
pub mod codegen;
|
||||||
|
pub mod heapview;
|
||||||
|
pub mod io;
|
||||||
|
pub mod iterators;
|
||||||
|
pub mod prolog_parser;
|
||||||
|
pub mod machine;
|
||||||
|
pub mod or_stack;
|
||||||
112
src/prolog/or_stack.rs
Normal file
112
src/prolog/or_stack.rs
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
use prolog::ast::*;
|
||||||
|
|
||||||
|
use std::ops::{Index, IndexMut};
|
||||||
|
use std::vec::Vec;
|
||||||
|
|
||||||
|
pub struct Frame {
|
||||||
|
pub global_index: usize,
|
||||||
|
pub e: usize,
|
||||||
|
pub cp: CodePtr,
|
||||||
|
pub b: usize,
|
||||||
|
pub bp: CodePtr,
|
||||||
|
pub tr: usize,
|
||||||
|
pub h: usize,
|
||||||
|
args: Vec<Addr>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Frame {
|
||||||
|
fn new(global_index: usize,
|
||||||
|
e: usize,
|
||||||
|
cp: CodePtr,
|
||||||
|
b: usize,
|
||||||
|
bp: CodePtr,
|
||||||
|
tr: usize,
|
||||||
|
h: usize,
|
||||||
|
n: usize)
|
||||||
|
-> Self
|
||||||
|
{
|
||||||
|
Frame {
|
||||||
|
global_index: global_index,
|
||||||
|
e: e,
|
||||||
|
cp: cp,
|
||||||
|
b: b,
|
||||||
|
bp: bp,
|
||||||
|
tr: tr,
|
||||||
|
h: h,
|
||||||
|
args: vec![Addr::HeapCell(0); n]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn num_args(&self) -> usize {
|
||||||
|
self.args.len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct OrStack(Vec<Frame>);
|
||||||
|
|
||||||
|
impl OrStack {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
OrStack(Vec::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push(&mut self,
|
||||||
|
global_index: usize,
|
||||||
|
e: usize,
|
||||||
|
cp: CodePtr,
|
||||||
|
b: usize,
|
||||||
|
bp: CodePtr,
|
||||||
|
tr: usize,
|
||||||
|
h: usize,
|
||||||
|
n: usize)
|
||||||
|
{
|
||||||
|
self.0.push(Frame::new(global_index, e, cp, b, bp, tr, h, n));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.0.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
self.0.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn top(&self) -> Option<&Frame> {
|
||||||
|
self.0.last()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop(&mut self) {
|
||||||
|
self.0.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.0.is_empty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Index<usize> for OrStack {
|
||||||
|
type Output = Frame;
|
||||||
|
|
||||||
|
fn index(&self, index: usize) -> &Self::Output {
|
||||||
|
self.0.index(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IndexMut<usize> for OrStack {
|
||||||
|
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
||||||
|
self.0.index_mut(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Index<usize> for Frame {
|
||||||
|
type Output = Addr;
|
||||||
|
|
||||||
|
fn index(&self, index: usize) -> &Self::Output {
|
||||||
|
self.args.index(index - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IndexMut<usize> for Frame {
|
||||||
|
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
||||||
|
self.args.index_mut(index - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
77
src/prolog/prolog_parser.lalrpop
Normal file
77
src/prolog/prolog_parser.lalrpop
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
use prolog::ast::*;
|
||||||
|
|
||||||
|
use std::cell::Cell;
|
||||||
|
|
||||||
|
grammar;
|
||||||
|
|
||||||
|
pub TopLevel: TopLevel = {
|
||||||
|
"?-" <t:Term> "." => TopLevel::Query(t),
|
||||||
|
<Predicate> => TopLevel::Predicate(<>),
|
||||||
|
<Rule> "." => TopLevel::Rule(<>),
|
||||||
|
<Term> "." => TopLevel::Fact(<>)
|
||||||
|
};
|
||||||
|
|
||||||
|
Atom : Atom = {
|
||||||
|
r"[a-z][a-z0-9_]*" => <>.trim().to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
BoxedTerm : Box<Term> = {
|
||||||
|
<t:Term> => Box::new(t)
|
||||||
|
};
|
||||||
|
|
||||||
|
Clause : Term = {
|
||||||
|
<a:Atom> "(" <ts: (<BoxedTerm> ",")*> <t:BoxedTerm> ")" => {
|
||||||
|
let mut ts = ts;
|
||||||
|
ts.push(t);
|
||||||
|
Term::Clause(Cell::default(), a, ts)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
List : Term = {
|
||||||
|
"[]" => Term::Constant(Cell::default(), Constant::EmptyList),
|
||||||
|
"[" <ListInternals> "]" => <>
|
||||||
|
};
|
||||||
|
|
||||||
|
ListInternals : Term = {
|
||||||
|
<t:BoxedTerm> => Term::Cons(Cell::default(),
|
||||||
|
t,
|
||||||
|
Box::new(Term::Constant(Cell::default(),
|
||||||
|
Constant::EmptyList))),
|
||||||
|
<t:BoxedTerm> "," <li: ListInternals> => Term::Cons(Cell::default(),
|
||||||
|
t,
|
||||||
|
Box::new(li)),
|
||||||
|
<t1:BoxedTerm> "|" <t2:BoxedTerm> => Term::Cons(Cell::default(), t1, t2)
|
||||||
|
};
|
||||||
|
|
||||||
|
Predicate : Vec<PredicateClause> = {
|
||||||
|
<pcs: (<PredicateClause>)+> <pc: PredicateClause> => {
|
||||||
|
let mut pcs = pcs;
|
||||||
|
pcs.push(pc);
|
||||||
|
pcs
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
PredicateClause : PredicateClause = {
|
||||||
|
<Rule> "." => PredicateClause::Rule(<>),
|
||||||
|
<Term> "." => PredicateClause::Fact(<>)
|
||||||
|
};
|
||||||
|
|
||||||
|
Rule : Rule = {
|
||||||
|
<c:Clause> ":-" <h:Term> <cs: ("," <Term>)*> =>
|
||||||
|
Rule { head: (c, h), clauses: cs },
|
||||||
|
<a:Atom> ":-" <h:Term> <cs: ("," <Term>)*> =>
|
||||||
|
Rule { head: (Term::Constant(Cell::default(), Constant::Atom(a)), h),
|
||||||
|
clauses: cs }
|
||||||
|
};
|
||||||
|
|
||||||
|
Term : Term = {
|
||||||
|
<Atom> => Term::Constant(Cell::default(), Constant::Atom(<>)),
|
||||||
|
<Clause> => <>,
|
||||||
|
<List> => <>,
|
||||||
|
<Var> => Term::Var(Cell::default(), <>),
|
||||||
|
"_" => Term::AnonVar
|
||||||
|
};
|
||||||
|
|
||||||
|
Var : Var = {
|
||||||
|
r"[A-Z][a-z0-9_]*" => <>.trim().to_string()
|
||||||
|
};
|
||||||
2815
src/prolog/prolog_parser.rs
Normal file
2815
src/prolog/prolog_parser.rs
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user