transition to l2
This commit is contained in:
32
Cargo.lock
generated
32
Cargo.lock
generated
@@ -1,9 +1,9 @@
|
|||||||
[root]
|
[root]
|
||||||
name = "rusty-wam"
|
name = "rusty-wam"
|
||||||
version = "0.1.0"
|
version = "0.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lalrpop 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lalrpop 0.12.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"lalrpop-util 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lalrpop-util 0.12.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -79,7 +79,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lalrpop"
|
name = "lalrpop"
|
||||||
version = "0.12.0"
|
version = "0.12.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atty 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"atty 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@@ -88,9 +88,9 @@ dependencies = [
|
|||||||
"diff 0.1.9 (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)",
|
"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)",
|
"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-intern 0.12.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"lalrpop-snap 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lalrpop-snap 0.12.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"lalrpop-util 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lalrpop-util 0.12.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"petgraph 0.1.18 (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 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)",
|
"regex-syntax 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@@ -101,12 +101,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lalrpop-intern"
|
name = "lalrpop-intern"
|
||||||
version = "0.12.0"
|
version = "0.12.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lalrpop-snap"
|
name = "lalrpop-snap"
|
||||||
version = "0.12.0"
|
version = "0.12.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atty 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"atty 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@@ -115,8 +115,8 @@ dependencies = [
|
|||||||
"diff 0.1.9 (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)",
|
"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)",
|
"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-intern 0.12.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"lalrpop-util 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lalrpop-util 0.12.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"petgraph 0.1.18 (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 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)",
|
"regex-syntax 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@@ -127,7 +127,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lalrpop-util"
|
name = "lalrpop-util"
|
||||||
version = "0.12.0"
|
version = "0.12.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -245,10 +245,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
"checksum fixedbitset 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c59882225c22dfcd2db6f0fce45dabe334e64ffa5efacb785b7ffb5af690cc6f"
|
"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 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 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 0.12.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a50b5cdf6b58f1753c86ebcc4d0852ff30478133fb370a27dbf303cbd5621fdc"
|
||||||
"checksum lalrpop-intern 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8acc7d538f0d74e035719d2b46dd34abf919e21f69d9eacd3d33d8bb91b4be91"
|
"checksum lalrpop-intern 0.12.5 (registry+https://github.com/rust-lang/crates.io-index)" = "39e21a3b0618b97e727f67d46bf1a21954384f6be6bf72558cc48f149881066e"
|
||||||
"checksum lalrpop-snap 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "40d7ede4572f90583b0bb05af8aec2dad705f865fcecf479b8ebe959b46f8435"
|
"checksum lalrpop-snap 0.12.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e82554f7abfe767e8a22286e7ca6d1ea7d873e91f0259981e15c7c6754d7340d"
|
||||||
"checksum lalrpop-util 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b2af45efc901171e23793f5edb55294dfab4fe1dc70d9df9450cb8f233ffea1f"
|
"checksum lalrpop-util 0.12.5 (registry+https://github.com/rust-lang/crates.io-index)" = "36497edf44be49f4663ebd9cfb154a81c84491986a62773c62624911efd3d84d"
|
||||||
"checksum lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "49247ec2a285bb3dcb23cbd9c35193c025e7251bfce77c1d5da97e6362dffe7f"
|
"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 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 memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "rusty-wam"
|
name = "rusty-wam"
|
||||||
version = "0.1.0"
|
version = "0.3.0"
|
||||||
authors = ["Mark Thom"]
|
authors = ["Mark Thom"]
|
||||||
|
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
@@ -8,7 +8,7 @@ build = "build.rs"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
|
|
||||||
[dependencies.lalrpop-util]
|
[dependencies.lalrpop-util]
|
||||||
version = "0.12.0"
|
version = "0.12.5"
|
||||||
|
|
||||||
[build-dependencies.lalrpop]
|
[build-dependencies.lalrpop]
|
||||||
version = "0.12.0"
|
version = "0.12.5"
|
||||||
73
README.md
73
README.md
@@ -8,55 +8,70 @@ pure Prolog.
|
|||||||
|
|
||||||
## Progress
|
## Progress
|
||||||
|
|
||||||
The language L1 is implemented as a simple REPL. It supports
|
The language L2 is implemented as a simple REPL. It supports
|
||||||
unification on facts and queries without backtracking and rules
|
unification on queries without backtracking, where rules and facts are
|
||||||
without clauses, in the familiar Prolog syntax. No data types apart
|
limited to a single name/arity pairing, in the familiar Prolog
|
||||||
from atoms are currently supported.
|
syntax. No data types apart from atoms are currently supported.
|
||||||
|
|
||||||
An example of the level of interaction currently supported is:
|
An example of the level of interaction currently supported is:
|
||||||
|
|
||||||
```
|
```
|
||||||
l1> p(Z, Z).
|
l2> p(Z, Z).
|
||||||
l1> ?- p(Z, Z).
|
l2> ?- p(Z, Z).
|
||||||
yes
|
yes
|
||||||
l1> ?- p(Z, z).
|
l2> ?- p(Z, z).
|
||||||
yes
|
yes
|
||||||
l1> ?- p(Z, w).
|
l2> ?- p(Z, w).
|
||||||
yes
|
yes
|
||||||
l1> clouds(are, nice).
|
l2> clouds(are, nice).
|
||||||
l1> ?- p(z, w).
|
l2> ?- p(z, w).
|
||||||
no
|
no
|
||||||
l1> ?- p(w, w).
|
l2> ?- p(w, w).
|
||||||
yes
|
yes
|
||||||
l1> ?- clouds(Z, Z).
|
l2> ?- clouds(Z, Z).
|
||||||
no
|
no
|
||||||
l1> ?- clouds(Z, W).
|
l2> ?- clouds(Z, W).
|
||||||
yes
|
yes
|
||||||
l1> ?- clouds(are, W).
|
l2> ?- clouds(are, W).
|
||||||
yes
|
yes
|
||||||
l1> ?- clouds(W, nice).
|
l2> ?- clouds(W, nice).
|
||||||
yes
|
yes
|
||||||
l1> ?- clouds(nice, are).
|
l2> ?- clouds(nice, are).
|
||||||
no
|
no
|
||||||
l1> ?- p(Z, h(Z, W), f(W)).
|
l2> ?- p(Z, h(Z, W), f(W)).
|
||||||
no
|
no
|
||||||
l1> p(Z, h(Z, W), f(W)).
|
l2> p(Z, h(Z, W), f(W)).
|
||||||
l1> ?- p(z, h(z, z), f(w)).
|
l2> ?- p(z, h(z, z), f(w)).
|
||||||
no
|
no
|
||||||
l1> ?- p(z, h(z, w), f(w)).
|
l2> ?- p(z, h(z, w), f(w)).
|
||||||
yes
|
yes
|
||||||
l1> ?- p(Z, h(z, W), f(w)).
|
l2> ?- p(Z, h(z, W), f(w)).
|
||||||
yes
|
yes
|
||||||
l1> ?- p(z, h(Z, w), f(w)).
|
l2> ?- p(z, h(Z, w), f(w)).
|
||||||
yes
|
yes
|
||||||
l1> ?- p(Z, h(Z, w), f(Z)).
|
l2> ?- p(Z, h(Z, w), f(Z)).
|
||||||
yes
|
yes
|
||||||
l1> ?- p(z, h(Z, w), f(Z)).
|
l2> ?- p(z, h(Z, w), f(Z)).
|
||||||
no
|
no
|
||||||
l1> p(f(X), h(Y, f(a)), Y).
|
l2> p(f(X), h(Y, f(a)), Y).
|
||||||
l1> ?- p(Z, h(Z, W), f(W)).
|
l2> ?- p(Z, h(Z, W), f(W)).
|
||||||
yes
|
yes
|
||||||
l1> quit
|
l2> p(X, Y) :- q(X, Z), r(Z, Y).
|
||||||
|
l2> q(q, s).
|
||||||
|
l2> r(s, t).
|
||||||
|
l2> ?- p(X, Y).
|
||||||
|
yes
|
||||||
|
l2> ?- p(q, t).
|
||||||
|
yes
|
||||||
|
l2> ?- p(t, q).
|
||||||
|
no
|
||||||
|
l2> ?- p(q, T).
|
||||||
|
yes
|
||||||
|
l2> ?- p(Q, t).
|
||||||
|
yes
|
||||||
|
l2> ?- p(t, t).
|
||||||
|
no
|
||||||
|
l2> quit
|
||||||
```
|
```
|
||||||
|
|
||||||
## Occurs check
|
## Occurs check
|
||||||
@@ -64,7 +79,7 @@ l1> quit
|
|||||||
There's no occurs check, so cyclic terms do unify:
|
There's no occurs check, so cyclic terms do unify:
|
||||||
|
|
||||||
```
|
```
|
||||||
l1> p(W, W).
|
l2> p(W, W).
|
||||||
l1> ?- p(f(f(W)), W).
|
l2> ?- p(f(f(W)), W).
|
||||||
yes
|
yes
|
||||||
```
|
```
|
||||||
200
src/l2/ast.rs
Normal file
200
src/l2/ast.rs
Normal file
@@ -0,0 +1,200 @@
|
|||||||
|
use std::cell::Cell;
|
||||||
|
use std::fmt;
|
||||||
|
use std::ops::{Add, AddAssign};
|
||||||
|
use std::vec::Vec;
|
||||||
|
|
||||||
|
pub type Var = String;
|
||||||
|
|
||||||
|
pub type Atom = String;
|
||||||
|
|
||||||
|
pub enum TopLevel {
|
||||||
|
Fact(Term),
|
||||||
|
Rule(Rule),
|
||||||
|
Query(Term)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum Level {
|
||||||
|
Shallow, Deep
|
||||||
|
}
|
||||||
|
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<RegType> for Addr {
|
||||||
|
fn from(reg: RegType) -> Addr {
|
||||||
|
match reg {
|
||||||
|
RegType::Perm(reg) => Addr::StackCell(reg),
|
||||||
|
RegType::Temp(reg) => Addr::RegNum(reg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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 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 ControlInstruction {
|
||||||
|
Allocate(usize),
|
||||||
|
Call(Atom, usize),
|
||||||
|
Deallocate,
|
||||||
|
Proceed
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type CompiledFact = Vec<FactInstruction>;
|
||||||
|
|
||||||
|
pub type CompiledQuery = Vec<QueryInstruction>;
|
||||||
|
|
||||||
|
pub enum Line {
|
||||||
|
Control(ControlInstruction),
|
||||||
|
Fact(CompiledFact),
|
||||||
|
Query(CompiledQuery)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type Code = Vec<Line>;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq)]
|
||||||
|
pub enum Addr {
|
||||||
|
HeapCell(usize),
|
||||||
|
RegNum(usize),
|
||||||
|
StackCell(usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum HeapCellValue {
|
||||||
|
NamedStr(usize, Atom),
|
||||||
|
Ref(usize),
|
||||||
|
Str(usize)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum CodePtr {
|
||||||
|
DirEntry(usize),
|
||||||
|
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<HeapCellValue>;
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
447
src/l2/codegen.rs
Normal file
447
src/l2/codegen.rs
Normal file
@@ -0,0 +1,447 @@
|
|||||||
|
use l2::ast::*;
|
||||||
|
use l2::iterators::{FactIterator, QueryIterator};
|
||||||
|
|
||||||
|
use std::cell::Cell;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::fmt;
|
||||||
|
use std::vec::Vec;
|
||||||
|
|
||||||
|
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 {}/{}, A{}", name, arity, r.reg_num()),
|
||||||
|
&QueryInstruction::PutStructure(Level::Shallow, ref name, ref arity, ref r) =>
|
||||||
|
write!(f, "put_structure {}/{}, {}", name, arity, r),
|
||||||
|
&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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 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(&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() }
|
||||||
|
}
|
||||||
|
|
||||||
|
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::<Target>::new();
|
||||||
|
|
||||||
|
self.marker.advance(term);
|
||||||
|
|
||||||
|
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 | TermStatus::Recurrent =>
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
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)));
|
||||||
|
body.push(Line::Fact(self.compile_target(p0)));
|
||||||
|
|
||||||
|
body.append(&mut self.compile_query(p1));
|
||||||
|
|
||||||
|
let mut 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 {
|
||||||
|
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 {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
compiled_query
|
||||||
|
}
|
||||||
|
}
|
||||||
175
src/l2/iterators.rs
Normal file
175
src/l2/iterators.rs
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
use l2::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)
|
||||||
|
}
|
||||||
|
}
|
||||||
42
src/l2/l2_parser.lalrpop
Normal file
42
src/l2/l2_parser.lalrpop
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
use l2::ast::*;
|
||||||
|
|
||||||
|
use std::cell::Cell;
|
||||||
|
|
||||||
|
grammar;
|
||||||
|
|
||||||
|
pub TopLevel: TopLevel = {
|
||||||
|
"?-" <t:Term> "." => TopLevel::Query(t),
|
||||||
|
<r:Rule> "." => TopLevel::Rule(r),
|
||||||
|
<t:Term> "." => TopLevel::Fact(t),
|
||||||
|
};
|
||||||
|
|
||||||
|
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)
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
Rule : Rule = {
|
||||||
|
<c:Clause> ":-" <h:Term> <cs: ("," <Term>)*> =>
|
||||||
|
Rule { head: (c, 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(),
|
||||||
|
};
|
||||||
1767
src/l2/l2_parser.rs
Normal file
1767
src/l2/l2_parser.rs
Normal file
File diff suppressed because it is too large
Load Diff
400
src/l2/machine.rs
Normal file
400
src/l2/machine.rs
Normal file
@@ -0,0 +1,400 @@
|
|||||||
|
use l2::ast::*;
|
||||||
|
use l2::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,
|
||||||
|
cp: CodePtr,
|
||||||
|
fail: bool,
|
||||||
|
heap: Heap,
|
||||||
|
mode: MachineMode,
|
||||||
|
stack: Stack,
|
||||||
|
registers: Registers
|
||||||
|
}
|
||||||
|
|
||||||
|
type CodeDir = HashMap<(Atom, usize), usize>;
|
||||||
|
|
||||||
|
pub struct Machine {
|
||||||
|
ms: MachineState,
|
||||||
|
code: Code,
|
||||||
|
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 {
|
||||||
|
ms: MachineState::new(),
|
||||||
|
code: Vec::new(),
|
||||||
|
code_dir: HashMap::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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.1.arity();
|
||||||
|
|
||||||
|
self.code.append(&mut code);
|
||||||
|
self.code_dir.insert((name, arity), p);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn execute_instr(&mut self, instr: &Line) -> bool {
|
||||||
|
let mut instr = instr;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
match 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() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
match self.ms.p {
|
||||||
|
CodePtr::DirEntry(p) if p < self.code.len() =>
|
||||||
|
instr = &self.code[p],
|
||||||
|
_ => break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn execute_query(&mut self, query: Code) -> bool {
|
||||||
|
let mut succeeded = true;
|
||||||
|
|
||||||
|
for instr in query {
|
||||||
|
succeeded = self.execute_instr(&instr);
|
||||||
|
if !succeeded {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.ms.reset();
|
||||||
|
succeeded
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MachineState {
|
||||||
|
fn new() -> MachineState {
|
||||||
|
MachineState { h: 0,
|
||||||
|
s: 0,
|
||||||
|
p: CodePtr::TopLevel,
|
||||||
|
cp: CodePtr::TopLevel,
|
||||||
|
fail: false,
|
||||||
|
heap: Vec::with_capacity(256),
|
||||||
|
mode: MachineMode::Write,
|
||||||
|
stack: Stack::new(),
|
||||||
|
registers: vec![HeapCellValue::Ref(0); 32] }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lookup(&self, a: Addr) -> &HeapCellValue {
|
||||||
|
match a {
|
||||||
|
Addr::HeapCell(hc) => &self.heap[hc],
|
||||||
|
Addr::RegNum(reg) => &self.registers[reg],
|
||||||
|
Addr::StackCell(sc) => &self.stack[sc]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deref(&self, a: Addr) -> Addr {
|
||||||
|
let mut a = a;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if let &HeapCellValue::Ref(value) = self.lookup(a) {
|
||||||
|
if let Addr::HeapCell(av) = a {
|
||||||
|
if value != av {
|
||||||
|
a = Addr::HeapCell(value);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
a = Addr::HeapCell(value);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return a;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_unbound(hc: &HeapCellValue, index: usize) -> bool {
|
||||||
|
match hc {
|
||||||
|
&HeapCellValue::Ref(r) => r == index,
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bind(&mut self, a: Addr, val: usize) {
|
||||||
|
let mut a = a;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
match a {
|
||||||
|
addr @ Addr::RegNum(_) | addr @ Addr::StackCell(_) => {
|
||||||
|
if let HeapCellValue::Ref(hc) = self[addr] {
|
||||||
|
a = Addr::HeapCell(hc);
|
||||||
|
} else if Self::is_unbound(&self.heap[val], val) {
|
||||||
|
self.heap[val] = self[addr].clone();
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
self.fail = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Addr::HeapCell(hc) => {
|
||||||
|
if Self::is_unbound(&self.heap[hc], hc) {
|
||||||
|
self.heap[hc] = HeapCellValue::Ref(val);
|
||||||
|
break;
|
||||||
|
} else if Self::is_unbound(&self.heap[val], val) {
|
||||||
|
self.heap[val] = HeapCellValue::Ref(hc);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
self.fail = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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.lookup(d1), self.lookup(d2)) {
|
||||||
|
(&HeapCellValue::Ref(hc), _) =>
|
||||||
|
self.bind(d2, hc),
|
||||||
|
(_, &HeapCellValue::Ref(hc)) =>
|
||||||
|
self.bind(d1, hc),
|
||||||
|
(&HeapCellValue::Str(a1), &HeapCellValue::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 {
|
||||||
|
pdl.push(Addr::HeapCell(a1 + i));
|
||||||
|
pdl.push(Addr::HeapCell(a2 + i));
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.fail = true;
|
||||||
|
},
|
||||||
|
_ => self.fail = true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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[Addr::from(reg)] = self.heap[self.h].clone();
|
||||||
|
|
||||||
|
self.h += 2;
|
||||||
|
},
|
||||||
|
&QueryInstruction::PutValue(norm, arg) =>
|
||||||
|
self.registers[arg] = self[Addr::from(norm)].clone(),
|
||||||
|
&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.h += 1;
|
||||||
|
},
|
||||||
|
&QueryInstruction::SetVariable(reg) => {
|
||||||
|
self.heap.push(HeapCellValue::Ref(self.h));
|
||||||
|
self[Addr::from(reg)] = self.heap[self.h].clone();
|
||||||
|
|
||||||
|
self.h += 1;
|
||||||
|
},
|
||||||
|
&QueryInstruction::SetValue(reg) => {
|
||||||
|
let heap_val = self[Addr::from(reg)].clone();
|
||||||
|
self.heap.push(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(Addr::from(reg));
|
||||||
|
|
||||||
|
match self.lookup(addr) {
|
||||||
|
&HeapCellValue::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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
&HeapCellValue::Ref(r) => {
|
||||||
|
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.h += 2;
|
||||||
|
self.mode = MachineMode::Write;
|
||||||
|
},
|
||||||
|
_ => self.fail = true,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
&FactInstruction::GetVariable(norm, arg) =>
|
||||||
|
self[Addr::from(norm)] = self.registers[arg].clone(),
|
||||||
|
&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(),
|
||||||
|
MachineMode::Write => {
|
||||||
|
self.heap.push(HeapCellValue::Ref(self.h));
|
||||||
|
|
||||||
|
self[Addr::from(reg)] = self.heap[self.h].clone();
|
||||||
|
self.h += 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.s += 1;
|
||||||
|
},
|
||||||
|
&FactInstruction::UnifyValue(reg) => {
|
||||||
|
let s = self.s;
|
||||||
|
|
||||||
|
match self.mode {
|
||||||
|
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);
|
||||||
|
self.h += 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.s += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn execute_ctrl_instr(&mut self, code_dir: &CodeDir, instr: &ControlInstruction)
|
||||||
|
{
|
||||||
|
match instr {
|
||||||
|
&ControlInstruction::Allocate(num_cells) => {
|
||||||
|
self.stack.push(self.cp, num_cells);
|
||||||
|
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.p = CodePtr::DirEntry(compiled_tl_index);
|
||||||
|
},
|
||||||
|
None => self.fail = true
|
||||||
|
};
|
||||||
|
},
|
||||||
|
&ControlInstruction::Deallocate => {
|
||||||
|
self.p = self.stack.get_cp();
|
||||||
|
self.stack.pop();
|
||||||
|
},
|
||||||
|
&ControlInstruction::Proceed => {
|
||||||
|
self.p = self.cp;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reset(&mut self) {
|
||||||
|
self.h = 0;
|
||||||
|
self.s = 0;
|
||||||
|
self.p = CodePtr::TopLevel;
|
||||||
|
self.cp = CodePtr::TopLevel;
|
||||||
|
|
||||||
|
self.fail = false;
|
||||||
|
self.heap.clear();
|
||||||
|
self.mode = MachineMode::Write;
|
||||||
|
self.stack = Stack::new();
|
||||||
|
self.registers = vec![HeapCellValue::Ref(0); 32];
|
||||||
|
}
|
||||||
|
}
|
||||||
6
src/l2/mod.rs
Normal file
6
src/l2/mod.rs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
pub mod ast;
|
||||||
|
pub mod iterators;
|
||||||
|
pub mod l2_parser;
|
||||||
|
pub mod codegen;
|
||||||
|
pub mod machine;
|
||||||
|
pub mod stack;
|
||||||
60
src/l2/stack.rs
Normal file
60
src/l2/stack.rs
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
use l2::ast::*;
|
||||||
|
|
||||||
|
use std::ops::{Index, IndexMut};
|
||||||
|
use std::vec::Vec;
|
||||||
|
|
||||||
|
struct Frame {
|
||||||
|
cp: CodePtr,
|
||||||
|
perms: Vec<HeapCellValue>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Frame {
|
||||||
|
fn new(cp: CodePtr, n: usize) -> Self {
|
||||||
|
Frame {
|
||||||
|
cp: cp,
|
||||||
|
perms: vec![HeapCellValue::Ref(0); n]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_pv(&self, i: usize) -> &HeapCellValue {
|
||||||
|
self.perms.index(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_pv_mut(&mut self, i: usize) -> &mut HeapCellValue {
|
||||||
|
self.perms.index_mut(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Stack(Vec<Frame>);
|
||||||
|
|
||||||
|
impl Stack {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Stack(Vec::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push(&mut self, cp: CodePtr, n: usize) {
|
||||||
|
self.0.push(Frame::new(cp, n));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_cp(&self) -> CodePtr {
|
||||||
|
self.0.last().unwrap().cp
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop(&mut self) {
|
||||||
|
self.0.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Index<usize> for Stack {
|
||||||
|
type Output = HeapCellValue;
|
||||||
|
|
||||||
|
fn index(&self, index: usize) -> &Self::Output {
|
||||||
|
self.0.last().unwrap().read_pv(index - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IndexMut<usize> for Stack {
|
||||||
|
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
||||||
|
self.0.last_mut().unwrap().read_pv_mut(index - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
54
src/main.rs
54
src/main.rs
@@ -1,56 +1,56 @@
|
|||||||
mod l1;
|
mod l2;
|
||||||
|
|
||||||
use l1::ast::TopLevel;
|
use l2::ast::*;
|
||||||
use l1::codegen::{compile_fact, compile_query};
|
use l2::codegen::*;
|
||||||
use l1::machine::Machine;
|
use l2::machine::*;
|
||||||
|
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
|
|
||||||
fn l1_repl() {
|
fn l2_repl() {
|
||||||
let mut ms = Machine::new();
|
let mut wam = Machine::new();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
print!("l1> ");
|
print!("l2> ");
|
||||||
|
|
||||||
let _ = io::stdout().flush();
|
let _ = io::stdout().flush();
|
||||||
let mut buffer = String::new();
|
let mut buffer = String::new();
|
||||||
|
|
||||||
io::stdin().read_line(&mut buffer).unwrap();
|
io::stdin().read_line(&mut buffer).unwrap();
|
||||||
|
|
||||||
let result = l1::l1_parser::parse_TopLevel(&*buffer);
|
let result = l2::l2_parser::parse_TopLevel(&*buffer);
|
||||||
|
|
||||||
if &*buffer == "quit\n" {
|
if &*buffer == "quit\n" {
|
||||||
break;
|
break;
|
||||||
} else if &*buffer == "clear\n" {
|
} else if &*buffer == "clear\n" {
|
||||||
ms = Machine::new();
|
wam = Machine::new();
|
||||||
}
|
}
|
||||||
|
|
||||||
match result {
|
let mut cg = CodeGenerator::new();
|
||||||
Ok(TopLevel::Fact(fact)) => {
|
|
||||||
let name = fact.name().to_owned();
|
|
||||||
let arity = fact.arity();
|
|
||||||
let fact = compile_fact(&fact);
|
|
||||||
|
|
||||||
ms.add_fact(fact, name, arity);
|
match &result {
|
||||||
|
&Ok(TopLevel::Fact(ref fact)) => {
|
||||||
|
let compiled_fact = cg.compile_fact(&fact);
|
||||||
|
wam.add_fact(fact, compiled_fact);
|
||||||
},
|
},
|
||||||
Ok(TopLevel::Query(query)) => {
|
&Ok(TopLevel::Rule(ref rule)) => {
|
||||||
let compiled_query = compile_query(&query);
|
let compiled_rule = cg.compile_rule(&rule);
|
||||||
|
wam.add_rule(rule, compiled_rule);
|
||||||
ms.execute_query(&compiled_query);
|
},
|
||||||
|
&Ok(TopLevel::Query(ref query)) => {
|
||||||
if ms.failed() {
|
let compiled_query = cg.compile_query(&query);
|
||||||
println!("no");
|
let succeeded = wam.execute_query(compiled_query);
|
||||||
} else {
|
|
||||||
|
if succeeded {
|
||||||
println!("yes");
|
println!("yes");
|
||||||
|
} else {
|
||||||
|
println!("no");
|
||||||
}
|
}
|
||||||
|
|
||||||
ms.reset_machine_state();
|
|
||||||
},
|
},
|
||||||
Err(_) => println!("Grammatical error of some kind!"),
|
&Err(_) => println!("Grammatical error of some kind!"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
l1_repl();
|
l2_repl();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user