add heapview, move registers to HeapCellRef

This commit is contained in:
Mark Thom
2017-02-24 16:16:14 -07:00
parent cde396650c
commit 2fccbb09c6
12 changed files with 669 additions and 326 deletions

2
Cargo.lock generated
View File

@@ -1,6 +1,6 @@
[root]
name = "rusty-wam"
version = "0.3.0"
version = "0.3.5"
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)",

View File

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

View File

@@ -19,10 +19,13 @@ An example of the level of interaction currently supported is:
l2> p(Z, Z).
l2> ?- p(Z, 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
@@ -30,14 +33,12 @@ l2> ?- p(w, w).
yes
l2> ?- clouds(Z, Z).
no
l2> ?- clouds(Z, W).
yes
l2> ?- clouds(are, W).
yes
W = nice
l2> ?- clouds(W, nice).
yes
l2> ?- clouds(nice, are).
no
W = are
l2> ?- p(Z, h(Z, W), f(W)).
no
l2> p(Z, h(Z, W), f(W)).
@@ -45,41 +46,64 @@ 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
l2> ?- p(z, h(Z, w), f(w)).
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
W = f(a)
Z = f(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
Y = t
X = q
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
X = _0
Y = _1
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
X = s
Y = t
l2> ?- p(t, s).
no
l2> quit
```
## Occurs check
There's no occurs check, so cyclic terms do unify:
There's no occurs check, but there probably should be. Currently,
attempting to unify on a cyclic term causes an infinite loop:
```
l2> p(W, W).
l2> ?- p(f(f(W)), W).
yes
*loops to infinity*
```

View File

@@ -48,6 +48,19 @@ impl RegType {
}
}
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 From<RegType> for Addr {
fn from(reg: RegType) -> Addr {
match reg {
@@ -78,6 +91,13 @@ impl VarReg {
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 {
@@ -139,13 +159,46 @@ pub enum Addr {
StackCell(usize),
}
#[derive(Clone)]
#[derive(Clone, PartialEq)]
pub enum HeapCellValue {
NamedStr(usize, Atom),
Ref(usize),
Str(usize)
}
impl HeapCellValue {
pub fn as_ref(&self, focus: usize) -> HeapCellRef {
match self {
&HeapCellValue::Ref(r) => HeapCellRef::Ref(r),
&HeapCellValue::Str(s) => HeapCellRef::Str(s),
&HeapCellValue::NamedStr(_, _) => HeapCellRef::Str(focus)
}
}
}
#[derive(Copy, Clone)]
pub enum HeapCellRef {
Ref(usize),
Str(usize)
}
impl HeapCellRef {
pub fn heap_offset(&self) -> usize {
match self {
&HeapCellRef::Ref(r) | &HeapCellRef::Str(r) => r
}
}
}
impl From<HeapCellRef> for HeapCellValue {
fn from(hcr: HeapCellRef) -> HeapCellValue {
match hcr {
HeapCellRef::Ref(r) => HeapCellValue::Ref(r),
HeapCellRef::Str(s) => HeapCellValue::Str(s)
}
}
}
#[derive(Clone, Copy)]
pub enum CodePtr {
DirEntry(usize),
@@ -173,7 +226,7 @@ impl AddAssign<usize> for CodePtr {
pub type Heap = Vec<HeapCellValue>;
pub type Registers = Vec<HeapCellValue>;
pub type Registers = Vec<HeapCellRef>;
impl Term {
pub fn subterms(&self) -> usize {

View File

@@ -259,6 +259,10 @@ impl<'a> CodeGenerator<'a> {
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,
@@ -323,7 +327,7 @@ impl<'a> CodeGenerator<'a> {
where Target: CompilationTarget<'a>
{
let iter = Target::iter(term);
let mut target = Vec::<Target>::new();
let mut target = Vec::new();
self.marker.advance(term);
@@ -412,7 +416,7 @@ impl<'a> CodeGenerator<'a> {
body.append(&mut self.compile_query(p1));
let mut body = clauses.iter()
body = clauses.iter()
.map(|ref term| self.compile_query(term))
.fold(body, |mut body, ref mut cqs| {
body.append(cqs);
@@ -433,13 +437,18 @@ impl<'a> CodeGenerator<'a> {
}
pub fn compile_query(&mut self, term: &'a Term) -> Code {
let mut compiled_query =
vec![Line::Query(self.compile_target(term))];
let mut compiled_query = vec![Line::Query(self.compile_target(term))];
if let &Term::Clause(_, ref atom, ref terms) = term {
let call = Line::Control(ControlInstruction::Call(atom.clone(),
terms.len()));
compiled_query.push(call);
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));
},
_ => {}
}
compiled_query

64
src/l2/heapview.rs Normal file
View File

@@ -0,0 +1,64 @@
use l2::ast::*;
use std::vec::Vec;
#[derive(Clone, Copy)]
pub enum HeapCellView<'a> {
Str(usize, &'a Atom),
Var(usize)
}
pub struct HeapCellViewer<'a> {
heap: &'a Heap,
state_stack: Vec<(usize, &'a HeapCellValue)>
}
impl<'a> HeapCellViewer<'a> {
pub fn new(heap: &'a Heap, focus: usize) -> Self {
HeapCellViewer {
heap: heap,
state_stack: vec![(focus, &heap[focus])]
}
}
fn follow(&self, value: &'a HeapCellValue) -> &'a HeapCellValue {
match value {
&HeapCellValue::NamedStr(_, _) => value,
&HeapCellValue::Ref(cell_num) | &HeapCellValue::Str(cell_num) =>
&self.heap[cell_num],
}
}
}
impl<'a> Iterator for HeapCellViewer<'a> {
type Item = HeapCellView<'a>;
fn next(&mut self) -> Option<Self::Item> {
while let Some(hcv) = self.state_stack.pop() {
match hcv {
(focus, &HeapCellValue::NamedStr(arity, ref name)) => {
for i in (1 .. arity + 1).rev() {
self.state_stack.push((focus + i, &self.heap[focus + i]));
}
return Some(HeapCellView::Str(arity, name));
},
(_, &HeapCellValue::Ref(cell_num)) => {
let new_hcv = self.follow(hcv.1);
if hcv.1 == new_hcv {
return Some(HeapCellView::Var(cell_num));
} else {
self.state_stack.push((cell_num, new_hcv));
}
},
(_, &HeapCellValue::Str(cell_num)) => {
let new_hcv = self.follow(hcv.1);
self.state_stack.push((cell_num, new_hcv));
}
}
}
None
}
}

View File

@@ -29,6 +29,9 @@ Clause : Term = {
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 = {

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,9 @@
use l2::ast::*;
use l2::codegen::*;
use l2::heapview::*;
use l2::stack::*;
use std::collections::HashMap;
use std::ops::{Index, IndexMut};
use std::vec::Vec;
#[derive(Clone, Copy)]
@@ -31,28 +32,6 @@ pub struct Machine {
code_dir: CodeDir
}
impl Index<Addr> for MachineState {
type Output = HeapCellValue;
fn index(&self, index: Addr) -> &Self::Output {
match index {
Addr::HeapCell(hc) => &self.heap[hc],
Addr::RegNum(reg) => &self.registers[reg],
Addr::StackCell(sc) => &self.stack[sc]
}
}
}
impl IndexMut<Addr> for MachineState {
fn index_mut(&mut self, index: Addr) -> &mut Self::Output {
match index {
Addr::HeapCell(hc) => &mut self.heap[hc],
Addr::RegNum(reg) => &mut self.registers[reg],
Addr::StackCell(sc) => &mut self.stack[sc]
}
}
}
impl Machine {
pub fn new() -> Self {
Machine {
@@ -119,18 +98,91 @@ impl Machine {
true
}
pub fn execute_query(&mut self, query: Code) -> bool {
let mut succeeded = true;
fn heap_view(&self, var_dir: HashMap<&Var, HeapCellRef>) -> String {
let mut result = String::new();
for instr in query {
succeeded = self.execute_instr(&instr);
if !succeeded {
break;
for (var, hcr) in var_dir {
let mut arities = Vec::new();
let viewer = HeapCellViewer::new(&self.ms.heap, hcr.heap_offset());
if result != "" {
result += "\n";
}
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::Var(cell_num) => {
result += "_";
result += cell_num.to_string().as_str();
}
}
while let Some(&0) = arities.last() {
result += ")";
arities.pop();
}
}
}
self.ms.reset();
succeeded
result
}
pub fn run_query(&mut self, code: Code, cg: &CodeGenerator) -> Option<String>
{
let mut succeeded = true;
for instr in code.iter().take(1) {
succeeded = self.execute_instr(&instr);
}
if succeeded {
let mut heap_locs = HashMap::new();
for (var, vr) in cg.vars() {
let hcr = self.ms.registers[vr.root_register()];
heap_locs.insert(*var, hcr);
}
for instr in code.iter().skip(1) {
succeeded = self.execute_instr(&instr);
if !succeeded {
break;
}
}
if succeeded {
let result = Some(self.heap_view(heap_locs));
self.ms.reset();
result
} else {
self.ms.reset();
None
}
} else {
self.ms.reset();
None
}
}
}
@@ -144,14 +196,29 @@ impl MachineState {
heap: Vec::with_capacity(256),
mode: MachineMode::Write,
stack: Stack::new(),
registers: vec![HeapCellValue::Ref(0); 32] }
registers: vec![HeapCellRef::Ref(0); 32] }
}
fn register_mut(&mut self, r: RegType) -> &mut HeapCellRef {
match r {
RegType::Temp(r) => &mut self.registers[r],
RegType::Perm(r) => &mut self.stack[r]
}
}
fn lookup(&self, a: Addr) -> HeapCellRef {
match a {
Addr::HeapCell(r) => self.heap[r].as_ref(r),
Addr::RegNum(r) => self.registers[r],
Addr::StackCell(s) => self.stack[s]
}
}
fn deref(&self, a: Addr) -> Addr {
let mut a = a;
loop {
if let &HeapCellValue::Ref(value) = &self[a] {
if let HeapCellRef::Ref(value) = self.lookup(a) {
if let Addr::HeapCell(av) = a {
if value != av {
a = Addr::HeapCell(value);
@@ -180,10 +247,10 @@ impl MachineState {
loop {
match a {
addr @ Addr::RegNum(_) | addr @ Addr::StackCell(_) => {
if let HeapCellValue::Ref(hc) = self[addr] {
if let HeapCellRef::Ref(hc) = self.lookup(addr) {
a = Addr::HeapCell(hc);
} else if Self::is_unbound(&self.heap[val], val) {
self.heap[val] = self[addr].clone();
self.heap[val] = HeapCellValue::from(self.lookup(addr));
break;
} else {
self.fail = true;
@@ -216,19 +283,19 @@ impl MachineState {
let d2 = self.deref(pdl.pop().unwrap());
if d1 != d2 {
match (&self[d1], &self[d2]) {
(&HeapCellValue::Ref(hc), _) =>
match (self.lookup(d1), self.lookup(d2)) {
(HeapCellRef::Ref(hc), _) =>
self.bind(d2, hc),
(_, &HeapCellValue::Ref(hc)) =>
(_, HeapCellRef::Ref(hc)) =>
self.bind(d1, hc),
(&HeapCellValue::Str(a1), &HeapCellValue::Str(a2)) => {
(HeapCellRef::Str(a1), HeapCellRef::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 {
for i in 1 .. n1 + 1 {
pdl.push(Addr::HeapCell(a1 + i));
pdl.push(Addr::HeapCell(a2 + i));
}
@@ -240,7 +307,6 @@ impl MachineState {
self.fail = true;
},
_ => self.fail = true,
};
}
}
@@ -252,29 +318,33 @@ impl MachineState {
self.heap.push(HeapCellValue::Str(self.h + 1));
self.heap.push(HeapCellValue::NamedStr(arity, name.clone()));
self[Addr::from(reg)] = self.heap[self.h].clone();
*self.register_mut(reg) = HeapCellRef::Str(self.h + 1);
self.h += 2;
},
&QueryInstruction::PutValue(norm, arg) =>
self.registers[arg] = self[Addr::from(norm)].clone(),
self.registers[arg] = match norm {
RegType::Temp(reg) => self.registers[reg],
RegType::Perm(reg) => self.stack[reg]
},
&QueryInstruction::PutVariable(norm, arg) => {
self.heap.push(HeapCellValue::Ref(self.h));
self[Addr::from(norm)] = self.heap[self.h].clone();
self.registers[arg] = self.heap[self.h].clone();
*self.register_mut(norm) = HeapCellRef::Ref(self.h);
self.registers[arg] = HeapCellRef::Ref(self.h);
self.h += 1;
},
&QueryInstruction::SetVariable(reg) => {
self.heap.push(HeapCellValue::Ref(self.h));
self[Addr::from(reg)] = self.heap[self.h].clone();
*self.register_mut(reg) = HeapCellRef::Ref(self.h);
self.h += 1;
},
&QueryInstruction::SetValue(reg) => {
let heap_val = self[Addr::from(reg)].clone();
self.heap.push(heap_val);
let heap_val = self.lookup(Addr::from(reg));
self.heap.push(HeapCellValue::from(heap_val));
self.h += 1;
},
}
@@ -285,8 +355,8 @@ impl MachineState {
&FactInstruction::GetStructure(_, ref name, arity, reg) => {
let addr = self.deref(Addr::from(reg));
match &self[addr] {
&HeapCellValue::Str(a) => {
match self.lookup(addr) {
HeapCellRef::Str(a) => {
let result = &self.heap[a];
if let &HeapCellValue::NamedStr(narity, ref str) = result {
@@ -298,32 +368,30 @@ impl MachineState {
}
}
},
&HeapCellValue::Ref(r) => {
HeapCellRef::Ref(_) => {
self.heap.push(HeapCellValue::Str(self.h + 1));
self.heap.push(HeapCellValue::NamedStr(arity, name.clone()));
let h = self.h;
self.bind(Addr::HeapCell(r), h);
self.bind(addr, h);
self.h += 2;
self.mode = MachineMode::Write;
},
_ => self.fail = true,
}
};
},
&FactInstruction::GetVariable(norm, arg) =>
self[Addr::from(norm)] = self.registers[arg].clone(),
*self.register_mut(norm) = self.registers[arg],
&FactInstruction::GetValue(norm, arg) =>
self.unify(Addr::from(norm), Addr::RegNum(arg)),
&FactInstruction::UnifyVariable(reg) => {
match self.mode {
MachineMode::Read =>
self[Addr::from(reg)] = self.heap[self.s].clone(),
*self.register_mut(reg) = self.heap[self.s].as_ref(self.s),
MachineMode::Write => {
self.heap.push(HeapCellValue::Ref(self.h));
self[Addr::from(reg)] = self.heap[self.h].clone();
*self.register_mut(reg) = HeapCellRef::Ref(self.h);
self.h += 1;
}
};
@@ -337,8 +405,8 @@ impl MachineState {
MachineMode::Read =>
self.unify(Addr::from(reg), Addr::HeapCell(s)),
MachineMode::Write => {
let heap_val = self[Addr::from(reg)].clone();
self.heap.push(heap_val);
let heap_val = self.lookup(Addr::from(reg));
self.heap.push(HeapCellValue::from(heap_val));
self.h += 1;
}
};
@@ -371,9 +439,8 @@ impl MachineState {
self.p = self.stack.get_cp();
self.stack.pop();
},
&ControlInstruction::Proceed => {
self.p = self.cp;
}
&ControlInstruction::Proceed =>
self.p = self.cp,
};
}
@@ -387,6 +454,6 @@ impl MachineState {
self.heap.clear();
self.mode = MachineMode::Write;
self.stack = Stack::new();
self.registers = vec![HeapCellValue::Ref(0); 32];
self.registers = vec![HeapCellRef::Ref(0); 32];
}
}

View File

@@ -1,4 +1,5 @@
pub mod ast;
pub mod heapview;
pub mod iterators;
pub mod l2_parser;
pub mod codegen;

View File

@@ -5,22 +5,22 @@ use std::vec::Vec;
struct Frame {
cp: CodePtr,
perms: Vec<HeapCellValue>
perms: Vec<HeapCellRef>
}
impl Frame {
fn new(cp: CodePtr, n: usize) -> Self {
Frame {
cp: cp,
perms: vec![HeapCellValue::Ref(0); n]
perms: vec![HeapCellRef::Ref(0); n]
}
}
fn read_pv(&self, i: usize) -> &HeapCellValue {
fn read_pv(&self, i: usize) -> &HeapCellRef {
self.perms.index(i)
}
fn read_pv_mut(&mut self, i: usize) -> &mut HeapCellValue {
fn read_pv_mut(&mut self, i: usize) -> &mut HeapCellRef {
self.perms.index_mut(i)
}
}
@@ -46,7 +46,7 @@ impl Stack {
}
impl Index<usize> for Stack {
type Output = HeapCellValue;
type Output = HeapCellRef;
fn index(&self, index: usize) -> &Self::Output {
self.0.last().unwrap().read_pv(index - 1)

View File

@@ -23,6 +23,7 @@ fn l2_repl() {
break;
} else if &*buffer == "clear\n" {
wam = Machine::new();
continue;
}
let mut cg = CodeGenerator::new();
@@ -38,12 +39,17 @@ fn l2_repl() {
},
&Ok(TopLevel::Query(ref query)) => {
let compiled_query = cg.compile_query(&query);
let succeeded = wam.execute_query(compiled_query);
let output = wam.run_query(compiled_query, &cg);
if succeeded {
println!("yes");
} else {
println!("no");
match output {
Some(result) => {
println!("yes");
if result != "" {
println!("{}", result);
}
},
None => println!("no")
}
},
&Err(_) => println!("Grammatical error of some kind!"),