optimized up to section 5.11

This commit is contained in:
Mark Thom
2017-03-30 00:51:23 -06:00
parent 02482aec8a
commit 79ae4abb81
10 changed files with 770 additions and 89 deletions

View File

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

View File

@@ -11,7 +11,7 @@ pure Prolog.
Pure Prolog is implemented as a simple REPL. "Pure Prolog" is Prolog
without cut, meta- or extra-logical operators, or side effects of any
kind. In terms of the tutorial pacing, the work has progressed to the
end of section 5.9, skipping past 5.4. Atoms and lists are the only
end of section 5.10, skipping past 5.4. Atoms and lists are the only
two data types currently supported.
While proper environment trimming code is emitted by the code

View File

@@ -239,6 +239,154 @@ mod tests {
assert_eq!(submit(&mut wam, "?- member([X, Y, Y], [a, [b, c], [b, b], [Z, x], [d, f]]).").failed_query(), true);
assert_eq!(submit(&mut wam, "?- member([X, Y, Z], [a, [b, c], [b, b], [Z, x], [d, f]]).").failed_query(), true);
}
#[test]
fn test_queries_on_indexed_predicates() {
let mut wam = Machine::new();
submit(&mut wam, "p(a) :- a.
p(b) :- b, f(X).
p(c) :- c, g(X).
p(f(a)) :- a.
p(g(b, c)) :- b.
p(g(b)) :- b.
p([a|b]) :- a.
p([]).
p(X) :- x.
p([c, d, e]).");
assert_eq!(submit(&mut wam, "?- p(a).").failed_query(), true);
assert_eq!(submit(&mut wam, "?- p(b).").failed_query(), true);
assert_eq!(submit(&mut wam, "?- p(c).").failed_query(), true);
assert_eq!(submit(&mut wam, "?- p(f(a)).").failed_query(), true);
assert_eq!(submit(&mut wam, "?- p(g(b, X)).").failed_query(), true);
assert_eq!(submit(&mut wam, "?- p(g(Y, X)).").failed_query(), true);
assert_eq!(submit(&mut wam, "?- p(g(Y, c)).").failed_query(), true);
assert_eq!(submit(&mut wam, "?- p(g(b)).").failed_query(), true);
assert_eq!(submit(&mut wam, "?- p([]).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p([c, d, e]).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p([c, d | X]).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p([c|X]).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p([Y|X]).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p([Y|[d|Xs]]).").failed_query(), false);
submit(&mut wam, "a.");
assert_eq!(submit(&mut wam, "?- p(a).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(b).").failed_query(), true);
assert_eq!(submit(&mut wam, "?- p(c).").failed_query(), true);
assert_eq!(submit(&mut wam, "?- p(f(a)).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(g(b, X)).").failed_query(), true);
assert_eq!(submit(&mut wam, "?- p(g(Y, X)).").failed_query(), true);
assert_eq!(submit(&mut wam, "?- p(g(Y, c)).").failed_query(), true);
assert_eq!(submit(&mut wam, "?- p(g(b)).").failed_query(), true);
assert_eq!(submit(&mut wam, "?- p([]).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p([c, d, e]).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p([c, d | X]).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p([c|X]).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p([Y|X]).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p([Y|[d|Xs]]).").failed_query(), false);
submit(&mut wam, "b.");
submit(&mut wam, "f(x).");
assert_eq!(submit(&mut wam, "?- p(a).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(b).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(c).").failed_query(), true);
assert_eq!(submit(&mut wam, "?- p(f(a)).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(g(b, X)).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(g(Y, X)).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(g(Y, c)).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(g(b)).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p([]).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p([c, d, e]).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p([c, d | X]).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p([c|X]).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p([Y|X]).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p([Y|[d|Xs]]).").failed_query(), false);
submit(&mut wam, "c.");
submit(&mut wam, "g(X).");
assert_eq!(submit(&mut wam, "?- p(a).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(b).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(c).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(f(a)).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(g(b, X)).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(g(Y, X)).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(g(Y, c)).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(g(b)).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p([]).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p([c, d, e]).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p([c, d | X]).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p([c|X]).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p([Y|X]).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p([Y|[d|Xs]]).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(blah).").failed_query(), true);
submit(&mut wam, "x.");
assert_eq!(submit(&mut wam, "?- p(a).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(b).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(c).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(f(a)).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(g(b, X)).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(g(Y, X)).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(g(Y, c)).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(g(b)).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p([]).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p([c, d, e]).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p([c, d | X]).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p([c|X]).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p([Y|X]).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p([Y|[d|Xs]]).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- p(blah).").failed_query(), false);
submit(&mut wam, "call(or(X, Y)) :- call(X).
call(trace) :- trace.
call(or(X, Y)) :- call(Y).
call(notrace) :- notrace.
call(nl) :- nl.
call(X) :- builtin(X).
call(X) :- extern(X).
call(call(X)) :- call(X).
call(repeat).
call(repeat) :- call(repeat).
call(true).");
assert_eq!(submit(&mut wam, "?- call(repeat).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- call(true).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- call(call(repeat)).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- call(call(true)).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- call(notrace).").failed_query(), true);
assert_eq!(submit(&mut wam, "?- call(nl).").failed_query(), true);
assert_eq!(submit(&mut wam, "?- call(builtin(X)).").failed_query(), true);
assert_eq!(submit(&mut wam, "?- call(extern(X)).").failed_query(), true);
submit(&mut wam, "notrace.");
submit(&mut wam, "nl.");
assert_eq!(submit(&mut wam, "?- call(repeat).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- call(true).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- call(call(repeat)).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- call(call(true)).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- call(notrace).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- call(nl).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- call(builtin(X)).").failed_query(), true);
assert_eq!(submit(&mut wam, "?- call(extern(X)).").failed_query(), true);
submit(&mut wam, "builtin(X).");
submit(&mut wam, "extern(x).");
assert_eq!(submit(&mut wam, "?- call(repeat).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- call(true).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- call(call(repeat)).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- call(call(true)).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- call(notrace).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- call(nl).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- call(builtin(X)).").failed_query(), false);
assert_eq!(submit(&mut wam, "?- call(extern(X)).").failed_query(), false);
}
}
fn prolog_repl() {

View File

@@ -1,6 +1,5 @@
use std::cell::Cell;
use std::cmp::Ordering;
use std::collections::HashMap;
use std::collections::{HashMap, VecDeque};
use std::ops::{Add, AddAssign};
use std::vec::Vec;
@@ -21,6 +20,13 @@ impl PredicateClause {
}
}
pub fn first_arg(&self) -> Option<&Term> {
match self {
&PredicateClause::Fact(ref t) => t.first_arg(),
&PredicateClause::Rule(ref rule) => rule.head.0.first_arg()
}
}
pub fn arity(&self) -> usize {
match self {
&PredicateClause::Fact(ref t) => t.arity(),
@@ -99,7 +105,7 @@ impl Default for VarReg {
}
}
#[derive(Clone, PartialEq)]
#[derive(Clone, Hash, PartialEq, Eq)]
pub enum Constant {
Atom(Atom),
EmptyList
@@ -135,6 +141,54 @@ pub enum TermRef<'a> {
Var(Level, &'a Cell<VarReg>, &'a Var)
}
pub enum ChoiceInstruction {
RetryMeElse(usize),
TrustMe,
TryMeElse(usize)
}
pub enum IndexedChoiceInstruction {
Retry(usize),
Trust(usize),
Try(usize)
}
impl From<IndexedChoiceInstruction> for Line {
fn from(i: IndexedChoiceInstruction) -> Self {
Line::IndexedChoice(i)
}
}
impl IndexedChoiceInstruction {
pub fn offset(&self) -> usize {
match self {
&IndexedChoiceInstruction::Retry(offset) => offset,
&IndexedChoiceInstruction::Trust(offset) => offset,
&IndexedChoiceInstruction::Try(offset) => offset
}
}
}
pub enum ControlInstruction {
Allocate(usize),
Call(Atom, usize, usize),
Deallocate,
Execute(Atom, usize),
Proceed
}
pub enum IndexingInstruction {
SwitchOnTerm(usize, usize, usize, usize),
SwitchOnConstant(usize, HashMap<Constant, usize>),
SwitchOnStructure(usize, HashMap<(Atom, usize), usize>)
}
impl From<IndexingInstruction> for Line {
fn from(i: IndexingInstruction) -> Self {
Line::Indexing(i)
}
}
pub enum FactInstruction {
GetConstant(Level, Constant, RegType),
GetList(Level, RegType),
@@ -162,20 +216,6 @@ pub enum QueryInstruction {
SetVoid(usize)
}
pub enum ChoiceInstruction {
RetryMeElse(usize),
TrustMe,
TryMeElse(usize)
}
pub enum ControlInstruction {
Allocate(usize),
Call(Atom, usize, usize),
Deallocate,
Execute(Atom, usize),
Proceed
}
pub type CompiledFact = Vec<FactInstruction>;
pub type CompiledQuery = Vec<QueryInstruction>;
@@ -184,6 +224,8 @@ pub enum Line {
Choice(ChoiceInstruction),
Control(ControlInstruction),
Fact(CompiledFact),
Indexing(IndexingInstruction),
IndexedChoice(IndexedChoiceInstruction),
Query(CompiledQuery)
}
@@ -198,8 +240,11 @@ impl<'a> From<&'a Line> for LineOrCodeOffset<'a> {
}
}
pub type ThirdLevelIndex = Vec<IndexedChoiceInstruction>;
pub type Code = Vec<Line>;
pub type CodeDeque = VecDeque<Line>;
#[derive(Clone, PartialEq)]
pub enum Addr {
@@ -287,26 +332,6 @@ impl HeapCellValue {
}
}
impl PartialOrd for Ref {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
match (*self, *other) {
(Ref::HeapCell(hc1), Ref::HeapCell(hc2)) =>
Some(hc1.cmp(&hc2)),
(Ref::HeapCell(_), _) =>
Some(Ordering::Less),
(Ref::StackCell(fr1, sc1), Ref::StackCell(fr2, sc2)) =>
if fr1 < fr2 {
Some(Ordering::Less)
} else if fr1 == fr2 {
Some(sc1.cmp(&sc2))
} else {
Some(Ordering::Greater)
},
_ => Some(Ordering::Greater)
}
}
}
#[derive(Clone, Copy)]
pub enum CodePtr {
DirEntry(usize),
@@ -344,6 +369,14 @@ pub type Heap = Vec<HeapCellValue>;
pub type Registers = Vec<Addr>;
impl Term {
pub fn first_arg(&self) -> Option<&Term> {
match self {
&Term::Clause(_, _, ref terms) =>
terms.first().map(|bt| bt.as_ref()),
_ => None
}
}
pub fn is_clause(&self) -> bool {
if let &Term::Clause(_, _, _) = self {
true

View File

@@ -3,7 +3,8 @@ use prolog::iterators::{FactIterator, QueryIterator};
use std::cell::Cell;
use std::cmp::max;
use std::collections::HashMap;
use std::collections::{HashMap, VecDeque};
use std::hash::Hash;
use std::vec::Vec;
trait CompilationTarget<'a> {
@@ -244,6 +245,239 @@ impl<'a> TermMarker<'a> {
}
}
#[derive(Clone, Copy)]
enum IntIndex {
External(usize), Fail, Internal(usize)
}
impl Into<usize> for IntIndex {
fn into(self) -> usize {
match self {
IntIndex::Internal(i) => i,
_ => 0
}
}
}
struct CodeOffsets {
constants: HashMap<Constant, ThirdLevelIndex>,
lists: ThirdLevelIndex,
structures: HashMap<(Atom, usize), ThirdLevelIndex>
}
impl CodeOffsets {
fn new() -> Self {
CodeOffsets {
constants: HashMap::new(),
lists: Vec::new(),
structures: HashMap::new()
}
}
fn cap_choice_seq_with_trust(prelude: &mut ThirdLevelIndex) {
prelude.last_mut().map(|instr| {
match instr {
&mut IndexedChoiceInstruction::Retry(i) =>
*instr = IndexedChoiceInstruction::Trust(i),
_ => {}
};
});
}
fn add_index(is_first_index: bool, index: usize) -> IndexedChoiceInstruction {
if is_first_index {
IndexedChoiceInstruction::Try(index)
} else {
IndexedChoiceInstruction::Retry(index)
}
}
fn index_term(&mut self, first_arg: &Term, index: usize) {
match first_arg {
&Term::Clause(_, ref name, ref terms) => {
let code = self.structures.entry((name.clone(), terms.len()))
.or_insert(Vec::new());
let is_initial_index = code.is_empty();
code.push(Self::add_index(is_initial_index, index));
},
&Term::Cons(_, _, _) => {
let is_initial_index = self.lists.is_empty();
self.lists.push(Self::add_index(is_initial_index, index));
},
&Term::Constant(_, ref constant) => {
let code = self.constants.entry(constant.clone())
.or_insert(Vec::new());
let is_initial_index = code.is_empty();
code.push(Self::add_index(is_initial_index, index));
},
_ => {}
};
}
fn second_level_index<Index>(indices: HashMap<Index, ThirdLevelIndex>,
prelude: &mut CodeDeque)
-> HashMap<Index, IntIndex>
where Index: Eq + Hash
{
let mut index_locs = HashMap::new();
for (key, mut code) in indices.into_iter() {
if code.len() > 1 {
index_locs.insert(key, IntIndex::Internal(prelude.len()));
Self::cap_choice_seq_with_trust(&mut code);
prelude.extend(code.into_iter().map(|code| Line::from(code)));
} else {
code.first().map(|i| {
index_locs.insert(key, IntIndex::External(i.offset()));
});
}
}
index_locs
}
fn no_indices(&self) -> bool {
let no_constants = self.constants.is_empty();
let no_structures = self.structures.is_empty();
let no_lists = self.lists.is_empty();
no_constants && no_structures && no_lists
}
fn flatten_index<Index>(index: HashMap<Index, IntIndex>, len: usize)
-> HashMap<Index, usize>
where Index: Eq + Hash
{
let mut flattened_index = HashMap::new();
for (key, int_index) in index.into_iter() {
match int_index {
IntIndex::External(offset) => {
flattened_index.insert(key, offset + len + 1);
},
IntIndex::Internal(offset) => {
flattened_index.insert(key, offset + 1);
},
_ => {}
};
}
flattened_index
}
fn switch_on_constant(con_ind: HashMap<Constant, ThirdLevelIndex>,
prelude: &mut CodeDeque)
-> IntIndex
{
let con_ind = Self::second_level_index(con_ind, prelude);
if con_ind.len() > 1 {
let index = Self::flatten_index(con_ind, prelude.len());
let instr = IndexingInstruction::SwitchOnConstant(index.len(), index);
prelude.push_front(Line::from(instr));
IntIndex::Internal(1)
} else {
con_ind.values().next()
.map(|i| *i)
.unwrap_or(IntIndex::Fail)
}
}
fn switch_on_list(mut lists: ThirdLevelIndex, prelude: &mut CodeDeque) -> IntIndex
{
if lists.len() > 1 {
Self::cap_choice_seq_with_trust(&mut lists);
prelude.extend(lists.into_iter().map(|i| Line::from(i)));
IntIndex::Internal(0)
} else {
lists.first()
.map(|i| IntIndex::External(i.offset()))
.unwrap_or(IntIndex::Fail)
}
}
fn switch_on_structure(str_ind: HashMap<(Atom, usize), ThirdLevelIndex>,
prelude: &mut CodeDeque)
-> IntIndex
{
let str_ind = Self::second_level_index(str_ind, prelude);
if str_ind.len() > 1 {
let index = Self::flatten_index(str_ind, prelude.len());
let instr = IndexingInstruction::SwitchOnStructure(index.len(), index);
prelude.push_front(Line::from(instr));
IntIndex::Internal(1)
} else {
str_ind.values().next()
.map(|i| *i)
.unwrap_or(IntIndex::Fail)
}
}
fn add_indices(self, code: &mut Code, mut code_body: Code)
{
if self.no_indices() {
*code = code_body;
return;
}
let mut prelude = VecDeque::new();
let lst_step = Self::switch_on_list(self.lists, &mut prelude);
let lst_offset = prelude.len();
let str_step = Self::switch_on_structure(self.structures, &mut prelude);
let con_step = Self::switch_on_constant(self.constants, &mut prelude);
let prelude_length = prelude.len();
for (index, line) in prelude.iter_mut().enumerate() {
match line {
&mut Line::IndexedChoice(IndexedChoiceInstruction::Try(ref mut i))
| &mut Line::IndexedChoice(IndexedChoiceInstruction::Retry(ref mut i))
| &mut Line::IndexedChoice(IndexedChoiceInstruction::Trust(ref mut i)) =>
*i += prelude_length - index,
_ => {}
}
}
let str_step = match str_step {
IntIndex::External(o) => o + prelude.len() + 1,
IntIndex::Fail => 0,
IntIndex::Internal(_) => match con_step {
IntIndex::Internal(_) => 2,
_ => 1
}
};
let con_step = match con_step {
IntIndex::External(offset) => offset + prelude.len() + 1,
IntIndex::Fail => 0,
IntIndex::Internal(offset) => offset,
};
let lst_step = match lst_step {
IntIndex::External(o) => o + prelude.len() + 1,
IntIndex::Fail => 0,
IntIndex::Internal(_) => prelude.len() - lst_offset + 1
};
let switch_instr = IndexingInstruction::SwitchOnTerm(prelude.len() + 1,
con_step,
lst_step,
str_step);
prelude.push_front(Line::from(switch_instr));
*code = Vec::from(prelude);
code.append(&mut code_body);
}
}
#[derive(Copy, Clone)]
enum VarStatus {
New, Old, Permanent(usize)
@@ -643,7 +877,7 @@ impl<'a> CodeGenerator<'a> {
Self::add_conditional_call(&mut body, p1, perm_vars);
body = clauses.iter().enumerate()
.map(|(i, ref term)| {
.map(|(i, term)| {
let num_vars = Self::vars_above_threshold(&vs, i+1);
self.compile_internal_query(term, num_vars)
})
@@ -751,9 +985,35 @@ impl<'a> CodeGenerator<'a> {
code
}
pub fn compile_predicate(&mut self, clauses: &'a Vec<PredicateClause>) -> Code
fn split_predicate(clauses: &Vec<PredicateClause>) -> Vec<(usize, usize)>
{
let mut code = Vec::new();
let mut subseqs = Vec::new();
let mut left_index = 0;
for (right_index, clause) in clauses.iter().enumerate() {
if let Some(&Term::Var(_, _)) = clause.first_arg() {
if left_index < right_index {
subseqs.push((left_index, right_index));
}
subseqs.push((right_index, right_index + 1));
left_index = right_index + 1;
}
}
if left_index < clauses.len() {
subseqs.push((left_index, clauses.len()));
}
subseqs
}
fn compile_pred_subseq(&mut self, clauses: &'a [PredicateClause]) -> Code
{
let mut code_body = Vec::new();
let mut code_offsets = CodeOffsets::new();
let multi_clause = clauses.len() > 1;
for (i, clause) in clauses.iter().enumerate() {
self.marker.reset();
@@ -765,14 +1025,50 @@ impl<'a> CodeGenerator<'a> {
self.compile_rule(rule)
};
if multi_clause {
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_body.push(Line::Choice(choice));
}
clause.first_arg().map(|arg| {
let index = code_body.len();
code_offsets.index_term(arg, index);
});
code_body.append(&mut clause_code);
}
let mut code = Vec::new();
code_offsets.add_indices(&mut code, code_body);
code
}
pub fn compile_predicate(&mut self, clauses: &'a Vec<PredicateClause>) -> Code
{
let mut code = Vec::new();
let split_pred = Self::split_predicate(clauses);
let multi_seq = split_pred.len() > 1;
for &(l, r) in split_pred.iter() {
let mut code_segment = self.compile_pred_subseq(&clauses[l .. r]);
if multi_seq {
let choice = match l {
0 => ChoiceInstruction::TryMeElse(code_segment.len() + 1),
_ if r == clauses.len() => ChoiceInstruction::TrustMe,
_ => ChoiceInstruction::RetryMeElse(code_segment.len() + 1)
};
code.push(Line::Choice(choice));
code.append(&mut clause_code);
}
code.append(&mut code_segment);
}
code

View File

@@ -106,6 +106,19 @@ impl fmt::Display for ControlInstruction {
}
}
impl fmt::Display for IndexedChoiceInstruction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&IndexedChoiceInstruction::Try(offset) =>
write!(f, "try {}", offset),
&IndexedChoiceInstruction::Retry(offset) =>
write!(f, "retry {}", offset),
&IndexedChoiceInstruction::Trust(offset) =>
write!(f, "trust {}", offset)
}
}
}
impl fmt::Display for ChoiceInstruction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
@@ -119,6 +132,19 @@ impl fmt::Display for ChoiceInstruction {
}
}
impl fmt::Display for IndexingInstruction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&IndexingInstruction::SwitchOnTerm(v, c, l, s) =>
write!(f, "switch_on_term {}, {}, {}, {}", v, c, l, s),
&IndexingInstruction::SwitchOnConstant(num_cs, _) =>
write!(f, "switch_on_constant {}", num_cs),
&IndexingInstruction::SwitchOnStructure(num_ss, _) =>
write!(f, "switch_on_structure {}", num_ss)
}
}
}
impl fmt::Display for Level {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
@@ -176,6 +202,10 @@ pub fn print_code(code: &Code) {
println!("{}", choice),
&Line::Control(ref control) =>
println!("{}", control),
&Line::IndexedChoice(ref choice) =>
println!("{}", choice),
&Line::Indexing(ref indexing) =>
println!("{}", indexing),
&Line::Query(ref query) =>
for query_instr in query {
println!("{}", query_instr);

View File

@@ -106,8 +106,8 @@ impl<'a> Iterator for QueryIterator<'a> {
},
IteratorState::InitialCons(lvl, cell, head, tail) => {
self.push_final_cons(lvl, cell, head, tail);
self.push_subterm(Level::Deep, head);
self.push_subterm(Level::Deep, tail);
self.push_subterm(Level::Deep, head);
},
IteratorState::FinalCons(lvl, cell, head, tail) =>
return Some(TermRef::Cons(lvl, cell, head, tail)),

View File

@@ -110,7 +110,7 @@ impl Machine {
self.code_dir.insert((name, arity), p);
}
fn execute_instr<'a>(&mut self, instr_src: LineOrCodeOffset<'a>) -> bool
fn execute_instr<'b>(&mut self, instr_src: LineOrCodeOffset<'b>) -> bool
{
let mut instr = match instr_src {
LineOrCodeOffset::Instruction(instr) => instr,
@@ -121,6 +121,8 @@ impl Machine {
match instr {
&Line::Choice(ref choice_instr) =>
self.ms.execute_choice_instr(choice_instr),
&Line::Control(ref control_instr) =>
self.ms.execute_ctrl_instr(&self.code_dir, control_instr),
&Line::Fact(ref fact) => {
for fact_instr in fact {
if self.failed() {
@@ -131,6 +133,10 @@ impl Machine {
}
self.ms.p += 1;
},
&Line::Indexing(ref indexing_instr) =>
self.ms.execute_indexing_instr(&indexing_instr),
&Line::IndexedChoice(ref choice_instr) =>
self.ms.execute_indexed_choice_instr(choice_instr),
&Line::Query(ref query) => {
for query_instr in query {
if self.failed() {
@@ -140,9 +146,7 @@ impl Machine {
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() {
@@ -556,6 +560,8 @@ impl MachineState {
self.h += 1;
}
};
self.s += 1;
},
&FactInstruction::UnifyVariable(reg) => {
match self.mode {
@@ -640,6 +646,69 @@ impl MachineState {
};
}
fn execute_indexing_instr(&mut self, instr: &IndexingInstruction) {
match instr {
&IndexingInstruction::SwitchOnTerm(v, c, l, s) => {
let a1 = self.registers[1].clone();
let addr = self.store(self.deref(a1));
let offset = match addr {
Addr::HeapCell(_) | Addr::StackCell(_, _) => v,
Addr::Con(_) => c,
Addr::Lis(_) => l,
Addr::Str(_) => s
};
match offset {
0 => self.fail = true,
o => self.p += o
};
},
&IndexingInstruction::SwitchOnConstant(_, ref hm) => {
let a1 = self.registers[1].clone();
let addr = self.store(self.deref(a1));
let offset = match addr {
Addr::Con(constant) => {
match hm.get(&constant) {
Some(offset) => *offset,
_ => 0
}
},
_ => 0
};
match offset {
0 => self.fail = true,
o => self.p += o,
};
},
&IndexingInstruction::SwitchOnStructure(_, ref hm) => {
let a1 = self.registers[1].clone();
let addr = self.store(self.deref(a1));
let offset = match addr {
Addr::Str(s) => {
if let &HeapCellValue::NamedStr(arity, ref name) = &self.heap[s] {
match hm.get(&(name.clone(), arity)) {
Some(offset) => *offset,
_ => 0
}
} else {
0
}
},
_ => 0
};
match offset {
0 => self.fail = true,
o => self.p += o
};
}
};
}
fn execute_query_instr(&mut self, instr: &QueryInstruction) {
match instr {
&QueryInstruction::PutConstant(_, ref constant, reg) =>
@@ -782,6 +851,91 @@ impl MachineState {
};
}
fn execute_indexed_choice_instr(&mut self, instr: &IndexedChoiceInstruction)
{
match instr {
&IndexedChoiceInstruction::Try(l) => {
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 + 1,
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].clone();
}
self.hb = self.h;
self.p += l;
},
&IndexedChoiceInstruction::Retry(l) => {
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].clone();
}
self.e = self.or_stack[b].e;
self.cp = self.or_stack[b].cp;
self.or_stack[b].bp = self.p + 1;
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 += l;
},
&IndexedChoiceInstruction::Trust(l) => {
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].clone();
}
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 += l;
}
};
}
fn execute_choice_instr(&mut self, instr: &ChoiceInstruction)
{
match instr {

View File

@@ -12,7 +12,7 @@ pub TopLevel: TopLevel = {
};
Atom : Atom = {
r"[a-z][a-z0-9_]*" => <>.trim().to_string(),
r"[a-z][A-Za-z0-9_]*" => <>.trim().to_string(),
};
BoxedTerm : Box<Term> = {
@@ -73,5 +73,5 @@ Term : Term = {
};
Var : Var = {
r"[A-Z][a-z0-9_]*" => <>.trim().to_string()
r"[A-Z][A-Za-z0-9_]*" => <>.trim().to_string()
};

View File

@@ -21,8 +21,8 @@ mod __parse__TopLevel {
Term_22_5d_22(&'input str),
Term_22___22(&'input str),
Term_22_7c_22(&'input str),
Termr_23_22_5bA_2dZ_5d_5ba_2dz0_2d9___5d_2a_22_23(&'input str),
Termr_23_22_5ba_2dz_5d_5ba_2dz0_2d9___5d_2a_22_23(&'input str),
Termr_23_22_5bA_2dZ_5d_5bA_2dZa_2dz0_2d9___5d_2a_22_23(&'input str),
Termr_23_22_5ba_2dz_5d_5bA_2dZa_2dz0_2d9___5d_2a_22_23(&'input str),
Termerror(__lalrpop_util::ErrorRecovery<usize, (usize, &'input str), ()>),
Nt_28_22_2c_22_20_3cTerm_3e_29(Term),
Nt_28_22_2c_22_20_3cTerm_3e_29_2a(::std::vec::Vec<Term>),
@@ -719,8 +719,8 @@ mod __parse__TopLevel {
r###""]""###,
r###""_""###,
r###""|""###,
r###"r#"[A-Z][a-z0-9_]*"#"###,
r###"r#"[a-z][a-z0-9_]*"#"###,
r###"r#"[A-Z][A-Za-z0-9_]*"#"###,
r###"r#"[a-z][A-Za-z0-9_]*"#"###,
];
__ACTION[(__state * 14)..].iter().zip(__TERMINAL).filter_map(|(&state, terminal)| {
if state == 0 {
@@ -822,11 +822,11 @@ mod __parse__TopLevel {
_ => unreachable!(),
},
11 => match __lookahead.1 {
(11, __tok0) => __Symbol::Termr_23_22_5bA_2dZ_5d_5ba_2dz0_2d9___5d_2a_22_23(__tok0),
(11, __tok0) => __Symbol::Termr_23_22_5bA_2dZ_5d_5bA_2dZa_2dz0_2d9___5d_2a_22_23(__tok0),
_ => unreachable!(),
},
12 => match __lookahead.1 {
(12, __tok0) => __Symbol::Termr_23_22_5ba_2dz_5d_5ba_2dz0_2d9___5d_2a_22_23(__tok0),
(12, __tok0) => __Symbol::Termr_23_22_5ba_2dz_5d_5bA_2dZa_2dz0_2d9___5d_2a_22_23(__tok0),
_ => unreachable!(),
},
_ => unreachable!(),
@@ -1028,8 +1028,8 @@ mod __parse__TopLevel {
7
}
14 => {
// Atom = r#"[a-z][a-z0-9_]*"# => ActionFn(5);
let __sym0 = __pop_Termr_23_22_5ba_2dz_5d_5ba_2dz0_2d9___5d_2a_22_23(__symbols);
// Atom = r#"[a-z][A-Za-z0-9_]*"# => ActionFn(5);
let __sym0 = __pop_Termr_23_22_5ba_2dz_5d_5bA_2dZa_2dz0_2d9___5d_2a_22_23(__symbols);
let __start = __sym0.0.clone();
let __end = __sym0.2.clone();
let __nt = super::__action5::<>(input, __sym0);
@@ -1333,8 +1333,8 @@ mod __parse__TopLevel {
17
}
39 => {
// Var = r#"[A-Z][a-z0-9_]*"# => ActionFn(23);
let __sym0 = __pop_Termr_23_22_5bA_2dZ_5d_5ba_2dz0_2d9___5d_2a_22_23(__symbols);
// Var = r#"[A-Z][A-Za-z0-9_]*"# => ActionFn(23);
let __sym0 = __pop_Termr_23_22_5bA_2dZ_5d_5bA_2dZa_2dz0_2d9___5d_2a_22_23(__symbols);
let __start = __sym0.0.clone();
let __end = __sym0.2.clone();
let __nt = super::__action23::<>(input, __sym0);
@@ -1468,23 +1468,23 @@ mod __parse__TopLevel {
_ => panic!("symbol type mismatch")
}
}
fn __pop_Termr_23_22_5bA_2dZ_5d_5ba_2dz0_2d9___5d_2a_22_23<
fn __pop_Termr_23_22_5bA_2dZ_5d_5bA_2dZa_2dz0_2d9___5d_2a_22_23<
'input,
>(
__symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>
) -> (usize, &'input str, usize) {
match __symbols.pop().unwrap() {
(__l, __Symbol::Termr_23_22_5bA_2dZ_5d_5ba_2dz0_2d9___5d_2a_22_23(__v), __r) => (__l, __v, __r),
(__l, __Symbol::Termr_23_22_5bA_2dZ_5d_5bA_2dZa_2dz0_2d9___5d_2a_22_23(__v), __r) => (__l, __v, __r),
_ => panic!("symbol type mismatch")
}
}
fn __pop_Termr_23_22_5ba_2dz_5d_5ba_2dz0_2d9___5d_2a_22_23<
fn __pop_Termr_23_22_5ba_2dz_5d_5bA_2dZa_2dz0_2d9___5d_2a_22_23<
'input,
>(
__symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>
) -> (usize, &'input str, usize) {
match __symbols.pop().unwrap() {
(__l, __Symbol::Termr_23_22_5ba_2dz_5d_5ba_2dz0_2d9___5d_2a_22_23(__v), __r) => (__l, __v, __r),
(__l, __Symbol::Termr_23_22_5ba_2dz_5d_5bA_2dZa_2dz0_2d9___5d_2a_22_23(__v), __r) => (__l, __v, __r),
_ => panic!("symbol type mismatch")
}
}
@@ -1845,6 +1845,11 @@ mod __intern_token {
__current_state = 16;
continue;
}
65 ... 90 => {
__current_match = Some((11, __index + __ch.len_utf8()));
__current_state = 16;
continue;
}
95 => /* '_' */ {
__current_match = Some((11, __index + 1));
__current_state = 16;
@@ -1897,6 +1902,11 @@ mod __intern_token {
__current_state = 18;
continue;
}
65 ... 90 => {
__current_match = Some((12, __index + __ch.len_utf8()));
__current_state = 18;
continue;
}
95 => /* '_' */ {
__current_match = Some((12, __index + 1));
__current_state = 18;
@@ -1952,6 +1962,11 @@ mod __intern_token {
__current_state = 16;
continue;
}
65 ... 90 => {
__current_match = Some((11, __index + __ch.len_utf8()));
__current_state = 16;
continue;
}
95 => /* '_' */ {
__current_match = Some((11, __index + 1));
__current_state = 16;
@@ -1983,6 +1998,11 @@ mod __intern_token {
__current_state = 18;
continue;
}
65 ... 90 => {
__current_match = Some((12, __index + __ch.len_utf8()));
__current_state = 18;
continue;
}
95 => /* '_' */ {
__current_match = Some((12, __index + 1));
__current_state = 18;