transition to l3

This commit is contained in:
Mark Thom
2017-03-04 19:22:43 -07:00
parent 97f6bee8c3
commit 42ce902b3c
15 changed files with 4592 additions and 233 deletions

12
Cargo.lock generated
View File

@@ -1,9 +1,10 @@
[root]
name = "rusty-wam"
version = "0.3.5"
version = "0.4.0"
dependencies = [
"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)",
"termion 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -197,6 +198,14 @@ dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "termion"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "thread-id"
version = "2.0.0"
@@ -259,6 +268,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "6159e4e6e559c81bd706afe9c8fd68f547d3e851ce12e76b1de7914bab61691b"
"checksum strsim 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "50c069df92e4b01425a8bf3576d5d417943a6a7272fbabaf5bd80b1aaa76442e"
"checksum term 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3deff8a2b3b6607d6d7cc32ac25c0b33709453ca9cceac006caac51e963cf94a"
"checksum termion 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6e710c59ecea168019486885ade43ea5329bb9a08a117410052fb81b250f40ae"
"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03"
"checksum thread_local 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "55dd963dbaeadc08aa7266bf7f91c3154a7805e32bb94b820b769d2ef3b4744d"
"checksum unicode-xid 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f69506a2561962651710609304bbb961fa3da598c812f877975a82e48ee144f9"

View File

@@ -1,14 +1,16 @@
[package]
name = "rusty-wam"
version = "0.3.5"
version = "0.4.0"
authors = ["Mark Thom"]
build = "build.rs"
[dependencies]
[dependencies.termion]
version = "1.2.0"
[dependencies.lalrpop-util]
version = "0.12.5"
[build-dependencies.lalrpop]
version = "0.12.5"
version = "0.12.5"

161
README.md
View File

@@ -8,135 +8,56 @@ pure Prolog.
## Progress
The language L2 is implemented as a simple REPL. It supports
unification on queries without backtracking, where rules and facts are
limited to a single name/arity pairing, in the familiar Prolog
syntax. No data types apart from atoms are currently supported.
The language L3 is implemented as a simple REPL. L3 is pure Prolog --
Prolog without cuts, meta- or extra-logical operators, or side effects
of any kind. No data types apart from atoms are currently supported.
An example of the level of interaction currently supported is:
## Tutorial
To enter a multi-clause predicate, the brackets ":{" and "}:" are used
as delimiters. They must be entirely contained with their own lines.
For example,
```
l2> p(Z, Z).
l2> ?- p(Z, Z).
l3> :{
p(f(f(X)), h(W), Y) :- g(W), h(W), f(X).
p(X, Y, Z) :- h(Y), z(Z).
}:
l3> :{
h(x).
h(y).
h(z).
}:
```
Single clause predicates can entered without brackets, as in
```
l3> p(X) :- q(X).
l3> f(s).
l3> z(Z).
```
Queries are issued as
```
l3> ?- p(X, Y, Z).
```
Given the above work, the result of the query will be
```
l3> ?- p(X, Y, Z).
yes
Z = _0
l2> ?- p(Z, z).
yes
Z = z
l2> ?- p(Z, w).
yes
Z = w
l2> clouds(are, nice).
l2> ?- p(z, w).
no
l2> ?- p(w, w).
yes
l2> ?- clouds(Z, Z).
no
l2> ?- clouds(are, W).
yes
W = nice
l2> ?- clouds(W, nice).
yes
W = are
l2> ?- p(Z, h(Z, W), f(W)).
no
l2> p(Z, h(Z, W), f(W)).
l2> ?- p(z, h(z, z), f(w)).
no
l2> ?- p(z, h(z, w), f(w)).
yes
l2> ?- p(z, h(z, W), f(w)).
yes
W = w
l2> ?- p(Z, h(Z, w), f(Z)).
yes
Z = w
l2> ?- p(z, h(Z, w), f(Z)).
no
l2> p(f(X), h(Y, f(a)), Y).
l2> ?- p(Z, h(Z, W), f(W)).
yes
Z = f(f(a))
W = f(a)
l2> p(X, Y) :- q(X, Z), r(Z, Y).
l2> q(q, s).
l2> r(s, t).
l2> ?- p(X, Y).
yes
X = q
Y = t
l2> ?- p(q, t).
yes
l2> ?- p(t, q).
no
l2> ?- p(q, T).
yes
T = t
l2> ?- p(Q, t).
yes
Q = q
l2> ?- p(t, t).
no
l2> p(X, Y) :- q(f(f(X)), R), r(S, T).
l2> q(f(f(X)), r).
l2> ?- p(X, Y).
yes
Y = _1
X = _0
l2> q(f(f(x)), r).
l2> ?- p(X, Y).
yes
Y = _1
X = x
l2> p(X, Y) :- q(X, Y), r(X, Y).
l2> q(s, t).
l2> r(X, Y) :- r(a).
l2> r(a).
l2> ?- p(X, Y).
yes
Y = t
X = s
l2> ?- p(t, S).
no
l2> ?- p(t, s).
no
l2> ?- p(s, T).
yes
T = t
l2> ?- p(S, t).
yes
S = s
l2> p(f(f(a), g(b), X), g(b), h) :- q(X, Y).
l2> q(X, Y).
l2> ?- p(f(X, Y, Z), g(b), h).
yes
Z = _4
X = f(a)
Y = g(b)
l2> ?- p(f(X, g(Y), c), g(Z), X).
no
l2> ?- p(f(X, g(Y), c), g(Z), h).
yes
Z = b
Y = b
X = f(a)
l2> ?- p(Z, Y, X).
yes
X = h
Z = f(f(a), g(b), _7)
Y = g(b)
l2> ?- p(f(X, Y, Z), Y, h).
yes
X = f(a)
Z = _4
Y = g(b)
l2> quit
Y = x
Z = _2
Press ; to continue or A to abort.
```
Pressing ; will backtrack through other possible answers, if any exist.
Pressing A will abort the search and return to the prompt.
Note that the values of variables belonging to successful queries are
printed out, on one line each. Uninstantiated variables are denoted by
a number preceded by an underscore.
a number preceded by an underscore (X = _0 is an example in the
above).
## Occurs check

80
src/l3/and_stack.rs Normal file
View File

@@ -0,0 +1,80 @@
use l3::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)
}
}

