optimized up to chapter 6
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -1,6 +1,6 @@
|
||||
[root]
|
||||
name = "rusty-wam"
|
||||
version = "0.5.11"
|
||||
version = "0.5.12"
|
||||
dependencies = [
|
||||
"lalrpop 0.12.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lalrpop-util 0.12.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "rusty-wam"
|
||||
version = "0.5.11"
|
||||
version = "0.5.12"
|
||||
authors = ["Mark Thom"]
|
||||
|
||||
build = "build.rs"
|
||||
@@ -12,5 +12,4 @@ version = "1.2.0"
|
||||
version = "0.12.5"
|
||||
|
||||
[build-dependencies.lalrpop]
|
||||
version = "0.12.5"
|
||||
|
||||
version = "0.12.5"
|
||||
10
README.md
10
README.md
@@ -8,11 +8,11 @@ pure Prolog.
|
||||
|
||||
## Progress
|
||||
|
||||
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.10, skipping past 5.4. Atoms and lists are the only
|
||||
two data types currently supported.
|
||||
Prolog is implemented as a simple REPL. It is without without meta- or
|
||||
extra-logical operators, or side effects of any kind, with the lone
|
||||
exception of cut. In terms of the tutorial pacing, the work has
|
||||
progressed to the end of section 5.11, 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
|
||||
generator, it has no effect on the bytecode WAM, which lacks
|
||||
|
||||
81
src/main.rs
81
src/main.rs
@@ -194,6 +194,87 @@ mod tests {
|
||||
assert_eq!(submit(&mut wam, "?- p(X).").failed_query(), false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_queries_on_cuts() {
|
||||
let mut wam = Machine::new();
|
||||
|
||||
// test shallow cuts.
|
||||
submit(&mut wam, "memberchk(X, [X|_]) :- !.
|
||||
memberchk(X, [_|Xs]) :- !, memberchk(X, Xs).");
|
||||
|
||||
assert_eq!(submit(&mut wam, "?- memberchk(X, [a,b,c]).").failed_query(), false);
|
||||
assert_eq!(submit(&mut wam, "?- memberchk([X,X], [a,b,c,[d,e],[d,d]]).").failed_query(), false);
|
||||
assert_eq!(submit(&mut wam, "?- memberchk([X,X], [a,b,c,[D,d],[e,e]]).").failed_query(), false);
|
||||
assert_eq!(submit(&mut wam, "?- memberchk([X,X], [a,b,c,[e,d],[f,e]]).").failed_query(), true);
|
||||
assert_eq!(submit(&mut wam, "?- memberchk([X,X,Y], [a,b,c,[e,d],[f,e]]).").failed_query(), true);
|
||||
assert_eq!(submit(&mut wam, "?- memberchk([X,X,Y], [a,b,c,[e,e,d],[f,e]]).").failed_query(), false);
|
||||
|
||||
// test deep cuts.
|
||||
submit(&mut wam, "commit :- a, !.");
|
||||
|
||||
assert_eq!(submit(&mut wam, "?- commit.").failed_query(), true);
|
||||
|
||||
submit(&mut wam, "a.");
|
||||
|
||||
assert_eq!(submit(&mut wam, "?- commit.").failed_query(), false);
|
||||
|
||||
submit(&mut wam, "commit(X) :- a(X), !.");
|
||||
|
||||
assert_eq!(submit(&mut wam, "?- commit(X).").failed_query(), true);
|
||||
|
||||
submit(&mut wam, "a(x).");
|
||||
|
||||
assert_eq!(submit(&mut wam, "?- commit(X).").failed_query(), false);
|
||||
|
||||
submit(&mut wam, "a :- b, !, c. a :- d.");
|
||||
|
||||
assert_eq!(submit(&mut wam, "?- a.").failed_query(), true);
|
||||
|
||||
submit(&mut wam, "b.");
|
||||
|
||||
assert_eq!(submit(&mut wam, "?- a.").failed_query(), true);
|
||||
|
||||
submit(&mut wam, "d.");
|
||||
|
||||
// we've committed to the first clause since the query on b
|
||||
// succeeds, so we expect failure here.
|
||||
assert_eq!(submit(&mut wam, "?- a.").failed_query(), true);
|
||||
|
||||
submit(&mut wam, "c.");
|
||||
|
||||
assert_eq!(submit(&mut wam, "?- a.").failed_query(), false);
|
||||
|
||||
submit(&mut wam, "a(X) :- b, !, c(X). a(X) :- d(X).");
|
||||
|
||||
assert_eq!(submit(&mut wam, "?- a(X).").failed_query(), true);
|
||||
|
||||
submit(&mut wam, "c(c).");
|
||||
submit(&mut wam, "d(d).");
|
||||
|
||||
assert_eq!(submit(&mut wam, "?- a(X).").failed_query(), false);
|
||||
|
||||
submit(&mut wam, "b.");
|
||||
|
||||
assert_eq!(submit(&mut wam, "?- a(X).").failed_query(), false);
|
||||
|
||||
wam.clear();
|
||||
|
||||
assert_eq!(submit(&mut wam, "?- c(X).").failed_query(), true);
|
||||
|
||||
submit(&mut wam, "a(X) :- b, c(X), !. a(X) :- d(X).");
|
||||
submit(&mut wam, "b.");
|
||||
|
||||
assert_eq!(submit(&mut wam, "?- a(X).").failed_query(), true);
|
||||
|
||||
submit(&mut wam, "d(d).");
|
||||
|
||||
assert_eq!(submit(&mut wam, "?- a(X).").failed_query(), false);
|
||||
|
||||
submit(&mut wam, "c(c).");
|
||||
|
||||
assert_eq!(submit(&mut wam, "?- a(X).").failed_query(), false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_queries_on_lists() {
|
||||
let mut wam = Machine::new();
|
||||
|
||||
@@ -5,6 +5,7 @@ use std::vec::Vec;
|
||||
|
||||
pub struct Frame {
|
||||
pub global_index: usize,
|
||||
pub b0: usize,
|
||||
pub e: usize,
|
||||
pub cp: CodePtr,
|
||||
perms: Vec<Addr>
|
||||
@@ -14,6 +15,7 @@ impl Frame {
|
||||
fn new(global_index: usize, e: usize, cp: CodePtr, n: usize) -> Self {
|
||||
Frame {
|
||||
global_index: global_index,
|
||||
b0: 0,
|
||||
e: e,
|
||||
cp: cp,
|
||||
perms: vec![Addr::HeapCell(0); n]
|
||||
|
||||
@@ -119,13 +119,27 @@ pub enum Term {
|
||||
Var(Cell<VarReg>, Var)
|
||||
}
|
||||
|
||||
pub struct Rule {
|
||||
pub head: (Term, Term),
|
||||
pub clauses: Vec<Term>
|
||||
pub enum TermOrCut {
|
||||
Cut,
|
||||
Term(Term)
|
||||
}
|
||||
|
||||
impl Rule {
|
||||
pub fn last_clause(&self) -> &Term {
|
||||
impl TermOrCut {
|
||||
pub fn arity(&self) -> usize {
|
||||
match self {
|
||||
&TermOrCut::Term(ref term) => term.arity(),
|
||||
_ => 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Rule {
|
||||
pub head: (Term, TermOrCut),
|
||||
pub clauses: Vec<TermOrCut>
|
||||
}
|
||||
|
||||
impl Rule {
|
||||
pub fn last_clause(&self) -> &TermOrCut {
|
||||
match self.clauses.last() {
|
||||
None => &self.head.1,
|
||||
Some(clause) => clause
|
||||
@@ -141,12 +155,22 @@ pub enum TermRef<'a> {
|
||||
Var(Level, &'a Cell<VarReg>, &'a Var)
|
||||
}
|
||||
|
||||
pub enum ChoiceInstruction {
|
||||
RetryMeElse(usize),
|
||||
TrustMe,
|
||||
pub enum ChoiceInstruction {
|
||||
RetryMeElse(usize),
|
||||
TrustMe,
|
||||
TryMeElse(usize)
|
||||
}
|
||||
|
||||
pub enum Terminal {
|
||||
Terminal, Non
|
||||
}
|
||||
|
||||
pub enum CutInstruction {
|
||||
Cut(Terminal),
|
||||
GetLevel,
|
||||
NeckCut(Terminal)
|
||||
}
|
||||
|
||||
pub enum IndexedChoiceInstruction {
|
||||
Retry(usize),
|
||||
Trust(usize),
|
||||
@@ -223,6 +247,7 @@ pub type CompiledQuery = Vec<QueryInstruction>;
|
||||
pub enum Line {
|
||||
Choice(ChoiceInstruction),
|
||||
Control(ControlInstruction),
|
||||
Cut(CutInstruction),
|
||||
Fact(CompiledFact),
|
||||
Indexing(IndexingInstruction),
|
||||
IndexedChoice(IndexedChoiceInstruction),
|
||||
@@ -373,18 +398,18 @@ impl Term {
|
||||
match self {
|
||||
&Term::Clause(_, _, ref terms) =>
|
||||
terms.first().map(|bt| bt.as_ref()),
|
||||
_ => None
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn is_clause(&self) -> bool {
|
||||
if let &Term::Clause(_, _, _) = self {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub fn subterms(&self) -> usize {
|
||||
match self {
|
||||
&Term::Clause(_, _, ref terms) => terms.len(),
|
||||
|
||||
@@ -441,9 +441,9 @@ impl CodeOffsets {
|
||||
IntIndex::External(o) => o + prelude_len + 1,
|
||||
IntIndex::Fail => 0,
|
||||
IntIndex::Internal(_) => prelude_len - lst_offset + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn add_indices(self, code: &mut Code, mut code_body: Code)
|
||||
{
|
||||
if self.no_indices() {
|
||||
@@ -470,11 +470,11 @@ impl CodeOffsets {
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let str_loc = Self::switch_on_str_offset_from(str_loc, prelude.len(), con_loc);
|
||||
let con_loc = Self::switch_on_con_offset_from(con_loc, prelude.len());
|
||||
let lst_loc = Self::switch_on_lst_offset_from(lst_loc, prelude.len(), lst_offset);
|
||||
|
||||
|
||||
let switch_instr = IndexingInstruction::SwitchOnTerm(prelude.len() + 1,
|
||||
con_loc,
|
||||
lst_loc,
|
||||
@@ -752,21 +752,40 @@ impl<'a> CodeGenerator<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn mark_perm_vars(rule: &'a Rule) -> VariableFixtures {
|
||||
fn mark_perm_vars(rule: &'a Rule) -> (VariableFixtures, bool)
|
||||
{
|
||||
let &Rule { head: (ref p0, ref p1), ref clauses } = rule;
|
||||
let mut vs = HashMap::new();
|
||||
|
||||
let iter = p0.breadth_first_iter().chain(p1.breadth_first_iter());
|
||||
|
||||
Self::mark_vars_in_term(iter, &mut vs, 0);
|
||||
|
||||
for (i, term) in clauses.iter().enumerate() {
|
||||
Self::mark_vars_in_term(term.breadth_first_iter(), &mut vs, i + 1);
|
||||
let mut vs = HashMap::new();
|
||||
|
||||
match p1 {
|
||||
&TermOrCut::Cut => {
|
||||
let iter = p0.breadth_first_iter();
|
||||
Self::mark_vars_in_term(iter, &mut vs, 0);
|
||||
},
|
||||
&TermOrCut::Term(ref p1) => {
|
||||
let iter = p0.breadth_first_iter().chain(p1.breadth_first_iter());
|
||||
Self::mark_vars_in_term(iter, &mut vs, 0);
|
||||
}
|
||||
}
|
||||
|
||||
for (i, term) in clauses.iter().enumerate() {
|
||||
if let &TermOrCut::Term(ref term) = term {
|
||||
Self::mark_vars_in_term(term.breadth_first_iter(), &mut vs, i + 1)
|
||||
}
|
||||
}
|
||||
|
||||
let mut deep_cuts = false;
|
||||
|
||||
for term in clauses {
|
||||
if let &TermOrCut::Cut = term {
|
||||
deep_cuts = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Self::set_perm_vals(&vs);
|
||||
|
||||
vs
|
||||
(vs, deep_cuts)
|
||||
}
|
||||
|
||||
fn add_conditional_call(compiled_query: &mut Code, term: &Term, pvs: usize)
|
||||
@@ -787,8 +806,8 @@ impl<'a> CodeGenerator<'a> {
|
||||
fn vars_above_threshold(vs: &VariableFixtures, index: usize) -> usize {
|
||||
let mut var_count = 0;
|
||||
|
||||
for &(term_status, _) in vs.values() {
|
||||
if let VarStatus::Permanent(i) = term_status {
|
||||
for &(var_status, _) in vs.values() {
|
||||
if let VarStatus::Permanent(i) = var_status {
|
||||
if i > index {
|
||||
var_count += 1;
|
||||
}
|
||||
@@ -803,8 +822,8 @@ impl<'a> CodeGenerator<'a> {
|
||||
let mut dealloc_index = body.len() - 1;
|
||||
|
||||
match rule.last_clause() {
|
||||
&Term::Clause(_, ref name, _)
|
||||
| &Term::Constant(_, Constant::Atom(ref name)) => {
|
||||
&TermOrCut::Term(Term::Clause(_, ref name, _))
|
||||
| &TermOrCut::Term(Term::Constant(_, Constant::Atom(ref name))) => {
|
||||
if let &mut Line::Control(ref mut ctrl) = body.last_mut().unwrap() {
|
||||
*ctrl = ControlInstruction::Execute(name.clone(), last_arity);
|
||||
}
|
||||
@@ -863,8 +882,9 @@ impl<'a> CodeGenerator<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compile_rule(&mut self, rule: &'a Rule) -> Code {
|
||||
let vs = Self::mark_perm_vars(&rule);
|
||||
pub fn compile_rule(&mut self, rule: &'a Rule) -> Code
|
||||
{
|
||||
let (vs, deep_cuts) = Self::mark_perm_vars(&rule);
|
||||
let &Rule { head: (ref p0, ref p1), ref clauses } = rule;
|
||||
|
||||
let perm_vars = Self::vars_above_threshold(&vs, 0);
|
||||
@@ -872,23 +892,63 @@ impl<'a> CodeGenerator<'a> {
|
||||
|
||||
if clauses.len() > 0 {
|
||||
body.push(Line::Control(ControlInstruction::Allocate(perm_vars)));
|
||||
|
||||
if deep_cuts {
|
||||
body.push(Line::Cut(CutInstruction::GetLevel));
|
||||
}
|
||||
}
|
||||
|
||||
let iter = p0.breadth_first_iter().chain(p1.breadth_first_iter());
|
||||
self.update_var_count(iter);
|
||||
match p1 {
|
||||
&TermOrCut::Cut => {
|
||||
let iter = p0.breadth_first_iter();
|
||||
self.update_var_count(iter);
|
||||
},
|
||||
&TermOrCut::Term(ref p1) => {
|
||||
let iter = p0.breadth_first_iter().chain(p1.breadth_first_iter());
|
||||
self.update_var_count(iter);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
self.marker.advance(p0);
|
||||
body.push(Line::Fact(self.compile_target(p0, false)));
|
||||
|
||||
self.marker.advance_at_head(p1);
|
||||
body.push(Line::Query(self.compile_target(p1, false)));
|
||||
if p0.is_clause() {
|
||||
body.push(Line::Fact(self.compile_target(p0, false)));
|
||||
}
|
||||
|
||||
Self::add_conditional_call(&mut body, p1, perm_vars);
|
||||
match p1 {
|
||||
&TermOrCut::Cut => {
|
||||
let term = if clauses.is_empty() {
|
||||
Terminal::Terminal
|
||||
} else {
|
||||
Terminal::Non
|
||||
};
|
||||
|
||||
body.push(Line::Cut(CutInstruction::NeckCut(term)));
|
||||
},
|
||||
&TermOrCut::Term(ref p1) => {
|
||||
self.marker.advance_at_head(p1);
|
||||
|
||||
if p1.is_clause() {
|
||||
body.push(Line::Query(self.compile_target(p1, false)));
|
||||
}
|
||||
|
||||
Self::add_conditional_call(&mut body, p1, perm_vars);
|
||||
}
|
||||
};
|
||||
|
||||
body = clauses.iter().enumerate()
|
||||
.map(|(i, term)| {
|
||||
let num_vars = Self::vars_above_threshold(&vs, i+1);
|
||||
self.compile_internal_query(term, num_vars)
|
||||
match term {
|
||||
&TermOrCut::Cut if i + 1 < clauses.len() =>
|
||||
vec![Line::Cut(CutInstruction::Cut(Terminal::Non))],
|
||||
&TermOrCut::Cut =>
|
||||
vec![Line::Cut(CutInstruction::Cut(Terminal::Terminal))],
|
||||
&TermOrCut::Term(ref term) => {
|
||||
let num_vars = Self::vars_above_threshold(&vs, i + 1);
|
||||
self.compile_internal_query(term, num_vars)
|
||||
}
|
||||
}
|
||||
})
|
||||
.fold(body, |mut body, ref mut cqs| {
|
||||
body.append(cqs);
|
||||
|
||||
@@ -145,6 +145,19 @@ impl fmt::Display for IndexingInstruction {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for CutInstruction {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&CutInstruction::Cut(_) =>
|
||||
write!(f, "cut"),
|
||||
&CutInstruction::NeckCut(_) =>
|
||||
write!(f, "neck_cut"),
|
||||
&CutInstruction::GetLevel =>
|
||||
write!(f, "get_level")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Level {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
@@ -198,6 +211,8 @@ pub fn print_code(code: &Code) {
|
||||
for fact_instr in fact {
|
||||
println!("{}", fact_instr);
|
||||
},
|
||||
&Line::Cut(ref cut) =>
|
||||
println!("{}", cut),
|
||||
&Line::Choice(ref choice) =>
|
||||
println!("{}", choice),
|
||||
&Line::Control(ref control) =>
|
||||
|
||||
@@ -19,6 +19,7 @@ struct MachineState {
|
||||
s: usize,
|
||||
p: CodePtr,
|
||||
b: usize,
|
||||
b0: usize,
|
||||
e: usize,
|
||||
num_of_args: usize,
|
||||
cp: CodePtr,
|
||||
@@ -82,7 +83,7 @@ impl Machine {
|
||||
|
||||
pub fn add_fact(&mut self, fact: &Term, mut code: Code) {
|
||||
if let Some(name) = fact.name() {
|
||||
let p = self.code.len();
|
||||
let p = self.code.len();
|
||||
let arity = fact.arity();
|
||||
|
||||
self.code.append(&mut code);
|
||||
@@ -121,6 +122,8 @@ impl Machine {
|
||||
match instr {
|
||||
&Line::Choice(ref choice_instr) =>
|
||||
self.ms.execute_choice_instr(choice_instr),
|
||||
&Line::Cut(ref cut_instr) =>
|
||||
self.ms.execute_cut_instr(cut_instr),
|
||||
&Line::Control(ref control_instr) =>
|
||||
self.ms.execute_ctrl_instr(&self.code_dir, control_instr),
|
||||
&Line::Fact(ref fact) => {
|
||||
@@ -132,7 +135,7 @@ impl Machine {
|
||||
self.ms.execute_fact_instr(&fact_instr);
|
||||
}
|
||||
self.ms.p += 1;
|
||||
},
|
||||
},
|
||||
&Line::Indexing(ref indexing_instr) =>
|
||||
self.ms.execute_indexing_instr(&indexing_instr),
|
||||
&Line::IndexedChoice(ref choice_instr) =>
|
||||
@@ -146,21 +149,29 @@ impl Machine {
|
||||
self.ms.execute_query_instr(&query_instr);
|
||||
}
|
||||
self.ms.p += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if self.failed() {
|
||||
let p = self.ms
|
||||
.or_stack
|
||||
.top()
|
||||
.map(|fr| fr.bp)
|
||||
.unwrap_or_default();
|
||||
let b0 = self.ms
|
||||
.or_stack
|
||||
.top()
|
||||
.map(|fr| fr.b0)
|
||||
.unwrap_or(0);
|
||||
|
||||
let p = if self.ms.b > 0 {
|
||||
let b = self.ms.b - 1;
|
||||
self.ms.or_stack[b].bp
|
||||
} else {
|
||||
CodePtr::TopLevel
|
||||
};
|
||||
|
||||
if let CodePtr::TopLevel = p {
|
||||
return false;
|
||||
} else {
|
||||
self.ms.fail = false;
|
||||
self.ms.p = p;
|
||||
self.ms.b0 = b0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,7 +278,11 @@ impl Machine {
|
||||
pub fn continue_query(&mut self) -> EvalResult
|
||||
{
|
||||
if !self.or_stack_is_empty() {
|
||||
let b = self.ms.b;
|
||||
if self.ms.b == 0 {
|
||||
return EvalResult::QueryFailure;
|
||||
}
|
||||
|
||||
let b = self.ms.b - 1;
|
||||
self.ms.p = self.ms.or_stack[b].bp;
|
||||
|
||||
let succeeded = if let CodePtr::DirEntry(p) = self.ms.p {
|
||||
@@ -286,6 +301,13 @@ impl Machine {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn clear(&mut self) {
|
||||
self.reset();
|
||||
self.code.clear();
|
||||
self.code_dir.clear();
|
||||
}
|
||||
|
||||
pub fn reset(&mut self) {
|
||||
self.ms.reset();
|
||||
}
|
||||
@@ -297,6 +319,7 @@ impl MachineState {
|
||||
s: 0,
|
||||
p: CodePtr::TopLevel,
|
||||
b: 0,
|
||||
b0: 0,
|
||||
e: 0,
|
||||
num_of_args: 0,
|
||||
cp: CodePtr::TopLevel,
|
||||
@@ -419,7 +442,12 @@ impl MachineState {
|
||||
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
|
||||
if self.b > 0 {
|
||||
let b = self.b - 1;
|
||||
self.or_stack[b].global_index
|
||||
} else {
|
||||
0
|
||||
}
|
||||
} else {
|
||||
0
|
||||
};
|
||||
@@ -443,6 +471,48 @@ impl MachineState {
|
||||
}
|
||||
}
|
||||
|
||||
fn tidy_trail(&mut self) {
|
||||
if self.b == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
let b = self.b - 1;
|
||||
let mut i = self.or_stack[b].tr;
|
||||
|
||||
while i < self.tr {
|
||||
let tr_i = self.trail[i];
|
||||
let hb = self.hb;
|
||||
|
||||
match tr_i {
|
||||
Ref::HeapCell(tr_i) =>
|
||||
if tr_i < hb { //|| ((h < tr_i) && tr_i < b) {
|
||||
i += 1;
|
||||
} else {
|
||||
let tr = self.tr;
|
||||
let val = self.trail[tr - 1];
|
||||
self.trail[i] = val;
|
||||
},
|
||||
Ref::StackCell(fr, _) => {
|
||||
let b = self.b - 1;
|
||||
let fr_gi = self.and_stack[fr].global_index;
|
||||
let b_gi = if !self.or_stack.is_empty() {
|
||||
self.or_stack[b].global_index
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
if fr_gi < b_gi {
|
||||
i += 1;
|
||||
} else {
|
||||
let tr = self.tr;
|
||||
let val = self.trail[tr - 1];
|
||||
self.trail[i] = val;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn execute_fact_instr(&mut self, instr: &FactInstruction) {
|
||||
match instr {
|
||||
&FactInstruction::GetConstant(_, ref constant, reg) => {
|
||||
@@ -703,12 +773,12 @@ impl MachineState {
|
||||
|
||||
match offset {
|
||||
0 => self.fail = true,
|
||||
o => self.p += o
|
||||
};
|
||||
o => self.p += o
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
fn execute_query_instr(&mut self, instr: &QueryInstruction) {
|
||||
match instr {
|
||||
&QueryInstruction::PutConstant(_, ref constant, reg) =>
|
||||
@@ -821,6 +891,7 @@ impl MachineState {
|
||||
Some(compiled_tl_index) => {
|
||||
self.cp = self.p + 1;
|
||||
self.num_of_args = arity;
|
||||
self.b0 = self.b;
|
||||
self.p = CodePtr::DirEntry(compiled_tl_index);
|
||||
},
|
||||
None => self.fail = true
|
||||
@@ -841,7 +912,8 @@ impl MachineState {
|
||||
match compiled_tl_index {
|
||||
Some(compiled_tl_index) => {
|
||||
self.num_of_args = arity;
|
||||
self.p = CodePtr::DirEntry(compiled_tl_index);
|
||||
self.b0 = self.b;
|
||||
self.p = CodePtr::DirEntry(compiled_tl_index);
|
||||
},
|
||||
None => self.fail = true
|
||||
};
|
||||
@@ -865,10 +937,11 @@ impl MachineState {
|
||||
self.p + 1,
|
||||
self.tr,
|
||||
self.h,
|
||||
self.b0,
|
||||
self.num_of_args);
|
||||
|
||||
self.b = self.or_stack.len() - 1;
|
||||
let b = self.b;
|
||||
self.b = self.or_stack.len();
|
||||
let b = self.b - 1;
|
||||
|
||||
for i in 1 .. n + 1 {
|
||||
self.or_stack[b][i] = self.registers[i].clone();
|
||||
@@ -878,7 +951,7 @@ impl MachineState {
|
||||
self.p += l;
|
||||
},
|
||||
&IndexedChoiceInstruction::Retry(l) => {
|
||||
let b = self.b;
|
||||
let b = self.b - 1;
|
||||
let n = self.or_stack[b].num_args();
|
||||
|
||||
for i in 1 .. n + 1 {
|
||||
@@ -905,7 +978,7 @@ impl MachineState {
|
||||
self.p += l;
|
||||
},
|
||||
&IndexedChoiceInstruction::Trust(l) => {
|
||||
let b = self.b;
|
||||
let b = self.b - 1;
|
||||
let n = self.or_stack[b].num_args();
|
||||
|
||||
for i in 1 .. n + 1 {
|
||||
@@ -935,10 +1008,10 @@ impl MachineState {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
fn execute_choice_instr(&mut self, instr: &ChoiceInstruction)
|
||||
{
|
||||
match instr {
|
||||
match instr {
|
||||
&ChoiceInstruction::TryMeElse(offset) => {
|
||||
let n = self.num_of_args;
|
||||
let num_frames = self.num_frames();
|
||||
@@ -950,10 +1023,11 @@ impl MachineState {
|
||||
self.p + offset,
|
||||
self.tr,
|
||||
self.h,
|
||||
self.b0,
|
||||
self.num_of_args);
|
||||
|
||||
self.b = self.or_stack.len() - 1;
|
||||
let b = self.b;
|
||||
self.b = self.or_stack.len();
|
||||
let b = self.b - 1;
|
||||
|
||||
for i in 1 .. n + 1 {
|
||||
self.or_stack[b][i] = self.registers[i].clone();
|
||||
@@ -961,9 +1035,9 @@ impl MachineState {
|
||||
|
||||
self.hb = self.h;
|
||||
self.p += 1;
|
||||
},
|
||||
},
|
||||
&ChoiceInstruction::RetryMeElse(offset) => {
|
||||
let b = self.b;
|
||||
let b = self.b - 1;
|
||||
let n = self.or_stack[b].num_args();
|
||||
|
||||
for i in 1 .. n + 1 {
|
||||
@@ -990,7 +1064,7 @@ impl MachineState {
|
||||
self.p += 1;
|
||||
},
|
||||
&ChoiceInstruction::TrustMe => {
|
||||
let b = self.b;
|
||||
let b = self.b - 1;
|
||||
let n = self.or_stack[b].num_args();
|
||||
|
||||
for i in 1 .. n + 1 {
|
||||
@@ -1021,11 +1095,55 @@ impl MachineState {
|
||||
}
|
||||
}
|
||||
|
||||
fn execute_cut_instr(&mut self, instr: &CutInstruction) {
|
||||
match instr {
|
||||
&CutInstruction::Cut(ref term) => {
|
||||
let b = self.b;
|
||||
let e = self.e;
|
||||
let b0 = self.and_stack[e].b0; // STACK[E+2+1]
|
||||
|
||||
if b > b0 {
|
||||
self.b = b0;
|
||||
self.tidy_trail();
|
||||
}
|
||||
|
||||
if let &Terminal::Terminal = term {
|
||||
self.p = CodePtr::TopLevel;
|
||||
} else {
|
||||
self.p += 1;
|
||||
}
|
||||
},
|
||||
&CutInstruction::GetLevel => {
|
||||
let b0 = self.b0;
|
||||
let e = self.e;
|
||||
|
||||
self.and_stack[e].b0 = b0;
|
||||
self.p += 1;
|
||||
},
|
||||
&CutInstruction::NeckCut(ref term) => {
|
||||
let b = self.b;
|
||||
let b0 = self.b0;
|
||||
|
||||
if b > b0 {
|
||||
self.b = b0;
|
||||
self.tidy_trail();
|
||||
}
|
||||
|
||||
if let &Terminal::Terminal = term {
|
||||
self.p = CodePtr::TopLevel;
|
||||
} else {
|
||||
self.p += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn reset(&mut self) {
|
||||
self.h = 0;
|
||||
self.hb = 0;
|
||||
self.e = 0;
|
||||
self.b = 0;
|
||||
self.b0 = 0;
|
||||
self.s = 0;
|
||||
self.tr = 0;
|
||||
self.p = CodePtr::TopLevel;
|
||||
@@ -1039,5 +1157,5 @@ impl MachineState {
|
||||
self.and_stack.clear();
|
||||
self.or_stack.clear();
|
||||
self.registers = vec![Addr::HeapCell(0); 64];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,10 +7,11 @@ pub struct Frame {
|
||||
pub global_index: usize,
|
||||
pub e: usize,
|
||||
pub cp: CodePtr,
|
||||
pub b: usize,
|
||||
pub b: usize,
|
||||
pub bp: CodePtr,
|
||||
pub tr: usize,
|
||||
pub h: usize,
|
||||
pub b0: usize,
|
||||
args: Vec<Addr>
|
||||
}
|
||||
|
||||
@@ -22,6 +23,7 @@ impl Frame {
|
||||
bp: CodePtr,
|
||||
tr: usize,
|
||||
h: usize,
|
||||
b0: usize,
|
||||
n: usize)
|
||||
-> Self
|
||||
{
|
||||
@@ -33,6 +35,7 @@ impl Frame {
|
||||
bp: bp,
|
||||
tr: tr,
|
||||
h: h,
|
||||
b0: b0,
|
||||
args: vec![Addr::HeapCell(0); n]
|
||||
}
|
||||
}
|
||||
@@ -57,9 +60,10 @@ impl OrStack {
|
||||
bp: CodePtr,
|
||||
tr: usize,
|
||||
h: usize,
|
||||
b0: usize,
|
||||
n: usize)
|
||||
{
|
||||
self.0.push(Frame::new(global_index, e, cp, b, bp, tr, h, n));
|
||||
self.0.push(Frame::new(global_index, e, cp, b, bp, tr, h, b0, n));
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
|
||||
@@ -57,19 +57,25 @@ PredicateClause : PredicateClause = {
|
||||
};
|
||||
|
||||
Rule : Rule = {
|
||||
<c:Clause> ":-" <h:Term> <cs: ("," <Term>)*> =>
|
||||
<c:Clause> ":-" <h:TermOrCut> <cs: ("," <TermOrCut>)*> =>
|
||||
Rule { head: (c, h), clauses: cs },
|
||||
<a:Atom> ":-" <h:Term> <cs: ("," <Term>)*> =>
|
||||
Rule { head: (Term::Constant(Cell::default(), Constant::Atom(a)), h),
|
||||
<a:Atom> ":-" <h:TermOrCut> <cs: ("," <TermOrCut>)*> =>
|
||||
Rule { head: (Term::Constant(Cell::default(), Constant::Atom(a)),
|
||||
h),
|
||||
clauses: cs }
|
||||
};
|
||||
|
||||
TermOrCut : TermOrCut = {
|
||||
"!" => TermOrCut::Cut,
|
||||
<Term> => TermOrCut::Term(<>)
|
||||
};
|
||||
|
||||
Term : Term = {
|
||||
<Atom> => Term::Constant(Cell::default(), Constant::Atom(<>)),
|
||||
<Clause> => <>,
|
||||
<List> => <>,
|
||||
<Var> => Term::Var(Cell::default(), <>),
|
||||
"_" => Term::AnonVar
|
||||
"_" => Term::AnonVar
|
||||
};
|
||||
|
||||
Var : Var = {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user