fix faulty chunking on call/N.
This commit is contained in:
@@ -549,7 +549,7 @@ mod tests {
|
|||||||
submit(&mut wam, "maplist(Pred, []).
|
submit(&mut wam, "maplist(Pred, []).
|
||||||
maplist(Pred, [X|Xs]) :- call(Pred, X), maplist(Pred, Xs).");
|
maplist(Pred, [X|Xs]) :- call(Pred, X), maplist(Pred, Xs).");
|
||||||
submit(&mut wam, "f(a). f(b). f(c).");
|
submit(&mut wam, "f(a). f(b). f(c).");
|
||||||
|
|
||||||
assert_eq!(submit(&mut wam, "?- maplist(f, [X,Y,Z])."), true);
|
assert_eq!(submit(&mut wam, "?- maplist(f, [X,Y,Z])."), true);
|
||||||
assert_eq!(submit(&mut wam, "?- maplist(f, [a,Y,Z])."), true);
|
assert_eq!(submit(&mut wam, "?- maplist(f, [a,Y,Z])."), true);
|
||||||
assert_eq!(submit(&mut wam, "?- maplist(f, [X,a,b])."), true);
|
assert_eq!(submit(&mut wam, "?- maplist(f, [X,a,b])."), true);
|
||||||
@@ -647,6 +647,9 @@ mod tests {
|
|||||||
assert_eq!(submit(&mut wam, "?- call_mult(p(two), one)."), false);
|
assert_eq!(submit(&mut wam, "?- call_mult(p(two), one)."), false);
|
||||||
assert_eq!(submit(&mut wam, "?- call_mult(p(two), two)."), true);
|
assert_eq!(submit(&mut wam, "?- call_mult(p(two), two)."), true);
|
||||||
|
|
||||||
|
assert_eq!(submit(&mut wam, "?- call(call(p(one)), X), call(call(p(two)), two)."), true);
|
||||||
|
assert_eq!(submit(&mut wam, "?- call(call(p(one)), X), call(call(p(two)), one)."), false);
|
||||||
|
|
||||||
submit(&mut wam, "f(call(f, undefined)). f(undefined).");
|
submit(&mut wam, "f(call(f, undefined)). f(undefined).");
|
||||||
submit(&mut wam, "call_var(P) :- P.");
|
submit(&mut wam, "call_var(P) :- P.");
|
||||||
|
|
||||||
|
|||||||
@@ -301,6 +301,7 @@ pub fn eval<'a, 'b: 'a>(wam: &'a mut Machine, tl: &'b TopLevel) -> EvalSession<'
|
|||||||
|
|
||||||
if is_consistent(clauses) {
|
if is_consistent(clauses) {
|
||||||
let compiled_pred = cg.compile_predicate(clauses);
|
let compiled_pred = cg.compile_predicate(clauses);
|
||||||
|
print_code(&compiled_pred);
|
||||||
wam.add_predicate(clauses, compiled_pred)
|
wam.add_predicate(clauses, compiled_pred)
|
||||||
} else {
|
} else {
|
||||||
let msg = r"Error: predicate is inconsistent.
|
let msg = r"Error: predicate is inconsistent.
|
||||||
@@ -319,12 +320,14 @@ Each predicate must have the same name and arity.";
|
|||||||
let mut cg = CodeGenerator::<DebrayAllocator>::new();
|
let mut cg = CodeGenerator::<DebrayAllocator>::new();
|
||||||
|
|
||||||
let compiled_rule = cg.compile_rule(rule);
|
let compiled_rule = cg.compile_rule(rule);
|
||||||
|
print_code(&compiled_rule);
|
||||||
wam.add_rule(rule, compiled_rule)
|
wam.add_rule(rule, compiled_rule)
|
||||||
},
|
},
|
||||||
&TopLevel::Query(ref query) => {
|
&TopLevel::Query(ref query) => {
|
||||||
let mut cg = CodeGenerator::<DebrayAllocator>::new();
|
let mut cg = CodeGenerator::<DebrayAllocator>::new();
|
||||||
|
|
||||||
let compiled_query = cg.compile_query(query);
|
let compiled_query = cg.compile_query(query);
|
||||||
|
print_code(&compiled_query);
|
||||||
wam.submit_query(compiled_query, cg.take_vars())
|
wam.submit_query(compiled_query, cg.take_vars())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -285,7 +285,7 @@ impl<'a> ChunkedIterator<'a>
|
|||||||
result.push(term);
|
result.push(term);
|
||||||
arity = child_terms.len() + 1;
|
arity = child_terms.len() + 1;
|
||||||
break;
|
break;
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
result.push(term);
|
result.push(term);
|
||||||
self.deep_cut_encountered = true;
|
self.deep_cut_encountered = true;
|
||||||
@@ -312,6 +312,8 @@ impl<'a> Iterator for ChunkedIterator<'a>
|
|||||||
},
|
},
|
||||||
Some(QueryTermRef::Term(term)) if term.is_callable() =>
|
Some(QueryTermRef::Term(term)) if term.is_callable() =>
|
||||||
return Some((term.arity(), vec![QueryTermRef::Term(term)])),
|
return Some((term.arity(), vec![QueryTermRef::Term(term)])),
|
||||||
|
Some(QueryTermRef::CallN(child_terms)) =>
|
||||||
|
return Some((child_terms.len() + 1, vec![QueryTermRef::CallN(child_terms)])),
|
||||||
Some(term_or_cut_ref) =>
|
Some(term_or_cut_ref) =>
|
||||||
return Some(self.take_chunk(term_or_cut_ref))
|
return Some(self.take_chunk(term_or_cut_ref))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ struct MachineState {
|
|||||||
trail: Vec<Ref>,
|
trail: Vec<Ref>,
|
||||||
tr: usize,
|
tr: usize,
|
||||||
hb: usize,
|
hb: usize,
|
||||||
lco: bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
@@ -98,7 +97,8 @@ impl Index<CodePtr> for Machine {
|
|||||||
impl Machine {
|
impl Machine {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let mut code_dir = HashMap::new();
|
let mut code_dir = HashMap::new();
|
||||||
let code = vec![Line::BuiltIn(BuiltInInstruction::InternalCallN)];
|
let code = vec![Line::BuiltIn(BuiltInInstruction::InternalCallN),
|
||||||
|
Line::Control(ControlInstruction::Proceed)];
|
||||||
|
|
||||||
// there are 64 registers in the VM, so call/N is defined for all 0 <= N <= 63
|
// there are 64 registers in the VM, so call/N is defined for all 0 <= N <= 63
|
||||||
// (an extra register is needed for the predicate name)
|
// (an extra register is needed for the predicate name)
|
||||||
@@ -450,7 +450,6 @@ impl MachineState {
|
|||||||
trail: Vec::new(),
|
trail: Vec::new(),
|
||||||
tr: 0,
|
tr: 0,
|
||||||
hb: 0,
|
hb: 0,
|
||||||
lco: false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -993,22 +992,27 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_call_predicate(&mut self, code_dir: &CodeDir, name: Atom, arity: usize, lco: bool)
|
fn try_call_predicate(&mut self, code_dir: &CodeDir, name: Atom, arity: usize)
|
||||||
{
|
{
|
||||||
let compiled_tl_index = code_dir.get(&(name, arity)).map(|index| index.1);
|
let compiled_tl_index = code_dir.get(&(name, arity)).map(|index| index.1);
|
||||||
|
|
||||||
match compiled_tl_index {
|
match compiled_tl_index {
|
||||||
Some(compiled_tl_index) if lco => {
|
Some(compiled_tl_index) => {
|
||||||
self.lco = true;
|
self.cp = self.p + 1;
|
||||||
|
|
||||||
self.num_of_args = arity;
|
self.num_of_args = arity;
|
||||||
self.b0 = self.b;
|
self.b0 = self.b;
|
||||||
self.p = CodePtr::DirEntry(compiled_tl_index);
|
self.p = CodePtr::DirEntry(compiled_tl_index);
|
||||||
},
|
},
|
||||||
|
None => self.fail = true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_execute_predicate(&mut self, code_dir: &CodeDir, name: Atom, arity: usize)
|
||||||
|
{
|
||||||
|
let compiled_tl_index = code_dir.get(&(name, arity)).map(|index| index.1);
|
||||||
|
|
||||||
|
match compiled_tl_index {
|
||||||
Some(compiled_tl_index) => {
|
Some(compiled_tl_index) => {
|
||||||
self.lco = false;
|
|
||||||
|
|
||||||
self.cp = self.p + 1;
|
|
||||||
self.num_of_args = arity;
|
self.num_of_args = arity;
|
||||||
self.b0 = self.b;
|
self.b0 = self.b;
|
||||||
self.p = CodePtr::DirEntry(compiled_tl_index);
|
self.p = CodePtr::DirEntry(compiled_tl_index);
|
||||||
@@ -1020,7 +1024,6 @@ impl MachineState {
|
|||||||
fn handle_internal_call_n(&mut self, code_dir: &CodeDir)
|
fn handle_internal_call_n(&mut self, code_dir: &CodeDir)
|
||||||
{
|
{
|
||||||
let arity = self.num_of_args + 1;
|
let arity = self.num_of_args + 1;
|
||||||
let lco = self.lco;
|
|
||||||
let pred = self.registers[1].clone();
|
let pred = self.registers[1].clone();
|
||||||
|
|
||||||
for i in 2 .. arity {
|
for i in 2 .. arity {
|
||||||
@@ -1029,15 +1032,18 @@ impl MachineState {
|
|||||||
|
|
||||||
if arity > 1 {
|
if arity > 1 {
|
||||||
self.registers[arity - 1] = pred;
|
self.registers[arity - 1] = pred;
|
||||||
self.execute_call_n(code_dir, arity - 1, lco);
|
|
||||||
|
if let Some((name, arity)) = self.setup_call_n(arity - 1) {
|
||||||
|
self.try_execute_predicate(code_dir, name, arity);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
self.fail = true;
|
self.fail = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn execute_call_n(&mut self, code_dir: &CodeDir, arity: usize, lco: bool)
|
fn setup_call_n(&mut self, arity: usize) -> Option<PredicateKey>
|
||||||
{
|
{
|
||||||
let addr = self.deref(self.registers[arity].clone());
|
let addr = self.deref(self.registers[arity].clone());
|
||||||
|
|
||||||
let (name, narity) = match self.store(addr) {
|
let (name, narity) = match self.store(addr) {
|
||||||
Addr::Str(a) => {
|
Addr::Str(a) => {
|
||||||
@@ -1055,17 +1061,17 @@ impl MachineState {
|
|||||||
(name, narity)
|
(name, narity)
|
||||||
} else {
|
} else {
|
||||||
self.fail = true;
|
self.fail = true;
|
||||||
return;
|
return None;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Addr::Con(Constant::Atom(name)) => (name, 0),
|
Addr::Con(Constant::Atom(name)) => (name, 0),
|
||||||
_ => {
|
_ => {
|
||||||
self.fail = true;
|
self.fail = true;
|
||||||
return;
|
return None;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.try_call_predicate(code_dir, name, arity + narity - 1, lco);
|
Some((name, arity + narity - 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn execute_ctrl_instr(&mut self, code_dir: &CodeDir, instr: &ControlInstruction)
|
fn execute_ctrl_instr(&mut self, code_dir: &CodeDir, instr: &ControlInstruction)
|
||||||
@@ -1080,9 +1086,11 @@ impl MachineState {
|
|||||||
self.p += 1;
|
self.p += 1;
|
||||||
},
|
},
|
||||||
&ControlInstruction::Call(ref name, arity, _) =>
|
&ControlInstruction::Call(ref name, arity, _) =>
|
||||||
self.try_call_predicate(code_dir, name.clone(), arity, false),
|
self.try_call_predicate(code_dir, name.clone(), arity),
|
||||||
&ControlInstruction::CallN(arity) =>
|
&ControlInstruction::CallN(arity) =>
|
||||||
self.execute_call_n(code_dir, arity, false),
|
if let Some((name, arity)) = self.setup_call_n(arity) {
|
||||||
|
self.try_call_predicate(code_dir, name, arity);
|
||||||
|
},
|
||||||
&ControlInstruction::Deallocate => {
|
&ControlInstruction::Deallocate => {
|
||||||
let e = self.e;
|
let e = self.e;
|
||||||
|
|
||||||
@@ -1091,10 +1099,12 @@ impl MachineState {
|
|||||||
|
|
||||||
self.p += 1;
|
self.p += 1;
|
||||||
},
|
},
|
||||||
&ControlInstruction::Execute(ref name, arity) =>
|
&ControlInstruction::Execute(ref name, arity) =>
|
||||||
self.try_call_predicate(code_dir, name.clone(), arity, true),
|
self.try_execute_predicate(code_dir, name.clone(), arity),
|
||||||
&ControlInstruction::ExecuteN(arity) =>
|
&ControlInstruction::ExecuteN(arity) =>
|
||||||
self.execute_call_n(code_dir, arity, true),
|
if let Some((name, arity)) = self.setup_call_n(arity) {
|
||||||
|
self.try_execute_predicate(code_dir, name, arity);
|
||||||
|
},
|
||||||
&ControlInstruction::Proceed =>
|
&ControlInstruction::Proceed =>
|
||||||
self.p = self.cp,
|
self.p = self.cp,
|
||||||
};
|
};
|
||||||
@@ -1189,7 +1199,7 @@ impl MachineState {
|
|||||||
fn execute_builtin_instr(&mut self, code_dir: &CodeDir, instr: &BuiltInInstruction)
|
fn execute_builtin_instr(&mut self, code_dir: &CodeDir, instr: &BuiltInInstruction)
|
||||||
{
|
{
|
||||||
match instr {
|
match instr {
|
||||||
&BuiltInInstruction::InternalCallN => self.handle_internal_call_n(code_dir)
|
&BuiltInInstruction::InternalCallN => self.handle_internal_call_n(code_dir)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user