Merge branch 'master' of https://github.com/mthom/rusty-wam
This commit is contained in:
6
Cargo.lock
generated
6
Cargo.lock
generated
@@ -311,7 +311,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "prolog_parser"
|
name = "prolog_parser"
|
||||||
version = "0.8.36"
|
version = "0.8.37"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lexical 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lexical 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@@ -447,7 +447,7 @@ dependencies = [
|
|||||||
"nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"num-rug-adapter 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"num-rug-adapter 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ordered-float 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ordered-float 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"prolog_parser 0.8.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
"prolog_parser 0.8.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ref_thread_local 0.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ref_thread_local 0.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rug 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rug 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rustyline 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rustyline 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@@ -590,7 +590,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
"checksum num-traits 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "443c53b3c3531dfcbfa499d8893944db78474ad7a1d87fa2d94d1a2231693ac6"
|
"checksum num-traits 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "443c53b3c3531dfcbfa499d8893944db78474ad7a1d87fa2d94d1a2231693ac6"
|
||||||
"checksum ordered-float 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7eb5259643245d3f292c7a146b2df53bba24d7eab159410e648eb73dc164669d"
|
"checksum ordered-float 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7eb5259643245d3f292c7a146b2df53bba24d7eab159410e648eb73dc164669d"
|
||||||
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
|
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
|
||||||
"checksum prolog_parser 0.8.36 (registry+https://github.com/rust-lang/crates.io-index)" = "fea0ae985b51f28cb3582469fbe9318e238d504a7358d90eb671f0d772fb5061"
|
"checksum prolog_parser 0.8.37 (registry+https://github.com/rust-lang/crates.io-index)" = "cb3da90085db170f1045f7d6851da12400ab205af9ec2acaa5ee42ab45a25dd8"
|
||||||
"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
|
"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
|
||||||
"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
|
"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
|
||||||
"checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
|
"checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ libc = "0.2.62"
|
|||||||
nix = "0.15.0"
|
nix = "0.15.0"
|
||||||
num-rug-adapter = { optional = true, version = "0.1.1" }
|
num-rug-adapter = { optional = true, version = "0.1.1" }
|
||||||
ordered-float = "0.5.0"
|
ordered-float = "0.5.0"
|
||||||
prolog_parser = { version = "0.8.36", default-features = false }
|
prolog_parser = { version = "0.8.37", default-features = false }
|
||||||
ref_thread_local = "0.0.0"
|
ref_thread_local = "0.0.0"
|
||||||
rug = { version = "1.4.0", optional = true }
|
rug = { version = "1.4.0", optional = true }
|
||||||
rustyline = "5.0.3"
|
rustyline = "5.0.3"
|
||||||
|
|||||||
11
README.md
11
README.md
@@ -50,6 +50,8 @@ Extend Scryer Prolog to include the following, among other features:
|
|||||||
- [x] Backtrackable and non-backtrackable global variables via `bb_get/2`
|
- [x] Backtrackable and non-backtrackable global variables via `bb_get/2`
|
||||||
`bb_put/2` (non-backtrackable) and `bb_b_put/2`
|
`bb_put/2` (non-backtrackable) and `bb_b_put/2`
|
||||||
(backtrackable).
|
(backtrackable).
|
||||||
|
- [ ] Delimited continuations based on reset/3, shift/1 (documented in
|
||||||
|
"Delimited Continuations for Prolog") (_in progress_).
|
||||||
- [ ] clp(B) and clp(ℤ) as builtin libraries (_in progress_).
|
- [ ] clp(B) and clp(ℤ) as builtin libraries (_in progress_).
|
||||||
- [ ] Streams and predicates for stream control (_in progress_).
|
- [ ] Streams and predicates for stream control (_in progress_).
|
||||||
- [ ] An incremental compacting garbage collector satisfying the five
|
- [ ] An incremental compacting garbage collector satisfying the five
|
||||||
@@ -79,15 +81,12 @@ Programming?"
|
|||||||
unum implementation or an ad hoc one. Unums are described in
|
unum implementation or an ad hoc one. Unums are described in
|
||||||
Gustafson's book "The End of Error."
|
Gustafson's book "The End of Error."
|
||||||
|
|
||||||
3. Add support for shift/reset delimited continuations, see "Delimited
|
3. Add concurrent tables to manage shared references to atoms and
|
||||||
Continuations for Prolog."
|
|
||||||
|
|
||||||
4. Add concurrent tables to manage shared references to atoms and
|
|
||||||
strings.
|
strings.
|
||||||
|
|
||||||
5. Add optional SLG resolution for fast memoization of predicates.
|
4. Add optional SLG resolution for fast memoization of predicates.
|
||||||
|
|
||||||
6. Add some form of JIT predicate indexing.
|
5. Add some form of JIT predicate indexing.
|
||||||
|
|
||||||
## Installing Scryer Prolog
|
## Installing Scryer Prolog
|
||||||
|
|
||||||
|
|||||||
@@ -1,51 +0,0 @@
|
|||||||
use std::cell::{Cell};
|
|
||||||
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(Cell<usize>, Atom),
|
|
||||||
Clause(Cell<usize>, Atom, Vec<Box<Term>>),
|
|
||||||
Var(Cell<usize>, Var)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum FactInstruction {
|
|
||||||
GetStructure(Atom, usize, usize),
|
|
||||||
UnifyVariable(usize),
|
|
||||||
UnifyValue(usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum QueryInstruction {
|
|
||||||
PutStructure(Atom, usize, usize),
|
|
||||||
SetVariable(usize),
|
|
||||||
SetValue(usize),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type CompiledFact = Vec<FactInstruction>;
|
|
||||||
|
|
||||||
pub type CompiledQuery = Vec<QueryInstruction>;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
|
||||||
pub enum Addr {
|
|
||||||
HeapCell(usize),
|
|
||||||
RegNum(usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Term {
|
|
||||||
pub fn set_cell(&self, cell_num: usize) {
|
|
||||||
match self {
|
|
||||||
&Term::Atom(ref cell, _) => cell.set(cell_num),
|
|
||||||
&Term::Clause(ref cell, _, _) => cell.set(cell_num),
|
|
||||||
&Term::Var(ref cell, _) => cell.set(cell_num)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,126 +0,0 @@
|
|||||||
use l0::ast::{Atom, Term, FactInstruction, QueryInstruction, Var};
|
|
||||||
use l0::iterators::{BreadthFirstIterator, PostOrderIterator};
|
|
||||||
|
|
||||||
use std::collections::{HashSet};
|
|
||||||
use std::fmt;
|
|
||||||
use std::vec::{Vec};
|
|
||||||
|
|
||||||
impl fmt::Display for QueryInstruction {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&QueryInstruction::PutStructure(ref a, ref s, ref r) =>
|
|
||||||
write!(f, "put_structure {}/{}, X{}", a, s, r),
|
|
||||||
&QueryInstruction::SetVariable(ref r) =>
|
|
||||||
write!(f, "set_variable X{}", r),
|
|
||||||
&QueryInstruction::SetValue(ref r) =>
|
|
||||||
write!(f, "set_value X{}", r),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for FactInstruction {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&FactInstruction::GetStructure(ref a, ref s, ref r) =>
|
|
||||||
write!(f, "get_structure {}/{}, X{}", a, s, r),
|
|
||||||
&FactInstruction::UnifyVariable(ref r) =>
|
|
||||||
write!(f, "unify_variable X{}", r),
|
|
||||||
&FactInstruction::UnifyValue(ref r) =>
|
|
||||||
write!(f, "unify_value X{}", r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait CompilationTarget<'a> {
|
|
||||||
type Iterator : Iterator<Item=&'a Term>;
|
|
||||||
|
|
||||||
fn iter(term: &'a Term) -> Self::Iterator;
|
|
||||||
|
|
||||||
fn to_structure(name: Atom, arity: usize, cell_num: usize) -> Self;
|
|
||||||
fn to_value(cell_num: usize) -> Self;
|
|
||||||
fn to_variable(cell_num: usize) -> Self;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> CompilationTarget<'a> for FactInstruction {
|
|
||||||
type Iterator = BreadthFirstIterator<'a>;
|
|
||||||
|
|
||||||
fn iter(term: &'a Term) -> Self::Iterator {
|
|
||||||
term.breadth_first_iter()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_structure(name: Atom, arity: usize, cell_num: usize) -> Self {
|
|
||||||
FactInstruction::GetStructure(name, arity, cell_num)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_value(cell_num: usize) -> Self {
|
|
||||||
FactInstruction::UnifyValue(cell_num)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_variable(cell_num: usize) -> Self {
|
|
||||||
FactInstruction::UnifyVariable(cell_num)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> CompilationTarget<'a> for QueryInstruction {
|
|
||||||
type Iterator = PostOrderIterator<'a>;
|
|
||||||
|
|
||||||
fn iter(term: &'a Term) -> Self::Iterator {
|
|
||||||
term.post_order_iter()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_structure(name: Atom, arity: usize, cell_num: usize) -> Self {
|
|
||||||
QueryInstruction::PutStructure(name, arity, cell_num)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_value(cell_num: usize) -> Self {
|
|
||||||
QueryInstruction::SetValue(cell_num)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_variable(cell_num: usize) -> Self {
|
|
||||||
QueryInstruction::SetVariable(cell_num)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subterm_to_instr<'a, Target>(subterm: &'a Term,
|
|
||||||
bindings: &mut HashSet<&'a Var>)
|
|
||||||
-> Target
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
match subterm {
|
|
||||||
&Term::Atom(ref cell_num, _) =>
|
|
||||||
Target::to_value(cell_num.get()),
|
|
||||||
&Term::Var(ref cell_num, ref atom) if bindings.contains(atom) =>
|
|
||||||
Target::to_value(cell_num.get()),
|
|
||||||
&Term::Var(ref cell_num, ref atom) => {
|
|
||||||
bindings.insert(atom);
|
|
||||||
Target::to_variable(cell_num.get())
|
|
||||||
},
|
|
||||||
&Term::Clause(ref cell_num, _, _) =>
|
|
||||||
Target::to_value(cell_num.get())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compile_target<'a, Target>(term: &'a Term) -> Vec<Target>
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
let mut iter = Target::iter(term);
|
|
||||||
let mut target = Vec::<Target>::new();
|
|
||||||
let mut bindings = HashSet::new();
|
|
||||||
|
|
||||||
while let Some(term) = iter.next() {
|
|
||||||
match term {
|
|
||||||
&Term::Atom(ref cell_num, ref atom) =>
|
|
||||||
target.push(Target::to_structure(atom.clone(), 0, cell_num.get())),
|
|
||||||
&Term::Clause(ref cell_num, ref atom, ref terms) => {
|
|
||||||
target.push(Target::to_structure(atom.clone(), 0, cell_num.get()));
|
|
||||||
|
|
||||||
for subterm in terms {
|
|
||||||
target.push(subterm_to_instr(subterm.as_ref(), &mut bindings));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => {},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
target
|
|
||||||
}
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
use l0::ast::{Term};
|
|
||||||
|
|
||||||
use std::collections::{VecDeque};
|
|
||||||
use std::vec::{Vec};
|
|
||||||
|
|
||||||
enum DepthFirstIteratorState<'a> {
|
|
||||||
// child no., the containing clause, its vector.
|
|
||||||
Clause(usize, &'a Term, &'a Vec<Box<Term>>),
|
|
||||||
NonClause(&'a Term)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct PostOrderIterator<'a> {
|
|
||||||
state_stack: Vec<DepthFirstIteratorState<'a>>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> PostOrderIterator<'a> {
|
|
||||||
fn push_clause(&mut self,
|
|
||||||
child_num: usize,
|
|
||||||
term: &'a Term,
|
|
||||||
child_terms: &'a Vec<Box<Term>>)
|
|
||||||
{
|
|
||||||
self.state_stack.push(DepthFirstIteratorState::Clause(child_num,
|
|
||||||
term,
|
|
||||||
child_terms));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render_new_state(term: &'a Term) -> DepthFirstIteratorState<'a> {
|
|
||||||
match term {
|
|
||||||
&Term::Clause(_, _, ref child_terms) =>
|
|
||||||
DepthFirstIteratorState::Clause(0, term, child_terms),
|
|
||||||
_ => DepthFirstIteratorState::NonClause(term)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn push_term(&mut self, term: &'a Term) {
|
|
||||||
self.state_stack.push(Self::render_new_state(term));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for PostOrderIterator<'a> {
|
|
||||||
type Item = &'a Term;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
while let Some(iter_state) = self.state_stack.pop() {
|
|
||||||
match iter_state {
|
|
||||||
DepthFirstIteratorState::Clause(child_num, term, child_terms) => {
|
|
||||||
if child_num == child_terms.len() {
|
|
||||||
return Some(term);
|
|
||||||
} else {
|
|
||||||
self.push_clause(child_num + 1, term, child_terms);
|
|
||||||
self.push_term(child_terms[child_num].as_ref());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
DepthFirstIteratorState::NonClause(term) => return Some(term),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct BreadthFirstIterator<'a> {
|
|
||||||
state_queue : VecDeque<&'a Term>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for BreadthFirstIterator<'a> {
|
|
||||||
type Item = &'a Term;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
if let Some(term) = self.state_queue.pop_front() {
|
|
||||||
if let &Term::Clause(_, _, ref child_terms) = term {
|
|
||||||
for term in child_terms {
|
|
||||||
self.state_queue.push_back(term);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Some(term);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Some(term);
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Term {
|
|
||||||
pub fn post_order_iter(&'a self) -> PostOrderIterator<'a> {
|
|
||||||
let initial_state = PostOrderIterator::render_new_state(self);
|
|
||||||
PostOrderIterator { state_stack: vec![initial_state] }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn breadth_first_iter(&'a self) -> BreadthFirstIterator<'a> {
|
|
||||||
let mut queue = VecDeque::new();
|
|
||||||
queue.push_back(self);
|
|
||||||
|
|
||||||
BreadthFirstIterator { state_queue: queue }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
use std::cell::{Cell};
|
|
||||||
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(Cell::new(0), a, ts)
|
|
||||||
},
|
|
||||||
<Atom> => Term::Atom(Cell::new(0), <>),
|
|
||||||
<Var> => Term::Var(Cell::new(0), <>),
|
|
||||||
};
|
|
||||||
1595
src/l0/l0_parser.rs
1595
src/l0/l0_parser.rs
File diff suppressed because it is too large
Load Diff
@@ -1,238 +0,0 @@
|
|||||||
use l0::ast::{Addr, Atom, CompiledFact, FactInstruction, QueryInstruction};
|
|
||||||
|
|
||||||
use std::vec::{Vec};
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
enum HeapCell {
|
|
||||||
NamedStr(usize, Atom),
|
|
||||||
Ref(usize),
|
|
||||||
Str(usize),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
enum MachineMode {
|
|
||||||
Read,
|
|
||||||
Write
|
|
||||||
}
|
|
||||||
|
|
||||||
type Heap = Vec<HeapCell>;
|
|
||||||
|
|
||||||
type Registers = Vec<HeapCell>;
|
|
||||||
|
|
||||||
pub struct Machine {
|
|
||||||
h : usize,
|
|
||||||
s : usize,
|
|
||||||
pub fail : bool,
|
|
||||||
heap : Heap,
|
|
||||||
mode : MachineMode,
|
|
||||||
pub program : Option<CompiledFact>,
|
|
||||||
registers : Registers
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Machine {
|
|
||||||
pub fn new() -> Machine {
|
|
||||||
Machine { 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 let Addr::HeapCell(av) = a {
|
|
||||||
if value != av {
|
|
||||||
a = Addr::HeapCell(value);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return a;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_unbound(hc: &HeapCell, index: usize) -> bool {
|
|
||||||
match hc {
|
|
||||||
&HeapCell::Ref(r) => r == index,
|
|
||||||
_ => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: try to compress this function. currently it is dog shit.
|
|
||||||
fn bind(&mut self, a: Addr, val: usize) {
|
|
||||||
let mut a = a;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
match a {
|
|
||||||
Addr::RegNum(reg) => {
|
|
||||||
if let HeapCell::Ref(hc) = self.registers[reg] {
|
|
||||||
a = Addr::HeapCell(hc);
|
|
||||||
} else if Machine::is_unbound(&self.heap[val], val) {
|
|
||||||
self.heap[val] = self.registers[reg].clone();
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
self.fail = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Addr::HeapCell(hc) if Machine::is_unbound(&self.heap[hc], hc) => {
|
|
||||||
self.heap[hc] = HeapCell::Ref(val);
|
|
||||||
break;
|
|
||||||
},
|
|
||||||
Addr::HeapCell(hc) if Machine::is_unbound(&self.heap[val], val) => {
|
|
||||||
self.heap[val] = HeapCell::Ref(hc);
|
|
||||||
break;
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
self.fail = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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(hc), _) =>
|
|
||||||
self.bind(d2, hc),
|
|
||||||
(_, &HeapCell::Ref(hc)) =>
|
|
||||||
self.bind(d1, hc),
|
|
||||||
(&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_query_instr<'a, 'b : 'a>(&'a mut self, instr: &'b QueryInstruction) {
|
|
||||||
match instr {
|
|
||||||
&QueryInstruction::PutStructure(ref name, arity, reg) => {
|
|
||||||
self.heap.push(HeapCell::Str(self.h + 1));
|
|
||||||
self.heap.push(HeapCell::NamedStr(arity, name.clone()));
|
|
||||||
|
|
||||||
self.registers[reg] = self.heap[self.h].clone();
|
|
||||||
|
|
||||||
self.h += 2;
|
|
||||||
},
|
|
||||||
&QueryInstruction::SetVariable(reg) => {
|
|
||||||
self.heap.push(HeapCell::Ref(self.h));
|
|
||||||
self.registers[reg] = self.heap[self.h].clone();
|
|
||||||
|
|
||||||
self.h += 1;
|
|
||||||
},
|
|
||||||
&QueryInstruction::SetValue(reg) => {
|
|
||||||
self.heap.push(self.registers[reg].clone());
|
|
||||||
self.h += 1;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn execute_fact_instr<'a, 'b : 'a>(&'a mut self, instr: &'b FactInstruction) {
|
|
||||||
match instr {
|
|
||||||
&FactInstruction::GetStructure(ref 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(r) => {
|
|
||||||
self.heap.push(HeapCell::Str(self.h + 1));
|
|
||||||
self.heap.push(HeapCell::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::UnifyVariable(reg) => {
|
|
||||||
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;
|
|
||||||
},
|
|
||||||
&FactInstruction::UnifyValue(reg) => {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reset_heap(&mut self) {
|
|
||||||
let program = self.program.take();
|
|
||||||
|
|
||||||
*self = Machine::new();
|
|
||||||
self.program = program;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
mod l0_parser;
|
|
||||||
|
|
||||||
pub mod ast;
|
|
||||||
pub mod iterators;
|
|
||||||
pub mod parser;
|
|
||||||
pub mod codegen;
|
|
||||||
pub mod machine;
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
use l0::ast::{Term, TopLevel, Var};
|
|
||||||
use l0::l0_parser::{parse_TopLevel};
|
|
||||||
|
|
||||||
use std::collections::{HashMap};
|
|
||||||
|
|
||||||
extern crate lalrpop_util as __lalrpop_util;
|
|
||||||
|
|
||||||
pub type ParseResult<'a> =
|
|
||||||
Result<TopLevel, __lalrpop_util::ParseError<usize,(usize, &'a str),()>>;
|
|
||||||
|
|
||||||
pub fn parse_top_level<'a>(input: &'a str) -> ParseResult {
|
|
||||||
let result = parse_TopLevel(&*input);
|
|
||||||
|
|
||||||
if let Ok(result) = result {
|
|
||||||
return Ok(mark_cells(result));
|
|
||||||
}
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn mark_cells(tl: TopLevel) -> TopLevel {
|
|
||||||
match tl {
|
|
||||||
TopLevel::Fact(term) => TopLevel::Fact(mark_term_cells(term)),
|
|
||||||
TopLevel::Query(term) => TopLevel::Query(mark_term_cells(term))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_term_cells(term: Term) -> Term {
|
|
||||||
let mut cell_num = 1;
|
|
||||||
|
|
||||||
{
|
|
||||||
let mut bindings: HashMap<&Var, usize> = HashMap::new();
|
|
||||||
let mut iter = term.breadth_first_iter();
|
|
||||||
|
|
||||||
while let Some(term) = iter.next() {
|
|
||||||
if let &Term::Var(ref cell, ref var) = term {
|
|
||||||
let cell_num_in_map = bindings.entry(var).or_insert(cell_num);
|
|
||||||
|
|
||||||
if *cell_num_in_map != cell_num {
|
|
||||||
cell.set(*cell_num_in_map);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
term.set_cell(cell_num);
|
|
||||||
cell_num += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
term
|
|
||||||
}
|
|
||||||
123
src/l1/ast.rs
123
src/l1/ast.rs
@@ -1,123 +0,0 @@
|
|||||||
use std::cell::Cell;
|
|
||||||
use std::fmt;
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
pub type Var = String;
|
|
||||||
|
|
||||||
pub type Atom = String;
|
|
||||||
|
|
||||||
pub enum TopLevel {
|
|
||||||
Fact(Term),
|
|
||||||
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 Reg {
|
|
||||||
ArgAndNorm(usize, usize),
|
|
||||||
Norm(usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Reg {
|
|
||||||
pub fn has_arg(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
&Reg::ArgAndNorm(_, _) => true,
|
|
||||||
_ => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn norm(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
&Reg::ArgAndNorm(_, norm) | &Reg::Norm(norm) => norm
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum Term {
|
|
||||||
Atom(Cell<usize>, Atom),
|
|
||||||
Clause(Cell<usize>, Atom, Vec<Box<Term>>),
|
|
||||||
Var(Cell<Reg>, Var)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum TermRef<'a> {
|
|
||||||
Atom(Level, &'a Cell<usize>, &'a Atom),
|
|
||||||
Clause(Level, &'a Cell<usize>, &'a Atom, &'a Vec<Box<Term>>),
|
|
||||||
Var(Level, &'a Cell<Reg>, &'a Var)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub enum FactInstruction {
|
|
||||||
GetStructure(Level, Atom, usize, usize),
|
|
||||||
GetValue(usize, usize),
|
|
||||||
GetVariable(usize, usize),
|
|
||||||
Proceed,
|
|
||||||
UnifyVariable(usize),
|
|
||||||
UnifyValue(usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum QueryInstruction {
|
|
||||||
Call(Atom, usize),
|
|
||||||
PutStructure(Level, Atom, usize, usize),
|
|
||||||
PutValue(usize, usize),
|
|
||||||
PutVariable(usize, usize),
|
|
||||||
SetVariable(usize),
|
|
||||||
SetValue(usize),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type CompiledFact = Vec<FactInstruction>;
|
|
||||||
|
|
||||||
pub type CompiledQuery = Vec<QueryInstruction>;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
|
||||||
pub enum Addr {
|
|
||||||
HeapCell(usize),
|
|
||||||
RegNum(usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub enum HeapCellValue {
|
|
||||||
NamedStr(usize, Atom),
|
|
||||||
Ref(usize),
|
|
||||||
Str(usize),
|
|
||||||
}
|
|
||||||
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,312 +0,0 @@
|
|||||||
use l1::ast::{Atom, CompiledFact, CompiledQuery, FactInstruction,
|
|
||||||
Level, QueryInstruction, Reg, Term, TermRef, Var};
|
|
||||||
use l1::iterators::{FactIterator, QueryIterator};
|
|
||||||
|
|
||||||
use std::cell::Cell;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::fmt;
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
impl fmt::Display for QueryInstruction {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&QueryInstruction::Call(ref name, ref arity) =>
|
|
||||||
write!(f, "call {}/{}", name, arity),
|
|
||||||
&QueryInstruction::PutStructure(ref lvl, ref a, ref s, ref r) =>
|
|
||||||
write!(f, "put_structure {}/{}, {}{}", a, s, lvl, r),
|
|
||||||
&QueryInstruction::PutValue(ref a, ref x) =>
|
|
||||||
write!(f, "put_value X{}, A{}", x, a),
|
|
||||||
&QueryInstruction::PutVariable(ref a, ref x) =>
|
|
||||||
write!(f, "put_variable X{}, A{}", x, a),
|
|
||||||
&QueryInstruction::SetVariable(ref r) =>
|
|
||||||
write!(f, "set_variable X{}", r),
|
|
||||||
&QueryInstruction::SetValue(ref r) =>
|
|
||||||
write!(f, "set_value X{}", r),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for FactInstruction {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&FactInstruction::GetStructure(ref lvl, ref a, ref s, ref r) =>
|
|
||||||
write!(f, "get_structure {}/{}, {}{}", a, s, lvl, r),
|
|
||||||
&FactInstruction::GetValue(ref a, ref x) =>
|
|
||||||
write!(f, "get_value X{}, A{}", x, a),
|
|
||||||
&FactInstruction::GetVariable(ref a, ref x) =>
|
|
||||||
write!(f, "get_variable X{}, A{}", x, a),
|
|
||||||
&FactInstruction::Proceed =>
|
|
||||||
write!(f, "proceed"),
|
|
||||||
&FactInstruction::UnifyVariable(ref r) =>
|
|
||||||
write!(f, "unify_variable X{}", r),
|
|
||||||
&FactInstruction::UnifyValue(ref r) =>
|
|
||||||
write!(f, "unify_value X{}", r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct TermMarker<'a> {
|
|
||||||
bindings: HashMap<&'a Var, Reg>,
|
|
||||||
arg_c: usize,
|
|
||||||
norm_c: usize
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> TermMarker<'a> {
|
|
||||||
fn new(term: &'a Term) -> TermMarker<'a> {
|
|
||||||
TermMarker { bindings: HashMap::new(),
|
|
||||||
arg_c: 1,
|
|
||||||
norm_c: term.subterms() + 1 }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn contains_var(&self, var: &'a Var) -> bool {
|
|
||||||
self.bindings.contains_key(var)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get(&self, var: &'a Var) -> Reg {
|
|
||||||
*self.bindings.get(var).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn insert(&mut self, var: &'a Var, r: Reg) {
|
|
||||||
self.bindings.insert(var, r);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_non_var(&mut self, lvl: Level, cell: &Cell<usize>) {
|
|
||||||
if cell.get() == 0 {
|
|
||||||
match lvl {
|
|
||||||
Level::Deep => {
|
|
||||||
let norm = self.norm_c;
|
|
||||||
self.norm_c += 1;
|
|
||||||
cell.set(norm);
|
|
||||||
},
|
|
||||||
Level::Shallow => {
|
|
||||||
let arg = self.arg_c;
|
|
||||||
self.arg_c += 1;
|
|
||||||
cell.set(arg);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_var(&mut self, lvl: Level, var: &'a Var) -> Reg {
|
|
||||||
if self.contains_var(var) {
|
|
||||||
let reg = self.get(var);
|
|
||||||
|
|
||||||
match lvl {
|
|
||||||
Level::Deep => Reg::Norm(reg.norm()),
|
|
||||||
Level::Shallow if reg.has_arg() => {
|
|
||||||
let arg = self.arg_c;
|
|
||||||
self.arg_c += 1;
|
|
||||||
|
|
||||||
Reg::ArgAndNorm(arg, reg.norm())
|
|
||||||
},
|
|
||||||
Level::Shallow => {
|
|
||||||
let norm = reg.norm();
|
|
||||||
let reg = Reg::ArgAndNorm(self.arg_c, norm);
|
|
||||||
|
|
||||||
self.arg_c += 1;
|
|
||||||
self.insert(var, reg);
|
|
||||||
|
|
||||||
reg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let reg = match lvl {
|
|
||||||
Level::Deep => Reg::Norm(self.norm_c),
|
|
||||||
Level::Shallow => {
|
|
||||||
let reg = Reg::ArgAndNorm(self.arg_c, self.norm_c);
|
|
||||||
self.arg_c += 1;
|
|
||||||
reg
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.norm_c += 1;
|
|
||||||
self.insert(var, reg);
|
|
||||||
reg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
trait CompilationTarget<'a> {
|
|
||||||
type Iterator : Iterator<Item=TermRef<'a>>;
|
|
||||||
|
|
||||||
fn iter(&'a Term) -> Self::Iterator;
|
|
||||||
|
|
||||||
fn to_structure(Level, Atom, usize, usize) -> Self;
|
|
||||||
|
|
||||||
fn argument_to_variable(usize, usize) -> Self;
|
|
||||||
fn argument_to_value(usize, usize) -> Self;
|
|
||||||
fn subterm_to_variable(usize) -> Self;
|
|
||||||
fn subterm_to_value(usize) -> Self;
|
|
||||||
|
|
||||||
fn clause_arg_to_instr(usize) -> 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, cell_num: usize) -> Self {
|
|
||||||
FactInstruction::GetStructure(lvl, atom, arity, cell_num)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn argument_to_variable(arg: usize, val: usize) -> Self {
|
|
||||||
FactInstruction::GetVariable(arg, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn argument_to_value(arg: usize, val: usize) -> Self {
|
|
||||||
FactInstruction::GetValue(arg, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subterm_to_variable(val: usize) -> Self {
|
|
||||||
FactInstruction::UnifyVariable(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subterm_to_value(val: usize) -> Self {
|
|
||||||
FactInstruction::UnifyValue(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clause_arg_to_instr(val: usize) -> 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, cell_num: usize) -> Self {
|
|
||||||
QueryInstruction::PutStructure(lvl, atom, arity, cell_num)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn argument_to_variable(arg: usize, val: usize) -> Self {
|
|
||||||
QueryInstruction::PutVariable(arg, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn argument_to_value(arg: usize, val: usize) -> Self {
|
|
||||||
QueryInstruction::PutValue(arg, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subterm_to_variable(val: usize) -> Self {
|
|
||||||
QueryInstruction::SetVariable(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subterm_to_value(val: usize) -> Self {
|
|
||||||
QueryInstruction::SetValue(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clause_arg_to_instr(val: usize) -> Self {
|
|
||||||
QueryInstruction::SetValue(val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_structure<'a, Target>(tm: &mut TermMarker<'a>,
|
|
||||||
lvl: Level,
|
|
||||||
name: &'a Atom,
|
|
||||||
cell: &'a Cell<usize>,
|
|
||||||
arity: usize)
|
|
||||||
-> Target
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
tm.mark_non_var(lvl, cell);
|
|
||||||
Target::to_structure(lvl, name.clone(), arity, cell.get())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn non_var_subterm<'a, Target>(tm: &mut TermMarker<'a>, cell: &'a Cell<usize>)
|
|
||||||
-> Target
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
tm.mark_non_var(Level::Deep, cell);
|
|
||||||
Target::clause_arg_to_instr(cell.get())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn var_term<'a, Target>(tm: &mut TermMarker<'a>,
|
|
||||||
lvl: Level,
|
|
||||||
cell: &'a Cell<Reg>,
|
|
||||||
var: &'a Var)
|
|
||||||
-> Target
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
if !tm.contains_var(var) {
|
|
||||||
let reg = tm.mark_var(lvl, var);
|
|
||||||
cell.set(reg);
|
|
||||||
|
|
||||||
match reg {
|
|
||||||
Reg::ArgAndNorm(arg, norm) =>
|
|
||||||
Target::argument_to_variable(arg, norm),
|
|
||||||
Reg::Norm(norm) =>
|
|
||||||
Target::subterm_to_variable(norm)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let reg = tm.mark_var(lvl, var);
|
|
||||||
cell.set(reg);
|
|
||||||
|
|
||||||
match reg {
|
|
||||||
Reg::ArgAndNorm(arg, norm) =>
|
|
||||||
Target::argument_to_value(arg, norm),
|
|
||||||
Reg::Norm(norm) =>
|
|
||||||
Target::subterm_to_value(norm)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subterm_to_instr<'a, Target>(tm: &mut TermMarker<'a>, subterm: &'a Term)
|
|
||||||
-> Target
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
match subterm {
|
|
||||||
&Term::Atom(ref cell, _) | &Term::Clause(ref cell, _, _) =>
|
|
||||||
non_var_subterm(tm, cell),
|
|
||||||
&Term::Var(ref cell, ref var) =>
|
|
||||||
var_term(tm, Level::Deep, cell, var)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compile_target<'a, Target>(term: &'a Term) -> Vec<Target>
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
let iter = Target::iter(term);
|
|
||||||
let mut target = Vec::<Target>::new();
|
|
||||||
let mut marker = TermMarker::new(term);
|
|
||||||
|
|
||||||
for term in iter {
|
|
||||||
match term {
|
|
||||||
TermRef::Atom(lvl, term, atom) =>
|
|
||||||
target.push(to_structure(&mut marker, lvl, atom, term, 0)),
|
|
||||||
TermRef::Clause(lvl, term, atom, terms) => {
|
|
||||||
target.push(to_structure(&mut marker, lvl, atom, term, terms.len()));
|
|
||||||
|
|
||||||
for subterm in terms {
|
|
||||||
target.push(subterm_to_instr(&mut marker, subterm.as_ref()));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TermRef::Var(lvl @ Level::Shallow, ref cell, ref var) =>
|
|
||||||
target.push(var_term(&mut marker, lvl, cell, var)),
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
target
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compile_fact(term: &Term) -> CompiledFact {
|
|
||||||
let mut compiled_fact = compile_target(term);
|
|
||||||
|
|
||||||
compiled_fact.push(FactInstruction::Proceed);
|
|
||||||
compiled_fact
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compile_query<'a>(term: &'a Term) -> CompiledQuery {
|
|
||||||
let mut compiled_query = compile_target(term);
|
|
||||||
|
|
||||||
if let &Term::Clause(_, ref atom, ref terms) = term {
|
|
||||||
compiled_query.push(QueryInstruction::Call(atom.clone(), terms.len()));
|
|
||||||
}
|
|
||||||
|
|
||||||
compiled_query
|
|
||||||
}
|
|
||||||
@@ -1,175 +0,0 @@
|
|||||||
use l1::ast::{Atom, Level, Reg, Term, TermRef, Var};
|
|
||||||
|
|
||||||
use std::cell::Cell;
|
|
||||||
use std::collections::VecDeque;
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
enum IteratorState<'a> {
|
|
||||||
Atom(Level, &'a Cell<usize>, &'a Atom),
|
|
||||||
Clause(Level, usize, &'a Cell<usize>, &'a Atom, &'a Vec<Box<Term>>),
|
|
||||||
IsolatedAtom(&'a Cell<usize>, &'a Atom),
|
|
||||||
IsolatedVar(&'a Cell<Reg>, &'a Var),
|
|
||||||
RootClause(usize, &'a Vec<Box<Term>>),
|
|
||||||
Var(Level, &'a Cell<Reg>, &'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<usize>,
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
use std::cell::Cell;
|
|
||||||
|
|
||||||
use l1::ast::{Atom, Reg, 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(Cell::new(0), a, ts)
|
|
||||||
},
|
|
||||||
<Atom> => Term::Atom(Cell::new(0), <>),
|
|
||||||
<Var> => Term::Var(Cell::new(Reg::Norm(0)), <>)
|
|
||||||
};
|
|
||||||
1595
src/l1/l1_parser.rs
1595
src/l1/l1_parser.rs
File diff suppressed because it is too large
Load Diff
@@ -1,309 +0,0 @@
|
|||||||
use l1::ast::{Addr, Atom, CompiledFact, CompiledQuery,
|
|
||||||
FactInstruction, Heap, HeapCellValue, QueryInstruction,
|
|
||||||
Registers};
|
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
enum MachineMode {
|
|
||||||
Read,
|
|
||||||
Write
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Machine {
|
|
||||||
h : usize,
|
|
||||||
s : usize,
|
|
||||||
p : usize,
|
|
||||||
code : CompiledFact,
|
|
||||||
code_dir : HashMap<(Atom, usize), usize>,
|
|
||||||
fail : bool,
|
|
||||||
heap : Heap,
|
|
||||||
mode : MachineMode,
|
|
||||||
registers : Registers
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Machine {
|
|
||||||
pub fn new() -> Machine {
|
|
||||||
Machine { h : 0,
|
|
||||||
s : 0,
|
|
||||||
p : 0,
|
|
||||||
code : Vec::new(),
|
|
||||||
code_dir : HashMap::new(),
|
|
||||||
fail : false,
|
|
||||||
heap : Vec::with_capacity(256),
|
|
||||||
mode : MachineMode::Write,
|
|
||||||
registers : vec![HeapCellValue::Ref(0); 32] }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_fact(&mut self, mut fact: CompiledFact, name: Atom, arity: usize)
|
|
||||||
{
|
|
||||||
let index = self.code.len();
|
|
||||||
|
|
||||||
self.code.append(&mut fact);
|
|
||||||
self.code_dir.insert((name, arity), index);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn failed(&self) -> bool {
|
|
||||||
self.fail
|
|
||||||
}
|
|
||||||
|
|
||||||
fn lookup(&self, a: Addr) -> &HeapCellValue {
|
|
||||||
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 &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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: try to compress this function.
|
|
||||||
fn bind(&mut self, a: Addr, val: usize) {
|
|
||||||
let mut a = a;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
match a {
|
|
||||||
Addr::RegNum(reg) => {
|
|
||||||
if let HeapCellValue::Ref(hc) = self.registers[reg] {
|
|
||||||
a = Addr::HeapCell(hc);
|
|
||||||
} else if Machine::is_unbound(&self.heap[val], val) {
|
|
||||||
self.heap[val] = self.registers[reg].clone();
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
self.fail = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Addr::HeapCell(hc) if Machine::is_unbound(&self.heap[hc], hc) => {
|
|
||||||
self.heap[hc] = HeapCellValue::Ref(val);
|
|
||||||
break;
|
|
||||||
},
|
|
||||||
Addr::HeapCell(hc) if Machine::is_unbound(&self.heap[val], val) => {
|
|
||||||
self.heap[val] = HeapCellValue::Ref(hc);
|
|
||||||
break;
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
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,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn execute_fact(&mut self) {
|
|
||||||
loop {
|
|
||||||
if let &FactInstruction::Proceed = &self.code[self.p] {
|
|
||||||
break;
|
|
||||||
} else if self.fail {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
let fact_instr = self.code[self.p].clone();
|
|
||||||
self.execute_fact_instr(fact_instr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn execute_query(&mut self, query: &CompiledQuery) {
|
|
||||||
for instr in query {
|
|
||||||
self.execute_query_instr(instr);
|
|
||||||
|
|
||||||
if self.fail {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn execute_query_instr<'a, 'b: 'a>(&'a mut self, instr: &'b QueryInstruction) {
|
|
||||||
match instr {
|
|
||||||
&QueryInstruction::Call(ref name, arity) => {
|
|
||||||
// why is Option<&T> not Deref?!?!?
|
|
||||||
// is it because if the value is None, there's nothing to
|
|
||||||
// dereference?
|
|
||||||
let compiled_fact_index =
|
|
||||||
self.code_dir.get(&(name.clone(), arity))
|
|
||||||
.map(|index| *index);
|
|
||||||
|
|
||||||
match compiled_fact_index {
|
|
||||||
Some(compiled_fact_index) => {
|
|
||||||
self.p = compiled_fact_index;
|
|
||||||
self.execute_fact();
|
|
||||||
},
|
|
||||||
None => self.fail = true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
&QueryInstruction::PutStructure(_, ref name, arity, reg) => {
|
|
||||||
self.heap.push(HeapCellValue::Str(self.h + 1));
|
|
||||||
self.heap.push(HeapCellValue::NamedStr(arity, name.clone()));
|
|
||||||
|
|
||||||
self.registers[reg] = self.heap[self.h].clone();
|
|
||||||
|
|
||||||
self.h += 2;
|
|
||||||
},
|
|
||||||
&QueryInstruction::PutValue(arg, norm) =>
|
|
||||||
self.registers[arg] = self.registers[norm].clone(),
|
|
||||||
&QueryInstruction::PutVariable(arg, norm) => {
|
|
||||||
self.heap.push(HeapCellValue::Ref(self.h));
|
|
||||||
|
|
||||||
self.registers[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.registers[reg] = self.heap[self.h].clone();
|
|
||||||
|
|
||||||
self.h += 1;
|
|
||||||
},
|
|
||||||
&QueryInstruction::SetValue(reg) => {
|
|
||||||
self.heap.push(self.registers[reg].clone());
|
|
||||||
self.h += 1;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn execute_fact_instr(&mut self, instr: FactInstruction) {
|
|
||||||
match instr {
|
|
||||||
FactInstruction::Proceed => return,
|
|
||||||
FactInstruction::GetStructure(_, name, arity, reg) => {
|
|
||||||
let addr = self.deref(Addr::RegNum(reg));
|
|
||||||
|
|
||||||
match self.lookup(addr) {
|
|
||||||
&HeapCellValue::Str(a) => {
|
|
||||||
let result = &self.heap[a];
|
|
||||||
|
|
||||||
if let &HeapCellValue::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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
&HeapCellValue::Ref(r) => {
|
|
||||||
self.heap.push(HeapCellValue::Str(self.h + 1));
|
|
||||||
self.heap.push(HeapCellValue::NamedStr(arity, name));
|
|
||||||
|
|
||||||
let h = self.h;
|
|
||||||
|
|
||||||
self.bind(Addr::HeapCell(r), h);
|
|
||||||
|
|
||||||
self.h += 2;
|
|
||||||
self.mode = MachineMode::Write;
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
self.fail = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
},
|
|
||||||
FactInstruction::GetVariable(arg, norm) =>
|
|
||||||
self.registers[norm] = self.registers[arg].clone(),
|
|
||||||
FactInstruction::GetValue(arg, norm) =>
|
|
||||||
self.unify(Addr::RegNum(norm), Addr::RegNum(arg)),
|
|
||||||
FactInstruction::UnifyVariable(reg) => {
|
|
||||||
match self.mode {
|
|
||||||
MachineMode::Read => self.registers[reg] = self.heap[self.s].clone(),
|
|
||||||
MachineMode::Write => {
|
|
||||||
self.heap.push(HeapCellValue::Ref(self.h));
|
|
||||||
self.registers[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::RegNum(reg), Addr::HeapCell(s)),
|
|
||||||
MachineMode::Write => {
|
|
||||||
self.heap.push(self.registers[reg].clone());
|
|
||||||
self.h += 1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.s += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.p += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reset_machine_state(&mut self) {
|
|
||||||
self.h = 0;
|
|
||||||
self.s = 0;
|
|
||||||
self.p = 0;
|
|
||||||
|
|
||||||
self.fail = false;
|
|
||||||
self.heap = Vec::with_capacity(256);
|
|
||||||
self.mode = MachineMode::Write;
|
|
||||||
self.registers = vec![HeapCellValue::Ref(0); 32];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
pub mod ast;
|
|
||||||
pub mod iterators;
|
|
||||||
pub mod l1_parser;
|
|
||||||
pub mod codegen;
|
|
||||||
pub mod machine;
|
|
||||||
253
src/l2/ast.rs
253
src/l2/ast.rs
@@ -1,253 +0,0 @@
|
|||||||
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 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 {
|
|
||||||
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 fn root_register(self) -> usize {
|
|
||||||
match self {
|
|
||||||
VarReg::ArgAndNorm(_, root) => root,
|
|
||||||
VarReg::Norm(root) => root.reg_num()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum Term {
|
|
||||||
Atom(Cell<RegType>, Atom),
|
|
||||||
Clause(Cell<RegType>, Atom, Vec<Box<Term>>),
|
|
||||||
Var(Cell<VarReg>, Var)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Rule {
|
|
||||||
pub head: (Term, Term),
|
|
||||||
pub clauses: Vec<Term>
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum TermRef<'a> {
|
|
||||||
Atom(Level, &'a Cell<RegType>, &'a Atom),
|
|
||||||
Clause(Level, &'a Cell<RegType>, &'a Atom, &'a Vec<Box<Term>>),
|
|
||||||
Var(Level, &'a Cell<VarReg>, &'a Var)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum FactInstruction {
|
|
||||||
GetStructure(Level, Atom, usize, RegType),
|
|
||||||
GetValue(RegType, usize),
|
|
||||||
GetVariable(RegType, usize),
|
|
||||||
UnifyVariable(RegType),
|
|
||||||
UnifyValue(RegType)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum QueryInstruction {
|
|
||||||
PutStructure(Level, Atom, usize, RegType),
|
|
||||||
PutValue(RegType, usize),
|
|
||||||
PutVariable(RegType, usize),
|
|
||||||
SetVariable(RegType),
|
|
||||||
SetValue(RegType)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum 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, 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),
|
|
||||||
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<HeapCellRef>;
|
|
||||||
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,469 +0,0 @@
|
|||||||
use l2::ast::*;
|
|
||||||
use l2::iterators::{FactIterator, QueryIterator};
|
|
||||||
|
|
||||||
use std::cell::Cell;
|
|
||||||
use std::cmp::max;
|
|
||||||
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_at_header(&mut self, term: &'a Term) {
|
|
||||||
self.arg_c = 1;
|
|
||||||
self.temp_c = max(term.subterms(), self.temp_c) + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn advance(&mut self, term: &'a Term) {
|
|
||||||
self.arg_c = 1;
|
|
||||||
self.temp_c = term.subterms() + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
enum TermStatus {
|
|
||||||
New, Old, Recurrent
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct CodeGenerator<'a> {
|
|
||||||
marker: TermMarker<'a>
|
|
||||||
}
|
|
||||||
|
|
||||||
type VariableFixture<'a> = (TermStatus, Vec<&'a Cell<VarReg>>);
|
|
||||||
type VariableFixtures<'a> = HashMap<&'a Var, VariableFixture<'a>>;
|
|
||||||
|
|
||||||
impl<'a> CodeGenerator<'a> {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
CodeGenerator { marker: TermMarker::new() }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn vars(&self) -> &HashMap<&Var, VarReg> {
|
|
||||||
&self.marker.bindings
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_structure<Target>(&mut self,
|
|
||||||
lvl: Level,
|
|
||||||
name: &'a Atom,
|
|
||||||
cell: &'a Cell<RegType>,
|
|
||||||
arity: usize)
|
|
||||||
-> Target
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
self.marker.mark_non_var(lvl, cell);
|
|
||||||
Target::to_structure(lvl, name.clone(), arity, cell.get())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn var_term<Target>(&mut self,
|
|
||||||
lvl: Level,
|
|
||||||
cell: &'a Cell<VarReg>,
|
|
||||||
var: &'a Var)
|
|
||||||
-> Target
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
if !self.marker.contains_var(var) {
|
|
||||||
let reg = self.marker.mark_new_var(lvl, var, cell.get().norm());
|
|
||||||
cell.set(reg);
|
|
||||||
|
|
||||||
match reg {
|
|
||||||
VarReg::ArgAndNorm(arg, norm) =>
|
|
||||||
Target::argument_to_variable(arg, norm),
|
|
||||||
VarReg::Norm(norm) =>
|
|
||||||
Target::subterm_to_variable(norm)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let reg = self.marker.mark_old_var(lvl, var);
|
|
||||||
cell.set(reg);
|
|
||||||
|
|
||||||
match reg {
|
|
||||||
VarReg::ArgAndNorm(arg, norm) =>
|
|
||||||
Target::argument_to_value(arg, norm),
|
|
||||||
VarReg::Norm(norm) =>
|
|
||||||
Target::subterm_to_value(norm)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn non_var_subterm<Target>(&mut self, cell: &'a Cell<RegType>) -> Target
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
self.marker.mark_non_var(Level::Deep, cell);
|
|
||||||
Target::clause_arg_to_instr(cell.get())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subterm_to_instr<Target>(&mut self, subterm: &'a Term) -> Target
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
match subterm {
|
|
||||||
&Term::Atom(ref cell, _) | &Term::Clause(ref cell, _, _) =>
|
|
||||||
self.non_var_subterm(cell),
|
|
||||||
&Term::Var(ref cell, ref var) =>
|
|
||||||
self.var_term(Level::Deep, cell, var)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compile_target<Target>(&mut self, term: &'a Term) -> Vec<Target>
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
let iter = Target::iter(term);
|
|
||||||
let mut target = Vec::new();
|
|
||||||
|
|
||||||
for term in iter {
|
|
||||||
match term {
|
|
||||||
TermRef::Atom(lvl, term, atom) =>
|
|
||||||
target.push(self.to_structure(lvl, atom, term, 0)),
|
|
||||||
TermRef::Clause(lvl, term, atom, terms) => {
|
|
||||||
target.push(self.to_structure(lvl, atom, term, terms.len()));
|
|
||||||
|
|
||||||
for subterm in terms {
|
|
||||||
target.push(self.subterm_to_instr(subterm.as_ref()));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TermRef::Var(lvl @ Level::Shallow, ref cell, ref var) =>
|
|
||||||
target.push(self.var_term(lvl, cell, var)),
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
target
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_vars_in_term<Iter>(iter: Iter, vs: &mut VariableFixtures<'a>)
|
|
||||||
where Iter : Iterator<Item=TermRef<'a>>
|
|
||||||
{
|
|
||||||
for term in iter {
|
|
||||||
if let TermRef::Var(_, reg_cell, var) = term {
|
|
||||||
let mut status = vs.entry(var)
|
|
||||||
.or_insert((TermStatus::New, Vec::new()));
|
|
||||||
|
|
||||||
status.1.push(reg_cell);
|
|
||||||
|
|
||||||
match status.0 {
|
|
||||||
TermStatus::Old => status.0 = TermStatus::Recurrent,
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for &mut (ref mut term_status, ref mut cb) in vs.values_mut() {
|
|
||||||
match *term_status {
|
|
||||||
TermStatus::New => *term_status = TermStatus::Old,
|
|
||||||
TermStatus::Recurrent => {
|
|
||||||
for cell_reg in cb.drain(0..) {
|
|
||||||
cell_reg.set(VarReg::Norm(RegType::Perm(0)));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_perm_vars(rule: &'a Rule) -> VariableFixtures {
|
|
||||||
let &Rule { head: (ref p0, ref p1), ref clauses } = rule;
|
|
||||||
let mut vfs = HashMap::new();
|
|
||||||
|
|
||||||
let iter = p0.breadth_first_iter().chain(p1.breadth_first_iter());
|
|
||||||
|
|
||||||
Self::mark_vars_in_term(iter, &mut vfs);
|
|
||||||
|
|
||||||
for term in clauses {
|
|
||||||
Self::mark_vars_in_term(term.breadth_first_iter(), &mut vfs);
|
|
||||||
}
|
|
||||||
|
|
||||||
vfs
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_conditional_call(compiled_query: &mut Code, term: &Term) {
|
|
||||||
match term {
|
|
||||||
&Term::Atom(_, ref atom) => {
|
|
||||||
let call = ControlInstruction::Call(atom.clone(), 0);
|
|
||||||
compiled_query.push(Line::Control(call));
|
|
||||||
},
|
|
||||||
&Term::Clause(_, ref atom, ref terms) => {
|
|
||||||
let call = ControlInstruction::Call(atom.clone(), terms.len());
|
|
||||||
compiled_query.push(Line::Control(call));
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compile_rule(&mut self, rule: &'a Rule) -> Code {
|
|
||||||
let vfs = Self::mark_perm_vars(&rule);
|
|
||||||
let &Rule { head: (ref p0, ref p1), ref clauses } = rule;
|
|
||||||
let mut perm_vars = 0;
|
|
||||||
|
|
||||||
for &(term_status, _) in vfs.values() {
|
|
||||||
if let TermStatus::Recurrent = term_status {
|
|
||||||
perm_vars += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut body = Vec::new();
|
|
||||||
|
|
||||||
body.push(Line::Control(ControlInstruction::Allocate(perm_vars)));
|
|
||||||
|
|
||||||
self.marker.advance(p0);
|
|
||||||
body.push(Line::Fact(self.compile_target(p0)));
|
|
||||||
|
|
||||||
self.marker.advance_at_header(p1);
|
|
||||||
body.push(Line::Query(self.compile_target(p1)));
|
|
||||||
Self::add_conditional_call(&mut body, p1);
|
|
||||||
|
|
||||||
body = clauses.iter()
|
|
||||||
.map(|ref term| self.compile_query(term))
|
|
||||||
.fold(body, |mut body, ref mut cqs| {
|
|
||||||
body.append(cqs);
|
|
||||||
body
|
|
||||||
});
|
|
||||||
|
|
||||||
body.push(Line::Control(ControlInstruction::Deallocate));
|
|
||||||
|
|
||||||
body
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compile_fact(&mut self, term: &'a Term) -> Code {
|
|
||||||
self.marker.advance(term);
|
|
||||||
|
|
||||||
let mut compiled_fact = vec![Line::Fact(self.compile_target(term))];
|
|
||||||
let proceed = Line::Control(ControlInstruction::Proceed);
|
|
||||||
|
|
||||||
compiled_fact.push(proceed);
|
|
||||||
compiled_fact
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compile_query(&mut self, term: &'a Term) -> Code {
|
|
||||||
self.marker.advance(term);
|
|
||||||
|
|
||||||
let mut compiled_query = vec![Line::Query(self.compile_target(term))];
|
|
||||||
Self::add_conditional_call(&mut compiled_query, term);
|
|
||||||
|
|
||||||
compiled_query
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,175 +0,0 @@
|
|||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
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 },
|
|
||||||
<a:Atom> ":-" <h:Term> <cs: ("," <Term>)*> =>
|
|
||||||
Rule { head: (Term::Atom(Cell::new(RegType::Temp(0)), a), h),
|
|
||||||
clauses: cs }
|
|
||||||
};
|
|
||||||
|
|
||||||
Term : Term = {
|
|
||||||
<Clause> => <>,
|
|
||||||
<Atom> => Term::Atom(Cell::new(RegType::Temp(0)), <>),
|
|
||||||
<Var> => Term::Var(Cell::new(VarReg::Norm(RegType::Temp(0))), <>),
|
|
||||||
};
|
|
||||||
|
|
||||||
Var : Var = {
|
|
||||||
r"[A-Z][a-z0-9_]*" => <>.trim().to_string(),
|
|
||||||
};
|
|
||||||
1883
src/l2/l2_parser.rs
1883
src/l2/l2_parser.rs
File diff suppressed because it is too large
Load Diff
@@ -1,456 +0,0 @@
|
|||||||
use l2::ast::*;
|
|
||||||
use l2::codegen::*;
|
|
||||||
use l2::heapview::*;
|
|
||||||
use l2::stack::*;
|
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
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 Machine {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Machine {
|
|
||||||
ms: MachineState::new(),
|
|
||||||
code: Vec::new(),
|
|
||||||
code_dir: HashMap::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn failed(&self) -> bool {
|
|
||||||
self.ms.fail
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_fact(&mut self, fact: &Term, mut code: Code) {
|
|
||||||
let p = self.code.len();
|
|
||||||
let name = fact.name().clone();
|
|
||||||
let arity = fact.arity();
|
|
||||||
|
|
||||||
self.code.append(&mut code);
|
|
||||||
self.code_dir.insert((name, arity), p);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_rule(&mut self, rule: &Rule, mut code: Code) {
|
|
||||||
let p = self.code.len();
|
|
||||||
let name = rule.head.0.name().clone();
|
|
||||||
let arity = rule.head.0.arity();
|
|
||||||
|
|
||||||
self.code.append(&mut code);
|
|
||||||
self.code_dir.insert((name, arity), p);
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
fn heap_view(&self, var_dir: HashMap<&Var, HeapCellRef>) -> String {
|
|
||||||
let mut result = String::new();
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut heap_locs = HashMap::new();
|
|
||||||
|
|
||||||
if succeeded {
|
|
||||||
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 {
|
|
||||||
Some(self.heap_view(heap_locs))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reset(&mut self) {
|
|
||||||
self.ms.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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![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 HeapCellRef::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 HeapCellRef::Ref(hc) = self.lookup(addr) {
|
|
||||||
a = Addr::HeapCell(hc);
|
|
||||||
} else if Self::is_unbound(&self.heap[val], val) {
|
|
||||||
self.heap[val] = HeapCellValue::from(self.lookup(addr));
|
|
||||||
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)) {
|
|
||||||
(HeapCellRef::Ref(hc), _) =>
|
|
||||||
self.bind(d2, hc),
|
|
||||||
(_, HeapCellRef::Ref(hc)) =>
|
|
||||||
self.bind(d1, hc),
|
|
||||||
(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 + 1 {
|
|
||||||
pdl.push(Addr::HeapCell(a1 + i));
|
|
||||||
pdl.push(Addr::HeapCell(a2 + i));
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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.register_mut(reg) = HeapCellRef::Str(self.h + 1);
|
|
||||||
|
|
||||||
self.h += 2;
|
|
||||||
},
|
|
||||||
&QueryInstruction::PutValue(norm, arg) =>
|
|
||||||
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.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.register_mut(reg) = HeapCellRef::Ref(self.h);
|
|
||||||
|
|
||||||
self.h += 1;
|
|
||||||
},
|
|
||||||
&QueryInstruction::SetValue(reg) => {
|
|
||||||
let heap_val = self.lookup(Addr::from(reg));
|
|
||||||
self.heap.push(HeapCellValue::from(heap_val));
|
|
||||||
|
|
||||||
self.h += 1;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn execute_fact_instr(&mut self, instr: &FactInstruction) {
|
|
||||||
match instr {
|
|
||||||
&FactInstruction::GetStructure(_, ref name, arity, reg) => {
|
|
||||||
let addr = self.deref(Addr::from(reg));
|
|
||||||
|
|
||||||
match self.lookup(addr) {
|
|
||||||
HeapCellRef::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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
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, h);
|
|
||||||
|
|
||||||
self.h += 2;
|
|
||||||
self.mode = MachineMode::Write;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
},
|
|
||||||
&FactInstruction::GetVariable(norm, arg) =>
|
|
||||||
*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.register_mut(reg) = self.heap[self.s].as_ref(self.s),
|
|
||||||
MachineMode::Write => {
|
|
||||||
self.heap.push(HeapCellValue::Ref(self.h));
|
|
||||||
*self.register_mut(reg) = HeapCellRef::Ref(self.h);
|
|
||||||
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.lookup(Addr::from(reg));
|
|
||||||
self.heap.push(HeapCellValue::from(heap_val));
|
|
||||||
self.h += 1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.s += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn execute_ctrl_instr(&mut self, code_dir: &CodeDir, instr: &ControlInstruction)
|
|
||||||
{
|
|
||||||
match instr {
|
|
||||||
&ControlInstruction::Allocate(num_cells) => {
|
|
||||||
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![HeapCellRef::Ref(0); 32];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
pub mod ast;
|
|
||||||
pub mod heapview;
|
|
||||||
pub mod iterators;
|
|
||||||
pub mod l2_parser;
|
|
||||||
pub mod codegen;
|
|
||||||
pub mod machine;
|
|
||||||
pub mod stack;
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
use l2::ast::*;
|
|
||||||
|
|
||||||
use std::ops::{Index, IndexMut};
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
struct Frame {
|
|
||||||
cp: CodePtr,
|
|
||||||
perms: Vec<HeapCellRef>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Frame {
|
|
||||||
fn new(cp: CodePtr, n: usize) -> Self {
|
|
||||||
Frame {
|
|
||||||
cp: cp,
|
|
||||||
perms: vec![HeapCellRef::Ref(0); n]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_pv(&self, i: usize) -> &HeapCellRef {
|
|
||||||
self.perms.index(i)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_pv_mut(&mut self, i: usize) -> &mut HeapCellRef {
|
|
||||||
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 = HeapCellRef;
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
use l3::ast::*;
|
|
||||||
|
|
||||||
use std::ops::{Index, IndexMut};
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
pub struct Frame {
|
|
||||||
pub global_index: usize,
|
|
||||||
pub e: usize,
|
|
||||||
pub cp: CodePtr,
|
|
||||||
perms: Vec<Addr>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Frame {
|
|
||||||
fn new(global_index: usize, e: usize, cp: CodePtr, n: usize) -> Self {
|
|
||||||
Frame {
|
|
||||||
global_index: global_index,
|
|
||||||
e: e,
|
|
||||||
cp: cp,
|
|
||||||
perms: vec![Addr::HeapCell(0); n]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct AndStack(Vec<Frame>);
|
|
||||||
|
|
||||||
impl AndStack {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
AndStack(Vec::new())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push(&mut self, global_index: usize, e: usize, cp: CodePtr, n: usize) {
|
|
||||||
self.0.push(Frame::new(global_index, e, cp, n));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn top(&self) -> Option<&Frame> {
|
|
||||||
self.0.last()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
|
||||||
self.0.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clear(&mut self) {
|
|
||||||
self.0.clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
// drop the last n frames.
|
|
||||||
pub fn drop_frames(&mut self, n: usize) {
|
|
||||||
let len = self.0.len();
|
|
||||||
self.0.truncate(len - n);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Index<usize> for AndStack {
|
|
||||||
type Output = Frame;
|
|
||||||
|
|
||||||
fn index(&self, index: usize) -> &Self::Output {
|
|
||||||
self.0.index(index)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IndexMut<usize> for AndStack {
|
|
||||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
|
||||||
self.0.index_mut(index)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Index<usize> for Frame {
|
|
||||||
type Output = Addr;
|
|
||||||
|
|
||||||
fn index(&self, index: usize) -> &Self::Output {
|
|
||||||
self.perms.index(index - 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IndexMut<usize> for Frame {
|
|
||||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
|
||||||
self.perms.index_mut(index - 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
303
src/l3/ast.rs
303
src/l3/ast.rs
@@ -1,303 +0,0 @@
|
|||||||
use std::cell::Cell;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::ops::{Add, AddAssign};
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
pub type Var = String;
|
|
||||||
|
|
||||||
pub type Atom = String;
|
|
||||||
|
|
||||||
pub enum PredicateClause {
|
|
||||||
Fact(Term),
|
|
||||||
Rule(Rule)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PredicateClause {
|
|
||||||
pub fn name(&self) -> &Atom {
|
|
||||||
match self {
|
|
||||||
&PredicateClause::Fact(ref t) => t.name(),
|
|
||||||
&PredicateClause::Rule(ref rule) => rule.head.0.name()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn arity(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
&PredicateClause::Fact(ref t) => t.arity(),
|
|
||||||
&PredicateClause::Rule(ref rule) => rule.head.0.arity()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum TopLevel {
|
|
||||||
Fact(Term),
|
|
||||||
Predicate(Vec<PredicateClause>),
|
|
||||||
Query(Term),
|
|
||||||
Rule(Rule)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub enum Level {
|
|
||||||
Deep, Shallow
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub enum RegType {
|
|
||||||
Perm(usize),
|
|
||||||
Temp(usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RegType {
|
|
||||||
pub fn reg_num(self) -> usize {
|
|
||||||
match self {
|
|
||||||
RegType::Perm(reg_num) | RegType::Temp(reg_num) => reg_num
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_perm(self) -> bool {
|
|
||||||
match self {
|
|
||||||
RegType::Perm(_) => true,
|
|
||||||
_ => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub enum VarReg {
|
|
||||||
ArgAndNorm(RegType, usize),
|
|
||||||
Norm(RegType)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl VarReg {
|
|
||||||
pub fn norm(self) -> RegType {
|
|
||||||
match self {
|
|
||||||
VarReg::ArgAndNorm(reg, _) | VarReg::Norm(reg) => reg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn root_register(self) -> usize {
|
|
||||||
match self {
|
|
||||||
VarReg::ArgAndNorm(_, root) => root,
|
|
||||||
VarReg::Norm(root) => root.reg_num()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum Term {
|
|
||||||
Atom(Cell<RegType>, Atom),
|
|
||||||
Clause(Cell<RegType>, Atom, Vec<Box<Term>>),
|
|
||||||
Var(Cell<VarReg>, Var)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Rule {
|
|
||||||
pub head: (Term, Term),
|
|
||||||
pub clauses: Vec<Term>
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum TermRef<'a> {
|
|
||||||
Atom(Level, &'a Cell<RegType>, &'a Atom),
|
|
||||||
Clause(Level, &'a Cell<RegType>, &'a Atom, &'a Vec<Box<Term>>),
|
|
||||||
Var(Level, &'a Cell<VarReg>, &'a Var)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum FactInstruction {
|
|
||||||
GetStructure(Level, Atom, usize, RegType),
|
|
||||||
GetValue(RegType, usize),
|
|
||||||
GetVariable(RegType, usize),
|
|
||||||
UnifyVariable(RegType),
|
|
||||||
UnifyValue(RegType)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum QueryInstruction {
|
|
||||||
PutStructure(Level, Atom, usize, RegType),
|
|
||||||
PutValue(RegType, usize),
|
|
||||||
PutVariable(RegType, usize),
|
|
||||||
SetVariable(RegType),
|
|
||||||
SetValue(RegType)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum ChoiceInstruction {
|
|
||||||
RetryMeElse(usize),
|
|
||||||
TrustMe,
|
|
||||||
TryMeElse(usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum ControlInstruction {
|
|
||||||
Allocate(usize),
|
|
||||||
Call(Atom, usize),
|
|
||||||
Deallocate,
|
|
||||||
Proceed
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type CompiledFact = Vec<FactInstruction>;
|
|
||||||
|
|
||||||
pub type CompiledQuery = Vec<QueryInstruction>;
|
|
||||||
|
|
||||||
pub enum Line {
|
|
||||||
Choice(ChoiceInstruction),
|
|
||||||
Control(ControlInstruction),
|
|
||||||
Fact(CompiledFact),
|
|
||||||
Query(CompiledQuery)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum LineOrCodeOffset<'a> {
|
|
||||||
Instruction(&'a Line),
|
|
||||||
Offset(usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<&'a Line> for LineOrCodeOffset<'a> {
|
|
||||||
fn from(line: &'a Line) -> Self {
|
|
||||||
LineOrCodeOffset::Instruction(line)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type Code = Vec<Line>;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
|
||||||
pub enum Addr {
|
|
||||||
HeapCell(usize),
|
|
||||||
StackCell(usize, usize),
|
|
||||||
Str(usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Addr {
|
|
||||||
pub fn is_ref(self) -> bool {
|
|
||||||
match self {
|
|
||||||
Addr::HeapCell(_) | Addr::StackCell(_, _) => true,
|
|
||||||
_ => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_ref(self) -> Option<Ref> {
|
|
||||||
match self {
|
|
||||||
Addr::HeapCell(hc) => Some(Ref::HeapCell(hc)),
|
|
||||||
Addr::StackCell(fr, sc) => Some(Ref::StackCell(fr, sc)),
|
|
||||||
_ => None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Ref> for Addr {
|
|
||||||
fn from(r: Ref) -> Self {
|
|
||||||
match r {
|
|
||||||
Ref::HeapCell(hc) => Addr::HeapCell(hc),
|
|
||||||
Ref::StackCell(fr, sc) => Addr::StackCell(fr, sc)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
|
||||||
pub enum Ref {
|
|
||||||
HeapCell(usize),
|
|
||||||
StackCell(usize, usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq)]
|
|
||||||
pub enum HeapCellValue {
|
|
||||||
NamedStr(usize, Atom),
|
|
||||||
Ref(Ref),
|
|
||||||
Str(usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Addr> for HeapCellValue {
|
|
||||||
fn from(addr: Addr) -> HeapCellValue {
|
|
||||||
match addr {
|
|
||||||
Addr::HeapCell(hc) =>
|
|
||||||
HeapCellValue::Ref(Ref::HeapCell(hc)),
|
|
||||||
Addr::StackCell(fr, sc) =>
|
|
||||||
HeapCellValue::Ref(Ref::StackCell(fr, sc)),
|
|
||||||
Addr::Str(hc) =>
|
|
||||||
HeapCellValue::Str(hc)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HeapCellValue {
|
|
||||||
pub fn as_addr(&self, focus: usize) -> Addr {
|
|
||||||
match self {
|
|
||||||
&HeapCellValue::Ref(r) => Addr::from(r),
|
|
||||||
&HeapCellValue::Str(s) => Addr::Str(s),
|
|
||||||
&HeapCellValue::NamedStr(_, _) => Addr::Str(focus)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub enum CodePtr {
|
|
||||||
DirEntry(usize),
|
|
||||||
TopLevel
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for CodePtr {
|
|
||||||
fn default() -> Self {
|
|
||||||
CodePtr::TopLevel
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Add<usize> for CodePtr {
|
|
||||||
type Output = CodePtr;
|
|
||||||
|
|
||||||
fn add(self, rhs: usize) -> Self::Output {
|
|
||||||
match self {
|
|
||||||
CodePtr::DirEntry(p) => CodePtr::DirEntry(p + rhs),
|
|
||||||
CodePtr::TopLevel => CodePtr::TopLevel
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AddAssign<usize> for CodePtr {
|
|
||||||
fn add_assign(&mut self, rhs: usize) {
|
|
||||||
match self {
|
|
||||||
&mut CodePtr::DirEntry(ref mut p) => *p += rhs,
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type Heap = Vec<HeapCellValue>;
|
|
||||||
|
|
||||||
pub type Registers = Vec<Addr>;
|
|
||||||
|
|
||||||
impl Term {
|
|
||||||
pub fn subterms(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
&Term::Clause(_, _, ref terms) => terms.len(),
|
|
||||||
_ => 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn name(&self) -> &Atom {
|
|
||||||
match self {
|
|
||||||
&Term::Atom(_, ref atom)
|
|
||||||
| &Term::Var(_, ref atom)
|
|
||||||
| &Term::Clause(_, ref atom, _) => atom
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn arity(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
&Term::Atom(_, _) | &Term::Var(_, _) => 0,
|
|
||||||
&Term::Clause(_, _, ref child_terms) => child_terms.len()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type HeapVarDict = HashMap<Var, Addr>;
|
|
||||||
|
|
||||||
pub enum EvalResult {
|
|
||||||
EntryFailure,
|
|
||||||
EntrySuccess,
|
|
||||||
InitialQuerySuccess(HeapVarDict),
|
|
||||||
QueryFailure,
|
|
||||||
SubsequentQuerySuccess,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EvalResult {
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn failed_query(&self) -> bool {
|
|
||||||
if let &EvalResult::QueryFailure = self {
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,447 +0,0 @@
|
|||||||
use l3::ast::*;
|
|
||||||
use l3::iterators::{FactIterator, QueryIterator};
|
|
||||||
|
|
||||||
use std::cell::Cell;
|
|
||||||
use std::cmp::max;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
trait CompilationTarget<'a> {
|
|
||||||
type Iterator : Iterator<Item=TermRef<'a>>;
|
|
||||||
|
|
||||||
fn iter(&'a Term) -> Self::Iterator;
|
|
||||||
|
|
||||||
fn to_structure(Level, Atom, usize, RegType) -> Self;
|
|
||||||
|
|
||||||
fn argument_to_variable(RegType, usize) -> Self;
|
|
||||||
fn argument_to_value(RegType, usize) -> Self;
|
|
||||||
fn subterm_to_variable(RegType) -> Self;
|
|
||||||
fn subterm_to_value(RegType) -> Self;
|
|
||||||
|
|
||||||
fn clause_arg_to_instr(RegType) -> Self;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> CompilationTarget<'a> for FactInstruction {
|
|
||||||
type Iterator = FactIterator<'a>;
|
|
||||||
|
|
||||||
fn iter(term: &'a Term) -> Self::Iterator {
|
|
||||||
term.breadth_first_iter()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_structure(lvl: Level, atom: Atom, arity: usize, reg: RegType) -> Self {
|
|
||||||
FactInstruction::GetStructure(lvl, atom, arity, reg)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn argument_to_variable(arg: RegType, val: usize) -> Self {
|
|
||||||
FactInstruction::GetVariable(arg, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn argument_to_value(arg: RegType, val: usize) -> Self {
|
|
||||||
FactInstruction::GetValue(arg, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subterm_to_variable(val: RegType) -> Self {
|
|
||||||
FactInstruction::UnifyVariable(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subterm_to_value(val: RegType) -> Self {
|
|
||||||
FactInstruction::UnifyValue(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clause_arg_to_instr(val: RegType) -> Self {
|
|
||||||
FactInstruction::UnifyVariable(val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> CompilationTarget<'a> for QueryInstruction {
|
|
||||||
type Iterator = QueryIterator<'a>;
|
|
||||||
|
|
||||||
fn iter(term: &'a Term) -> Self::Iterator {
|
|
||||||
term.post_order_iter()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_structure(lvl: Level, atom: Atom, arity: usize, reg: RegType) -> Self {
|
|
||||||
QueryInstruction::PutStructure(lvl, atom, arity, reg)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn argument_to_variable(arg: RegType, val: usize) -> Self {
|
|
||||||
QueryInstruction::PutVariable(arg, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn argument_to_value(arg: RegType, val: usize) -> Self {
|
|
||||||
QueryInstruction::PutValue(arg, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subterm_to_variable(val: RegType) -> Self {
|
|
||||||
QueryInstruction::SetVariable(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subterm_to_value(val: RegType) -> Self {
|
|
||||||
QueryInstruction::SetValue(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clause_arg_to_instr(val: RegType) -> Self {
|
|
||||||
QueryInstruction::SetValue(val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct TermMarker<'a> {
|
|
||||||
bindings: HashMap<&'a Var, VarReg>,
|
|
||||||
arg_c: usize,
|
|
||||||
perm_c: usize,
|
|
||||||
temp_c: usize
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> TermMarker<'a> {
|
|
||||||
fn new() -> TermMarker<'a> {
|
|
||||||
TermMarker { bindings: HashMap::new(),
|
|
||||||
arg_c: 1,
|
|
||||||
perm_c: 1,
|
|
||||||
temp_c: 1 }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reset(&mut self) {
|
|
||||||
self.bindings.clear();
|
|
||||||
self.perm_c = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn contains_var(&self, var: &'a Var) -> bool {
|
|
||||||
self.bindings.contains_key(var)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get(&self, var: &'a Var) -> VarReg {
|
|
||||||
*self.bindings.get(var).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn insert(&mut self, var: &'a Var, r: VarReg) {
|
|
||||||
self.bindings.insert(var, r);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_non_var(&mut self, lvl: Level, cell: &Cell<RegType>) {
|
|
||||||
let reg_type = cell.get();
|
|
||||||
|
|
||||||
if reg_type.reg_num() == 0 {
|
|
||||||
match lvl {
|
|
||||||
Level::Deep if reg_type.is_perm() => {
|
|
||||||
let perm = self.perm_c;
|
|
||||||
self.perm_c += 1;
|
|
||||||
cell.set(RegType::Perm(perm));
|
|
||||||
},
|
|
||||||
Level::Deep => {
|
|
||||||
let temp = self.temp_c;
|
|
||||||
self.temp_c += 1;
|
|
||||||
cell.set(RegType::Temp(temp));
|
|
||||||
},
|
|
||||||
Level::Shallow if reg_type.is_perm() => {
|
|
||||||
let arg = self.arg_c;
|
|
||||||
self.arg_c += 1;
|
|
||||||
cell.set(RegType::Perm(arg));
|
|
||||||
},
|
|
||||||
Level::Shallow => {
|
|
||||||
let arg = self.arg_c;
|
|
||||||
self.arg_c += 1;
|
|
||||||
cell.set(RegType::Temp(arg));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_old_var(&mut self, lvl: Level, var: &'a Var) -> VarReg
|
|
||||||
{
|
|
||||||
let reg = self.get(var);
|
|
||||||
|
|
||||||
match lvl {
|
|
||||||
Level::Deep => VarReg::Norm(reg.norm()),
|
|
||||||
Level::Shallow => {
|
|
||||||
let reg = VarReg::ArgAndNorm(reg.norm(), self.arg_c);
|
|
||||||
|
|
||||||
self.arg_c += 1;
|
|
||||||
self.insert(var, reg);
|
|
||||||
|
|
||||||
reg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_new_var(&mut self, lvl: Level, var: &'a Var, reg: RegType) -> VarReg
|
|
||||||
{
|
|
||||||
let inner_reg = if reg.is_perm() {
|
|
||||||
let perm = self.perm_c;
|
|
||||||
self.perm_c += 1;
|
|
||||||
RegType::Perm(perm)
|
|
||||||
} else {
|
|
||||||
let temp = self.temp_c;
|
|
||||||
self.temp_c += 1;
|
|
||||||
RegType::Temp(temp)
|
|
||||||
};
|
|
||||||
|
|
||||||
let reg = match lvl {
|
|
||||||
Level::Deep => VarReg::Norm(inner_reg),
|
|
||||||
Level::Shallow => {
|
|
||||||
let reg = VarReg::ArgAndNorm(inner_reg, self.arg_c);
|
|
||||||
self.arg_c += 1;
|
|
||||||
reg
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.insert(var, reg);
|
|
||||||
reg
|
|
||||||
}
|
|
||||||
|
|
||||||
fn advance_at_head(&mut self, term: &'a Term) {
|
|
||||||
self.arg_c = 1;
|
|
||||||
self.temp_c = max(term.subterms(), self.temp_c) + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn advance(&mut self, term: &'a Term) {
|
|
||||||
self.arg_c = 1;
|
|
||||||
self.temp_c = term.subterms() + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
enum TermStatus {
|
|
||||||
New, Old, Recurrent
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct CodeGenerator<'a> {
|
|
||||||
marker: TermMarker<'a>
|
|
||||||
}
|
|
||||||
|
|
||||||
type VariableFixture<'a> = (TermStatus, Vec<&'a Cell<VarReg>>);
|
|
||||||
type VariableFixtures<'a> = HashMap<&'a Var, VariableFixture<'a>>;
|
|
||||||
|
|
||||||
impl<'a> CodeGenerator<'a> {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
CodeGenerator { marker: TermMarker::new() }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn vars(&self) -> &HashMap<&Var, VarReg> {
|
|
||||||
&self.marker.bindings
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_structure<Target>(&mut self,
|
|
||||||
lvl: Level,
|
|
||||||
name: &'a Atom,
|
|
||||||
cell: &'a Cell<RegType>,
|
|
||||||
arity: usize)
|
|
||||||
-> Target
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
self.marker.mark_non_var(lvl, cell);
|
|
||||||
Target::to_structure(lvl, name.clone(), arity, cell.get())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn var_term<Target>(&mut self,
|
|
||||||
lvl: Level,
|
|
||||||
cell: &'a Cell<VarReg>,
|
|
||||||
var: &'a Var)
|
|
||||||
-> Target
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
if !self.marker.contains_var(var) {
|
|
||||||
let reg = self.marker.mark_new_var(lvl, var, cell.get().norm());
|
|
||||||
cell.set(reg);
|
|
||||||
|
|
||||||
match reg {
|
|
||||||
VarReg::ArgAndNorm(arg, norm) =>
|
|
||||||
Target::argument_to_variable(arg, norm),
|
|
||||||
VarReg::Norm(norm) =>
|
|
||||||
Target::subterm_to_variable(norm)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let reg = self.marker.mark_old_var(lvl, var);
|
|
||||||
cell.set(reg);
|
|
||||||
|
|
||||||
match reg {
|
|
||||||
VarReg::ArgAndNorm(arg, norm) =>
|
|
||||||
Target::argument_to_value(arg, norm),
|
|
||||||
VarReg::Norm(norm) =>
|
|
||||||
Target::subterm_to_value(norm)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn non_var_subterm<Target>(&mut self, cell: &'a Cell<RegType>) -> Target
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
self.marker.mark_non_var(Level::Deep, cell);
|
|
||||||
Target::clause_arg_to_instr(cell.get())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subterm_to_instr<Target>(&mut self, subterm: &'a Term) -> Target
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
match subterm {
|
|
||||||
&Term::Atom(ref cell, _) | &Term::Clause(ref cell, _, _) =>
|
|
||||||
self.non_var_subterm(cell),
|
|
||||||
&Term::Var(ref cell, ref var) =>
|
|
||||||
self.var_term(Level::Deep, cell, var)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compile_target<Target>(&mut self, term: &'a Term) -> Vec<Target>
|
|
||||||
where Target: CompilationTarget<'a>
|
|
||||||
{
|
|
||||||
let iter = Target::iter(term);
|
|
||||||
let mut target = Vec::new();
|
|
||||||
|
|
||||||
for term in iter {
|
|
||||||
match term {
|
|
||||||
TermRef::Atom(lvl, term, atom) =>
|
|
||||||
target.push(self.to_structure(lvl, atom, term, 0)),
|
|
||||||
TermRef::Clause(lvl, term, atom, terms) => {
|
|
||||||
target.push(self.to_structure(lvl, atom, term, terms.len()));
|
|
||||||
|
|
||||||
for subterm in terms {
|
|
||||||
target.push(self.subterm_to_instr(subterm.as_ref()));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TermRef::Var(lvl @ Level::Shallow, ref cell, ref var) =>
|
|
||||||
target.push(self.var_term(lvl, cell, var)),
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
target
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_vars_in_term<Iter>(iter: Iter, vs: &mut VariableFixtures<'a>)
|
|
||||||
where Iter : Iterator<Item=TermRef<'a>>
|
|
||||||
{
|
|
||||||
for term in iter {
|
|
||||||
if let TermRef::Var(_, reg_cell, var) = term {
|
|
||||||
let mut status = vs.entry(var)
|
|
||||||
.or_insert((TermStatus::New, Vec::new()));
|
|
||||||
|
|
||||||
status.1.push(reg_cell);
|
|
||||||
|
|
||||||
match status.0 {
|
|
||||||
TermStatus::Old => status.0 = TermStatus::Recurrent,
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for &mut (ref mut term_status, ref mut cb) in vs.values_mut() {
|
|
||||||
match *term_status {
|
|
||||||
TermStatus::New => *term_status = TermStatus::Old,
|
|
||||||
TermStatus::Recurrent => {
|
|
||||||
for cell_reg in cb.drain(0..) {
|
|
||||||
cell_reg.set(VarReg::Norm(RegType::Perm(0)));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_perm_vars(rule: &'a Rule) -> VariableFixtures {
|
|
||||||
let &Rule { head: (ref p0, ref p1), ref clauses } = rule;
|
|
||||||
let mut vfs = HashMap::new();
|
|
||||||
|
|
||||||
let iter = p0.breadth_first_iter().chain(p1.breadth_first_iter());
|
|
||||||
|
|
||||||
Self::mark_vars_in_term(iter, &mut vfs);
|
|
||||||
|
|
||||||
for term in clauses {
|
|
||||||
Self::mark_vars_in_term(term.breadth_first_iter(), &mut vfs);
|
|
||||||
}
|
|
||||||
|
|
||||||
vfs
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_conditional_call(compiled_query: &mut Code, term: &Term) {
|
|
||||||
match term {
|
|
||||||
&Term::Atom(_, ref atom) => {
|
|
||||||
let call = ControlInstruction::Call(atom.clone(), 0);
|
|
||||||
compiled_query.push(Line::Control(call));
|
|
||||||
},
|
|
||||||
&Term::Clause(_, ref atom, ref terms) => {
|
|
||||||
let call = ControlInstruction::Call(atom.clone(), terms.len());
|
|
||||||
compiled_query.push(Line::Control(call));
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compile_rule(&mut self, rule: &'a Rule) -> Code {
|
|
||||||
let vfs = Self::mark_perm_vars(&rule);
|
|
||||||
let &Rule { head: (ref p0, ref p1), ref clauses } = rule;
|
|
||||||
let mut perm_vars = 0;
|
|
||||||
|
|
||||||
for &(term_status, _) in vfs.values() {
|
|
||||||
if let TermStatus::Recurrent = term_status {
|
|
||||||
perm_vars += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut body = Vec::new();
|
|
||||||
|
|
||||||
body.push(Line::Control(ControlInstruction::Allocate(perm_vars)));
|
|
||||||
|
|
||||||
self.marker.advance(p0);
|
|
||||||
body.push(Line::Fact(self.compile_target(p0)));
|
|
||||||
|
|
||||||
self.marker.advance_at_head(p1);
|
|
||||||
body.push(Line::Query(self.compile_target(p1)));
|
|
||||||
|
|
||||||
Self::add_conditional_call(&mut body, p1);
|
|
||||||
|
|
||||||
body = clauses.iter()
|
|
||||||
.map(|ref term| self.compile_query(term))
|
|
||||||
.fold(body, |mut body, ref mut cqs| {
|
|
||||||
body.append(cqs);
|
|
||||||
body
|
|
||||||
});
|
|
||||||
|
|
||||||
body.push(Line::Control(ControlInstruction::Deallocate));
|
|
||||||
body
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compile_fact(&mut self, term: &'a Term) -> Code {
|
|
||||||
self.marker.advance(term);
|
|
||||||
|
|
||||||
let mut compiled_fact = vec![Line::Fact(self.compile_target(term))];
|
|
||||||
let proceed = Line::Control(ControlInstruction::Proceed);
|
|
||||||
|
|
||||||
compiled_fact.push(proceed);
|
|
||||||
compiled_fact
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compile_query(&mut self, term: &'a Term) -> Code {
|
|
||||||
self.marker.advance(term);
|
|
||||||
|
|
||||||
let mut compiled_query = vec![Line::Query(self.compile_target(term))];
|
|
||||||
Self::add_conditional_call(&mut compiled_query, term);
|
|
||||||
|
|
||||||
compiled_query
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compile_predicate(&mut self, clauses: &'a Vec<PredicateClause>) -> Code
|
|
||||||
{
|
|
||||||
let mut code = Vec::new();
|
|
||||||
|
|
||||||
for (i, clause) in clauses.iter().enumerate() {
|
|
||||||
self.marker.reset();
|
|
||||||
|
|
||||||
let mut clause_code = match clause {
|
|
||||||
&PredicateClause::Fact(ref fact) =>
|
|
||||||
self.compile_fact(fact),
|
|
||||||
&PredicateClause::Rule(ref rule) =>
|
|
||||||
self.compile_rule(rule)
|
|
||||||
};
|
|
||||||
|
|
||||||
let choice = match i {
|
|
||||||
0 => ChoiceInstruction::TryMeElse(clause_code.len() + 1),
|
|
||||||
_ if i == clauses.len() - 1 => ChoiceInstruction::TrustMe,
|
|
||||||
_ => ChoiceInstruction::RetryMeElse(clause_code.len() + 1)
|
|
||||||
};
|
|
||||||
|
|
||||||
code.push(Line::Choice(choice));
|
|
||||||
code.append(&mut clause_code);
|
|
||||||
}
|
|
||||||
|
|
||||||
code
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
use l3::and_stack::*;
|
|
||||||
use l3::ast::*;
|
|
||||||
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub enum HeapCellView<'a> {
|
|
||||||
Str(usize, &'a Atom),
|
|
||||||
HeapVar(usize),
|
|
||||||
StackVar(usize, usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct HeapCellViewer<'a> {
|
|
||||||
heap: &'a Heap,
|
|
||||||
and_stack: &'a AndStack,
|
|
||||||
state_stack: Vec<Addr>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> HeapCellViewer<'a> {
|
|
||||||
pub fn new(heap: &'a Heap, and_stack: &'a AndStack, focus: Addr) -> Self {
|
|
||||||
HeapCellViewer {
|
|
||||||
heap: heap,
|
|
||||||
and_stack: and_stack,
|
|
||||||
state_stack: vec![focus]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn follow_stack_ref(&mut self, mut fr: usize, mut sc: usize) -> HeapCellView<'a>
|
|
||||||
{
|
|
||||||
loop {
|
|
||||||
match self.and_stack[fr][sc] {
|
|
||||||
Addr::HeapCell(hc) | Addr::Str(hc) =>
|
|
||||||
return self.follow_heap_ref(hc),
|
|
||||||
Addr::StackCell(fr1, sc1) => {
|
|
||||||
if fr1 == fr && sc1 == sc {
|
|
||||||
return HeapCellView::StackVar(fr, sc);
|
|
||||||
}
|
|
||||||
|
|
||||||
fr = fr1; sc = sc1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn follow_heap_ref(&mut self, mut focus: usize) -> HeapCellView<'a> {
|
|
||||||
loop {
|
|
||||||
match &self.heap[focus] {
|
|
||||||
&HeapCellValue::NamedStr(arity, ref name) => {
|
|
||||||
for i in (1 .. arity + 1).rev() {
|
|
||||||
self.state_stack.push(Addr::HeapCell(focus + i));
|
|
||||||
}
|
|
||||||
|
|
||||||
return HeapCellView::Str(arity, name);
|
|
||||||
},
|
|
||||||
&HeapCellValue::Ref(Ref::HeapCell(hc)) => {
|
|
||||||
if focus == hc {
|
|
||||||
return HeapCellView::HeapVar(hc);
|
|
||||||
} else {
|
|
||||||
focus = hc;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
&HeapCellValue::Ref(Ref::StackCell(fr, sc)) =>
|
|
||||||
return self.follow_stack_ref(fr, sc),
|
|
||||||
&HeapCellValue::Str(cell_num) =>
|
|
||||||
focus = cell_num,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for HeapCellViewer<'a> {
|
|
||||||
type Item = HeapCellView<'a>;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
if let Some(addr) = self.state_stack.pop() {
|
|
||||||
match addr {
|
|
||||||
Addr::HeapCell(hc) | Addr::Str(hc) =>
|
|
||||||
return Some(self.follow_heap_ref(hc)),
|
|
||||||
Addr::StackCell(fr, sc) =>
|
|
||||||
return Some(self.follow_stack_ref(fr, sc))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
255
src/l3/io.rs
255
src/l3/io.rs
@@ -1,255 +0,0 @@
|
|||||||
use l3::ast::*;
|
|
||||||
use l3::codegen::*;
|
|
||||||
use l3::l3_parser::*;
|
|
||||||
use l3::machine::*;
|
|
||||||
|
|
||||||
use termion::raw::IntoRawMode;
|
|
||||||
use termion::input::TermRead;
|
|
||||||
use termion::event::Key;
|
|
||||||
|
|
||||||
use std::io::{Write, stdin, stdout};
|
|
||||||
use std::fmt;
|
|
||||||
|
|
||||||
impl fmt::Display for FactInstruction {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&FactInstruction::GetStructure(Level::Deep, ref name, ref arity, ref r) =>
|
|
||||||
write!(f, "get_structure {}/{}, {}", name, arity, r),
|
|
||||||
&FactInstruction::GetStructure(Level::Shallow, ref name, ref arity, ref r) =>
|
|
||||||
write!(f, "get_structure {}/{}, A{}", name, arity, r.reg_num()),
|
|
||||||
&FactInstruction::GetValue(ref x, ref a) =>
|
|
||||||
write!(f, "get_value {}, A{}", x, a),
|
|
||||||
&FactInstruction::GetVariable(ref x, ref a) =>
|
|
||||||
write!(f, "get_variable {}, A{}", x, a),
|
|
||||||
&FactInstruction::UnifyVariable(ref r) =>
|
|
||||||
write!(f, "unify_variable {}", r),
|
|
||||||
&FactInstruction::UnifyValue(ref r) =>
|
|
||||||
write!(f, "unify_value {}", r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for QueryInstruction {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&QueryInstruction::PutStructure(Level::Deep, ref name, ref arity, ref r) =>
|
|
||||||
write!(f, "put_structure {}/{}, {}", name, arity, r.reg_num()),
|
|
||||||
&QueryInstruction::PutStructure(Level::Shallow, ref name, ref arity, ref r) =>
|
|
||||||
write!(f, "put_structure {}/{}, A{}", name, arity, r.reg_num()),
|
|
||||||
&QueryInstruction::PutValue(ref x, ref a) =>
|
|
||||||
write!(f, "put_value {}, A{}", x, a),
|
|
||||||
&QueryInstruction::PutVariable(ref x, ref a) =>
|
|
||||||
write!(f, "put_variable {}, A{}", x, a),
|
|
||||||
&QueryInstruction::SetVariable(ref r) =>
|
|
||||||
write!(f, "set_variable {}", r),
|
|
||||||
&QueryInstruction::SetValue(ref r) =>
|
|
||||||
write!(f, "set_value {}", r),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for ControlInstruction {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&ControlInstruction::Allocate(num_cells) =>
|
|
||||||
write!(f, "allocate {}", num_cells),
|
|
||||||
&ControlInstruction::Call(ref name, ref arity) =>
|
|
||||||
write!(f, "call {}/{}", name, arity),
|
|
||||||
&ControlInstruction::Deallocate =>
|
|
||||||
write!(f, "deallocate"),
|
|
||||||
&ControlInstruction::Proceed =>
|
|
||||||
write!(f, "proceed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for ChoiceInstruction {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&ChoiceInstruction::TryMeElse(offset) =>
|
|
||||||
write!(f, "try_me_else {}", offset),
|
|
||||||
&ChoiceInstruction::RetryMeElse(offset) =>
|
|
||||||
write!(f, "retry_me_else {}", offset),
|
|
||||||
&ChoiceInstruction::TrustMe =>
|
|
||||||
write!(f, "trust_me")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Level {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&Level::Shallow => write!(f, "A"),
|
|
||||||
&Level::Deep => write!(f, "X")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for VarReg {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&VarReg::Norm(RegType::Perm(reg)) => write!(f, "Y{}", reg),
|
|
||||||
&VarReg::Norm(RegType::Temp(reg)) => write!(f, "X{}", reg),
|
|
||||||
&VarReg::ArgAndNorm(RegType::Perm(reg), arg) =>
|
|
||||||
write!(f, "Y{} A{}", reg, arg),
|
|
||||||
&VarReg::ArgAndNorm(RegType::Temp(reg), arg) =>
|
|
||||||
write!(f, "X{} A{}", reg, arg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for RegType {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
&RegType::Perm(val) => write!(f, "Y{}", val),
|
|
||||||
&RegType::Temp(val) => write!(f, "X{}", val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fn is_consistent(predicate: &Vec<PredicateClause>) -> bool {
|
|
||||||
let name = predicate.first().unwrap().name();
|
|
||||||
let arity = predicate.first().unwrap().arity();
|
|
||||||
|
|
||||||
for clause in predicate.iter().skip(1) {
|
|
||||||
if !(name == clause.name() && arity == clause.arity()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn print_code(code: &Code) {
|
|
||||||
for clause in code {
|
|
||||||
match clause {
|
|
||||||
&Line::Fact(ref fact) =>
|
|
||||||
for fact_instr in fact {
|
|
||||||
println!("{}", fact_instr);
|
|
||||||
},
|
|
||||||
&Line::Choice(ref choice) =>
|
|
||||||
println!("{}", choice),
|
|
||||||
&Line::Control(ref control) =>
|
|
||||||
println!("{}", control),
|
|
||||||
&Line::Query(ref query) =>
|
|
||||||
for query_instr in query {
|
|
||||||
println!("{}", query_instr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read() -> String {
|
|
||||||
let _ = stdout().flush();
|
|
||||||
|
|
||||||
let mut buffer = String::new();
|
|
||||||
let mut result = String::new();
|
|
||||||
|
|
||||||
let stdin = stdin();
|
|
||||||
stdin.read_line(&mut buffer).unwrap();
|
|
||||||
|
|
||||||
if &*buffer.trim() == ":{" {
|
|
||||||
buffer.clear();
|
|
||||||
|
|
||||||
stdin.read_line(&mut buffer).unwrap();
|
|
||||||
|
|
||||||
while &*buffer.trim() != "}:" {
|
|
||||||
result += buffer.as_str();
|
|
||||||
buffer.clear();
|
|
||||||
stdin.read_line(&mut buffer).unwrap();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
result = buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn eval(wam: &mut Machine, buffer: &str) -> EvalResult
|
|
||||||
{
|
|
||||||
let result = parse_TopLevel(buffer);
|
|
||||||
let mut cg = CodeGenerator::new();
|
|
||||||
|
|
||||||
match &result {
|
|
||||||
&Ok(TopLevel::Predicate(ref clauses)) => {
|
|
||||||
if is_consistent(clauses) {
|
|
||||||
let compiled_pred = cg.compile_predicate(clauses);
|
|
||||||
wam.add_predicate(clauses, compiled_pred);
|
|
||||||
|
|
||||||
EvalResult::EntrySuccess
|
|
||||||
} else {
|
|
||||||
let msg = r"Error: predicate is inconsistent.
|
|
||||||
Each predicate must have the same name and arity.";
|
|
||||||
|
|
||||||
println!("{}", msg);
|
|
||||||
EvalResult::EntryFailure
|
|
||||||
}
|
|
||||||
},
|
|
||||||
&Ok(TopLevel::Fact(ref fact)) => {
|
|
||||||
let compiled_fact = cg.compile_fact(&fact);
|
|
||||||
wam.add_fact(fact, compiled_fact);
|
|
||||||
EvalResult::EntrySuccess
|
|
||||||
},
|
|
||||||
&Ok(TopLevel::Rule(ref rule)) => {
|
|
||||||
let compiled_rule = cg.compile_rule(&rule);
|
|
||||||
wam.add_rule(rule, compiled_rule);
|
|
||||||
EvalResult::EntrySuccess
|
|
||||||
},
|
|
||||||
&Ok(TopLevel::Query(ref query)) => {
|
|
||||||
let compiled_query = cg.compile_query(&query);
|
|
||||||
wam.run_query(compiled_query, &cg)
|
|
||||||
},
|
|
||||||
&Err(_) => {
|
|
||||||
println!("Grammatical error of some kind!");
|
|
||||||
EvalResult::EntryFailure
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn print(wam: &mut Machine, result: EvalResult) {
|
|
||||||
match result {
|
|
||||||
EvalResult::InitialQuerySuccess(heap_locs) => {
|
|
||||||
println!("yes");
|
|
||||||
|
|
||||||
'outer: loop {
|
|
||||||
let mut result = EvalResult::QueryFailure;
|
|
||||||
let bindings = wam.heap_view(&heap_locs);
|
|
||||||
|
|
||||||
let stdin = stdin();
|
|
||||||
let mut stdout = stdout().into_raw_mode().unwrap();
|
|
||||||
|
|
||||||
write!(stdout, "{}\n\r", bindings).unwrap();
|
|
||||||
stdout.flush().unwrap();
|
|
||||||
|
|
||||||
if !wam.or_stack_is_empty() {
|
|
||||||
write!(stdout, "Press ; to continue or A to abort.\n\r").unwrap();
|
|
||||||
stdout.flush().unwrap();
|
|
||||||
|
|
||||||
for c in stdin.keys() {
|
|
||||||
match c.unwrap() {
|
|
||||||
Key::Char(';') => {
|
|
||||||
result = wam.continue_query();
|
|
||||||
break;
|
|
||||||
},
|
|
||||||
Key::Char('a') | Key::Char('A') =>
|
|
||||||
break 'outer,
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if let &EvalResult::QueryFailure = &result {
|
|
||||||
write!(stdout, "no\n\r").unwrap();
|
|
||||||
stdout.flush().unwrap();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
EvalResult::QueryFailure => println!("no"),
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,175 +0,0 @@
|
|||||||
use l3::ast::*;
|
|
||||||
|
|
||||||
use std::cell::Cell;
|
|
||||||
use std::collections::VecDeque;
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
enum IteratorState<'a> {
|
|
||||||
Atom(Level, &'a Cell<RegType>, &'a Atom),
|
|
||||||
Clause(Level, usize, &'a Cell<RegType>, &'a Atom, &'a Vec<Box<Term>>),
|
|
||||||
IsolatedAtom(&'a Cell<RegType>, &'a Atom),
|
|
||||||
IsolatedVar(&'a Cell<VarReg>, &'a Var),
|
|
||||||
RootClause(usize, &'a Vec<Box<Term>>),
|
|
||||||
Var(Level, &'a Cell<VarReg>, &'a Var)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> IteratorState<'a> {
|
|
||||||
fn to_state(lvl: Level, term: &'a Term) -> IteratorState<'a>
|
|
||||||
{
|
|
||||||
match term {
|
|
||||||
&Term::Atom(ref cell, ref atom) =>
|
|
||||||
IteratorState::Atom(lvl, cell, atom),
|
|
||||||
&Term::Clause(ref cell, ref atom, ref child_terms) =>
|
|
||||||
IteratorState::Clause(lvl, 0, cell, atom, child_terms),
|
|
||||||
&Term::Var(ref cell, ref var) =>
|
|
||||||
IteratorState::Var(lvl, cell, var)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct QueryIterator<'a> {
|
|
||||||
state_stack: Vec<IteratorState<'a>>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> QueryIterator<'a> {
|
|
||||||
fn push_clause(&mut self,
|
|
||||||
lvl: Level,
|
|
||||||
child_num: usize,
|
|
||||||
cell: &'a Cell<RegType>,
|
|
||||||
name: &'a Atom,
|
|
||||||
child_terms: &'a Vec<Box<Term>>)
|
|
||||||
{
|
|
||||||
self.state_stack.push(IteratorState::Clause(lvl,
|
|
||||||
child_num,
|
|
||||||
cell,
|
|
||||||
name,
|
|
||||||
child_terms));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn push_root_clause(&mut self,
|
|
||||||
child_num: usize,
|
|
||||||
child_terms: &'a Vec<Box<Term>>)
|
|
||||||
{
|
|
||||||
self.state_stack.push(IteratorState::RootClause(child_num, child_terms));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
|
|
||||||
self.state_stack.push(IteratorState::to_state(lvl, term));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new(term: &'a Term) -> QueryIterator<'a> {
|
|
||||||
let state = match term {
|
|
||||||
&Term::Atom(ref cell, ref atom) =>
|
|
||||||
IteratorState::IsolatedAtom(cell, atom),
|
|
||||||
&Term::Clause(_, _, ref terms) =>
|
|
||||||
IteratorState::RootClause(0, terms),
|
|
||||||
&Term::Var(ref cell, ref var) =>
|
|
||||||
IteratorState::IsolatedVar(cell, var)
|
|
||||||
};
|
|
||||||
|
|
||||||
QueryIterator { state_stack: vec![state] }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for QueryIterator<'a> {
|
|
||||||
type Item = TermRef<'a>;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
while let Some(iter_state) = self.state_stack.pop() {
|
|
||||||
match iter_state {
|
|
||||||
IteratorState::Atom(lvl, cell, atom) =>
|
|
||||||
return Some(TermRef::Atom(lvl, cell, atom)),
|
|
||||||
IteratorState::Clause(lvl, child_num, cell, atom, child_terms) => {
|
|
||||||
if child_num == child_terms.len() {
|
|
||||||
return Some(TermRef::Clause(lvl, cell, atom, child_terms));
|
|
||||||
} else {
|
|
||||||
self.push_clause(lvl, child_num + 1, cell, atom, child_terms);
|
|
||||||
self.push_subterm(Level::Deep, child_terms[child_num].as_ref());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
IteratorState::IsolatedAtom(cell, atom) =>
|
|
||||||
return Some(TermRef::Atom(Level::Shallow, cell, atom)),
|
|
||||||
IteratorState::IsolatedVar(cell, var) =>
|
|
||||||
return Some(TermRef::Var(Level::Shallow, cell, var)),
|
|
||||||
IteratorState::RootClause(child_num, child_terms) => {
|
|
||||||
if child_num == child_terms.len() {
|
|
||||||
return None;
|
|
||||||
} else {
|
|
||||||
self.push_root_clause(child_num + 1, child_terms);
|
|
||||||
self.push_subterm(Level::Shallow, child_terms[child_num].as_ref());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
IteratorState::Var(lvl, cell, var) =>
|
|
||||||
return Some(TermRef::Var(lvl, cell, var))
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct FactIterator<'a> {
|
|
||||||
state_queue: VecDeque<IteratorState<'a>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> FactIterator<'a> {
|
|
||||||
fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
|
|
||||||
self.state_queue.push_back(IteratorState::to_state(lvl, term));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new(term: &'a Term) -> FactIterator<'a> {
|
|
||||||
let states = match term {
|
|
||||||
&Term::Atom(ref cell, ref atom) =>
|
|
||||||
vec![IteratorState::IsolatedAtom(cell, atom)],
|
|
||||||
&Term::Clause(_, _, ref terms) =>
|
|
||||||
vec![IteratorState::RootClause(0, terms)],
|
|
||||||
&Term::Var(ref cell, ref var) =>
|
|
||||||
vec![IteratorState::IsolatedVar(cell, var)]
|
|
||||||
};
|
|
||||||
|
|
||||||
FactIterator { state_queue: VecDeque::from(states) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for FactIterator<'a> {
|
|
||||||
type Item = TermRef<'a>;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
while let Some(state) = self.state_queue.pop_front() {
|
|
||||||
match state {
|
|
||||||
IteratorState::Atom(lvl, cell, atom) =>
|
|
||||||
return Some(TermRef::Atom(lvl, cell, atom)),
|
|
||||||
IteratorState::Clause(lvl, _, cell, atom, child_terms) => {
|
|
||||||
for child_term in child_terms {
|
|
||||||
self.push_subterm(Level::Deep, child_term);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Some(TermRef::Clause(lvl, cell, atom, child_terms));
|
|
||||||
},
|
|
||||||
IteratorState::IsolatedAtom(cell, atom) =>
|
|
||||||
return Some(TermRef::Atom(Level::Shallow, cell, atom)),
|
|
||||||
IteratorState::IsolatedVar(cell, var) =>
|
|
||||||
return Some(TermRef::Var(Level::Shallow, cell, var)),
|
|
||||||
IteratorState::RootClause(_, child_terms) => {
|
|
||||||
for child_term in child_terms {
|
|
||||||
self.push_subterm(Level::Shallow, child_term);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
IteratorState::Var(lvl, cell, var) =>
|
|
||||||
return Some(TermRef::Var(lvl, cell, var))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Term {
|
|
||||||
pub fn post_order_iter(&self) -> QueryIterator {
|
|
||||||
QueryIterator::new(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn breadth_first_iter(&self) -> FactIterator {
|
|
||||||
FactIterator::new(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
use l3::ast::*;
|
|
||||||
|
|
||||||
use std::cell::Cell;
|
|
||||||
|
|
||||||
grammar;
|
|
||||||
|
|
||||||
pub TopLevel: TopLevel = {
|
|
||||||
"?-" <t:Term> "." => TopLevel::Query(t),
|
|
||||||
<Predicate> => TopLevel::Predicate(<>),
|
|
||||||
<Rule> "." => TopLevel::Rule(<>),
|
|
||||||
<Term> "." => TopLevel::Fact(<>)
|
|
||||||
};
|
|
||||||
|
|
||||||
Atom : Atom = {
|
|
||||||
r"[a-z][a-z0-9_]*" => <>.trim().to_string(),
|
|
||||||
};
|
|
||||||
|
|
||||||
BoxedTerm : Box<Term> = {
|
|
||||||
<t:Term> => Box::new(t)
|
|
||||||
};
|
|
||||||
|
|
||||||
Clause : Term = {
|
|
||||||
<a:Atom> "(" <ts: (<BoxedTerm> ",")*> <t:BoxedTerm> ")" => {
|
|
||||||
let mut ts = ts;
|
|
||||||
ts.push(t);
|
|
||||||
Term::Clause(Cell::new(RegType::Temp(0)), a, ts)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Predicate : Vec<PredicateClause> = {
|
|
||||||
<pcs: (<PredicateClause>)+> <pc: PredicateClause> => {
|
|
||||||
let mut pcs = pcs;
|
|
||||||
pcs.push(pc);
|
|
||||||
pcs
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
PredicateClause : PredicateClause = {
|
|
||||||
<Rule> "." => PredicateClause::Rule(<>),
|
|
||||||
<Term> "." => PredicateClause::Fact(<>)
|
|
||||||
};
|
|
||||||
|
|
||||||
Rule : Rule = {
|
|
||||||
<c:Clause> ":-" <h:Term> <cs: ("," <Term>)*> =>
|
|
||||||
Rule { head: (c, h), clauses: cs },
|
|
||||||
<a:Atom> ":-" <h:Term> <cs: ("," <Term>)*> =>
|
|
||||||
Rule { head: (Term::Atom(Cell::new(RegType::Temp(0)), a), h),
|
|
||||||
clauses: cs }
|
|
||||||
};
|
|
||||||
|
|
||||||
Term : Term = {
|
|
||||||
<Clause> => <>,
|
|
||||||
<Atom> => Term::Atom(Cell::new(RegType::Temp(0)), <>),
|
|
||||||
<Var> => Term::Var(Cell::new(VarReg::Norm(RegType::Temp(0))), <>)
|
|
||||||
};
|
|
||||||
|
|
||||||
Var : Var = {
|
|
||||||
r"[A-Z][a-z0-9_]*" => <>.trim().to_string(),
|
|
||||||
};
|
|
||||||
2177
src/l3/l3_parser.rs
2177
src/l3/l3_parser.rs
File diff suppressed because it is too large
Load Diff
@@ -1,677 +0,0 @@
|
|||||||
use l3::ast::*;
|
|
||||||
use l3::codegen::*;
|
|
||||||
use l3::heapview::*;
|
|
||||||
use l3::and_stack::*;
|
|
||||||
use l3::or_stack::*;
|
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::ops::{Index, IndexMut};
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
enum MachineMode {
|
|
||||||
Read,
|
|
||||||
Write
|
|
||||||
}
|
|
||||||
|
|
||||||
struct MachineState {
|
|
||||||
h: usize,
|
|
||||||
s: usize,
|
|
||||||
p: CodePtr,
|
|
||||||
b: usize,
|
|
||||||
e: usize,
|
|
||||||
num_of_args: usize,
|
|
||||||
cp: CodePtr,
|
|
||||||
fail: bool,
|
|
||||||
heap: Heap,
|
|
||||||
mode: MachineMode,
|
|
||||||
and_stack: AndStack,
|
|
||||||
or_stack: OrStack,
|
|
||||||
registers: Registers,
|
|
||||||
trail: Vec<Ref>,
|
|
||||||
tr: usize,
|
|
||||||
hb: usize
|
|
||||||
}
|
|
||||||
|
|
||||||
type CodeDir = HashMap<(Atom, usize), usize>;
|
|
||||||
|
|
||||||
impl Index<RegType> for MachineState {
|
|
||||||
type Output = Addr;
|
|
||||||
|
|
||||||
fn index(&self, reg: RegType) -> &Self::Output {
|
|
||||||
match reg {
|
|
||||||
RegType::Temp(temp) => &self.registers[temp],
|
|
||||||
RegType::Perm(perm) => {
|
|
||||||
let e = self.e;
|
|
||||||
&self.and_stack[e][perm]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IndexMut<RegType> for MachineState {
|
|
||||||
fn index_mut(&mut self, reg: RegType) -> &mut Self::Output {
|
|
||||||
match reg {
|
|
||||||
RegType::Temp(temp) => &mut self.registers[temp],
|
|
||||||
RegType::Perm(perm) => {
|
|
||||||
let e = self.e;
|
|
||||||
&mut self.and_stack[e][perm]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Machine {
|
|
||||||
ms: MachineState,
|
|
||||||
code: Code,
|
|
||||||
code_dir: CodeDir
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Machine {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Machine {
|
|
||||||
ms: MachineState::new(),
|
|
||||||
code: Vec::new(),
|
|
||||||
code_dir: HashMap::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn failed(&self) -> bool {
|
|
||||||
self.ms.fail
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_fact(&mut self, fact: &Term, mut code: Code) {
|
|
||||||
let p = self.code.len();
|
|
||||||
let name = fact.name().clone();
|
|
||||||
let arity = fact.arity();
|
|
||||||
|
|
||||||
self.code.append(&mut code);
|
|
||||||
self.code_dir.insert((name, arity), p);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_rule(&mut self, rule: &Rule, mut code: Code) {
|
|
||||||
let p = self.code.len();
|
|
||||||
let name = rule.head.0.name().clone();
|
|
||||||
let arity = rule.head.0.arity();
|
|
||||||
|
|
||||||
self.code.append(&mut code);
|
|
||||||
self.code_dir.insert((name, arity), p);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_predicate(&mut self, pred: &Vec<PredicateClause>, mut code: Code)
|
|
||||||
{
|
|
||||||
let p = self.code.len();
|
|
||||||
let name = pred.first().unwrap().name().clone();
|
|
||||||
let arity = pred.first().unwrap().arity();
|
|
||||||
|
|
||||||
self.code.append(&mut code);
|
|
||||||
self.code_dir.insert((name, arity), p);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn execute_instr<'a>(&mut self, instr_src: LineOrCodeOffset<'a>) -> bool
|
|
||||||
{
|
|
||||||
let mut instr = match instr_src {
|
|
||||||
LineOrCodeOffset::Instruction(instr) => instr,
|
|
||||||
LineOrCodeOffset::Offset(p) => &self.code[p]
|
|
||||||
};
|
|
||||||
|
|
||||||
loop {
|
|
||||||
match instr {
|
|
||||||
&Line::Choice(ref choice_instr) =>
|
|
||||||
self.ms.execute_choice_instr(choice_instr),
|
|
||||||
&Line::Fact(ref fact) => {
|
|
||||||
for fact_instr in fact {
|
|
||||||
self.ms.execute_fact_instr(&fact_instr);
|
|
||||||
}
|
|
||||||
self.ms.p += 1;
|
|
||||||
},
|
|
||||||
&Line::Query(ref query) => {
|
|
||||||
for query_instr in query {
|
|
||||||
self.ms.execute_query_instr(&query_instr);
|
|
||||||
}
|
|
||||||
self.ms.p += 1;
|
|
||||||
},
|
|
||||||
&Line::Control(ref control_instr) =>
|
|
||||||
self.ms.execute_ctrl_instr(&self.code_dir, control_instr),
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.failed() {
|
|
||||||
let p = self.ms
|
|
||||||
.or_stack
|
|
||||||
.top()
|
|
||||||
.map(|fr| fr.bp)
|
|
||||||
.unwrap_or_default();
|
|
||||||
|
|
||||||
if let CodePtr::TopLevel = p {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
self.ms.fail = false;
|
|
||||||
self.ms.p = p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match self.ms.p {
|
|
||||||
CodePtr::DirEntry(p) if p < self.code.len() =>
|
|
||||||
instr = &self.code[p],
|
|
||||||
_ => break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn heap_view(&self, var_dir: &HeapVarDict) -> String {
|
|
||||||
let mut result = String::new();
|
|
||||||
|
|
||||||
for (var, addr) in var_dir {
|
|
||||||
let mut arities = Vec::new();
|
|
||||||
let viewer = HeapCellViewer::new(&self.ms.heap,
|
|
||||||
&self.ms.and_stack,
|
|
||||||
*addr);
|
|
||||||
|
|
||||||
if result != "" {
|
|
||||||
result += "\n\r";
|
|
||||||
}
|
|
||||||
|
|
||||||
result += var.as_str();
|
|
||||||
result += " = ";
|
|
||||||
|
|
||||||
for view in viewer {
|
|
||||||
match arities.pop() {
|
|
||||||
Some(n) => arities.push(n-1),
|
|
||||||
None => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !(arities.is_empty() || result.ends_with("(")) {
|
|
||||||
result += ", ";
|
|
||||||
}
|
|
||||||
|
|
||||||
match view {
|
|
||||||
HeapCellView::Str(arity, ref name) => {
|
|
||||||
result += name.as_str();
|
|
||||||
|
|
||||||
if arity > 0 {
|
|
||||||
arities.push(arity);
|
|
||||||
result += "(";
|
|
||||||
}
|
|
||||||
},
|
|
||||||
HeapCellView::HeapVar(cell_num) => {
|
|
||||||
result += "_";
|
|
||||||
result += cell_num.to_string().as_str();
|
|
||||||
},
|
|
||||||
HeapCellView::StackVar(fr, sc) => {
|
|
||||||
result += "_s_";
|
|
||||||
result += fr.to_string().as_str();
|
|
||||||
result += "_";
|
|
||||||
result += sc.to_string().as_str();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while let Some(&0) = arities.last() {
|
|
||||||
result += ")";
|
|
||||||
arities.pop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn run_query(&mut self, code: Code, cg: &CodeGenerator) -> EvalResult
|
|
||||||
{
|
|
||||||
let mut succeeded = true;
|
|
||||||
let mut heap_locs = HashMap::new();
|
|
||||||
|
|
||||||
for instr in code.iter().take(1) {
|
|
||||||
succeeded = self.execute_instr(LineOrCodeOffset::from(instr));
|
|
||||||
}
|
|
||||||
|
|
||||||
if succeeded {
|
|
||||||
for (var, vr) in cg.vars() {
|
|
||||||
let addr = self.ms.registers[vr.root_register()];
|
|
||||||
heap_locs.insert((*var).clone(), addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
for instr in code.iter().skip(1) {
|
|
||||||
succeeded = self.execute_instr(LineOrCodeOffset::from(instr));
|
|
||||||
if !succeeded {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if succeeded {
|
|
||||||
EvalResult::InitialQuerySuccess(heap_locs)
|
|
||||||
} else {
|
|
||||||
EvalResult::QueryFailure
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn or_stack_is_empty(&self) -> bool {
|
|
||||||
self.ms.or_stack.is_empty()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn continue_query(&mut self) -> EvalResult
|
|
||||||
{
|
|
||||||
if !self.or_stack_is_empty() {
|
|
||||||
let b = self.ms.b;
|
|
||||||
self.ms.p = self.ms.or_stack[b].bp;
|
|
||||||
|
|
||||||
let succeeded = if let CodePtr::DirEntry(p) = self.ms.p {
|
|
||||||
self.execute_instr(LineOrCodeOffset::Offset(p))
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
};
|
|
||||||
|
|
||||||
if succeeded {
|
|
||||||
EvalResult::SubsequentQuerySuccess
|
|
||||||
} else {
|
|
||||||
EvalResult::QueryFailure
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
EvalResult::QueryFailure
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reset(&mut self) {
|
|
||||||
self.ms.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MachineState {
|
|
||||||
fn new() -> MachineState {
|
|
||||||
MachineState { h: 0,
|
|
||||||
s: 0,
|
|
||||||
p: CodePtr::TopLevel,
|
|
||||||
b: 0,
|
|
||||||
e: 0,
|
|
||||||
num_of_args: 0,
|
|
||||||
cp: CodePtr::TopLevel,
|
|
||||||
fail: false,
|
|
||||||
heap: Vec::with_capacity(256),
|
|
||||||
mode: MachineMode::Write,
|
|
||||||
and_stack: AndStack::new(),
|
|
||||||
or_stack: OrStack::new(),
|
|
||||||
registers: vec![Addr::HeapCell(0); 32],
|
|
||||||
trail: Vec::new(),
|
|
||||||
tr: 0,
|
|
||||||
hb: 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn num_frames(&self) -> usize {
|
|
||||||
self.and_stack.len() + self.or_stack.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn store(&self, a: Addr) -> Addr {
|
|
||||||
match a {
|
|
||||||
Addr::HeapCell(r) => self.heap[r].as_addr(r),
|
|
||||||
Addr::StackCell(fr, sc) => self.and_stack[fr][sc],
|
|
||||||
addr => addr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deref(&self, a: Addr) -> Addr {
|
|
||||||
let mut a = a;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
let value = self.store(a);
|
|
||||||
|
|
||||||
if value.is_ref() && value != a {
|
|
||||||
a = value;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return a;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bind(&mut self, r1: Ref, a2: Addr) {
|
|
||||||
let t2 = self.store(a2);
|
|
||||||
|
|
||||||
match r1 {
|
|
||||||
Ref::StackCell(fr, sc) =>
|
|
||||||
self.and_stack[fr][sc] = t2,
|
|
||||||
Ref::HeapCell(hc) =>
|
|
||||||
self.heap[hc] = HeapCellValue::from(t2)
|
|
||||||
};
|
|
||||||
|
|
||||||
self.trail(r1);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unify(&mut self, a1: Addr, a2: Addr) {
|
|
||||||
let mut pdl = vec![a1, a2];
|
|
||||||
|
|
||||||
self.fail = false;
|
|
||||||
|
|
||||||
while !(pdl.is_empty() || self.fail) {
|
|
||||||
let d1 = self.deref(pdl.pop().unwrap());
|
|
||||||
let d2 = self.deref(pdl.pop().unwrap());
|
|
||||||
|
|
||||||
if d1 != d2 {
|
|
||||||
match (self.store(d1), self.store(d2)) {
|
|
||||||
(Addr::HeapCell(hc), _) =>
|
|
||||||
self.bind(Ref::HeapCell(hc), d2),
|
|
||||||
(_, Addr::HeapCell(hc)) =>
|
|
||||||
self.bind(Ref::HeapCell(hc), d1),
|
|
||||||
(Addr::StackCell(fr, sc), _) =>
|
|
||||||
self.bind(Ref::StackCell(fr, sc), d2),
|
|
||||||
(_, Addr::StackCell(fr, sc)) =>
|
|
||||||
self.bind(Ref::StackCell(fr, sc), d1),
|
|
||||||
(Addr::Str(a1), Addr::Str(a2)) => {
|
|
||||||
let r1 = &self.heap[a1];
|
|
||||||
let r2 = &self.heap[a2];
|
|
||||||
|
|
||||||
if let &HeapCellValue::NamedStr(n1, ref f1) = r1 {
|
|
||||||
if let &HeapCellValue::NamedStr(n2, ref f2) = r2 {
|
|
||||||
if n1 == n2 && *f1 == *f2 {
|
|
||||||
for i in 1 .. n1 + 1 {
|
|
||||||
pdl.push(Addr::HeapCell(a1 + i));
|
|
||||||
pdl.push(Addr::HeapCell(a2 + i));
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.fail = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn trail(&mut self, r: Ref) {
|
|
||||||
match r {
|
|
||||||
Ref::HeapCell(hc) => {
|
|
||||||
if hc < self.hb {
|
|
||||||
self.trail.push(r);
|
|
||||||
self.tr += 1;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Ref::StackCell(fr, _) => {
|
|
||||||
let fr_gi = self.and_stack[fr].global_index;
|
|
||||||
let b_gi = if !self.or_stack.is_empty() {
|
|
||||||
self.or_stack[self.b].global_index
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
if fr_gi < b_gi {
|
|
||||||
self.trail.push(r);
|
|
||||||
self.tr += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unwind_trail(&mut self, a1: usize, a2: usize) {
|
|
||||||
for i in a1 .. a2 {
|
|
||||||
match self.trail[i] {
|
|
||||||
Ref::HeapCell(r) =>
|
|
||||||
self.heap[r] = HeapCellValue::Ref(self.trail[i]),
|
|
||||||
Ref::StackCell(fr, sc) =>
|
|
||||||
self.and_stack[fr][sc] = Addr::StackCell(fr, sc)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn execute_query_instr(&mut self, instr: &QueryInstruction) {
|
|
||||||
match instr {
|
|
||||||
&QueryInstruction::PutStructure(_, ref name, arity, reg) => {
|
|
||||||
self.heap.push(HeapCellValue::Str(self.h + 1));
|
|
||||||
self.heap.push(HeapCellValue::NamedStr(arity, name.clone()));
|
|
||||||
|
|
||||||
self[reg] = Addr::Str(self.h + 1);
|
|
||||||
|
|
||||||
self.h += 2;
|
|
||||||
},
|
|
||||||
&QueryInstruction::PutValue(norm, arg) =>
|
|
||||||
self.registers[arg] = self[norm],
|
|
||||||
&QueryInstruction::PutVariable(norm, arg) => {
|
|
||||||
self.heap.push(HeapCellValue::Ref(Ref::HeapCell(self.h)));
|
|
||||||
|
|
||||||
self[norm] = Addr::HeapCell(self.h);
|
|
||||||
self.registers[arg] = Addr::HeapCell(self.h);
|
|
||||||
|
|
||||||
self.h += 1;
|
|
||||||
},
|
|
||||||
&QueryInstruction::SetVariable(reg) => {
|
|
||||||
self.heap.push(HeapCellValue::Ref(Ref::HeapCell(self.h)));
|
|
||||||
self[reg] = Addr::HeapCell(self.h);
|
|
||||||
|
|
||||||
self.h += 1;
|
|
||||||
},
|
|
||||||
&QueryInstruction::SetValue(reg) => {
|
|
||||||
let heap_val = self[reg];
|
|
||||||
self.heap.push(HeapCellValue::from(heap_val));
|
|
||||||
|
|
||||||
self.h += 1;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn execute_fact_instr(&mut self, instr: &FactInstruction) {
|
|
||||||
match instr {
|
|
||||||
&FactInstruction::GetStructure(_, ref name, arity, reg) => {
|
|
||||||
let addr = self.deref(self[reg]);
|
|
||||||
|
|
||||||
match self.store(addr) {
|
|
||||||
Addr::Str(a) => {
|
|
||||||
let result = &self.heap[a];
|
|
||||||
|
|
||||||
if let &HeapCellValue::NamedStr(narity, ref str) = result {
|
|
||||||
if narity == arity && *name == *str {
|
|
||||||
self.s = a + 1;
|
|
||||||
self.mode = MachineMode::Read;
|
|
||||||
} else {
|
|
||||||
self.fail = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Addr::HeapCell(_) | Addr::StackCell(_, _) => {
|
|
||||||
self.heap.push(HeapCellValue::Str(self.h + 1));
|
|
||||||
self.heap.push(HeapCellValue::NamedStr(arity, name.clone()));
|
|
||||||
|
|
||||||
let h = self.h;
|
|
||||||
|
|
||||||
self.bind(addr.as_ref().unwrap(), Addr::HeapCell(h));
|
|
||||||
|
|
||||||
self.h += 2;
|
|
||||||
self.mode = MachineMode::Write;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
},
|
|
||||||
&FactInstruction::GetVariable(norm, arg) =>
|
|
||||||
self[norm] = self.registers[arg],
|
|
||||||
&FactInstruction::GetValue(norm, arg) => {
|
|
||||||
let norm_addr = self[norm];
|
|
||||||
let reg_addr = self.registers[arg];
|
|
||||||
|
|
||||||
self.unify(norm_addr, reg_addr);
|
|
||||||
},
|
|
||||||
&FactInstruction::UnifyVariable(reg) => {
|
|
||||||
match self.mode {
|
|
||||||
MachineMode::Read =>
|
|
||||||
self[reg] = self.heap[self.s].as_addr(self.s),
|
|
||||||
MachineMode::Write => {
|
|
||||||
self.heap.push(HeapCellValue::Ref(Ref::HeapCell(self.h)));
|
|
||||||
self[reg] = Addr::HeapCell(self.h);
|
|
||||||
self.h += 1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.s += 1;
|
|
||||||
},
|
|
||||||
&FactInstruction::UnifyValue(reg) => {
|
|
||||||
let s = self.s;
|
|
||||||
|
|
||||||
match self.mode {
|
|
||||||
MachineMode::Read => {
|
|
||||||
let reg_addr = self[reg];
|
|
||||||
self.unify(reg_addr, Addr::HeapCell(s));
|
|
||||||
},
|
|
||||||
MachineMode::Write => {
|
|
||||||
let heap_val = self.store(self[reg]);
|
|
||||||
self.heap.push(HeapCellValue::from(heap_val));
|
|
||||||
self.h += 1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.s += 1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn execute_ctrl_instr(&mut self, code_dir: &CodeDir, instr: &ControlInstruction)
|
|
||||||
{
|
|
||||||
match instr {
|
|
||||||
&ControlInstruction::Allocate(num_cells) => {
|
|
||||||
let num_frames = self.num_frames();
|
|
||||||
|
|
||||||
self.and_stack.push(num_frames + 1, self.e, self.cp, num_cells);
|
|
||||||
|
|
||||||
self.e = self.and_stack.len() - 1;
|
|
||||||
self.p += 1;
|
|
||||||
},
|
|
||||||
&ControlInstruction::Call(ref name, arity) => {
|
|
||||||
let compiled_tl_index = code_dir.get(&(name.clone(), arity))
|
|
||||||
.map(|index| *index);
|
|
||||||
|
|
||||||
match compiled_tl_index {
|
|
||||||
Some(compiled_tl_index) => {
|
|
||||||
self.cp = self.p + 1;
|
|
||||||
self.num_of_args = arity;
|
|
||||||
self.p = CodePtr::DirEntry(compiled_tl_index);
|
|
||||||
},
|
|
||||||
None => self.fail = true
|
|
||||||
};
|
|
||||||
},
|
|
||||||
&ControlInstruction::Deallocate => {
|
|
||||||
let e = self.e;
|
|
||||||
|
|
||||||
let num_frame_e = self.and_stack.top().unwrap().global_index;
|
|
||||||
let num_frame_b = self.or_stack
|
|
||||||
.top()
|
|
||||||
.map(|fr| fr.global_index)
|
|
||||||
.unwrap_or(0);
|
|
||||||
|
|
||||||
self.p = self.and_stack[e].cp;
|
|
||||||
self.e = self.and_stack[e].e;
|
|
||||||
|
|
||||||
if num_frame_e > num_frame_b {
|
|
||||||
let top_e = self.and_stack.top().unwrap().e;
|
|
||||||
self.and_stack.drop_frames(top_e - self.e + 1);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
&ControlInstruction::Proceed =>
|
|
||||||
self.p = self.cp,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn execute_choice_instr(&mut self, instr: &ChoiceInstruction)
|
|
||||||
{
|
|
||||||
match instr {
|
|
||||||
&ChoiceInstruction::TryMeElse(offset) => {
|
|
||||||
let n = self.num_of_args;
|
|
||||||
let num_frames = self.num_frames();
|
|
||||||
|
|
||||||
self.or_stack.push(num_frames + 1,
|
|
||||||
self.e,
|
|
||||||
self.cp,
|
|
||||||
self.b,
|
|
||||||
self.p + offset,
|
|
||||||
self.tr,
|
|
||||||
self.h,
|
|
||||||
self.num_of_args);
|
|
||||||
|
|
||||||
self.b = self.or_stack.len() - 1;
|
|
||||||
let b = self.b;
|
|
||||||
|
|
||||||
for i in 1 .. n + 1 {
|
|
||||||
self.or_stack[b][i] = self.registers[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
self.hb = self.h;
|
|
||||||
self.p += 1;
|
|
||||||
},
|
|
||||||
&ChoiceInstruction::RetryMeElse(offset) => {
|
|
||||||
let b = self.b;
|
|
||||||
let n = self.or_stack[b].num_args();
|
|
||||||
|
|
||||||
for i in 1 .. n + 1 {
|
|
||||||
self.registers[i] = self.or_stack[b][i];
|
|
||||||
}
|
|
||||||
|
|
||||||
self.e = self.or_stack[b].e;
|
|
||||||
self.cp = self.or_stack[b].cp;
|
|
||||||
|
|
||||||
self.or_stack[b].bp = self.p + offset;
|
|
||||||
|
|
||||||
let old_tr = self.or_stack[b].tr;
|
|
||||||
let curr_tr = self.tr;
|
|
||||||
|
|
||||||
self.unwind_trail(old_tr, curr_tr);
|
|
||||||
self.tr = self.or_stack[b].tr;
|
|
||||||
|
|
||||||
self.trail.truncate(self.tr);
|
|
||||||
self.heap.truncate(self.or_stack[b].h);
|
|
||||||
|
|
||||||
self.h = self.or_stack[b].h;
|
|
||||||
self.hb = self.h;
|
|
||||||
|
|
||||||
self.p += 1;
|
|
||||||
},
|
|
||||||
&ChoiceInstruction::TrustMe => {
|
|
||||||
let b = self.b;
|
|
||||||
let n = self.or_stack[b].num_args();
|
|
||||||
|
|
||||||
for i in 1 .. n + 1 {
|
|
||||||
self.registers[i] = self.or_stack[b][i];
|
|
||||||
}
|
|
||||||
|
|
||||||
self.e = self.or_stack[b].e;
|
|
||||||
self.cp = self.or_stack[b].cp;
|
|
||||||
|
|
||||||
let old_tr = self.or_stack[b].tr;
|
|
||||||
let curr_tr = self.tr;
|
|
||||||
|
|
||||||
self.unwind_trail(old_tr, curr_tr);
|
|
||||||
|
|
||||||
self.tr = self.or_stack[b].tr;
|
|
||||||
self.trail.truncate(self.tr);
|
|
||||||
|
|
||||||
self.h = self.or_stack[b].h;
|
|
||||||
self.heap.truncate(self.h);
|
|
||||||
|
|
||||||
self.b = self.or_stack[b].b;
|
|
||||||
|
|
||||||
self.or_stack.pop();
|
|
||||||
|
|
||||||
self.hb = self.h;
|
|
||||||
self.p += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reset(&mut self) {
|
|
||||||
self.h = 0;
|
|
||||||
self.hb = 0;
|
|
||||||
self.e = 0;
|
|
||||||
self.b = 0;
|
|
||||||
self.s = 0;
|
|
||||||
self.tr = 0;
|
|
||||||
self.p = CodePtr::TopLevel;
|
|
||||||
self.cp = CodePtr::TopLevel;
|
|
||||||
self.num_of_args = 0;
|
|
||||||
|
|
||||||
self.fail = false;
|
|
||||||
self.trail.clear();
|
|
||||||
self.heap.clear();
|
|
||||||
self.mode = MachineMode::Write;
|
|
||||||
self.and_stack.clear();
|
|
||||||
self.or_stack.clear();
|
|
||||||
self.registers = vec![Addr::HeapCell(0); 32];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
pub mod and_stack;
|
|
||||||
pub mod ast;
|
|
||||||
pub mod codegen;
|
|
||||||
pub mod heapview;
|
|
||||||
pub mod io;
|
|
||||||
pub mod iterators;
|
|
||||||
pub mod l3_parser;
|
|
||||||
pub mod machine;
|
|
||||||
pub mod or_stack;
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
use l3::ast::*;
|
|
||||||
|
|
||||||
use std::ops::{Index, IndexMut};
|
|
||||||
use std::vec::Vec;
|
|
||||||
|
|
||||||
pub struct Frame {
|
|
||||||
pub global_index: usize,
|
|
||||||
pub e: usize,
|
|
||||||
pub cp: CodePtr,
|
|
||||||
pub b: usize,
|
|
||||||
pub bp: CodePtr,
|
|
||||||
pub tr: usize,
|
|
||||||
pub h: usize,
|
|
||||||
args: Vec<Addr>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Frame {
|
|
||||||
fn new(global_index: usize,
|
|
||||||
e: usize,
|
|
||||||
cp: CodePtr,
|
|
||||||
b: usize,
|
|
||||||
bp: CodePtr,
|
|
||||||
tr: usize,
|
|
||||||
h: usize,
|
|
||||||
n: usize)
|
|
||||||
-> Self
|
|
||||||
{
|
|
||||||
Frame {
|
|
||||||
global_index: global_index,
|
|
||||||
e: e,
|
|
||||||
cp: cp,
|
|
||||||
b: b,
|
|
||||||
bp: bp,
|
|
||||||
tr: tr,
|
|
||||||
h: h,
|
|
||||||
args: vec![Addr::HeapCell(0); n]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn num_args(&self) -> usize {
|
|
||||||
self.args.len()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct OrStack(Vec<Frame>);
|
|
||||||
|
|
||||||
impl OrStack {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
OrStack(Vec::new())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push(&mut self,
|
|
||||||
global_index: usize,
|
|
||||||
e: usize,
|
|
||||||
cp: CodePtr,
|
|
||||||
b: usize,
|
|
||||||
bp: CodePtr,
|
|
||||||
tr: usize,
|
|
||||||
h: usize,
|
|
||||||
n: usize)
|
|
||||||
{
|
|
||||||
self.0.push(Frame::new(global_index, e, cp, b, bp, tr, h, n));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
|
||||||
self.0.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clear(&mut self) {
|
|
||||||
self.0.clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn top(&self) -> Option<&Frame> {
|
|
||||||
self.0.last()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pop(&mut self) {
|
|
||||||
self.0.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_empty(&self) -> bool {
|
|
||||||
self.0.is_empty()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Index<usize> for OrStack {
|
|
||||||
type Output = Frame;
|
|
||||||
|
|
||||||
fn index(&self, index: usize) -> &Self::Output {
|
|
||||||
self.0.index(index)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IndexMut<usize> for OrStack {
|
|
||||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
|
||||||
self.0.index_mut(index)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Index<usize> for Frame {
|
|
||||||
type Output = Addr;
|
|
||||||
|
|
||||||
fn index(&self, index: usize) -> &Self::Output {
|
|
||||||
self.args.index(index - 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IndexMut<usize> for Frame {
|
|
||||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
|
||||||
self.args.index_mut(index - 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -163,7 +163,9 @@ pub enum SystemClauseType {
|
|||||||
AtomChars,
|
AtomChars,
|
||||||
AtomCodes,
|
AtomCodes,
|
||||||
AtomLength,
|
AtomLength,
|
||||||
|
BindFromRegister,
|
||||||
CallAttributeGoals,
|
CallAttributeGoals,
|
||||||
|
CallContinuation,
|
||||||
CharCode,
|
CharCode,
|
||||||
CharsToNumber,
|
CharsToNumber,
|
||||||
ClearAttrVarBindings,
|
ClearAttrVarBindings,
|
||||||
@@ -192,6 +194,7 @@ pub enum SystemClauseType {
|
|||||||
GetAttrVarQueueBeyond,
|
GetAttrVarQueueBeyond,
|
||||||
GetBValue,
|
GetBValue,
|
||||||
GetClause,
|
GetClause,
|
||||||
|
GetContinuationChunk,
|
||||||
GetModuleClause,
|
GetModuleClause,
|
||||||
GetNextDBRef,
|
GetNextDBRef,
|
||||||
GetNextOpDBRef,
|
GetNextOpDBRef,
|
||||||
@@ -211,16 +214,19 @@ pub enum SystemClauseType {
|
|||||||
ModuleExists,
|
ModuleExists,
|
||||||
ModuleOf,
|
ModuleOf,
|
||||||
ModuleRetractClause,
|
ModuleRetractClause,
|
||||||
|
NextEP,
|
||||||
NoSuchPredicate,
|
NoSuchPredicate,
|
||||||
NumberToChars,
|
NumberToChars,
|
||||||
NumberToCodes,
|
NumberToCodes,
|
||||||
OpDeclaration,
|
OpDeclaration,
|
||||||
|
PointsToContinuationResetMarker,
|
||||||
REPL(REPLCodePtr),
|
REPL(REPLCodePtr),
|
||||||
ReadQueryTerm,
|
ReadQueryTerm,
|
||||||
ReadTerm,
|
ReadTerm,
|
||||||
RedoAttrVarBinding,
|
RedoAttrVarBinding,
|
||||||
RemoveCallPolicyCheck,
|
RemoveCallPolicyCheck,
|
||||||
RemoveInferenceCounter,
|
RemoveInferenceCounter,
|
||||||
|
ResetContinuationMarker,
|
||||||
ResetGlobalVarAtKey,
|
ResetGlobalVarAtKey,
|
||||||
ResetGlobalVarAtOffset,
|
ResetGlobalVarAtOffset,
|
||||||
RetractClause,
|
RetractClause,
|
||||||
@@ -250,6 +256,7 @@ pub enum SystemClauseType {
|
|||||||
TermVariables,
|
TermVariables,
|
||||||
TruncateLiftedHeapTo,
|
TruncateLiftedHeapTo,
|
||||||
UnifyWithOccursCheck,
|
UnifyWithOccursCheck,
|
||||||
|
UnwindEnvironments,
|
||||||
UnwindStack,
|
UnwindStack,
|
||||||
Variant,
|
Variant,
|
||||||
WAMInstructions,
|
WAMInstructions,
|
||||||
@@ -267,7 +274,9 @@ impl SystemClauseType {
|
|||||||
&SystemClauseType::AtomChars => clause_name!("$atom_chars"),
|
&SystemClauseType::AtomChars => clause_name!("$atom_chars"),
|
||||||
&SystemClauseType::AtomCodes => clause_name!("$atom_codes"),
|
&SystemClauseType::AtomCodes => clause_name!("$atom_codes"),
|
||||||
&SystemClauseType::AtomLength => clause_name!("$atom_length"),
|
&SystemClauseType::AtomLength => clause_name!("$atom_length"),
|
||||||
|
&SystemClauseType::BindFromRegister => clause_name!("$bind_from_register"),
|
||||||
&SystemClauseType::CallAttributeGoals => clause_name!("$call_attribute_goals"),
|
&SystemClauseType::CallAttributeGoals => clause_name!("$call_attribute_goals"),
|
||||||
|
&SystemClauseType::CallContinuation => clause_name!("$call_continuation"),
|
||||||
&SystemClauseType::CharCode => clause_name!("$char_code"),
|
&SystemClauseType::CharCode => clause_name!("$char_code"),
|
||||||
&SystemClauseType::CharsToNumber => clause_name!("$chars_to_number"),
|
&SystemClauseType::CharsToNumber => clause_name!("$chars_to_number"),
|
||||||
&SystemClauseType::ClearAttributeGoals => clause_name!("$clear_attribute_goals"),
|
&SystemClauseType::ClearAttributeGoals => clause_name!("$clear_attribute_goals"),
|
||||||
@@ -313,6 +322,7 @@ impl SystemClauseType {
|
|||||||
clause_name!("$get_attr_var_queue_delim")
|
clause_name!("$get_attr_var_queue_delim")
|
||||||
}
|
}
|
||||||
&SystemClauseType::GetAttrVarQueueBeyond => clause_name!("$get_attr_var_queue_beyond"),
|
&SystemClauseType::GetAttrVarQueueBeyond => clause_name!("$get_attr_var_queue_beyond"),
|
||||||
|
&SystemClauseType::GetContinuationChunk => clause_name!("$get_cont_chunk"),
|
||||||
&SystemClauseType::GetLiftedHeapFromOffset => clause_name!("$get_lh_from_offset"),
|
&SystemClauseType::GetLiftedHeapFromOffset => clause_name!("$get_lh_from_offset"),
|
||||||
&SystemClauseType::GetLiftedHeapFromOffsetDiff => {
|
&SystemClauseType::GetLiftedHeapFromOffsetDiff => {
|
||||||
clause_name!("$get_lh_from_offset_diff")
|
clause_name!("$get_lh_from_offset_diff")
|
||||||
@@ -347,6 +357,9 @@ impl SystemClauseType {
|
|||||||
&SystemClauseType::NoSuchPredicate => clause_name!("$no_such_predicate"),
|
&SystemClauseType::NoSuchPredicate => clause_name!("$no_such_predicate"),
|
||||||
&SystemClauseType::NumberToChars => clause_name!("$number_to_chars"),
|
&SystemClauseType::NumberToChars => clause_name!("$number_to_chars"),
|
||||||
&SystemClauseType::NumberToCodes => clause_name!("$number_to_codes"),
|
&SystemClauseType::NumberToCodes => clause_name!("$number_to_codes"),
|
||||||
|
&SystemClauseType::PointsToContinuationResetMarker => {
|
||||||
|
clause_name!("$points_to_cont_reset_marker")
|
||||||
|
}
|
||||||
&SystemClauseType::RawInputReadChar => clause_name!("$raw_input_read_char"),
|
&SystemClauseType::RawInputReadChar => clause_name!("$raw_input_read_char"),
|
||||||
&SystemClauseType::RedoAttrVarBinding => clause_name!("$redo_attr_var_binding"),
|
&SystemClauseType::RedoAttrVarBinding => clause_name!("$redo_attr_var_binding"),
|
||||||
&SystemClauseType::RemoveCallPolicyCheck => clause_name!("$remove_call_policy_check"),
|
&SystemClauseType::RemoveCallPolicyCheck => clause_name!("$remove_call_policy_check"),
|
||||||
@@ -367,12 +380,14 @@ impl SystemClauseType {
|
|||||||
&SystemClauseType::GetCurrentBlock => clause_name!("$get_current_block"),
|
&SystemClauseType::GetCurrentBlock => clause_name!("$get_current_block"),
|
||||||
&SystemClauseType::InstallNewBlock => clause_name!("$install_new_block"),
|
&SystemClauseType::InstallNewBlock => clause_name!("$install_new_block"),
|
||||||
&SystemClauseType::ModuleRetractClause => clause_name!("$module_retract_clause"),
|
&SystemClauseType::ModuleRetractClause => clause_name!("$module_retract_clause"),
|
||||||
|
&SystemClauseType::NextEP => clause_name!("$nextEP"),
|
||||||
&SystemClauseType::ReadQueryTerm => clause_name!("$read_query_term"),
|
&SystemClauseType::ReadQueryTerm => clause_name!("$read_query_term"),
|
||||||
&SystemClauseType::ReadTerm => clause_name!("$read_term"),
|
&SystemClauseType::ReadTerm => clause_name!("$read_term"),
|
||||||
&SystemClauseType::ResetGlobalVarAtKey => clause_name!("$reset_global_var_at_key"),
|
&SystemClauseType::ResetGlobalVarAtKey => clause_name!("$reset_global_var_at_key"),
|
||||||
&SystemClauseType::ResetGlobalVarAtOffset => clause_name!("$reset_global_var_at_offset"),
|
&SystemClauseType::ResetGlobalVarAtOffset => clause_name!("$reset_global_var_at_offset"),
|
||||||
&SystemClauseType::RetractClause => clause_name!("$retract_clause"),
|
&SystemClauseType::RetractClause => clause_name!("$retract_clause"),
|
||||||
&SystemClauseType::ResetBlock => clause_name!("$reset_block"),
|
&SystemClauseType::ResetBlock => clause_name!("$reset_block"),
|
||||||
|
&SystemClauseType::ResetContinuationMarker => clause_name!("$reset_cont_marker"),
|
||||||
&SystemClauseType::ReturnFromVerifyAttr => clause_name!("$return_from_verify_attr"),
|
&SystemClauseType::ReturnFromVerifyAttr => clause_name!("$return_from_verify_attr"),
|
||||||
&SystemClauseType::SetBall => clause_name!("$set_ball"),
|
&SystemClauseType::SetBall => clause_name!("$set_ball"),
|
||||||
&SystemClauseType::SetCutPointByDefault(_) => clause_name!("$set_cp_by_default"),
|
&SystemClauseType::SetCutPointByDefault(_) => clause_name!("$set_cp_by_default"),
|
||||||
@@ -382,6 +397,7 @@ impl SystemClauseType {
|
|||||||
&SystemClauseType::TermVariables => clause_name!("$term_variables"),
|
&SystemClauseType::TermVariables => clause_name!("$term_variables"),
|
||||||
&SystemClauseType::TruncateLiftedHeapTo => clause_name!("$truncate_lh_to"),
|
&SystemClauseType::TruncateLiftedHeapTo => clause_name!("$truncate_lh_to"),
|
||||||
&SystemClauseType::UnifyWithOccursCheck => clause_name!("$unify_with_occurs_check"),
|
&SystemClauseType::UnifyWithOccursCheck => clause_name!("$unify_with_occurs_check"),
|
||||||
|
&SystemClauseType::UnwindEnvironments => clause_name!("$unwind_environments"),
|
||||||
&SystemClauseType::UnwindStack => clause_name!("$unwind_stack"),
|
&SystemClauseType::UnwindStack => clause_name!("$unwind_stack"),
|
||||||
&SystemClauseType::Variant => clause_name!("$variant"),
|
&SystemClauseType::Variant => clause_name!("$variant"),
|
||||||
&SystemClauseType::WAMInstructions => clause_name!("$wam_instructions"),
|
&SystemClauseType::WAMInstructions => clause_name!("$wam_instructions"),
|
||||||
@@ -397,11 +413,13 @@ impl SystemClauseType {
|
|||||||
("$atom_codes", 2) => Some(SystemClauseType::AtomCodes),
|
("$atom_codes", 2) => Some(SystemClauseType::AtomCodes),
|
||||||
("$atom_length", 2) => Some(SystemClauseType::AtomLength),
|
("$atom_length", 2) => Some(SystemClauseType::AtomLength),
|
||||||
("$abolish_module_clause", 3) => Some(SystemClauseType::AbolishModuleClause),
|
("$abolish_module_clause", 3) => Some(SystemClauseType::AbolishModuleClause),
|
||||||
|
("$bind_from_register", 2) => Some(SystemClauseType::BindFromRegister),
|
||||||
("$module_asserta", 5) => Some(SystemClauseType::ModuleAssertDynamicPredicateToFront),
|
("$module_asserta", 5) => Some(SystemClauseType::ModuleAssertDynamicPredicateToFront),
|
||||||
("$module_assertz", 5) => Some(SystemClauseType::ModuleAssertDynamicPredicateToBack),
|
("$module_assertz", 5) => Some(SystemClauseType::ModuleAssertDynamicPredicateToBack),
|
||||||
("$asserta", 4) => Some(SystemClauseType::AssertDynamicPredicateToFront),
|
("$asserta", 4) => Some(SystemClauseType::AssertDynamicPredicateToFront),
|
||||||
("$assertz", 4) => Some(SystemClauseType::AssertDynamicPredicateToBack),
|
("$assertz", 4) => Some(SystemClauseType::AssertDynamicPredicateToBack),
|
||||||
("$call_attribute_goals", 2) => Some(SystemClauseType::CallAttributeGoals),
|
("$call_attribute_goals", 2) => Some(SystemClauseType::CallAttributeGoals),
|
||||||
|
("$call_continuation", 1) => Some(SystemClauseType::CallContinuation),
|
||||||
("$char_code", 2) => Some(SystemClauseType::CharCode),
|
("$char_code", 2) => Some(SystemClauseType::CharCode),
|
||||||
("$chars_to_number", 2) => Some(SystemClauseType::CharsToNumber),
|
("$chars_to_number", 2) => Some(SystemClauseType::CharsToNumber),
|
||||||
("$clear_attr_var_bindings", 0) => Some(SystemClauseType::ClearAttrVarBindings),
|
("$clear_attr_var_bindings", 0) => Some(SystemClauseType::ClearAttrVarBindings),
|
||||||
@@ -427,6 +445,9 @@ impl SystemClauseType {
|
|||||||
("$fetch_global_var", 2) => Some(SystemClauseType::FetchGlobalVar),
|
("$fetch_global_var", 2) => Some(SystemClauseType::FetchGlobalVar),
|
||||||
("$fetch_global_var_with_offset", 3) => Some(SystemClauseType::FetchGlobalVarWithOffset),
|
("$fetch_global_var_with_offset", 3) => Some(SystemClauseType::FetchGlobalVarWithOffset),
|
||||||
("$get_char", 1) => Some(SystemClauseType::GetChar),
|
("$get_char", 1) => Some(SystemClauseType::GetChar),
|
||||||
|
("$points_to_cont_reset_marker", 1) => {
|
||||||
|
Some(SystemClauseType::PointsToContinuationResetMarker)
|
||||||
|
}
|
||||||
("$reset_attr_var_state", 0) => Some(SystemClauseType::ResetAttrVarState),
|
("$reset_attr_var_state", 0) => Some(SystemClauseType::ResetAttrVarState),
|
||||||
("$truncate_if_no_lh_growth", 1) => {
|
("$truncate_if_no_lh_growth", 1) => {
|
||||||
Some(SystemClauseType::TruncateIfNoLiftedHeapGrowth)
|
Some(SystemClauseType::TruncateIfNoLiftedHeapGrowth)
|
||||||
@@ -468,13 +489,16 @@ impl SystemClauseType {
|
|||||||
("$get_attr_var_queue_beyond", 2) => Some(SystemClauseType::GetAttrVarQueueBeyond),
|
("$get_attr_var_queue_beyond", 2) => Some(SystemClauseType::GetAttrVarQueueBeyond),
|
||||||
("$get_attr_var_queue_delim", 1) => Some(SystemClauseType::GetAttrVarQueueDelimiter),
|
("$get_attr_var_queue_delim", 1) => Some(SystemClauseType::GetAttrVarQueueDelimiter),
|
||||||
("$get_ball", 1) => Some(SystemClauseType::GetBall),
|
("$get_ball", 1) => Some(SystemClauseType::GetBall),
|
||||||
|
("$get_cont_chunk", 3) => Some(SystemClauseType::GetContinuationChunk),
|
||||||
("$get_current_block", 1) => Some(SystemClauseType::GetCurrentBlock),
|
("$get_current_block", 1) => Some(SystemClauseType::GetCurrentBlock),
|
||||||
("$get_cp", 1) => Some(SystemClauseType::GetCutPoint),
|
("$get_cp", 1) => Some(SystemClauseType::GetCutPoint),
|
||||||
("$install_new_block", 1) => Some(SystemClauseType::InstallNewBlock),
|
("$install_new_block", 1) => Some(SystemClauseType::InstallNewBlock),
|
||||||
("$raw_input_read_char", 1) => Some(SystemClauseType::RawInputReadChar),
|
("$raw_input_read_char", 1) => Some(SystemClauseType::RawInputReadChar),
|
||||||
|
("$nextEP", 3) => Some(SystemClauseType::NextEP),
|
||||||
("$read_query_term", 2) => Some(SystemClauseType::ReadQueryTerm),
|
("$read_query_term", 2) => Some(SystemClauseType::ReadQueryTerm),
|
||||||
("$read_term", 2) => Some(SystemClauseType::ReadTerm),
|
("$read_term", 2) => Some(SystemClauseType::ReadTerm),
|
||||||
("$reset_block", 1) => Some(SystemClauseType::ResetBlock),
|
("$reset_block", 1) => Some(SystemClauseType::ResetBlock),
|
||||||
|
("$reset_cont_marker", 0) => Some(SystemClauseType::ResetContinuationMarker),
|
||||||
("$reset_global_var_at_key", 1) => Some(SystemClauseType::ResetGlobalVarAtKey),
|
("$reset_global_var_at_key", 1) => Some(SystemClauseType::ResetGlobalVarAtKey),
|
||||||
("$reset_global_var_at_offset", 3) => Some(SystemClauseType::ResetGlobalVarAtOffset),
|
("$reset_global_var_at_offset", 3) => Some(SystemClauseType::ResetGlobalVarAtOffset),
|
||||||
("$retract_clause", 4) => Some(SystemClauseType::RetractClause),
|
("$retract_clause", 4) => Some(SystemClauseType::RetractClause),
|
||||||
@@ -488,6 +512,7 @@ impl SystemClauseType {
|
|||||||
("$store_global_var_with_offset", 2) => Some(SystemClauseType::StoreGlobalVarWithOffset),
|
("$store_global_var_with_offset", 2) => Some(SystemClauseType::StoreGlobalVarWithOffset),
|
||||||
("$term_variables", 2) => Some(SystemClauseType::TermVariables),
|
("$term_variables", 2) => Some(SystemClauseType::TermVariables),
|
||||||
("$truncate_lh_to", 1) => Some(SystemClauseType::TruncateLiftedHeapTo),
|
("$truncate_lh_to", 1) => Some(SystemClauseType::TruncateLiftedHeapTo),
|
||||||
|
("$unwind_environments", 0) => Some(SystemClauseType::UnwindEnvironments),
|
||||||
("$unwind_stack", 0) => Some(SystemClauseType::UnwindStack),
|
("$unwind_stack", 0) => Some(SystemClauseType::UnwindStack),
|
||||||
("$unify_with_occurs_check", 2) => Some(SystemClauseType::UnifyWithOccursCheck),
|
("$unify_with_occurs_check", 2) => Some(SystemClauseType::UnifyWithOccursCheck),
|
||||||
("$use_module", 1) => Some(SystemClauseType::REPL(REPLCodePtr::UseModule)),
|
("$use_module", 1) => Some(SystemClauseType::REPL(REPLCodePtr::UseModule)),
|
||||||
|
|||||||
@@ -809,6 +809,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
Constant::CharCode(c) => self.append_str(&format!("{}", c)),
|
Constant::CharCode(c) => self.append_str(&format!("{}", c)),
|
||||||
|
Constant::CutPoint(b) => self.append_str(&format!("{}", b)),
|
||||||
Constant::EmptyList => self.append_str("[]"),
|
Constant::EmptyList => self.append_str("[]"),
|
||||||
Constant::Integer(n) => self.print_number(Number::Integer(n), op),
|
Constant::Integer(n) => self.print_number(Number::Integer(n), op),
|
||||||
Constant::Float(n) => self.print_number(Number::Float(n), op),
|
Constant::Float(n) => self.print_number(Number::Float(n), op),
|
||||||
|
|||||||
@@ -364,6 +364,17 @@ pub enum ControlInstruction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ControlInstruction {
|
impl ControlInstruction {
|
||||||
|
pub fn perm_vars(&self) -> Option<usize> {
|
||||||
|
match self {
|
||||||
|
ControlInstruction::CallClause(_, _, num_cells, ..) =>
|
||||||
|
Some(*num_cells),
|
||||||
|
ControlInstruction::JmpBy(_, _, num_cells, ..) =>
|
||||||
|
Some(*num_cells),
|
||||||
|
_ =>
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn to_functor(&self) -> MachineStub {
|
pub fn to_functor(&self) -> MachineStub {
|
||||||
match self {
|
match self {
|
||||||
&ControlInstruction::Allocate(num_frames) => {
|
&ControlInstruction::Allocate(num_frames) => {
|
||||||
|
|||||||
31
src/prolog/lib/cont.pl
Normal file
31
src/prolog/lib/cont.pl
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
|
||||||
|
:- module(cont, [reset/3, shift/1]).
|
||||||
|
|
||||||
|
reset(Goal, Ball, Cont) :-
|
||||||
|
call(Goal),
|
||||||
|
'$reset_cont_marker',
|
||||||
|
'$bind_from_register'(Cont, 3),
|
||||||
|
'$bind_from_register'(Ball, 4).
|
||||||
|
|
||||||
|
shift(Term) :-
|
||||||
|
'$nextEP'(first, E, P),
|
||||||
|
get_chunks(E, P, L),
|
||||||
|
( L == [] ->
|
||||||
|
Cont = none
|
||||||
|
; Cont = cont(call_continuation(L))
|
||||||
|
),
|
||||||
|
'$write_cont_and_term'(_, _, Cont, Term),
|
||||||
|
'$unwind_environments'.
|
||||||
|
|
||||||
|
get_chunks(E, P, L) :-
|
||||||
|
( '$points_to_cont_reset_marker'(P) ->
|
||||||
|
L = []
|
||||||
|
; '$get_cont_chunk'(E,P,TB),
|
||||||
|
L = [TB|Rest],
|
||||||
|
'$nextEP'(E, NextE, NextP),
|
||||||
|
get_chunks(NextE, NextP, Rest)
|
||||||
|
).
|
||||||
|
|
||||||
|
call_continuation(L) :- '$call_continuation'(L).
|
||||||
|
|
||||||
|
'$write_cont_and_term'(_, _, _, _).
|
||||||
@@ -117,7 +117,7 @@ impl MachineState {
|
|||||||
self.stack.index_and_frame_mut(e)[i] = self[RegType::Temp(i)].clone();
|
self.stack.index_and_frame_mut(e)[i] = self[RegType::Temp(i)].clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.stack.index_and_frame_mut(e)[self.num_of_args + 1] = Addr::Con(Constant::Usize(self.b0));
|
self.stack.index_and_frame_mut(e)[self.num_of_args + 1] = Addr::Con(Constant::CutPoint(self.b0));
|
||||||
self.stack.index_and_frame_mut(e)[self.num_of_args + 2] = Addr::Con(Constant::Usize(self.num_of_args));
|
self.stack.index_and_frame_mut(e)[self.num_of_args + 2] = Addr::Con(Constant::Usize(self.num_of_args));
|
||||||
|
|
||||||
self.verify_attributes();
|
self.verify_attributes();
|
||||||
|
|||||||
@@ -82,6 +82,50 @@ impl Heap {
|
|||||||
self.push(hcv);
|
self.push(hcv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_local_code_ptr(&self, addr: &Addr) -> Option<LocalCodePtr> {
|
||||||
|
let extract_integer = |s: usize| -> Option<usize> {
|
||||||
|
match self.heap[s].as_addr(s) {
|
||||||
|
Addr::Con(Constant::Integer(n)) => n.to_usize(),
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
match addr {
|
||||||
|
Addr::Str(s) => {
|
||||||
|
match &self.heap[*s] {
|
||||||
|
HeapCellValue::NamedStr(arity, ref name, _) => {
|
||||||
|
match (name.as_str(), *arity) {
|
||||||
|
("dir_entry", 1) => {
|
||||||
|
extract_integer(s+1).map(LocalCodePtr::DirEntry)
|
||||||
|
}
|
||||||
|
("in_situ_dir_entry", 1) => {
|
||||||
|
extract_integer(s+1).map(LocalCodePtr::InSituDirEntry)
|
||||||
|
}
|
||||||
|
("top_level", 2) => {
|
||||||
|
if let Some(chunk_num) = extract_integer(s+1) {
|
||||||
|
if let Some(p) = extract_integer(s+2) {
|
||||||
|
return Some(LocalCodePtr::TopLevel(chunk_num, p));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
("user_goal_expansion", 1) => {
|
||||||
|
extract_integer(s+1).map(LocalCodePtr::UserGoalExpansion)
|
||||||
|
}
|
||||||
|
("user_term_expansion", 1) => {
|
||||||
|
extract_integer(s+1).map(LocalCodePtr::UserTermExpansion)
|
||||||
|
}
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Index<usize> for Heap {
|
impl Index<usize> for Heap {
|
||||||
|
|||||||
@@ -4,7 +4,11 @@ use prolog_parser::tabled_rc::*;
|
|||||||
use crate::prolog::clause_types::*;
|
use crate::prolog::clause_types::*;
|
||||||
use crate::prolog::fixtures::*;
|
use crate::prolog::fixtures::*;
|
||||||
use crate::prolog::forms::*;
|
use crate::prolog::forms::*;
|
||||||
|
use crate::prolog::machine::code_repo::CodeRepo;
|
||||||
use crate::prolog::machine::Ball;
|
use crate::prolog::machine::Ball;
|
||||||
|
use crate::prolog::machine::heap::Heap;
|
||||||
|
use crate::prolog::instructions::*;
|
||||||
|
use crate::prolog::rug::Integer;
|
||||||
|
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
|
|
||||||
@@ -346,6 +350,69 @@ impl LocalCodePtr {
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_reset_cont_marker(&self, code_repo: &CodeRepo, last_call: bool) -> bool {
|
||||||
|
match code_repo.lookup_instr(last_call, &CodePtr::Local(*self)) {
|
||||||
|
Some(line) => {
|
||||||
|
match line.as_ref() {
|
||||||
|
Line::Control(ControlInstruction::CallClause(ref ct, ..)) => {
|
||||||
|
if let ClauseType::System(SystemClauseType::ResetContinuationMarker) = *ct {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_functor(&self, heap: &mut Heap) -> Addr {
|
||||||
|
let addr = Addr::HeapCell(heap.h);
|
||||||
|
|
||||||
|
match self {
|
||||||
|
LocalCodePtr::DirEntry(p) => {
|
||||||
|
heap.append(functor!(
|
||||||
|
"dir_entry",
|
||||||
|
1,
|
||||||
|
[heap_integer!(Integer::from(*p))]
|
||||||
|
));
|
||||||
|
}
|
||||||
|
LocalCodePtr::InSituDirEntry(p) => {
|
||||||
|
heap.append(functor!(
|
||||||
|
"in_situ_dir_entry",
|
||||||
|
1,
|
||||||
|
[heap_integer!(Integer::from(*p))]
|
||||||
|
));
|
||||||
|
}
|
||||||
|
LocalCodePtr::TopLevel(chunk_num, offset) => {
|
||||||
|
heap.append(functor!(
|
||||||
|
"top_level",
|
||||||
|
2,
|
||||||
|
[heap_integer!(Integer::from(*chunk_num)),
|
||||||
|
heap_integer!(Integer::from(*offset))]
|
||||||
|
));
|
||||||
|
}
|
||||||
|
LocalCodePtr::UserGoalExpansion(p) => {
|
||||||
|
heap.append(functor!(
|
||||||
|
"user_goal_expansion",
|
||||||
|
1,
|
||||||
|
[heap_integer!(Integer::from(*p))]
|
||||||
|
));
|
||||||
|
}
|
||||||
|
LocalCodePtr::UserTermExpansion(p) => {
|
||||||
|
heap.append(functor!(
|
||||||
|
"user_term_expansion",
|
||||||
|
1,
|
||||||
|
[heap_integer!(Integer::from(*p))]
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addr
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialOrd<CodePtr> for CodePtr {
|
impl PartialOrd<CodePtr> for CodePtr {
|
||||||
@@ -399,6 +466,25 @@ impl Add<usize> for LocalCodePtr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Sub<usize> for LocalCodePtr {
|
||||||
|
type Output = Option<LocalCodePtr>;
|
||||||
|
|
||||||
|
fn sub(self, rhs: usize) -> Self::Output {
|
||||||
|
match self {
|
||||||
|
LocalCodePtr::InSituDirEntry(p) =>
|
||||||
|
p.checked_sub(rhs).map(LocalCodePtr::InSituDirEntry),
|
||||||
|
LocalCodePtr::DirEntry(p) =>
|
||||||
|
p.checked_sub(rhs).map(LocalCodePtr::DirEntry),
|
||||||
|
LocalCodePtr::TopLevel(cn, p) =>
|
||||||
|
p.checked_sub(rhs).map(|r| LocalCodePtr::TopLevel(cn, r)),
|
||||||
|
LocalCodePtr::UserTermExpansion(p) =>
|
||||||
|
p.checked_sub(rhs).map(LocalCodePtr::UserTermExpansion),
|
||||||
|
LocalCodePtr::UserGoalExpansion(p) =>
|
||||||
|
p.checked_sub(rhs).map(LocalCodePtr::UserGoalExpansion),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl AddAssign<usize> for LocalCodePtr {
|
impl AddAssign<usize> for LocalCodePtr {
|
||||||
fn add_assign(&mut self, rhs: usize) {
|
fn add_assign(&mut self, rhs: usize) {
|
||||||
match self {
|
match self {
|
||||||
|
|||||||
@@ -1063,17 +1063,20 @@ downcast!(dyn CutPolicy);
|
|||||||
fn cut_body(machine_st: &mut MachineState, addr: Addr) -> bool {
|
fn cut_body(machine_st: &mut MachineState, addr: Addr) -> bool {
|
||||||
let b = machine_st.b;
|
let b = machine_st.b;
|
||||||
|
|
||||||
if let Addr::Con(Constant::Usize(b0)) = addr {
|
match addr {
|
||||||
if b > b0 {
|
Addr::Con(Constant::CutPoint(b0)) | Addr::Con(Constant::Usize(b0)) => {
|
||||||
machine_st.b = b0;
|
if b > b0 {
|
||||||
machine_st.tidy_trail();
|
machine_st.b = b0;
|
||||||
machine_st.tidy_pstr_trail();
|
machine_st.tidy_trail();
|
||||||
machine_st.truncate_stack();
|
machine_st.tidy_pstr_trail();
|
||||||
|
machine_st.truncate_stack();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
_ => {
|
||||||
machine_st.fail = true;
|
machine_st.fail = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
@@ -1148,15 +1151,19 @@ impl CutPolicy for SCCCutPolicy {
|
|||||||
fn cut(&mut self, machine_st: &mut MachineState, r: RegType) -> bool {
|
fn cut(&mut self, machine_st: &mut MachineState, r: RegType) -> bool {
|
||||||
let b = machine_st.b;
|
let b = machine_st.b;
|
||||||
|
|
||||||
if let Addr::Con(Constant::Usize(b0)) = machine_st[r].clone() {
|
match machine_st[r].clone() {
|
||||||
if b > b0 {
|
Addr::Con(Constant::Usize(b0)) | Addr::Con(Constant::CutPoint(b0)) => {
|
||||||
machine_st.b = b0;
|
if b > b0 {
|
||||||
machine_st.tidy_trail();
|
machine_st.b = b0;
|
||||||
machine_st.tidy_pstr_trail();
|
machine_st.tidy_trail();
|
||||||
|
machine_st.tidy_pstr_trail();
|
||||||
|
machine_st.truncate_stack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
machine_st.fail = true;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
machine_st.fail = true;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.run_cleaners(machine_st)
|
self.run_cleaners(machine_st)
|
||||||
|
|||||||
@@ -3337,7 +3337,7 @@ impl MachineState {
|
|||||||
&CutInstruction::GetLevel(r) => {
|
&CutInstruction::GetLevel(r) => {
|
||||||
let b0 = self.b0;
|
let b0 = self.b0;
|
||||||
|
|
||||||
self[r] = Addr::Con(Constant::Usize(b0));
|
self[r] = Addr::Con(Constant::CutPoint(b0));
|
||||||
self.p += 1;
|
self.p += 1;
|
||||||
}
|
}
|
||||||
&CutInstruction::GetLevelAndUnify(r) => {
|
&CutInstruction::GetLevelAndUnify(r) => {
|
||||||
|
|||||||
@@ -580,6 +580,51 @@ impl MachineState {
|
|||||||
functors
|
functors
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn call_continuation_chunk(&mut self, chunk: Addr, return_p: LocalCodePtr) -> LocalCodePtr {
|
||||||
|
let chunk = self.store(self.deref(chunk));
|
||||||
|
|
||||||
|
match chunk {
|
||||||
|
Addr::Str(s) => {
|
||||||
|
match &self.heap[s] {
|
||||||
|
HeapCellValue::NamedStr(arity, ..) => {
|
||||||
|
let num_cells = arity - 1;
|
||||||
|
let p_functor = self.heap[s+1].as_addr(s+1);
|
||||||
|
|
||||||
|
let cp = self.heap.to_local_code_ptr(&p_functor).unwrap();
|
||||||
|
let prev_e = self.e;
|
||||||
|
|
||||||
|
let e = self.stack.allocate_and_frame(num_cells);
|
||||||
|
let and_frame = self.stack.index_and_frame_mut(e);
|
||||||
|
|
||||||
|
and_frame.prelude.e = prev_e;
|
||||||
|
and_frame.prelude.cp = return_p;
|
||||||
|
|
||||||
|
self.p = CodePtr::Local(cp + 1);
|
||||||
|
|
||||||
|
// adjust cut point to occur after call_continuation.
|
||||||
|
if num_cells > 0 {
|
||||||
|
if let Addr::Con(Constant::CutPoint(_)) = self.heap[s+2].as_addr(s+2) {
|
||||||
|
and_frame[1] = Addr::Con(Constant::CutPoint(self.b));
|
||||||
|
} else {
|
||||||
|
and_frame[1] = self.heap[s+2].as_addr(s+2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for index in s+3 .. s+2+num_cells {
|
||||||
|
and_frame[index - (s+1)] = self.heap[index].as_addr(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.e = e;
|
||||||
|
|
||||||
|
self.p.local()
|
||||||
|
}
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn system_call(
|
pub(super) fn system_call(
|
||||||
&mut self,
|
&mut self,
|
||||||
ct: &SystemClauseType,
|
ct: &SystemClauseType,
|
||||||
@@ -604,6 +649,25 @@ impl MachineState {
|
|||||||
self.p = CodePtr::DynamicTransaction(trans_type, p);
|
self.p = CodePtr::DynamicTransaction(trans_type, p);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
&SystemClauseType::BindFromRegister => {
|
||||||
|
let reg = self.store(self.deref(self[temp_v!(2)].clone()));
|
||||||
|
let n = match reg {
|
||||||
|
Addr::Con(Constant::Integer(n)) => n.to_usize(),
|
||||||
|
_ => unreachable!()
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(n) = n {
|
||||||
|
if n <= MAX_ARITY {
|
||||||
|
let target = self[temp_v!(n)].clone();
|
||||||
|
let addr = self[temp_v!(1)].clone();
|
||||||
|
|
||||||
|
self.unify(addr, target);
|
||||||
|
return return_from_clause!(self.last_call, self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.fail = true;
|
||||||
|
}
|
||||||
&SystemClauseType::AssertDynamicPredicateToFront => {
|
&SystemClauseType::AssertDynamicPredicateToFront => {
|
||||||
let p = self.cp;
|
let p = self.cp;
|
||||||
let trans_type = DynamicTransactionType::Assert(DynamicAssertPlace::Front);
|
let trans_type = DynamicTransactionType::Assert(DynamicAssertPlace::Front);
|
||||||
@@ -765,6 +829,28 @@ impl MachineState {
|
|||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
&SystemClauseType::CallContinuation => {
|
||||||
|
let stub = MachineError::functor_stub(clause_name!("call_continuation"), 1);
|
||||||
|
|
||||||
|
match self.try_from_list(temp_v!(1), stub) {
|
||||||
|
Err(e) => return Err(e),
|
||||||
|
Ok(cont_chunks) => {
|
||||||
|
let mut return_p = if self.last_call {
|
||||||
|
self.cp
|
||||||
|
} else {
|
||||||
|
self.p.local() + 1
|
||||||
|
};
|
||||||
|
|
||||||
|
self.p = CodePtr::Local(return_p);
|
||||||
|
|
||||||
|
for chunk in cont_chunks.into_iter().rev() {
|
||||||
|
return_p = self.call_continuation_chunk(chunk, return_p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
&SystemClauseType::CharsToNumber => {
|
&SystemClauseType::CharsToNumber => {
|
||||||
let stub = MachineError::functor_stub(clause_name!("number_chars"), 2);
|
let stub = MachineError::functor_stub(clause_name!("number_chars"), 2);
|
||||||
|
|
||||||
@@ -878,7 +964,7 @@ impl MachineState {
|
|||||||
let addr = self.store(self.deref(self[temp_v!(1)].clone()));
|
let addr = self.store(self.deref(self[temp_v!(1)].clone()));
|
||||||
|
|
||||||
match addr {
|
match addr {
|
||||||
Addr::Con(Constant::Usize(old_b)) => {
|
Addr::Con(Constant::Usize(old_b)) | Addr::Con(Constant::CutPoint(old_b)) => {
|
||||||
let prev_b = self.stack.index_or_frame(self.b).prelude.b;
|
let prev_b = self.stack.index_or_frame(self.b).prelude.b;
|
||||||
let prev_b = self.stack.index_or_frame(prev_b).prelude.b;
|
let prev_b = self.stack.index_or_frame(prev_b).prelude.b;
|
||||||
|
|
||||||
@@ -1458,6 +1544,50 @@ impl MachineState {
|
|||||||
_ => self.fail = true,
|
_ => self.fail = true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
&SystemClauseType::GetContinuationChunk => {
|
||||||
|
let e = self.store(self.deref(self[temp_v!(1)].clone()));
|
||||||
|
|
||||||
|
let e = if let Addr::Con(Constant::Usize(e)) = e {
|
||||||
|
e
|
||||||
|
} else {
|
||||||
|
self.fail = true;
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
|
||||||
|
let p_functor = self.store(self.deref(self[temp_v!(2)].clone()));
|
||||||
|
let p = self.heap.to_local_code_ptr(&p_functor).unwrap();
|
||||||
|
|
||||||
|
let num_cells = match code_repo.lookup_instr(self.last_call, &CodePtr::Local(p)) {
|
||||||
|
Some(line) => {
|
||||||
|
let perm_vars = match line.as_ref() {
|
||||||
|
Line::Control(ref ctrl_instr) => ctrl_instr.perm_vars(),
|
||||||
|
_ => None
|
||||||
|
};
|
||||||
|
|
||||||
|
perm_vars.unwrap()
|
||||||
|
}
|
||||||
|
_ => unreachable!()
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut addrs = vec![];
|
||||||
|
|
||||||
|
for index in 1 .. num_cells + 1 {
|
||||||
|
addrs.push(self.stack.index_and_frame(e)[index].clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
let chunk = Addr::HeapCell(self.heap.h);
|
||||||
|
|
||||||
|
self.heap.push(HeapCellValue::NamedStr(
|
||||||
|
1 + num_cells,
|
||||||
|
clause_name!("cont_chunk"),
|
||||||
|
None,
|
||||||
|
));
|
||||||
|
|
||||||
|
self.heap.push(HeapCellValue::Addr(p_functor));
|
||||||
|
self.heap.extend(addrs.into_iter().map(HeapCellValue::Addr));
|
||||||
|
|
||||||
|
self.unify(self[temp_v!(3)].clone(), chunk);
|
||||||
|
}
|
||||||
&SystemClauseType::GetLiftedHeapFromOffsetDiff => {
|
&SystemClauseType::GetLiftedHeapFromOffsetDiff => {
|
||||||
let lh_offset = self[temp_v!(1)].clone();
|
let lh_offset = self[temp_v!(1)].clone();
|
||||||
|
|
||||||
@@ -1590,7 +1720,8 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
match (a1, a2.clone()) {
|
match (a1, a2.clone()) {
|
||||||
(Addr::Con(Constant::Usize(bp)), Addr::Con(Constant::Integer(n))) => {
|
(Addr::Con(Constant::Usize(bp)), Addr::Con(Constant::Integer(n)))
|
||||||
|
| (Addr::Con(Constant::CutPoint(bp)), Addr::Con(Constant::Integer(n))) => {
|
||||||
match call_policy.downcast_mut::<CWILCallPolicy>().ok() {
|
match call_policy.downcast_mut::<CWILCallPolicy>().ok() {
|
||||||
Some(call_policy) => {
|
Some(call_policy) => {
|
||||||
let count = call_policy.add_limit(n, bp);
|
let count = call_policy.add_limit(n, bp);
|
||||||
@@ -1752,14 +1883,17 @@ impl MachineState {
|
|||||||
Some(call_policy) => {
|
Some(call_policy) => {
|
||||||
let a1 = self.store(self.deref(self[temp_v!(1)].clone()));
|
let a1 = self.store(self.deref(self[temp_v!(1)].clone()));
|
||||||
|
|
||||||
if let Addr::Con(Constant::Usize(bp)) = a1 {
|
match a1 {
|
||||||
if call_policy.is_empty() && bp == self.b {
|
Addr::Con(Constant::Usize(bp)) | Addr::Con(Constant::CutPoint(bp)) => {
|
||||||
Some(call_policy.into_inner())
|
if call_policy.is_empty() && bp == self.b {
|
||||||
} else {
|
Some(call_policy.into_inner())
|
||||||
None
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
panic!("remove_call_policy_check: expected Usize in A1.");
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
panic!("remove_call_policy_check: expected Usize in A1.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => panic!(
|
None => panic!(
|
||||||
@@ -1777,15 +1911,18 @@ impl MachineState {
|
|||||||
Some(call_policy) => {
|
Some(call_policy) => {
|
||||||
let a1 = self.store(self.deref(self[temp_v!(1)].clone()));
|
let a1 = self.store(self.deref(self[temp_v!(1)].clone()));
|
||||||
|
|
||||||
if let Addr::Con(Constant::Usize(bp)) = a1 {
|
match a1 {
|
||||||
let count = call_policy.remove_limit(bp);
|
Addr::Con(Constant::Usize(bp)) | Addr::Con(Constant::CutPoint(bp)) => {
|
||||||
let count = Addr::Con(Constant::Integer(count.clone()));
|
let count = call_policy.remove_limit(bp);
|
||||||
|
let count = Addr::Con(Constant::Integer(count.clone()));
|
||||||
|
|
||||||
let a2 = self[temp_v!(2)].clone();
|
let a2 = self[temp_v!(2)].clone();
|
||||||
|
|
||||||
self.unify(a2, count);
|
self.unify(a2, count);
|
||||||
} else {
|
}
|
||||||
panic!("remove_inference_counter: expected Usize in A1.");
|
_ => {
|
||||||
|
panic!("remove_inference_counter: expected Usize in A1.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => panic!(
|
None => panic!(
|
||||||
@@ -1817,7 +1954,7 @@ impl MachineState {
|
|||||||
self[RegType::Temp(i)] = self.stack.index_and_frame(e)[i].clone();
|
self[RegType::Temp(i)] = self.stack.index_and_frame(e)[i].clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
if let &Addr::Con(Constant::Usize(b0)) = &self.stack.index_and_frame(e)[frame_len - 1] {
|
if let &Addr::Con(Constant::CutPoint(b0)) = &self.stack.index_and_frame(e)[frame_len - 1] {
|
||||||
self.b0 = b0;
|
self.b0 = b0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1865,7 +2002,7 @@ impl MachineState {
|
|||||||
let a2 = self.store(self.deref(self[temp_v!(2)].clone()));
|
let a2 = self.store(self.deref(self[temp_v!(2)].clone()));
|
||||||
|
|
||||||
match a2 {
|
match a2 {
|
||||||
Addr::Con(Constant::Usize(bp)) => {
|
Addr::Con(Constant::CutPoint(bp)) | Addr::Con(Constant::Usize(bp)) => {
|
||||||
let prev_b = self.stack.index_or_frame(self.b).prelude.b;
|
let prev_b = self.stack.index_or_frame(self.b).prelude.b;
|
||||||
|
|
||||||
if prev_b <= bp {
|
if prev_b <= bp {
|
||||||
@@ -1956,7 +2093,7 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
&SystemClauseType::GetCutPoint => {
|
&SystemClauseType::GetCutPoint => {
|
||||||
let a1 = self[temp_v!(1)].clone();
|
let a1 = self[temp_v!(1)].clone();
|
||||||
let a2 = Addr::Con(Constant::Usize(self.b0));
|
let a2 = Addr::Con(Constant::CutPoint(self.b0));
|
||||||
|
|
||||||
self.unify(a1, a2);
|
self.unify(a1, a2);
|
||||||
}
|
}
|
||||||
@@ -1978,6 +2115,72 @@ impl MachineState {
|
|||||||
let target = self[temp_v!(1)].clone();
|
let target = self[temp_v!(1)].clone();
|
||||||
self.unify(Addr::Con(Constant::Char(c)), target);
|
self.unify(Addr::Con(Constant::Char(c)), target);
|
||||||
}
|
}
|
||||||
|
&SystemClauseType::NextEP => {
|
||||||
|
let first_arg = self.store(self.deref(self[temp_v!(1)].clone()));
|
||||||
|
|
||||||
|
match first_arg {
|
||||||
|
Addr::Con(Constant::Atom(ref name, _))
|
||||||
|
if name.as_str() == "first" => {
|
||||||
|
if self.e == 0 {
|
||||||
|
self.fail = true;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let cp = (self.stack.index_and_frame(self.e).prelude.cp - 1).unwrap();
|
||||||
|
|
||||||
|
let e = self.stack.index_and_frame(self.e).prelude.e;
|
||||||
|
let e = Addr::Con(Constant::Usize(e));
|
||||||
|
|
||||||
|
let p = cp.as_functor(&mut self.heap);
|
||||||
|
|
||||||
|
self.unify(self[temp_v!(2)].clone(), e);
|
||||||
|
|
||||||
|
if !self.fail {
|
||||||
|
self.unify(self[temp_v!(3)].clone(), p);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Addr::Con(Constant::Usize(e)) => {
|
||||||
|
if e == 0 {
|
||||||
|
self.fail = true;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the call site so that the number of active permanent variables can be read
|
||||||
|
// from it later.
|
||||||
|
let cp = (self.stack.index_and_frame(e).prelude.cp - 1).unwrap();
|
||||||
|
|
||||||
|
let p = cp.as_functor(&mut self.heap);
|
||||||
|
let e = self.stack.index_and_frame(e).prelude.e;
|
||||||
|
|
||||||
|
let e = Addr::Con(Constant::Usize(e));
|
||||||
|
|
||||||
|
self.unify(self[temp_v!(2)].clone(), e);
|
||||||
|
|
||||||
|
if !self.fail {
|
||||||
|
self.unify(self[temp_v!(3)].clone(), p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&SystemClauseType::PointsToContinuationResetMarker => {
|
||||||
|
let addr = self.store(self.deref(self[temp_v!(1)].clone()));
|
||||||
|
|
||||||
|
let p = match self.heap.to_local_code_ptr(&addr) {
|
||||||
|
Some(p) => p + 1,
|
||||||
|
None => {
|
||||||
|
self.fail = true;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if p.is_reset_cont_marker(code_repo, self.last_call) {
|
||||||
|
return return_from_clause!(self.last_call, self);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.fail = true;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
&SystemClauseType::ReadQueryTerm => {
|
&SystemClauseType::ReadQueryTerm => {
|
||||||
readline::set_prompt(true);
|
readline::set_prompt(true);
|
||||||
let result = self.read_term(current_input_stream, indices);
|
let result = self.read_term(current_input_stream, indices);
|
||||||
@@ -1988,11 +2191,19 @@ impl MachineState {
|
|||||||
&SystemClauseType::ReadTerm => {
|
&SystemClauseType::ReadTerm => {
|
||||||
readline::set_prompt(false);
|
readline::set_prompt(false);
|
||||||
self.read_term(current_input_stream, indices)?;
|
self.read_term(current_input_stream, indices)?;
|
||||||
},
|
}
|
||||||
&SystemClauseType::ResetBlock => {
|
&SystemClauseType::ResetBlock => {
|
||||||
let addr = self.deref(self[temp_v!(1)].clone());
|
let addr = self.deref(self[temp_v!(1)].clone());
|
||||||
self.reset_block(addr);
|
self.reset_block(addr);
|
||||||
}
|
}
|
||||||
|
&SystemClauseType::ResetContinuationMarker => {
|
||||||
|
self[temp_v!(3)] = Addr::Con(Constant::Atom(clause_name!("none"), None));
|
||||||
|
|
||||||
|
let h = self.heap.h;
|
||||||
|
self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h)));
|
||||||
|
|
||||||
|
self[temp_v!(4)] = Addr::HeapCell(h);
|
||||||
|
}
|
||||||
&SystemClauseType::SetBall =>
|
&SystemClauseType::SetBall =>
|
||||||
self.set_ball(),
|
self.set_ball(),
|
||||||
&SystemClauseType::SetSeed => {
|
&SystemClauseType::SetSeed => {
|
||||||
@@ -2102,6 +2313,22 @@ impl MachineState {
|
|||||||
|
|
||||||
self.unify_with_occurs_check(a1, a2);
|
self.unify_with_occurs_check(a1, a2);
|
||||||
}
|
}
|
||||||
|
&SystemClauseType::UnwindEnvironments => {
|
||||||
|
let mut e = self.e;
|
||||||
|
let mut cp = self.cp;
|
||||||
|
|
||||||
|
while e > 0 {
|
||||||
|
if cp.is_reset_cont_marker(code_repo, self.last_call) {
|
||||||
|
self.e = e;
|
||||||
|
self.p = CodePtr::Local(cp + 1); // skip the reset marker.
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
cp = self.stack.index_and_frame(e).prelude.cp;
|
||||||
|
e = self.stack.index_and_frame(e).prelude.e;
|
||||||
|
}
|
||||||
|
}
|
||||||
&SystemClauseType::UnwindStack => self.unwind_stack(),
|
&SystemClauseType::UnwindStack => self.unwind_stack(),
|
||||||
&SystemClauseType::Variant => self.fail = self.structural_eq_test(),
|
&SystemClauseType::Variant => self.fail = self.structural_eq_test(),
|
||||||
&SystemClauseType::WAMInstructions => {
|
&SystemClauseType::WAMInstructions => {
|
||||||
|
|||||||
Reference in New Issue
Block a user