303
src/l3/ast.rs Normal file
View File

@@ -0,0 +1,303 @@
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(),
&PredicateClause::Rule(ref rule) => rule.head.0.name()
}
}
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 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()
}
}
}
pub enum Term {
Atom(Cell<RegType>, Atom),
Clause(Cell<RegType>, Atom, Vec<Box<Term>>),
Var(Cell<VarReg>, Var)
}
pub struct Rule {
pub head: (Term, Term),
pub clauses: Vec<Term>
}
pub enum TermRef<'a> {
Atom(Level, &'a Cell<RegType>, &'a Atom),
Clause(Level, &'a Cell<RegType>, &'a Atom, &'a Vec<Box<Term>>),
Var(Level, &'a Cell<VarReg>, &'a Var)
}
pub enum FactInstruction {
GetStructure(Level, Atom, usize, RegType),
GetValue(RegType, usize),
GetVariable(RegType, usize),
UnifyVariable(RegType),
UnifyValue(RegType)
}
pub enum QueryInstruction {
PutStructure(Level, Atom, usize, RegType),
PutValue(RegType, usize),
PutVariable(RegType, usize),
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, Copy, PartialEq)]
pub enum Addr {
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 {
NamedStr(usize, Atom),
Ref(Ref),
Str(usize)
}
impl From<Addr> for HeapCellValue {
fn from(addr: Addr) -> HeapCellValue {
match addr {
Addr::HeapCell(hc) =>
HeapCellValue::Ref(Ref::HeapCell(hc)),
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::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) -> &Atom {
match self {
&Term::Atom(_, ref atom)
| &Term::Var(_, ref atom)
| &Term::Clause(_, ref atom, _) => atom
}
}
pub fn arity(&self) -> usize {
match self {
&Term::Atom(_, _) | &Term::Var(_, _) => 0,
&Term::Clause(_, _, ref child_terms) => child_terms.len()
}
}
}
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
}
}
}

