optimized up to chapter 6
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -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)",
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|
||||||
|
|||||||
10
README.md
10
README.md
@@ -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
|
||||||
|
|||||||
81
src/main.rs
81
src/main.rs
@@ -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();
|
||||||
|
|||||||
@@ -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]
|
||||||
|
|||||||
@@ -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),
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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) =>
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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
Reference in New Issue
Block a user