Initial commit.

This commit is contained in:
Mark Thom
2016-10-28 19:53:08 -06:00
parent a8b1d8bd4d
commit 8d1441e20f
11 changed files with 2494 additions and 1 deletions

267
Cargo.lock generated Normal file
View File

@@ -0,0 +1,267 @@
[root]
name = "rusty-wam"
version = "0.1.0"
dependencies = [
"lalrpop 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lalrpop-util 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "aho-corasick"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "atty"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bit-set"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bit-vec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bit-vec"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bitflags"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "diff"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "docopt"
version = "0.6.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.1.75 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"strsim 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "fixedbitset"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "itertools"
version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "kernel32-sys"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "lalrpop"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"atty 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"bit-set 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"diff 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
"docopt 0.6.83 (registry+https://github.com/rust-lang/crates.io-index)",
"itertools 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)",
"lalrpop-intern 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lalrpop-snap 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lalrpop-util 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"petgraph 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.1.75 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"term 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "lalrpop-intern"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "lalrpop-snap"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"atty 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"bit-set 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"diff 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
"docopt 0.6.83 (registry+https://github.com/rust-lang/crates.io-index)",
"itertools 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)",
"lalrpop-intern 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lalrpop-util 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"petgraph 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.1.75 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"term 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "lalrpop-util"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "lazy_static"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libc"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "memchr"
version = "0.1.11"
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 = "petgraph"
version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"fixedbitset 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex"
version = "0.1.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"aho-corasick 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex-syntax"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "regex-syntax"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rustc-serialize"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "strsim"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "term"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "thread-id"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "thread_local"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "unicode-xid"
version = "0.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "utf8-ranges"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi-build"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum aho-corasick 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2b3fb52b09c1710b961acb35390d514be82e4ac96a9969a8e38565a29b878dc9"
"checksum atty 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d0fd4c0631f06448cc45a6bbb3b710ebb7ff8ccb96a0800c994afe23a70d5df2"
"checksum bit-set 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "84527c7b0452f22545cc010e72d366a435561d2b28b978035550b3778c4d428d"
"checksum bit-vec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5b97c2c8e8bbb4251754f559df8af22fb264853c7d009084a576cdf12565089d"
"checksum bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dead7461c1127cf637931a1e50934eb6eee8bff2f74433ac7909e9afcee04a3"
"checksum diff 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e48977eec6d3b7707462c2dc2e1363ad91b5dd822cf942537ccdc2085dc87587"
"checksum docopt 0.6.83 (registry+https://github.com/rust-lang/crates.io-index)" = "fc42c6077823a361410c37d47c2535b73a190cbe10838dc4f400fe87c10c8c3b"
"checksum fixedbitset 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c59882225c22dfcd2db6f0fce45dabe334e64ffa5efacb785b7ffb5af690cc6f"
"checksum itertools 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)" = "16b73f1c685cfd8ff8d75698ed87e6188cd09944b30c0863d45c2c3699d1da0c"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum lalrpop 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff7b1575ca8cc268def5a19fd73cea4849a56d2ade819bfe13b8eb78f8a85191"
"checksum lalrpop-intern 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8acc7d538f0d74e035719d2b46dd34abf919e21f69d9eacd3d33d8bb91b4be91"
"checksum lalrpop-snap 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "40d7ede4572f90583b0bb05af8aec2dad705f865fcecf479b8ebe959b46f8435"
"checksum lalrpop-util 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b2af45efc901171e23793f5edb55294dfab4fe1dc70d9df9450cb8f233ffea1f"
"checksum lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "49247ec2a285bb3dcb23cbd9c35193c025e7251bfce77c1d5da97e6362dffe7f"
"checksum libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)" = "408014cace30ee0f767b1c4517980646a573ec61a57957aeeabcac8ac0a02e8d"
"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20"
"checksum petgraph 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "bfd1de18b0a5f1777162e5b61aaf498032467d5409ab4ca6dbd03049f5708de1"
"checksum regex 0.1.75 (registry+https://github.com/rust-lang/crates.io-index)" = "f62414f9d3b0f53e827ac46d6f8ce2ff6a91afd724225a5986e54e81e170693c"
"checksum regex-syntax 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a21935ce5a4dfa48e3ded1aefbbe353fb9ab258b0d3fa0bd168bef00797b3dc7"
"checksum regex-syntax 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279401017ae31cf4e15344aa3f085d0e2e5c1e70067289ef906906fdbe92c8fd"
"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 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"
"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"

14
Cargo.toml Normal file
View File

@@ -0,0 +1,14 @@
[package]
name = "rusty-wam"
version = "0.1.0"
authors = ["Mark Thom"]
build = "build.rs"
[dependencies]
[dependencies.lalrpop-util]
version = "0.12.0"
[build-dependencies.lalrpop]
version = "0.12.0"

View File

@@ -1,2 +1,43 @@
# rusty-wam
The Warren Abstract Machine in Rust.
The beginnings of the Warren Abstract Machine in Rust, according to
the progression of languages in [Warren's Abstract Machine: A Tutorial
Reconstruction](http://wambook.sourceforge.net/wambook.pdf), ending in
pure Prolog.
## Progress
The language L0 is implemented as a simple REPL. It supports
unification on facts and queries without backtracking and clauses
without rules, in the familiar Prolog syntax. No data types apart from
atoms are currently supported.
An example of the level of interaction currently supported is:
`l0> p(Z, Z).
Program stored.
l0> ?- p(Z, Z).
yes
l0> ?- p(Z, z).
yes
l0> ?- p(Z, w).
yes
l0> ?- p(z, w).
no
l0> ?- p(w, w).
yes
l0> ?- p(Z, w).
yes
l0> ?- p(Z, h(Z, W), f(W)).
no
l0> p(Z, h(Z, W), f(W)).
Program stored.
l0> ?- p(z, h(z, z), f(w)).
no
l0> ?- p(z, h(z, w), f(w)).
yes
l0> ?- p(Z, h(z, W), f(w)).
yes
l0> ?- p(z, h(Z, w), f(w)).
yes
l0> quit`

5
build.rs Normal file
View File

@@ -0,0 +1,5 @@
extern crate lalrpop;
fn main() {
lalrpop::process_root().unwrap();
}

63
src/l0/ast.rs Normal file
View File

@@ -0,0 +1,63 @@
use std::vec::{Vec};
pub type Var = String;
pub type Atom = String;
#[derive(Debug)]
pub enum TopLevel {
Fact(Term),
Query(Term)
}
#[derive(Debug)]
pub enum Term {
Atom(Atom),
Clause(Atom, Vec<Box<Term>>),
Var(Var)
}
impl Term {
pub fn name(&self) -> &Atom {
match self {
&Term::Atom(ref atom) => atom,
&Term::Var(ref var) => var,
&Term::Clause(ref atom, _) => atom
}
}
pub fn is_variable(&self) -> bool {
if let &Term::Var(_) = self {
return true;
}
return false;
}
}
#[derive(Clone)]
pub enum MachineInstruction {
GetStructure(Atom, usize, usize),
PutStructure(Atom, usize, usize),
SetVariable(usize),
SetValue(usize),
UnifyVariable(usize),
UnifyValue(usize)
}
pub type Program = Vec<MachineInstruction>;
#[derive(Clone, Copy, PartialEq)]
pub enum Addr {
HeapCell(usize),
RegNum(usize)
}
impl Addr {
pub fn heap_offset(&self) -> usize {
match self {
&Addr::HeapCell(hc) => hc,
&Addr::RegNum(reg) => reg
}
}
}

160
src/l0/codegen.rs Normal file
View File

@@ -0,0 +1,160 @@
use l0::ast::{Atom, Term, MachineInstruction, Program, TopLevel, Var};
use std::collections::{HashMap, VecDeque};
use std::fmt;
use std::vec::{Vec};
impl fmt::Display for MachineInstruction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&MachineInstruction::GetStructure(ref a, ref s, ref r) =>
write!(f, "get_structure {}/{}, X{}", a, s, r),
&MachineInstruction::PutStructure(ref a, ref s, ref r) =>
write!(f, "put_structure {}/{}, X{}", a, s, r),
&MachineInstruction::SetVariable(ref r) =>
write!(f, "set_variable X{}", r),
&MachineInstruction::SetValue(ref r) =>
write!(f, "set_value X{}", r),
&MachineInstruction::UnifyVariable(ref r) =>
write!(f, "unify_variable X{}", r),
&MachineInstruction::UnifyValue(ref r) =>
write!(f, "unify_value X{}", r)
}
}
}
enum IntTerm<'a> {
FinishedClause(usize, &'a Atom, &'a Vec<Box<Term>>),
UnfinishedClause(usize, &'a Atom, &'a Vec<Box<Term>>),
FinishedAtom(usize, &'a Atom)
}
pub fn compile_query<'a>(t: &'a Term) -> Program
{
let mut stack : Vec<IntTerm<'a>> = Vec::new();
let mut variable_allocs : HashMap<&Var, (usize, bool)> = HashMap::new();
let mut query : Program = Vec::new();
match t {
&Term::Clause(ref atom, ref terms) => {
stack.push(IntTerm::UnfinishedClause(1, atom, terms));
variable_allocs.insert(atom, (1, true));
},
&Term::Atom(ref atom) => {
query.push(MachineInstruction::PutStructure(atom.clone(), 0, 1));
return query;
},
&Term::Var(_) => {
query.push(MachineInstruction::SetVariable(1));
return query;
},
};
while let Some(int_term) = stack.pop() {
match int_term {
IntTerm::UnfinishedClause(r, atom, terms) => {
stack.push(IntTerm::FinishedClause(r, atom, terms));
let mut counter : usize = r + 1;
for t in terms {
if t.is_variable() && !variable_allocs.contains_key(t.name()) {
variable_allocs.insert(t.name(), (counter, false));
}
counter += 1;
}
counter = r + terms.len();
for t in terms.iter().rev() {
let r = if t.is_variable() {
variable_allocs.get(t.name()).unwrap().0
} else {
counter
};
match t.as_ref() {
&Term::Atom(ref atom) =>
stack.push(IntTerm::FinishedAtom(r, atom)),
&Term::Clause(ref atom, ref terms) =>
stack.push(IntTerm::UnfinishedClause(r, atom, terms)),
_ => {}
};
counter -= 1;
}
},
IntTerm::FinishedAtom(r, atom) =>
query.push(MachineInstruction::PutStructure(atom.clone(), 0, r)),
IntTerm::FinishedClause(r, atom, terms) => {
query.push(MachineInstruction::PutStructure(atom.clone(), terms.len(), r));
let mut counter : usize = r + 1;
for t in terms {
if let &Term::Var(ref var) = t.as_ref() {
let &mut (reg, ref mut seen) = variable_allocs.get_mut(var).unwrap();
if !*seen {
query.push(MachineInstruction::SetVariable(reg));
*seen = true;
} else {
query.push(MachineInstruction::SetValue(reg));
}
} else {
query.push(MachineInstruction::SetValue(counter));
}
counter += 1;
}
}
};
}
query
}
pub fn compile_fact<'a>(t: &'a Term) -> Program {
let mut reg : usize = 2;
let mut queue : VecDeque<(usize, &'a Term)> = VecDeque::new();
let mut variable_allocs : HashMap<&Var, usize> = HashMap::new();
let mut fact : Program = Vec::new();
queue.push_back((1, t));
while let Some(t) = queue.pop_front() {
match t {
(r, &Term::Clause(ref atom, ref terms)) => {
fact.push(MachineInstruction::GetStructure(atom.clone(), terms.len(), r));
let mut counter : usize = reg;
for t in terms {
if t.is_variable() && !variable_allocs.contains_key(t.name()) {
variable_allocs.insert(t.name(), counter);
fact.push(MachineInstruction::UnifyVariable(counter));
counter += 1;
} else if t.is_variable() {
let r = variable_allocs.get(t.name()).unwrap();
fact.push(MachineInstruction::UnifyValue(*r));
} else {
fact.push(MachineInstruction::UnifyVariable(counter));
queue.push_back((counter, t));
counter += 1;
}
}
reg = counter;
},
(r, &Term::Atom(ref atom)) =>
fact.push(MachineInstruction::GetStructure(atom.clone(), 0, r)),
(r, &Term::Var(_)) => {
fact.push(MachineInstruction::UnifyVariable(r));
return fact;
}
};
}
fact
}

30
src/l0/l0_parser.lalrpop Normal file
View File

@@ -0,0 +1,30 @@
use l0::ast::{Atom, Term, TopLevel, Var};
grammar;
pub TopLevel: TopLevel = {
"?-" <t:Term> "." => TopLevel::Query(t),
<t:Term> "." => TopLevel::Fact(t),
};
Atom : Atom = {
r"[a-z][a-z0-9_]*" => <>.trim().to_string(),
};
Var : Var = {
r"[A-Z][a-z0-9_]*" => <>.trim().to_string(),
};
BoxedTerm : Box<Term> = {
<t:Term> => Box::new(t),
};
Term : Term = {
<a:Atom> "(" <ts: (<BoxedTerm> ",")*> <t:BoxedTerm> ")" => {
let mut ts = ts;
ts.push(t);
Term::Clause(a, ts)
},
<Atom> => Term::Atom(<>),
<Var> => Term::Var(<>),
};

1593
src/l0/l0_parser.rs Normal file

File diff suppressed because it is too large Load Diff

240
src/l0/machine.rs Normal file
View File

@@ -0,0 +1,240 @@
use l0::ast::{Addr, Atom, MachineInstruction, Program, Term, TopLevel, Var};
use std::fmt;
use std::vec::{Vec};
#[derive(Clone)]
enum HeapCell {
NamedStr(usize, Atom),
Ref(usize), // these offsets are always in reference to cells on the Heap!
Str(usize),
}
#[derive(Clone, Copy)]
enum MachineMode {
Read,
Write
}
type Heap = Vec<HeapCell>;
type Registers = Vec<HeapCell>;
pub struct MachineState {
h : usize,
s : usize,
pub fail : bool,
heap : Heap,
mode : MachineMode,
pub program : Option<Program>,
registers : Registers
}
impl MachineState {
pub fn new() -> MachineState {
MachineState { h : 0,
s : 0,
fail : false,
heap : Vec::with_capacity(256),
mode : MachineMode::Write,
program : None,
registers : vec![HeapCell::Ref(0); 33] }
}
fn lookup(&self, a: Addr) -> &HeapCell {
match a {
Addr::HeapCell(hc) => &self.heap[hc],
Addr::RegNum(reg) => &self.registers[reg]
}
}
fn deref(&self, a: Addr) -> Addr {
let mut a = a;
loop {
if let &HeapCell::Ref(value) = self.lookup(a) {
if value != a.heap_offset() {
a = Addr::HeapCell(value);
continue;
} else {
return a;
}
}
return a;
};
}
fn bind(&mut self, a: Addr, val: Addr) {
match a {
Addr::RegNum(reg) => self.registers[reg] = HeapCell::Ref(val.heap_offset()),
Addr::HeapCell(hc) => self.heap[hc] = HeapCell::Ref(val.heap_offset()),
};
}
fn unify(&mut self, a1: Addr, a2: Addr) {
let mut pdl : Vec<Addr> = 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.lookup(d1), self.lookup(d2)) {
(&HeapCell::Ref(_), _) | (_, &HeapCell::Ref(_)) =>
self.bind(d1, d2),
(&HeapCell::Str(a1), &HeapCell::Str(a2)) => {
let r1 = &self.heap[a1];
let r2 = &self.heap[a2];
if let &HeapCell::NamedStr(n1, ref f1) = r1 {
if let &HeapCell::NamedStr(n2, ref f2) = r2 {
if n1 == n2 && *f1 == *f2 {
for i in 1 .. n1 {
pdl.push(Addr::HeapCell(a1 + i));
pdl.push(Addr::HeapCell(a2 + i));
}
continue;
}
}
}
self.fail = true;
},
_ => self.fail = true,
};
}
}
}
pub fn execute(&mut self, instr: MachineInstruction) {
match instr {
MachineInstruction::GetStructure(name, arity, reg) => {
let addr = self.deref(Addr::RegNum(reg));
match self.lookup(addr) {
&HeapCell::Str(a) => {
let result = &self.heap[a];
if let &HeapCell::NamedStr(named_arity, ref named_str) = result {
if arity == named_arity && name == *named_str {
self.s = a + 1;
self.mode = MachineMode::Read;
} else {
self.fail = true;
}
}
},
&HeapCell::Ref(reg) => {
self.heap.push(HeapCell::Str(self.h + 1));
self.heap.push(HeapCell::NamedStr(arity, name));
let h = self.h;
self.bind(Addr::RegNum(reg), Addr::HeapCell(h));
self.h += 2;
self.mode = MachineMode::Write;
},
_ => {
self.fail = true;
}
};
},
MachineInstruction::PutStructure(name, arity, reg) => {
self.heap.push(HeapCell::Str(self.h + 1));
self.heap.push(HeapCell::NamedStr(arity, name));
self.registers[reg] = self.heap[self.h].clone();
self.h += 2;
},
MachineInstruction::SetVariable(reg) => {
self.heap.push(HeapCell::Ref(self.h));
self.registers[reg] = self.heap[self.h].clone();
self.h += 1;
},
MachineInstruction::SetValue(reg) => {
self.heap.push(self.registers[reg].clone());
self.h += 1;
},
MachineInstruction::UnifyVariable(reg) => {
if self.s < self.h {
match self.mode {
MachineMode::Read => self.registers[reg] = self.heap[self.s].clone(),
MachineMode::Write => {
self.heap.push(HeapCell::Ref(self.h));
self.registers[reg] = self.heap[self.h].clone();
self.h += 1;
}
};
self.s += 1;
} else {
self.fail = true;
}
},
MachineInstruction::UnifyValue(reg) => {
if self.s < self.h {
let s = self.s;
match self.mode {
MachineMode::Read => self.unify(Addr::RegNum(reg), Addr::HeapCell(s)),
MachineMode::Write => {
self.heap.push(self.registers[reg].clone());
self.h += 1;
}
};
self.s += 1;
} else {
self.fail = true;
}
}
}
}
pub fn reset_heap(&mut self) {
let program = self.program.take();
*self = MachineState::new();
self.program = program;
}
pub fn dump_registers_and_heap(&self) {
let mut c = 0;
let printer = |contents, c| {
match contents {
&HeapCell::NamedStr(ref arity, ref atom) => {
println!("{} = NAME({}, {})", c, arity, atom);
},
&HeapCell::Ref(hc) => {
println!("{} = REF({})", c, hc);
},
&HeapCell::Str(hc) => {
println!("{} = STR({})", c, hc);
}
};
};
for contents in &self.registers {
print!("X");
printer(contents, c);
c += 1;
}
println!("");
c = 0;
for contents in &self.heap {
printer(contents, c);
c += 1;
}
}
}