447
src/l3/codegen.rs Normal file
View File

@@ -0,0 +1,447 @@
use l3::ast::*;
use l3::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 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 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 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 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,
name: &'a Atom,
cell: &'a Cell<RegType>,
arity: usize)
-> Target
where Target: CompilationTarget<'a>
{
self.marker.mark_non_var(lvl, cell);
Target::to_structure(lvl, name.clone(), arity, cell.get())
}
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::Atom(ref cell, _) | &Term::Clause(ref cell, _, _) =>
self.non_var_subterm(cell),
&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::Atom(lvl, term, atom) =>
target.push(self.to_structure(lvl, atom, term, 0)),
TermRef::Clause(lvl, term, atom, terms) => {
target.push(self.to_structure(lvl, atom, term, terms.len()));
for subterm in terms {
target.push(self.subterm_to_instr(subterm.as_ref()));
}
},
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::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
}
}

86
src/l3/heapview.rs Normal file
View File

@@ -0,0 +1,86 @@
use l3::and_stack::*;
use l3::ast::*;
use std::vec::Vec;
#[derive(Clone, Copy)]
pub enum HeapCellView<'a> {
Str(usize, &'a Atom),
HeapVar(usize),
StackVar(usize, usize)
}
pub struct HeapCellViewer<'a> {
heap: &'a Heap,
and_stack: &'a AndStack,
state_stack: Vec<Addr>
}
impl<'a> HeapCellViewer<'a> {
pub fn new(heap: &'a Heap, and_stack: &'a AndStack, focus: Addr) -> Self {
HeapCellViewer {
heap: heap,
and_stack: and_stack,
state_stack: vec![focus]
}
}
fn follow_stack_ref(&mut self, mut fr: usize, mut sc: usize) -> HeapCellView<'a>
{
loop {
match self.and_stack[fr][sc] {
Addr::HeapCell(hc) | Addr::Str(hc) =>
return self.follow_heap_ref(hc),
Addr::StackCell(fr1, sc1) => {
if fr1 == fr && sc1 == sc {
return HeapCellView::StackVar(fr, sc);
}
fr = fr1; sc = sc1;
}
}
}
}
fn follow_heap_ref(&mut self, mut focus: usize) -> HeapCellView<'a> {
loop {
match &self.heap[focus] {
&HeapCellValue::NamedStr(arity, ref name) => {
for i in (1 .. arity + 1).rev() {
self.state_stack.push(Addr::HeapCell(focus + i));
}
return HeapCellView::Str(arity, name);
},
&HeapCellValue::Ref(Ref::HeapCell(hc)) => {
if focus == hc {
return HeapCellView::HeapVar(hc);
} else {
focus = hc;
}
},
&HeapCellValue::Ref(Ref::StackCell(fr, sc)) =>
return self.follow_stack_ref(fr, sc),
&HeapCellValue::Str(cell_num) =>
focus = cell_num,
}
}
}
}
impl<'a> Iterator for HeapCellViewer<'a> {
type Item = HeapCellView<'a>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(addr) = self.state_stack.pop() {
match addr {
Addr::HeapCell(hc) | Addr::Str(hc) =>
return Some(self.follow_heap_ref(hc)),
Addr::StackCell(fr, sc) =>
return Some(self.follow_stack_ref(fr, sc))
}
}
None
}
}

255
src/l3/io.rs Normal file
View File

@@ -0,0 +1,255 @@
use l3::ast::*;
use l3::codegen::*;
use l3::l3_parser::*;
use l3::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 FactInstruction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&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::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::PutStructure(Level::Deep, ref name, ref arity, ref r) =>
write!(f, "put_structure {}/{}, {}", name, arity, r.reg_num()),
&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::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");
'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 A 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('a') | Key::Char('A') =>
break 'outer,
_ => {}
}
};
if let &EvalResult::QueryFailure = &result {
write!(stdout, "no\n\r").unwrap();
stdout.flush().unwrap();
break;
}
} else {
break;
}
}
},
EvalResult::QueryFailure => println!("no"),
_ => {}
};
}

