optimized up to chapter 6

This commit is contained in:
Mark Thom
2017-04-09 19:12:36 -06:00
parent d2cf8626a1
commit 19ee43e186
12 changed files with 1132 additions and 726 deletions

2
Cargo.lock generated
View File

@@ -1,6 +1,6 @@
[root] [root]
name = "rusty-wam" name = "rusty-wam"
version = "0.5.11" version = "0.5.12"
dependencies = [ dependencies = [
"lalrpop 0.12.5 (registry+https://github.com/rust-lang/crates.io-index)", "lalrpop 0.12.5 (registry+https://github.com/rust-lang/crates.io-index)",
"lalrpop-util 0.12.5 (registry+https://github.com/rust-lang/crates.io-index)", "lalrpop-util 0.12.5 (registry+https://github.com/rust-lang/crates.io-index)",

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "rusty-wam" name = "rusty-wam"
version = "0.5.11" version = "0.5.12"
authors = ["Mark Thom"] authors = ["Mark Thom"]
build = "build.rs" build = "build.rs"
@@ -13,4 +13,3 @@ version = "0.12.5"
[build-dependencies.lalrpop] [build-dependencies.lalrpop]
version = "0.12.5" version = "0.12.5"

View File

@@ -8,11 +8,11 @@ pure Prolog.
## Progress ## Progress
Pure Prolog is implemented as a simple REPL. "Pure Prolog" is Prolog Prolog is implemented as a simple REPL. It is without without meta- or
without cut, meta- or extra-logical operators, or side effects of any extra-logical operators, or side effects of any kind, with the lone
kind. In terms of the tutorial pacing, the work has progressed to the exception of cut. In terms of the tutorial pacing, the work has
end of section 5.10, skipping past 5.4. Atoms and lists are the only progressed to the end of section 5.11, skipping past 5.4. Atoms and
two data types currently supported. lists are the only two data types currently supported.
While proper environment trimming code is emitted by the code While proper environment trimming code is emitted by the code
generator, it has no effect on the bytecode WAM, which lacks generator, it has no effect on the bytecode WAM, which lacks

View File

@@ -194,6 +194,87 @@ mod tests {
assert_eq!(submit(&mut wam, "?- p(X).").failed_query(), false); 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] #[test]
fn test_queries_on_lists() { fn test_queries_on_lists() {
let mut wam = Machine::new(); let mut wam = Machine::new();

View File

@@ -5,6 +5,7 @@ use std::vec::Vec;
pub struct Frame { pub struct Frame {
pub global_index: usize, pub global_index: usize,
pub b0: usize,
pub e: usize, pub e: usize,
pub cp: CodePtr, pub cp: CodePtr,
perms: Vec<Addr> perms: Vec<Addr>
@@ -14,6 +15,7 @@ impl Frame {
fn new(global_index: usize, e: usize, cp: CodePtr, n: usize) -> Self { fn new(global_index: usize, e: usize, cp: CodePtr, n: usize) -> Self {
Frame { Frame {
global_index: global_index, global_index: global_index,
b0: 0,
e: e, e: e,
cp: cp, cp: cp,
perms: vec![Addr::HeapCell(0); n] perms: vec![Addr::HeapCell(0); n]

View File

@@ -119,13 +119,27 @@ pub enum Term {
Var(Cell<VarReg>, Var) Var(Cell<VarReg>, Var)
} }
pub enum TermOrCut {
Cut,
Term(Term)
}
impl TermOrCut {
pub fn arity(&self) -> usize {
match self {
&TermOrCut::Term(ref term) => term.arity(),
_ => 0
}
}
}
pub struct Rule { pub struct Rule {
pub head: (Term, Term), pub head: (Term, TermOrCut),
pub clauses: Vec<Term> pub clauses: Vec<TermOrCut>
} }
impl Rule { impl Rule {
pub fn last_clause(&self) -> &Term { pub fn last_clause(&self) -> &TermOrCut {
match self.clauses.last() { match self.clauses.last() {
None => &self.head.1, None => &self.head.1,
Some(clause) => clause Some(clause) => clause
@@ -147,6 +161,16 @@ pub enum ChoiceInstruction {
TryMeElse(usize) TryMeElse(usize)
} }
pub enum Terminal {
Terminal, Non
}
pub enum CutInstruction {
Cut(Terminal),
GetLevel,
NeckCut(Terminal)
}
pub enum IndexedChoiceInstruction { pub enum IndexedChoiceInstruction {
Retry(usize), Retry(usize),
Trust(usize), Trust(usize),
@@ -223,6 +247,7 @@ pub type CompiledQuery = Vec<QueryInstruction>;
pub enum Line { pub enum Line {
Choice(ChoiceInstruction), Choice(ChoiceInstruction),
Control(ControlInstruction), Control(ControlInstruction),
Cut(CutInstruction),
Fact(CompiledFact), Fact(CompiledFact),
Indexing(IndexingInstruction), Indexing(IndexingInstruction),
IndexedChoice(IndexedChoiceInstruction), IndexedChoice(IndexedChoiceInstruction),

View File

@@ -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 &Rule { head: (ref p0, ref p1), ref clauses } = rule;
let mut vs = HashMap::new(); let mut vs = HashMap::new();
let iter = p0.breadth_first_iter().chain(p1.breadth_first_iter()); match p1 {
&TermOrCut::Cut => {
Self::mark_vars_in_term(iter, &mut vs, 0); 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() { for (i, term) in clauses.iter().enumerate() {
Self::mark_vars_in_term(term.breadth_first_iter(), &mut vs, i + 1); 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); Self::set_perm_vals(&vs);
vs (vs, deep_cuts)
} }
fn add_conditional_call(compiled_query: &mut Code, term: &Term, pvs: usize) 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 { fn vars_above_threshold(vs: &VariableFixtures, index: usize) -> usize {
let mut var_count = 0; let mut var_count = 0;
for &(term_status, _) in vs.values() { for &(var_status, _) in vs.values() {
if let VarStatus::Permanent(i) = term_status { if let VarStatus::Permanent(i) = var_status {
if i > index { if i > index {
var_count += 1; var_count += 1;
} }
@@ -803,8 +822,8 @@ impl<'a> CodeGenerator<'a> {
let mut dealloc_index = body.len() - 1; let mut dealloc_index = body.len() - 1;
match rule.last_clause() { match rule.last_clause() {
&Term::Clause(_, ref name, _) &TermOrCut::Term(Term::Clause(_, ref name, _))
| &Term::Constant(_, Constant::Atom(ref name)) => { | &TermOrCut::Term(Term::Constant(_, Constant::Atom(ref name))) => {
if let &mut Line::Control(ref mut ctrl) = body.last_mut().unwrap() { if let &mut Line::Control(ref mut ctrl) = body.last_mut().unwrap() {
*ctrl = ControlInstruction::Execute(name.clone(), last_arity); *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 { pub fn compile_rule(&mut self, rule: &'a Rule) -> Code
let vs = Self::mark_perm_vars(&rule); {
let (vs, deep_cuts) = Self::mark_perm_vars(&rule);
let &Rule { head: (ref p0, ref p1), ref clauses } = rule; let &Rule { head: (ref p0, ref p1), ref clauses } = rule;
let perm_vars = Self::vars_above_threshold(&vs, 0); let perm_vars = Self::vars_above_threshold(&vs, 0);
@@ -872,23 +892,63 @@ impl<'a> CodeGenerator<'a> {
if clauses.len() > 0 { if clauses.len() > 0 {
body.push(Line::Control(ControlInstruction::Allocate(perm_vars))); 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()); match p1 {
self.update_var_count(iter); &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); self.marker.advance(p0);
body.push(Line::Fact(self.compile_target(p0, false)));
self.marker.advance_at_head(p1); if p0.is_clause() {
body.push(Line::Query(self.compile_target(p1, false))); 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() body = clauses.iter().enumerate()
.map(|(i, term)| { .map(|(i, term)| {
let num_vars = Self::vars_above_threshold(&vs, i+1); match term {
self.compile_internal_query(term, num_vars) &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| { .fold(body, |mut body, ref mut cqs| {
body.append(cqs); body.append(cqs);

View File

@@ -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 { impl fmt::Display for Level {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
@@ -198,6 +211,8 @@ pub fn print_code(code: &Code) {
for fact_instr in fact { for fact_instr in fact {
println!("{}", fact_instr); println!("{}", fact_instr);
}, },
&Line::Cut(ref cut) =>
println!("{}", cut),
&Line::Choice(ref choice) => &Line::Choice(ref choice) =>
println!("{}", choice), println!("{}", choice),
&Line::Control(ref control) => &Line::Control(ref control) =>

View File

@@ -19,6 +19,7 @@ struct MachineState {
s: usize, s: usize,
p: CodePtr, p: CodePtr,
b: usize, b: usize,
b0: usize,
e: usize, e: usize,
num_of_args: usize, num_of_args: usize,
cp: CodePtr, cp: CodePtr,
@@ -121,6 +122,8 @@ impl Machine {
match instr { match instr {
&Line::Choice(ref choice_instr) => &Line::Choice(ref choice_instr) =>
self.ms.execute_choice_instr(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) => &Line::Control(ref control_instr) =>
self.ms.execute_ctrl_instr(&self.code_dir, control_instr), self.ms.execute_ctrl_instr(&self.code_dir, control_instr),
&Line::Fact(ref fact) => { &Line::Fact(ref fact) => {
@@ -150,17 +153,25 @@ impl Machine {
} }
if self.failed() { if self.failed() {
let p = self.ms let b0 = self.ms
.or_stack .or_stack
.top() .top()
.map(|fr| fr.bp) .map(|fr| fr.b0)
.unwrap_or_default(); .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 { if let CodePtr::TopLevel = p {
return false; return false;
} else { } else {
self.ms.fail = false; self.ms.fail = false;
self.ms.p = p; self.ms.p = p;
self.ms.b0 = b0;
} }
} }
@@ -267,7 +278,11 @@ impl Machine {
pub fn continue_query(&mut self) -> EvalResult pub fn continue_query(&mut self) -> EvalResult
{ {
if !self.or_stack_is_empty() { 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; self.ms.p = self.ms.or_stack[b].bp;
let succeeded = if let CodePtr::DirEntry(p) = self.ms.p { 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) { pub fn reset(&mut self) {
self.ms.reset(); self.ms.reset();
} }
@@ -297,6 +319,7 @@ impl MachineState {
s: 0, s: 0,
p: CodePtr::TopLevel, p: CodePtr::TopLevel,
b: 0, b: 0,
b0: 0,
e: 0, e: 0,
num_of_args: 0, num_of_args: 0,
cp: CodePtr::TopLevel, cp: CodePtr::TopLevel,
@@ -419,7 +442,12 @@ impl MachineState {
Ref::StackCell(fr, _) => { Ref::StackCell(fr, _) => {
let fr_gi = self.and_stack[fr].global_index; let fr_gi = self.and_stack[fr].global_index;
let b_gi = if !self.or_stack.is_empty() { 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 { } else {
0 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) { fn execute_fact_instr(&mut self, instr: &FactInstruction) {
match instr { match instr {
&FactInstruction::GetConstant(_, ref constant, reg) => { &FactInstruction::GetConstant(_, ref constant, reg) => {
@@ -821,6 +891,7 @@ impl MachineState {
Some(compiled_tl_index) => { Some(compiled_tl_index) => {
self.cp = self.p + 1; self.cp = self.p + 1;
self.num_of_args = arity; self.num_of_args = arity;
self.b0 = self.b;
self.p = CodePtr::DirEntry(compiled_tl_index); self.p = CodePtr::DirEntry(compiled_tl_index);
}, },
None => self.fail = true None => self.fail = true
@@ -841,7 +912,8 @@ impl MachineState {
match compiled_tl_index { match compiled_tl_index {
Some(compiled_tl_index) => { Some(compiled_tl_index) => {
self.num_of_args = arity; 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 None => self.fail = true
}; };
@@ -865,10 +937,11 @@ impl MachineState {
self.p + 1, self.p + 1,
self.tr, self.tr,
self.h, self.h,
self.b0,
self.num_of_args); self.num_of_args);
self.b = self.or_stack.len() - 1; self.b = self.or_stack.len();
let b = self.b; let b = self.b - 1;
for i in 1 .. n + 1 { for i in 1 .. n + 1 {
self.or_stack[b][i] = self.registers[i].clone(); self.or_stack[b][i] = self.registers[i].clone();
@@ -878,7 +951,7 @@ impl MachineState {
self.p += l; self.p += l;
}, },
&IndexedChoiceInstruction::Retry(l) => { &IndexedChoiceInstruction::Retry(l) => {
let b = self.b; let b = self.b - 1;
let n = self.or_stack[b].num_args(); let n = self.or_stack[b].num_args();
for i in 1 .. n + 1 { for i in 1 .. n + 1 {
@@ -905,7 +978,7 @@ impl MachineState {
self.p += l; self.p += l;
}, },
&IndexedChoiceInstruction::Trust(l) => { &IndexedChoiceInstruction::Trust(l) => {
let b = self.b; let b = self.b - 1;
let n = self.or_stack[b].num_args(); let n = self.or_stack[b].num_args();
for i in 1 .. n + 1 { for i in 1 .. n + 1 {
@@ -950,10 +1023,11 @@ impl MachineState {
self.p + offset, self.p + offset,
self.tr, self.tr,
self.h, self.h,
self.b0,
self.num_of_args); self.num_of_args);
self.b = self.or_stack.len() - 1; self.b = self.or_stack.len();
let b = self.b; let b = self.b - 1;
for i in 1 .. n + 1 { for i in 1 .. n + 1 {
self.or_stack[b][i] = self.registers[i].clone(); self.or_stack[b][i] = self.registers[i].clone();
@@ -963,7 +1037,7 @@ impl MachineState {
self.p += 1; self.p += 1;
}, },
&ChoiceInstruction::RetryMeElse(offset) => { &ChoiceInstruction::RetryMeElse(offset) => {
let b = self.b; let b = self.b - 1;
let n = self.or_stack[b].num_args(); let n = self.or_stack[b].num_args();
for i in 1 .. n + 1 { for i in 1 .. n + 1 {
@@ -990,7 +1064,7 @@ impl MachineState {
self.p += 1; self.p += 1;
}, },
&ChoiceInstruction::TrustMe => { &ChoiceInstruction::TrustMe => {
let b = self.b; let b = self.b - 1;
let n = self.or_stack[b].num_args(); let n = self.or_stack[b].num_args();
for i in 1 .. n + 1 { 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) { fn reset(&mut self) {
self.h = 0; self.h = 0;
self.hb = 0; self.hb = 0;
self.e = 0; self.e = 0;
self.b = 0; self.b = 0;
self.b0 = 0;
self.s = 0; self.s = 0;
self.tr = 0; self.tr = 0;
self.p = CodePtr::TopLevel; self.p = CodePtr::TopLevel;

View File

@@ -11,6 +11,7 @@ pub struct Frame {
pub bp: CodePtr, pub bp: CodePtr,
pub tr: usize, pub tr: usize,
pub h: usize, pub h: usize,
pub b0: usize,
args: Vec<Addr> args: Vec<Addr>
} }
@@ -22,6 +23,7 @@ impl Frame {
bp: CodePtr, bp: CodePtr,
tr: usize, tr: usize,
h: usize, h: usize,
b0: usize,
n: usize) n: usize)
-> Self -> Self
{ {
@@ -33,6 +35,7 @@ impl Frame {
bp: bp, bp: bp,
tr: tr, tr: tr,
h: h, h: h,
b0: b0,
args: vec![Addr::HeapCell(0); n] args: vec![Addr::HeapCell(0); n]
} }
} }
@@ -57,9 +60,10 @@ impl OrStack {
bp: CodePtr, bp: CodePtr,
tr: usize, tr: usize,
h: usize, h: usize,
b0: usize,
n: 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 { pub fn len(&self) -> usize {

View File

@@ -57,13 +57,19 @@ PredicateClause : PredicateClause = {
}; };
Rule : Rule = { Rule : Rule = {
<c:Clause> ":-" <h:Term> <cs: ("," <Term>)*> => <c:Clause> ":-" <h:TermOrCut> <cs: ("," <TermOrCut>)*> =>
Rule { head: (c, h), clauses: cs }, Rule { head: (c, h), clauses: cs },
<a:Atom> ":-" <h:Term> <cs: ("," <Term>)*> => <a:Atom> ":-" <h:TermOrCut> <cs: ("," <TermOrCut>)*> =>
Rule { head: (Term::Constant(Cell::default(), Constant::Atom(a)), h), Rule { head: (Term::Constant(Cell::default(), Constant::Atom(a)),
h),
clauses: cs } clauses: cs }
}; };
TermOrCut : TermOrCut = {
"!" => TermOrCut::Cut,
<Term> => TermOrCut::Term(<>)
};
Term : Term = { Term : Term = {
<Atom> => Term::Constant(Cell::default(), Constant::Atom(<>)), <Atom> => Term::Constant(Cell::default(), Constant::Atom(<>)),
<Clause> => <>, <Clause> => <>,

File diff suppressed because it is too large Load Diff