From: Mark Thom Date: Tue, 15 Aug 2017 17:06:19 +0000 (-0600) Subject: bug fixes. X-Git-Tag: v0.8.110~702 X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=cc82447c64c598f7c3d2a6c9bb1be896cf5caf81;p=scryer-prolog.git bug fixes. --- diff --git a/README.md b/README.md index 4e19b5ef..76ce76dc 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ argument indexing, and conjunctive queries. Extend rusty-wam to include the following, among other features: * call/N as a built-in meta-predicate (_done_). -* ISO Prolog compliant throw/catch (_in progress_). +* ISO Prolog compliant throw/catch (_done_). * Built-in and user-defined operators of all fixities, with custom associativity and precedence. * Bignum and floating point arithmetic. @@ -42,6 +42,18 @@ IR to get JIT-compiled and -executed Prolog programs. It's my hope to use rusty-wam as the logic engine of a low level (and ideally, very fast) [Shen](http://shenlanguage.org) implementation. +## Built-in predicates + +The following predicates are built-in to rusty-wam. + +* atomic +* call/N (0 <= N <= 62) +* catch/3 +* duplicate_term/2 +* false/0 +* not/1 +* var/1 + ## Tutorial To enter a multi-clause predicate, the brackets ":{" and "}:" are used as delimiters. They must be contained entirely within their own lines. diff --git a/src/main.rs b/src/main.rs index ae87f924..aea87ddb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -721,9 +721,16 @@ mod tests { submit(&mut wam, "g(g_success). g(g_success_2). g(X) :- throw(X)."); submit(&mut wam, "handle(x). handle(y). handle(z). handle(v) :- throw(X)."); - //TODO: fix this test. record the ball properly. currently it - // is unwound when the heap is truncated. assert_eq!(submit(&mut wam, "?- catch(f(X), E, E)."), true); + + submit(&mut wam, "handle(x). handle(y). handle(z). handle(v) :- throw(handle_top(X))."); + submit(&mut wam, "handle_top(an_error_1). handle_top(an_error_2)."); + + assert_eq!(submit(&mut wam, "?- catch(f(X), E, E)."), true); + + submit(&mut wam, "handle(x). handle(y). handle(z). handle(v) :- throw(X)."); + + assert_eq!(submit(&mut wam, "?- catch(f(X), E, handle_top(E))."), true); } } diff --git a/src/prolog/ast.rs b/src/prolog/ast.rs index 0737ef14..91f4ef38 100644 --- a/src/prolog/ast.rs +++ b/src/prolog/ast.rs @@ -297,7 +297,6 @@ pub enum BuiltInInstruction { Fail, GetBall, GetCurrentBlock, - Goto(usize, usize), InstallNewBlock, InternalCallN, IsAtomic, @@ -317,6 +316,7 @@ pub enum ControlInstruction { Deallocate, Execute(Atom, usize), ExecuteN(usize), + Goto(usize, usize), Proceed, ThrowCall, ThrowExecute @@ -333,6 +333,7 @@ impl ControlInstruction { &ControlInstruction::ExecuteN(_) => true, &ControlInstruction::ThrowCall => true, &ControlInstruction::ThrowExecute => true, + &ControlInstruction::Goto(_, _) => true, _ => false } } diff --git a/src/prolog/copier.rs b/src/prolog/copier.rs index 774e7ee3..6bff84e5 100644 --- a/src/prolog/copier.rs +++ b/src/prolog/copier.rs @@ -12,6 +12,12 @@ pub trait CopierTarget fn deref(&self, Addr) -> Addr; fn stack(&mut self) -> &mut AndStack; + //TODO: extend this so include a boundary() function which is constant!! + // this will return self.h. the threshold() will be used to set the addresses + // contained within the terms so that the offsets match those of the heap + // to be truncated by BLOCK, ie. starting at the BLOCK.H value. This should + // allow us to get around the latest bug. + // duplicate_term(L1, L2) uses Cheney's algorithm to copy the term at // L1 to L2. forwarding_terms is kept to restore the innards of L1 // after it's been copied to L2. @@ -67,7 +73,7 @@ pub trait CopierTarget match self[s].clone() { HeapCellValue::NamedStr(arity, name) => { let threshold = self.threshold(); - + self[scan] = HeapCellValue::Str(threshold); self[s] = HeapCellValue::Str(threshold); @@ -89,8 +95,8 @@ pub trait CopierTarget scan += 1; } }; - } - + } + for (r, hcv) in forward_trail { match r { Ref::HeapCell(hc) => self[hc] = hcv, @@ -99,4 +105,3 @@ pub trait CopierTarget } } } - diff --git a/src/prolog/io.rs b/src/prolog/io.rs index 5d59a2fb..f26453e7 100644 --- a/src/prolog/io.rs +++ b/src/prolog/io.rs @@ -114,6 +114,8 @@ impl fmt::Display for ControlInstruction { write!(f, "deallocate"), &ControlInstruction::Execute(ref name, arity) => write!(f, "execute {}/{}", name, arity), + &ControlInstruction::Goto(p, arity) => + write!(f, "goto {}/{}", p, arity), &ControlInstruction::Proceed => write!(f, "proceed"), &ControlInstruction::ThrowCall => @@ -372,7 +374,6 @@ 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. @@ -391,14 +392,12 @@ 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/machine.rs b/src/prolog/machine.rs index 90878363..a04d5361 100644 --- a/src/prolog/machine.rs +++ b/src/prolog/machine.rs @@ -36,7 +36,7 @@ struct MachineState { tr: usize, hb: usize, block: usize, // an offset into the OR stack. - ball: Heap + ball: (usize, Heap) // heap boundary, and a term copy } struct DuplicateTerm<'a> { @@ -111,7 +111,7 @@ impl<'a> Index for DuplicateBallTerm<'a> { &self.state.heap[index] } else { let index = index - self.heap_boundary; - &self.state.ball[index] + &self.state.ball.1[index] } } } @@ -122,7 +122,7 @@ impl<'a> IndexMut for DuplicateBallTerm<'a> { &mut self.state.heap[index] } else { let index = index - self.heap_boundary; - &mut self.state.ball[index] + &mut self.state.ball.1[index] } } } @@ -134,11 +134,11 @@ impl<'a> CopierTarget for DuplicateBallTerm<'a> { } fn threshold(&self) -> usize { - self.heap_boundary + self.state.ball.len() + self.heap_boundary + self.state.ball.1.len() } fn push(&mut self, hcv: HeapCellValue) { - self.state.ball.push(hcv); + self.state.ball.1.push(hcv); } fn store(&self, a: Addr) -> Addr { @@ -377,7 +377,7 @@ impl Machine { }; } } - + fn record_var_places<'a>(&self, chunk_num: usize, alloc_locs: &AllocVarDict<'a>, @@ -409,6 +409,10 @@ impl Machine { while self.ms.p < end_ptr { if let CodePtr::TopLevel(mut cn, p) = self.ms.p { + //TODO: Shouldn't have to work nearly this hard!! Why + // are we only recording addresses, for instance? Why + // not just offsets into the heap? Not like they + // change. if let &Line::Control(ref ctrl_instr) = &self[CodePtr::TopLevel(cn, p)] { if ctrl_instr.is_jump_instr() { self.record_var_places(cn, alloc_locs, heap_locs); @@ -558,7 +562,7 @@ impl MachineState { tr: 0, hb: 0, block: 0, - ball: Vec::new() + ball: (0, Vec::new()) } } @@ -1207,17 +1211,29 @@ impl MachineState { self.p += 1; }, &BuiltInInstruction::EraseBall => { - self.ball.truncate(0); + self.ball.0 = 0; + self.ball.1.truncate(0); self.p += 1; }, &BuiltInInstruction::GetBall => { let addr = self.store(self.deref(self[temp_v!(1)].clone())); let h = self.h; - if self.ball.len() > 0 { - let copied_ball_iter = self.ball.iter().cloned(); - self.heap.extend(copied_ball_iter); - self.h += self.ball.len(); + if self.ball.1.len() > 0 { + let diff = self.ball.0 - h; + + for heap_value in self.ball.1.iter().cloned() { + self.heap.push(match heap_value { + HeapCellValue::Con(c) => HeapCellValue::Con(c), + HeapCellValue::Lis(a) => HeapCellValue::Lis(a - diff), + HeapCellValue::Ref(Ref::HeapCell(hc)) => + HeapCellValue::Ref(Ref::HeapCell(hc - diff)), + HeapCellValue::Str(s) => HeapCellValue::Str(s - diff), + _ => heap_value + }); + } + + self.h += self.ball.1.len(); } else { self.fail = true; return; @@ -1237,6 +1253,8 @@ impl MachineState { let addr = self[temp_v!(1)].clone(); { + self.ball.0 = self.h; + let mut duplicator = DuplicateBallTerm::new(self); duplicator.duplicate_term(addr); } @@ -1304,12 +1322,7 @@ impl MachineState { &BuiltInInstruction::Fail => { self.fail = true; self.p += 1; - }, - &BuiltInInstruction::Goto(p, arity) => { - self.num_of_args = arity; - self.b0 = self.b; - self.p = CodePtr::DirEntry(p); - } + } }; } @@ -1355,6 +1368,11 @@ impl MachineState { if let Some((name, arity)) = self.setup_call_n(arity) { self.try_execute_predicate(code_dir, name, arity); }, + &ControlInstruction::Goto(p, arity) => { + self.num_of_args = arity; + self.b0 = self.b; + self.p = CodePtr::DirEntry(p); + }, &ControlInstruction::Proceed => self.p = self.cp, &ControlInstruction::ThrowCall => { @@ -1605,5 +1623,7 @@ impl MachineState { self.and_stack.clear(); self.or_stack.clear(); self.registers = vec![Addr::HeapCell(0); 64]; + self.block = 0; + self.ball = (0, Vec::new()); } } diff --git a/src/prolog/macros.rs b/src/prolog/macros.rs index 4b6e2951..077c52b7 100644 --- a/src/prolog/macros.rs +++ b/src/prolog/macros.rs @@ -146,7 +146,7 @@ macro_rules! install_new_block { macro_rules! goto { ($line:expr, $arity:expr) => ( - Line::BuiltIn(BuiltInInstruction::Goto($line, $arity)) + Line::Control(ControlInstruction::Goto($line, $arity)) ) }