175
src/l3/iterators.rs Normal file
View File

@@ -0,0 +1,175 @@
use l3::ast::*;
use std::cell::Cell;
use std::collections::VecDeque;
use std::vec::Vec;
enum IteratorState<'a> {
Atom(Level, &'a Cell<RegType>, &'a Atom),
Clause(Level, usize, &'a Cell<RegType>, &'a Atom, &'a Vec<Box<Term>>),
IsolatedAtom(&'a Cell<RegType>, &'a Atom),
IsolatedVar(&'a Cell<VarReg>, &'a Var),
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::Atom(ref cell, ref atom) =>
IteratorState::Atom(lvl, cell, atom),
&Term::Clause(ref cell, ref atom, ref child_terms) =>
IteratorState::Clause(lvl, 0, cell, atom, child_terms),
&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 new(term: &'a Term) -> QueryIterator<'a> {
let state = match term {
&Term::Atom(ref cell, ref atom) =>
IteratorState::IsolatedAtom(cell, atom),
&Term::Clause(_, _, ref terms) =>
IteratorState::RootClause(0, terms),
&Term::Var(ref cell, ref var) =>
IteratorState::IsolatedVar(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::Atom(lvl, cell, atom) =>
return Some(TermRef::Atom(lvl, cell, atom)),
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::IsolatedAtom(cell, atom) =>
return Some(TermRef::Atom(Level::Shallow, cell, atom)),
IteratorState::IsolatedVar(cell, var) =>
return Some(TermRef::Var(Level::Shallow, cell, var)),
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::Atom(ref cell, ref atom) =>
vec![IteratorState::IsolatedAtom(cell, atom)],
&Term::Clause(_, _, ref terms) =>
vec![IteratorState::RootClause(0, terms)],
&Term::Var(ref cell, ref var) =>
vec![IteratorState::IsolatedVar(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::Atom(lvl, cell, atom) =>
return Some(TermRef::Atom(lvl, cell, atom)),
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::IsolatedAtom(cell, atom) =>
return Some(TermRef::Atom(Level::Shallow, cell, atom)),
IteratorState::IsolatedVar(cell, var) =>
return Some(TermRef::Var(Level::Shallow, cell, var)),
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)
}
}

59
src/l3/l3_parser.lalrpop Normal file
View File

@@ -0,0 +1,59 @@
use l3::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::new(RegType::Temp(0)), a, ts)
}
};
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::Atom(Cell::new(RegType::Temp(0)), a), h),
clauses: cs }
};
Term : Term = {
<Clause> => <>,
<Atom> => Term::Atom(Cell::new(RegType::Temp(0)), <>),
<Var> => Term::Var(Cell::new(VarReg::Norm(RegType::Temp(0))), <>)
};
Var : Var = {
r"[A-Z][a-z0-9_]*" => <>.trim().to_string(),
};

2177
src/l3/l3_parser.rs Normal file

File diff suppressed because it is too large Load Diff

677
src/l3/machine.rs Normal file
View File