4
src/l0/mod.rs Normal file
View File

@@ -0,0 +1,4 @@
pub mod ast;
pub mod l0_parser;
pub mod codegen;
pub mod machine;

76
src/main.rs Normal file
View File

@@ -0,0 +1,76 @@
mod l0;
use l0::ast::{Atom, Program, Term, TopLevel, Var};
use l0::codegen::{compile_fact, compile_query};
use l0::machine::{MachineState};
use std::io::{self, Write};
fn print_instructions(program : Program) {
for instruction in program {
println!("{:}", instruction);
}
}
fn l0_repl<'a>() {
let mut ms = MachineState::new();
loop {
print!("l0> ");
io::stdout().flush();
let mut buffer = String::new();
io::stdin().read_line(&mut buffer).unwrap();
let result = l0::l0_parser::parse_TopLevel(&*buffer);
if &*buffer == "quit\n" {
break;
} else if &*buffer == "clear\n" {
ms = MachineState::new();
}
match result {
Ok(TopLevel::Fact(fact)) => {
let program = compile_fact(&fact);
ms = MachineState::new();
ms.program = Some(program);
println!("Program stored.");
},
Ok(TopLevel::Query(query)) => {
if let Some(program) = ms.program.clone().take() {
let query = compile_query(&query);
for instruction in query {
ms.execute(instruction);
}
for instruction in program {
ms.execute(instruction);
if ms.fail {
break;
}
}
if ms.fail {
println!("no");
} else {
println!("yes");
}
ms.reset_heap();
} else {
println!("No program to speak of.");
}
},
Err(_) => println!("Grammatical error of some kind!"),
};
}
}
fn main() {
l0_repl();
}