From 409d79719d4977580ea0338edf2be8587e9b4c9f Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Thu, 3 Aug 2017 10:55:43 -0600 Subject: [PATCH] fix faulty chunking on call/N. --- src/main.rs | 5 +++- src/prolog/io.rs | 3 +++ src/prolog/iterators.rs | 4 ++- src/prolog/machine.rs | 60 ++++++++++++++++++++++++----------------- 4 files changed, 45 insertions(+), 27 deletions(-) diff --git a/src/main.rs b/src/main.rs index cdf1f639..f98fd34c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -549,7 +549,7 @@ mod tests { submit(&mut wam, "maplist(Pred, []). maplist(Pred, [X|Xs]) :- call(Pred, X), maplist(Pred, Xs)."); 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, [a,Y,Z])."), 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), 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, "call_var(P) :- P."); diff --git a/src/prolog/io.rs b/src/prolog/io.rs index ef844cd7..ac1f720e 100644 --- a/src/prolog/io.rs +++ b/src/prolog/io.rs @@ -301,6 +301,7 @@ pub fn eval<'a, 'b: 'a>(wam: &'a mut Machine, tl: &'b TopLevel) -> EvalSession<' if is_consistent(clauses) { let compiled_pred = cg.compile_predicate(clauses); + print_code(&compiled_pred); wam.add_predicate(clauses, compiled_pred) } else { let msg = r"Error: predicate is inconsistent. @@ -319,12 +320,14 @@ Each predicate must have the same name and arity."; let mut cg = CodeGenerator::::new(); let compiled_rule = cg.compile_rule(rule); + print_code(&compiled_rule); wam.add_rule(rule, compiled_rule) }, &TopLevel::Query(ref query) => { let mut cg = CodeGenerator::::new(); let compiled_query = cg.compile_query(query); + print_code(&compiled_query); wam.submit_query(compiled_query, cg.take_vars()) } } diff --git a/src/prolog/iterators.rs b/src/prolog/iterators.rs index b4279a78..83a0178b 100644 --- a/src/prolog/iterators.rs +++ b/src/prolog/iterators.rs @@ -285,7 +285,7 @@ impl<'a> ChunkedIterator<'a> result.push(term); arity = child_terms.len() + 1; break; - }, + }, _ => { result.push(term); self.deep_cut_encountered = true; @@ -312,6 +312,8 @@ impl<'a> Iterator for ChunkedIterator<'a> }, Some(QueryTermRef::Term(term)) if term.is_callable() => 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) => return Some(self.take_chunk(term_or_cut_ref)) } diff --git a/src/prolog/machine.rs b/src/prolog/machine.rs index 4c39a26e..f0ea0c5b 100644 --- a/src/prolog/machine.rs +++ b/src/prolog/machine.rs @@ -33,7 +33,6 @@ struct MachineState { trail: Vec, tr: usize, hb: usize, - lco: bool } #[derive(Clone, Copy, PartialEq, Eq, Hash)] @@ -98,7 +97,8 @@ impl Index for Machine { impl Machine { pub fn new() -> Self { 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 // (an extra register is needed for the predicate name) @@ -450,7 +450,6 @@ impl MachineState { trail: Vec::new(), tr: 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 { - Some(compiled_tl_index) if lco => { - self.lco = true; - + 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 + }; + } + + 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) => { - self.lco = false; - - self.cp = self.p + 1; self.num_of_args = arity; self.b0 = self.b; self.p = CodePtr::DirEntry(compiled_tl_index); @@ -1020,7 +1024,6 @@ impl MachineState { fn handle_internal_call_n(&mut self, code_dir: &CodeDir) { let arity = self.num_of_args + 1; - let lco = self.lco; let pred = self.registers[1].clone(); for i in 2 .. arity { @@ -1029,15 +1032,18 @@ impl MachineState { if arity > 1 { 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 { 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 { - let addr = self.deref(self.registers[arity].clone()); + let addr = self.deref(self.registers[arity].clone()); let (name, narity) = match self.store(addr) { Addr::Str(a) => { @@ -1055,17 +1061,17 @@ impl MachineState { (name, narity) } else { self.fail = true; - return; + return None; } }, Addr::Con(Constant::Atom(name)) => (name, 0), _ => { 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) @@ -1080,9 +1086,11 @@ impl MachineState { self.p += 1; }, &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) => - 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 => { let e = self.e; @@ -1091,10 +1099,12 @@ impl MachineState { self.p += 1; }, - &ControlInstruction::Execute(ref name, arity) => - self.try_call_predicate(code_dir, name.clone(), arity, true), + &ControlInstruction::Execute(ref name, arity) => + self.try_execute_predicate(code_dir, name.clone(), 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 => self.p = self.cp, }; @@ -1189,7 +1199,7 @@ impl MachineState { fn execute_builtin_instr(&mut self, code_dir: &CodeDir, instr: &BuiltInInstruction) { match instr { - &BuiltInInstruction::InternalCallN => self.handle_internal_call_n(code_dir) + &BuiltInInstruction::InternalCallN => self.handle_internal_call_n(code_dir) } } -- 2.54.0