@@ -0,0 +1,677 @@
use l3::ast::*;
use l3::codegen::*;
use l3::heapview::*;
use l3::and_stack::*;
use l3::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>;
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]
}
}
}
}
pub struct Machine {
ms: MachineState,
code: Code,
code_dir: CodeDir
}
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) {
let p = self.code.len();
let name = fact.name().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) {
let p = self.code.len();
let name = rule.head.0.name().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 {
self.ms.execute_fact_instr(&fact_instr);
}
self.ms.p += 1;
},
&Line::Query(ref query) => {
for query_instr in query {
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 arities = Vec::new();
let viewer = HeapCellViewer::new(&self.ms.heap,
&self.ms.and_stack,
*addr);
if result != "" {
result += "\n\r";
}
result += var.as_str();
result += " = ";
for view in viewer {
match arities.pop() {
Some(n) => arities.push(n-1),
None => {}
}
if !(arities.is_empty() || result.ends_with("(")) {
result += ", ";
}
match view {
HeapCellView::Str(arity, ref name) => {
result += name.as_str();
if arity > 0 {
arities.push(arity);
result += "(";
}
},
HeapCellView::HeapVar(cell_num) => {
result += "_";
result += cell_num.to_string().as_str();
},
HeapCellView::StackVar(fr, sc) => {
result += "_s_";
result += fr.to_string().as_str();
result += "_";
result += sc.to_string().as_str();
}
}
while let Some(&0) = arities.last() {
result += ")";
arities.pop();
}
}
}
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()];
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); 32],
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],
addr => addr
}
}
fn deref(&self, a: Addr) -> Addr {
let mut a = a;
loop {
let value = self.store(a);
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), self.store(d2)) {
(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::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;
}
};
}
}
}
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(self.trail[i]),
Ref::StackCell(fr, sc) =>
self.and_stack[fr][sc] = Addr::StackCell(fr, sc)
}
}
}
fn execute_query_instr(&mut self, instr: &QueryInstruction) {
match instr {
&QueryInstruction::PutStructure(_, ref name, arity, reg) => {
self.heap.push(HeapCellValue::Str(self.h + 1));
self.heap.push(HeapCellValue::NamedStr(arity, name.clone()));
self[reg] = Addr::Str(self.h + 1);
self.h += 2;
},
&QueryInstruction::PutValue(norm, arg) =>
self.registers[arg] = self[norm],
&QueryInstruction::PutVariable(norm, arg) => {
self.heap.push(HeapCellValue::Ref(Ref::HeapCell(self.h)));
self[norm] = Addr::HeapCell(self.h);
self.registers[arg] = Addr::HeapCell(self.h);
self.h += 1;
},
&QueryInstruction::SetVariable(reg) => {
self.heap.push(HeapCellValue::Ref(Ref::HeapCell(self.h)));
self[reg] = Addr::HeapCell(self.h);
self.h += 1;
},
&QueryInstruction::SetValue(reg) => {
let heap_val = self[reg];
self.heap.push(HeapCellValue::from(heap_val));
self.h += 1;
},
}
}
fn execute_fact_instr(&mut self, instr: &FactInstruction) {
match instr {
&FactInstruction::GetStructure(_, ref name, arity, reg) => {
let addr = self.deref(self[reg]);
match self.store(addr) {
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;
}
};
},
&FactInstruction::GetVariable(norm, arg) =>
self[norm] = self.registers[arg],
&FactInstruction::GetValue(norm, arg) => {
let norm_addr = self[norm];
let reg_addr = self.registers[arg];
self.unify(norm_addr, reg_addr);
},
&FactInstruction::UnifyVariable(reg) => {
match self.mode {
MachineMode::Read =>
self[reg] = self.heap[self.s].as_addr(self.s),
MachineMode::Write => {
self.heap.push(HeapCellValue::Ref(Ref::HeapCell(self.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];
self.unify(reg_addr, Addr::HeapCell(s));
},
MachineMode::Write => {
let heap_val = self.store(self[reg]);
self.heap.push(HeapCellValue::from(heap_val));
self.h += 1;
}
};
self.s += 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];
}
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];
}
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];
}
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); 32];
}
}

9
src/l3/mod.rs Normal file
View 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 l3_parser;
pub mod machine;
pub mod or_stack;

112
src/l3/or_stack.rs Normal file
View File

@@ -0,0 +1,112 @@
use l3::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)
}
}

View File

@@ -1,157 +1,203 @@
mod l2;
extern crate termion;
mod l3;
use l2::ast::*;
use l2::codegen::*;
use l2::machine::*;
use std::io::{self, Write};
fn submit(wam: &mut Machine, buffer: String) -> bool {
let result = l2::l2_parser::parse_TopLevel(&*buffer);
let mut cg = CodeGenerator::new();
match &result {
&Ok(TopLevel::Fact(ref fact)) => {
let compiled_fact = cg.compile_fact(&fact);
wam.add_fact(fact, compiled_fact);
},
&Ok(TopLevel::Rule(ref rule)) => {
let compiled_rule = cg.compile_rule(&rule);
wam.add_rule(rule, compiled_rule);
},
&Ok(TopLevel::Query(ref query)) => {
let compiled_query = cg.compile_query(&query);
let output = wam.run_query(compiled_query, &cg);
match output {
Some(result) => {
println!("yes");
if result != "" {
println!("{}", result);
}
},
None => println!("no")
}
},
&Err(_) => println!("Grammatical error of some kind!"),
};
let result = wam.failed();
wam.reset();
result
}
use l3::io::*;
use l3::machine::*;
#[cfg(test)]
mod tests {
use super::*;
#[inline]
fn submit_ss(wam: &mut Machine, buffer: &'static str) -> bool {
submit(wam, String::from(buffer))
use l3::ast::*;
fn submit(wam: &mut Machine, buffer: &str) -> EvalResult {
let result = eval(wam, buffer);
wam.reset();
result
}
#[test]
fn test_queries_on_facts() {
let mut wam = Machine::new();
submit_ss(&mut wam, "p(Z, Z).");
submit_ss(&mut wam, "clouds(are, nice).");
submit(&mut wam, "p(Z, Z).");
submit(&mut wam, "clouds(are, nice).");
// submit_ss returns true on failure, false on success.
assert_eq!(submit_ss(&mut wam, "?- p(Z, Z)."), false);
assert_eq!(submit_ss(&mut wam, "?- p(Z, z)."), false);
assert_eq!(submit_ss(&mut wam, "?- p(Z, w)."), false);
assert_eq!(submit_ss(&mut wam, "?- p(z, w)."), true);
assert_eq!(submit_ss(&mut wam, "?- p(w, w)."), false);
assert_eq!(submit_ss(&mut wam, "?- clouds(Z, Z)."), true);
assert_eq!(submit_ss(&mut wam, "?- clouds(are, Z)."), false);
assert_eq!(submit_ss(&mut wam, "?- clouds(Z, nice)."), false);
// submit returns true on failure, false on success.
assert_eq!(submit(&mut wam, "?- p(Z, Z).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(Z, z).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(Z, w).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(z, w).").failed_query(), true);
assert_eq!(submit(&mut wam, "?- p(w, w).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- clouds(Z, Z).").failed_query(), true);
assert_eq!(submit(&mut wam, "?- clouds(are, Z).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- clouds(Z, nice).").failed_query(), false);
assert_eq!(submit_ss(&mut wam, "?- p(Z, h(Z, W), f(W))."), true);
assert_eq!(submit(&mut wam, "?- p(Z, h(Z, W), f(W)).").failed_query(), true);
submit_ss(&mut wam, "p(Z, h(Z, W), f(W)).");
submit(&mut wam, "p(Z, h(Z, W), f(W)).");
assert_eq!(submit_ss(&mut wam, "?- p(z, h(z, z), f(w))."), true);
assert_eq!(submit_ss(&mut wam, "?- p(z, h(z, w), f(w))."), false);
assert_eq!(submit_ss(&mut wam, "?- p(z, h(z, W), f(w))."), false);
assert_eq!(submit_ss(&mut wam, "?- p(Z, h(Z, w), f(Z))."), false);
assert_eq!(submit_ss(&mut wam, "?- p(z, h(Z, w), f(Z))."), true);
assert_eq!(submit(&mut wam, "?- p(z, h(z, z), f(w)).").failed_query(), true);
assert_eq!(submit(&mut wam, "?- p(z, h(z, w), f(w)).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(z, h(z, W), f(w)).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(Z, h(Z, w), f(Z)).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(z, h(Z, w), f(Z)).").failed_query(), true);
submit_ss(&mut wam, "p(f(X), h(Y, f(a)), Y).");
submit(&mut wam, "p(f(X), h(Y, f(a)), Y).");
assert_eq!(submit_ss(&mut wam, "?- p(Z, h(Z, W), f(W))."), false);
assert_eq!(submit(&mut wam, "?- p(Z, h(Z, W), f(W)).").failed_query(), false);
}
#[test]
fn test_queries_on_rules() {
let mut wam = Machine::new();
submit_ss(&mut wam, "p(X, Y) :- q(X, Z), r(Z, Y).");
submit_ss(&mut wam, "q(q, s).");
submit_ss(&mut wam, "r(s, t).");
submit(&mut wam, "p(X, Y) :- q(X, Z), r(Z, Y).");
submit(&mut wam, "q(q, s).");
submit(&mut wam, "r(s, t).");
assert_eq!(submit_ss(&mut wam, "?- p(X, Y)."), false);
assert_eq!(submit_ss(&mut wam, "?- p(q, t)."), false);
assert_eq!(submit_ss(&mut wam, "?- p(t, q)."), true);
assert_eq!(submit_ss(&mut wam, "?- p(q, T)."), false);
assert_eq!(submit_ss(&mut wam, "?- p(Q, t)."), false);
assert_eq!(submit_ss(&mut wam, "?- p(t, t)."), true);
assert_eq!(submit(&mut wam, "?- p(X, Y).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(q, t).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(t, q).").failed_query(), true);
assert_eq!(submit(&mut wam, "?- p(q, T).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(Q, t).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(t, t).").failed_query(), true);
submit_ss(&mut wam, "p(X, Y) :- q(f(f(X)), R), r(S, T).");
submit_ss(&mut wam, "q(f(f(X)), r).");
submit(&mut wam, "p(X, Y) :- q(f(f(X)), R), r(S, T).");
submit(&mut wam, "q(f(f(X)), r).");
assert_eq!(submit_ss(&mut wam, "?- p(X, Y)."), false);
assert_eq!(submit(&mut wam, "?- p(X, Y).").failed_query(), false);
submit_ss(&mut wam, "q(f(f(x)), r).");
submit(&mut wam, "q(f(f(x)), r).");
assert_eq!(submit_ss(&mut wam, "?- p(X, Y)."), false);
assert_eq!(submit(&mut wam, "?- p(X, Y).").failed_query(), false);
submit_ss(&mut wam, "p(X, Y) :- q(X, Y), r(X, Y).");
submit_ss(&mut wam, "q(s, t).");
submit_ss(&mut wam, "r(X, Y) :- r(a).");
submit_ss(&mut wam, "r(a).");
submit(&mut wam, "p(X, Y) :- q(X, Y), r(X, Y).");
submit(&mut wam, "q(s, t).");
submit(&mut wam, "r(X, Y) :- r(a).");
submit(&mut wam, "r(a).");
assert_eq!(submit_ss(&mut wam, "?- p(X, Y)."), false);
assert_eq!(submit_ss(&mut wam, "?- p(t, S)."), true);
assert_eq!(submit_ss(&mut wam, "?- p(t, s)."), true);
assert_eq!(submit_ss(&mut wam, "?- p(s, T)."), false);
assert_eq!(submit_ss(&mut wam, "?- p(S, t)."), false);
assert_eq!(submit(&mut wam, "?- p(X, Y).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(t, S).").failed_query(), true);
assert_eq!(submit(&mut wam, "?- p(t, s).").failed_query(), true);
assert_eq!(submit(&mut wam, "?- p(s, T).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(S, t).").failed_query(), false);
submit_ss(&mut wam, "p(f(f(a), g(b), X), g(b), h) :- q(X, Y).");
submit_ss(&mut wam, "q(X, Y).");
submit(&mut wam, "p(f(f(a), g(b), X), g(b), h) :- q(X, Y).");
submit(&mut wam, "q(X, Y).");
assert_eq!(submit_ss(&mut wam, "?- p(f(X, Y, Z), g(b), h)."), false);
assert_eq!(submit_ss(&mut wam, "?- p(f(X, g(Y), Z), g(Z), X)."), true);
assert_eq!(submit_ss(&mut wam, "?- p(f(X, g(Y), Z), g(Z), h)."), false);
assert_eq!(submit_ss(&mut wam, "?- p(Z, Y, X)."), false);
assert_eq!(submit_ss(&mut wam, "?- p(f(X, Y, Z), Y, h)."), false);
assert_eq!(submit(&mut wam, "?- p(f(X, Y, Z), g(b), h).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(f(X, g(Y), Z), g(Z), X).").failed_query(), true);
assert_eq!(submit(&mut wam, "?- p(f(X, g(Y), Z), g(Z), h).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(Z, Y, X).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(f(X, Y, Z), Y, h).").failed_query(), false);
}
#[test]
fn test_queries_on_predicates() {
let mut wam = Machine::new();
submit(&mut wam, "p(X, a). p(b, X).");
assert_eq!(submit(&mut wam, "?- p(x, Y).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(X, a).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(b, X).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(X, X).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(b, a).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(a, b).").failed_query(), true);
submit(&mut wam, "p(X, Y, a). p(X, a, Y). p(X, Y, a).");
assert_eq!(submit(&mut wam, "?- p(c, d, X).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(a, a, a).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(b, c, d).").failed_query(), true);
submit(&mut wam, "p(X, a). p(X, Y) :- q(Z), p(X, X).");
assert_eq!(submit(&mut wam, "?- p(X, Y).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(x, a).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(X, a).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(X, b).").failed_query(), true);
submit(&mut wam, "q(z).");
assert_eq!(submit(&mut wam, "?- p(X, b).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(x, a).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(X, Y).").failed_query(), false);
submit(&mut wam, "p(X, a). p(X, Y) :- q(Y), p(X, X).");
assert_eq!(submit(&mut wam, "?- p(X, Y).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(X, b).").failed_query(), true);
submit(&mut wam, "p(a, z). p(X, Y) :- q(Y), p(X, Y).");
assert_eq!(submit(&mut wam, "?- p(X, Y).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(X, z).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(a, z).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(a, X).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(b, a).").failed_query(), true);
submit(&mut wam, "p(X, Y, Z) :- q(X), r(Y), s(Z).
p(a, b, Z) :- q(Z).");
submit(&mut wam, "q(x).");
submit(&mut wam, "r(y).");
submit(&mut wam, "s(z).");
assert_eq!(submit(&mut wam, "?- p(X, Y, Z).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(a, b, c).").failed_query(), true);
assert_eq!(submit(&mut wam, "?- p(a, b, C).").failed_query(), false);
submit(&mut wam, "p(X) :- q(X). p(X) :- r(X).");
submit(&mut wam, "q(X) :- a.");
submit(&mut wam, "r(X) :- s(X, t). r(X) :- t(X, u).");
submit(&mut wam, "s(x, t).");
submit(&mut wam, "t(y, u).");
assert_eq!(submit(&mut wam, "?- p(X).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(x).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(y).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(z).").failed_query(), true);
submit(&mut wam, "p(f(f(X)), h(W), Y) :- g(W), h(W), f(X).
p(X, Y, Z) :- h(Y), g(W), z(Z).");
submit(&mut wam, "g(f(X)) :- z(X). g(X) :- h(X).");
submit(&mut wam, "h(w). h(x). h(z).");
submit(&mut wam, "f(s).");
submit(&mut wam, "z(Z).");
assert_eq!(submit(&mut wam, "?- p(X, Y, Z).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(X, X, Z).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(f(f(Z)), Y, Z).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(X, X, 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);
}
}
fn l2_repl() {
fn l3_repl() {
let mut wam = Machine::new();
loop {
print!("l2> ");
print!("l3> ");
let _ = io::stdout().flush();
let mut buffer = String::new();
let buffer = read();
io::stdin().read_line(&mut buffer).unwrap();
if &*buffer == "quit\n" {
if buffer == "quit\n" {
break;
} else if &*buffer == "clear\n" {
} else if buffer == "clear\n" {
wam = Machine::new();
continue;
}
submit(&mut wam, buffer);
let result = eval(&mut wam, buffer.trim());
print(&mut wam, result);
wam.reset();
}
}
fn main() {
l2_repl();
l3_repl();
}