From: Mark Thom Date: Thu, 14 Feb 2019 08:12:52 +0000 (-0700) Subject: fix attribute_goals/2 display bugs, cycle detection bug X-Git-Tag: v0.8.110~257 X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=cd5549ee5b8ab37edaac6423a64565668f6dc58d;p=scryer-prolog.git fix attribute_goals/2 display bugs, cycle detection bug --- diff --git a/README.md b/README.md index 620dfecd..e4517e85 100644 --- a/README.md +++ b/README.md @@ -163,6 +163,7 @@ The following predicates are built-in to rusty-wam. * `member/2` * `memberchk/2` * `must_be/2` +* `nl/0` * `nonvar/1` * `numbervars/2` * `once/1` diff --git a/src/prolog/compile.rs b/src/prolog/compile.rs index 3e70a381..21ea3585 100644 --- a/src/prolog/compile.rs +++ b/src/prolog/compile.rs @@ -118,7 +118,6 @@ fn compile_query(terms: Vec, queue: VecDeque, flags: Machin let mut code = try!(cg.compile_query(&terms)); compile_appendix(&mut code, &queue, false, flags)?; - Ok((code, cg.take_vars())) } diff --git a/src/prolog/heap_print.rs b/src/prolog/heap_print.rs index 76ec3b01..4ca1cf26 100644 --- a/src/prolog/heap_print.rs +++ b/src/prolog/heap_print.rs @@ -630,7 +630,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> pub fn print(mut self, addr: Addr) -> Outputter { let mut iter = self.machine_st.pre_order_iter(addr); - + loop { if let Some(loc_data) = self.state_stack.pop() { match loc_data { diff --git a/src/prolog/instructions.rs b/src/prolog/instructions.rs index a39cd1db..d44fbdd0 100644 --- a/src/prolog/instructions.rs +++ b/src/prolog/instructions.rs @@ -238,6 +238,7 @@ pub struct Module { #[derive(Copy, Clone, PartialEq)] pub enum SystemClauseType { CheckCutPoint, + Deallocate, DeleteAttribute, DeleteHeadAttribute, DynamicModuleResolution, @@ -279,6 +280,7 @@ impl SystemClauseType { pub fn name(&self) -> ClauseName { match self { &SystemClauseType::CheckCutPoint => clause_name!("$check_cp"), + &SystemClauseType::Deallocate => clause_name!("$deallocate"), &SystemClauseType::DeleteAttribute => clause_name!("$del_attr_non_head"), &SystemClauseType::DeleteHeadAttribute => clause_name!("$del_attr_head"), &SystemClauseType::DynamicModuleResolution => clause_name!("$module_call"), @@ -320,6 +322,7 @@ impl SystemClauseType { pub fn from(name: &str, arity: usize) -> Option { match (name, arity) { ("$check_cp", 1) => Some(SystemClauseType::CheckCutPoint), + ("$deallocate", 0) => Some(SystemClauseType::Deallocate), ("$del_attr_non_head", 1) => Some(SystemClauseType::DeleteAttribute), ("$del_attr_head", 1) => Some(SystemClauseType::DeleteHeadAttribute), ("$module_call", 2) => Some(SystemClauseType::DynamicModuleResolution), @@ -372,6 +375,7 @@ pub enum BuiltInClauseType { Ground, Is(RegType, ArithmeticTerm), KeySort, + Nl, NotEq, PartialString, Read, @@ -450,6 +454,7 @@ impl BuiltInClauseType { &BuiltInClauseType::Ground => clause_name!("ground"), &BuiltInClauseType::Is(..) => clause_name!("is"), &BuiltInClauseType::KeySort => clause_name!("keysort"), + &BuiltInClauseType::Nl => clause_name!("nl"), &BuiltInClauseType::NotEq => clause_name!("\\=="), &BuiltInClauseType::Read => clause_name!("read"), &BuiltInClauseType::Sort => clause_name!("sort"), @@ -471,6 +476,7 @@ impl BuiltInClauseType { &BuiltInClauseType::Is(..) => 2, &BuiltInClauseType::KeySort => 2, &BuiltInClauseType::NotEq => 2, + &BuiltInClauseType::Nl => 0, &BuiltInClauseType::Read => 1, &BuiltInClauseType::Sort => 2, &BuiltInClauseType::PartialString => 1, @@ -495,6 +501,7 @@ impl BuiltInClauseType { ("ground", 1) => Some(BuiltInClauseType::Ground), ("is", 2) => Some(BuiltInClauseType::Is(temp_v!(1), ArithmeticTerm::Reg(temp_v!(2)))), ("keysort", 2) => Some(BuiltInClauseType::KeySort), + ("nl", 0) => Some(BuiltInClauseType::Nl), ("\\==", 2) => Some(BuiltInClauseType::NotEq), ("sort", 2) => Some(BuiltInClauseType::Sort), ("read", 1) => Some(BuiltInClauseType::Read), @@ -927,7 +934,7 @@ pub enum CodePtr { BuiltInClause(BuiltInClauseType, LocalCodePtr), // local is the successor call. CallN(usize, LocalCodePtr), // arity, local. Local(LocalCodePtr), - VerifyAttrInterrupt(usize) // location of the verify attribute interrupt code in the CodeDir. + VerifyAttrInterrupt(usize), // location of the verify attribute interrupt code in the CodeDir. } impl CodePtr { @@ -936,7 +943,7 @@ impl CodePtr { &CodePtr::BuiltInClause(_, ref local) | &CodePtr::CallN(_, ref local) | &CodePtr::Local(ref local) => local.clone(), - &CodePtr::VerifyAttrInterrupt(p) => LocalCodePtr::DirEntry(p) + &CodePtr::VerifyAttrInterrupt(p) => LocalCodePtr::DirEntry(p), } } } diff --git a/src/prolog/lib/dif.pl b/src/prolog/lib/dif.pl index fadf9fea..5b6ba1c3 100644 --- a/src/prolog/lib/dif.pl +++ b/src/prolog/lib/dif.pl @@ -36,22 +36,23 @@ verify_attributes(Var, Value, Goals) :- % suggestions for improvement. dif(X, Y) :- ( X \= Y -> true - ; term_variables(X, XVars), term_variables(Y, YVars), - ( XVars == [], YVars == [] -> false + ; term_variables(X, XVars), term_variables(Y, YVars), + ( XVars == [], YVars == [] -> true ; dif_set_variables(XVars, X, Y), dif_set_variables(YVars, X, Y) ) ). -gather_dif_goals(Attrs, Goal, Goal) :- +gather_dif_goals(Attrs, _) :- var(Attrs), !. -gather_dif_goals([dif(X, Y)|Attrs], OldGoal, Goal) :- - ( var(OldGoal), !, gather_dif_goals(Attrs, dif(X, Y), Goal) - ; !, gather_dif_goals(Attrs, (dif(X, Y), OldGoal), Goal) - ). -gather_dif_goals([_|Attrs], OldGoal, Goal) :- - gather_dif_goals(Attrs, OldGoal, Goal). +gather_dif_goals([dif(X, Y) | Attrs], Goal) :- + gather_dif_goals(Attrs, OldGoal), + ( var(OldGoal), !, Goal = dif(X, Y) + ; !, Goal = (dif(X, Y), OldGoal) + ). +gather_dif_goals([_ | Attrs], Goal) :- + gather_dif_goals(Attrs, Goal). attribute_goals(X, Goal) :- '$get_attr_list'(X, Attrs), - gather_dif_goals(Attrs, _, Goal). + gather_dif_goals(Attrs, Goal). diff --git a/src/prolog/machine/attributed_variables.rs b/src/prolog/machine/attributed_variables.rs index 75ec9db2..b1b56fc7 100644 --- a/src/prolog/machine/attributed_variables.rs +++ b/src/prolog/machine/attributed_variables.rs @@ -1,11 +1,14 @@ +use prolog::heap_iter::*; use prolog::machine::*; +use std::collections::HashSet; + pub static VERIFY_ATTRS: &str = include_str!("attributed_variables.pl"); pub static PROJECT_ATTRS: &str = include_str!("project_attributes.pl"); pub(super) type Bindings = Vec<(usize, Addr)>; -pub(super) struct AttrVarInitializer { +pub(super) struct AttrVarInitializer { pub(super) bindings: Bindings, pub(super) cp: LocalCodePtr, pub(super) verify_attrs_loc: usize, @@ -52,7 +55,7 @@ impl MachineState { pub(super) fn calculate_register_threshold(&self) -> usize { let mut count = 0; - + for r in 1 .. MAX_ARITY + 1 { if let &Addr::HeapCell(0) = &self[RegType::Temp(r)] { break; @@ -63,7 +66,7 @@ impl MachineState { count } - + pub(super) fn verify_attributes(&mut self) { @@ -89,4 +92,79 @@ impl MachineState { self[temp_v!(1)] = var_list_addr; self[temp_v!(2)] = value_list_addr; } + + fn populate_project_attr_lists(&mut self, var_dict: &HeapVarDict) -> (Addr, Addr) + { + let mut query_vars = HashSet::new(); + let mut attr_vars = HashSet::new(); + + for (_, addr) in var_dict { + let iter = HCPreOrderIterator::new(&self, addr.clone()); + + for value in iter { + match value { + HeapCellValue::Addr(Addr::HeapCell(h)) => { + query_vars.insert(Addr::HeapCell(h)); + }, + HeapCellValue::Addr(Addr::StackCell(fr, sc)) => { + query_vars.insert(Addr::StackCell(fr, sc)); + }, + HeapCellValue::Addr(Addr::AttrVar(h)) => { + attr_vars.insert(Addr::AttrVar(h)); + }, + _ => {} + }; + } + } + + let query_var_list = Addr::HeapCell(self.heap.to_list(query_vars.into_iter())); + let attr_var_list = Addr::HeapCell(self.heap.to_list(attr_vars.into_iter())); + + (query_var_list, attr_var_list) + } + + pub(super) + fn verify_attr_interrupt(&mut self, p: usize) { + let rs = self.calculate_register_threshold(); + + // store temp vars in perm vars slots along with + // self.b0 and self.num_of_args. why self.bo? if we return to a + // NeckCut after finishing the interrupt, it won't + // work correctly if self.b == self.b0. we must + // change it back when we return, as if nothing happened. + self.allocate(rs + 2); + + let e = self.e; + self.and_stack[e].special_form_cp = self.attr_var_init.cp; + + for i in 1 .. rs + 1 { + self.and_stack[e][i] = self[RegType::Temp(i)].clone(); + } + + self.and_stack[e][rs + 1] = Addr::Con(Constant::Usize(self.b0)); + self.and_stack[e][rs + 2] = Addr::Con(Constant::Usize(self.num_of_args)); + + self.verify_attributes(); + + self.num_of_args = 2; + self.b0 = self.b; + self.p = CodePtr::Local(LocalCodePtr::DirEntry(p)); + } +} + +impl Machine { + pub + fn attribute_goals(&mut self, var_dict: &HeapVarDict) + { + let p = self.machine_st.attr_var_init.project_attrs_loc; + let (query_vars, attr_vars) = self.machine_st.populate_project_attr_lists(var_dict); + + self.machine_st.allocate(0); + + self.machine_st[temp_v!(1)] = query_vars; + self.machine_st[temp_v!(2)] = attr_vars; + + self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(p)); + self.machine_st.query_stepper(&mut self.indices, &mut self.policies, &mut self.code_repo); + } } diff --git a/src/prolog/machine/machine_state.rs b/src/prolog/machine/machine_state.rs index ffa6da86..ec979842 100644 --- a/src/prolog/machine/machine_state.rs +++ b/src/prolog/machine/machine_state.rs @@ -12,13 +12,13 @@ use prolog::or_stack::*; use downcast::Any; use std::cmp::Ordering; -use std::io::stdin; +use std::io::{Write, stdin, stdout}; use std::mem::swap; use std::ops::{Index, IndexMut}; use std::rc::Rc; pub(super) struct Ball { - pub(super) boundary: usize, // ball.0 + pub(super) boundary: usize, // ball.0 pub(super) stub: MachineStub, // ball.1 } @@ -378,7 +378,7 @@ pub(crate) trait CallPolicy: Any { machine_st.pstr_trail.truncate(machine_st.pstr_tr); machine_st.heap.truncate(machine_st.or_stack[b].h); - + machine_st.hb = machine_st.heap.h; machine_st.p += offset; @@ -547,6 +547,13 @@ pub(crate) trait CallPolicy: Any { machine_st.fail = !machine_st.is_cyclic_term(addr); return_from_clause!(machine_st.last_call, machine_st) }, + &BuiltInClauseType::Nl => { + let mut stdout = stdout(); + + write!(stdout, "\n\r").unwrap(); + stdout.flush().unwrap(); + return_from_clause!(machine_st.last_call, machine_st) + }, &BuiltInClauseType::Read => { match machine_st.read(stdin(), indices.atom_tbl.clone(), &indices.op_dir) { Ok(offset) => { diff --git a/src/prolog/machine/machine_state_impl.rs b/src/prolog/machine/machine_state_impl.rs index 4299c565..e9feda1a 100644 --- a/src/prolog/machine/machine_state_impl.rs +++ b/src/prolog/machine/machine_state_impl.rs @@ -152,7 +152,7 @@ impl MachineState { fn print_var_eq(&self, var: Rc, addr: Addr, var_dir: &HeapVarDict, mut output: Outputter) -> Outputter - where Outputter: HCValueOutputter + where Outputter: HCValueOutputter { let orig_len = output.len(); @@ -180,7 +180,7 @@ impl MachineState { pub(super) fn print_exception(&self, addr: Addr, var_dir: &HeapVarDict, output: Outputter) -> Outputter - where Outputter: HCValueOutputter + where Outputter: HCValueOutputter { let printer = HCPrinter::from_heap_locs(&self, output, var_dir); printer.print(addr) @@ -1626,7 +1626,7 @@ impl MachineState { | (HeapCellValue::Addr(Addr::HeapCell(hc1)), HeapCellValue::Addr(Addr::AttrVar(hc2))) | (HeapCellValue::Addr(Addr::AttrVar(hc1)), - HeapCellValue::Addr(Addr::AttrVar(hc2))) => + HeapCellValue::Addr(Addr::AttrVar(hc2))) => if hc1 != hc2 { return hc1.cmp(&hc2); }, @@ -2260,7 +2260,7 @@ impl MachineState { self.tr, self.pstr_tr, self.heap.h, - self.b0, + self.b0, self.num_of_args); self.b = self.or_stack.len(); diff --git a/src/prolog/machine/mod.rs b/src/prolog/machine/mod.rs index aa693685..1b6ac2a5 100644 --- a/src/prolog/machine/mod.rs +++ b/src/prolog/machine/mod.rs @@ -502,7 +502,7 @@ impl Machine { for (var, addr) in sorted_vars { output = self.machine_st.print_var_eq(var.clone(), addr.clone(), var_dir, output); } - + output } @@ -604,34 +604,7 @@ impl MachineState { _ => {} }; } - } - - fn verify_attr_interrupt(&mut self, p: usize) { - let rs = self.calculate_register_threshold(); - - // store temp vars in perm vars slots along with - // self.b0 and self.num_of_args. why self.bo? if we return to a - // NeckCut after finishing the interrupt, it won't - // work correctly if self.b == self.b0. we must - // change it back when we return, as if nothing happened. - self.allocate(rs + 2); - - let e = self.e; - self.and_stack[e].special_form_cp = self.attr_var_init.cp; - - for i in 1 .. rs + 1 { - self.and_stack[e][i] = self[RegType::Temp(i)].clone(); - } - - self.and_stack[e][rs + 1] = Addr::Con(Constant::Usize(self.b0)); - self.and_stack[e][rs + 2] = Addr::Con(Constant::Usize(self.num_of_args)); - - self.verify_attributes(); - - self.num_of_args = 2; - self.b0 = self.b; - self.p = CodePtr::Local(LocalCodePtr::DirEntry(p)); - } + } fn record_var_places(&self, chunk_num: usize, alloc_locs: &AllocVarDict, heap_locs: &mut HeapVarDict) diff --git a/src/prolog/machine/project_attributes.pl b/src/prolog/machine/project_attributes.pl index d876e5b5..d163aa27 100644 --- a/src/prolog/machine/project_attributes.pl +++ b/src/prolog/machine/project_attributes.pl @@ -1,46 +1,43 @@ -:- use_module(library(dcgs)). - driver(QueryVars, AttrVars) :- - phrase(gather_modules(AttrVars), Modules0), + gather_modules(AttrVars, Modules0, _), sort(Modules0, Modules), call_project_attributes(Modules, QueryVars, AttrVars), - call_attribute_goals(QueryVars), - call_attribute_goals(AttrVars). + call_attribute_goals(Modules, QueryVars), + call_attribute_goals(Modules, AttrVars), + '$deallocate'. call_project_attributes([], _, _). call_project_attributes([Module|Modules], QueryVars, AttrVars) :- ( catch(Module:project_attributes(QueryVars, AttrVars), - error(evaluation_error((Module:project_attributes/2), project_attributes/2)), + error(evaluation_error((Module:project_attributes)/2), project_attributes/2), true) -> true ; true ), call_project_attributes(Modules, QueryVars, AttrVars). -call_attribute_goals([]). -call_attribute_goals([AttrVar | AttrVars]) :- - ( '$get_attr_list'(AttrVar, Ls) -> call_goals(Ls, AttrVar) - ; true - ), - call_attribute_goals(AttrVars). +call_attribute_goals([], _). +call_attribute_goals([Module | Modules], AttrVars) :- + call_goals(AttrVars, Module), + call_attribute_goals(Modules, AttrVars). -call_goals(Ls, _) :- var(Ls), !. -call_goals([Attr|Attrs], X) :- - '$module_of'(Module, Attr), - ( catch(Module:attribute_goals(X, Goal), - error(evaluation_error((Module:attribute_goals/2), attribute_goals/2)), - writeq(Goal)) -> true +call_goals([], _). +call_goals([AttrVar|AttrVars], Module) :- + ( catch(Module:attribute_goals(AttrVar, Goal), + error(evaluation_error((Module:attribute_goals)/2), attribute_goals/2), + true), + nonvar(Goal) -> nl, writeq(Goal) ; true ), - call_goals(Attrs, X). + call_goals(AttrVars, Module). -gather_modules([]) --> []. -gather_modules([AttrVar|AttrVars]) --> - { '$get_attr_list'(AttrVar, Attrs) }, - gather_modules_for_attrs(Attrs), - gather_modules(AttrVars). +gather_modules([], [], _). +gather_modules([AttrVar|AttrVars], Modules, Modules0) :- + '$get_attr_list'(AttrVar, Attrs), + gather_modules_for_attrs(Attrs, Modules, Modules0), + gather_modules(AttrVars, Modules0, _). -gather_modules_for_attrs(Attrs) --> { var(Attrs), ! }. -gather_modules_for_attrs([Attr|Attrs]) --> - { '$module_of'(Module, Attr) }, - [Module], - gather_modules_for_attrs(Attrs). +gather_modules_for_attrs(Attrs, Modules, Modules) :- + var(Attrs), !. +gather_modules_for_attrs([Attr|Attrs], [Module|Modules], Modules0) :- + '$module_of'(Module, Attr), + gather_modules_for_attrs(Attrs, Modules, Modules0). diff --git a/src/prolog/machine/system_calls.rs b/src/prolog/machine/system_calls.rs index 6a96180a..5dec7962 100644 --- a/src/prolog/machine/system_calls.rs +++ b/src/prolog/machine/system_calls.rs @@ -30,20 +30,7 @@ impl MachineState { // a step in Brent's algorithm. fn brents_alg_step(&self, brent_st: &mut BrentAlgState) -> Option { - match self.heap[brent_st.hare].clone() { - HeapCellValue::Addr(Addr::Lis(l)) => { - brent_st.hare = l + 1; - brent_st.steps += 1; - - if brent_st.tortoise == brent_st.hare { - return Some(CycleSearchResult::NotList); - } else if brent_st.steps == brent_st.power { - brent_st.tortoise = brent_st.hare; - brent_st.power <<= 1; - } - - None - }, + match self.heap[brent_st.hare].clone() { HeapCellValue::NamedStr(..) => Some(CycleSearchResult::NotList), HeapCellValue::Addr(addr) => @@ -52,6 +39,19 @@ impl MachineState { Some(CycleSearchResult::ProperList(brent_st.steps)), Addr::HeapCell(_) | Addr::StackCell(..) => Some(CycleSearchResult::PartialList(brent_st.steps, brent_st.hare)), + Addr::Lis(l) => { + brent_st.hare = l + 1; + brent_st.steps += 1; + + if brent_st.tortoise == brent_st.hare { + return Some(CycleSearchResult::NotList); + } else if brent_st.steps == brent_st.power { + brent_st.tortoise = brent_st.hare; + brent_st.power <<= 1; + } + + None + }, _ => Some(CycleSearchResult::NotList) } @@ -204,6 +204,10 @@ impl MachineState { _ => self.fail = true }; }, + &SystemClauseType::Deallocate => { + self.deallocate(); + return Ok(()); + }, &SystemClauseType::DeleteAttribute => { let ls0 = self.store(self.deref(self[temp_v!(1)].clone())); @@ -453,11 +457,11 @@ impl MachineState { let e = self.e; let frame_len = self.and_stack[e].len(); - - for i in 1 .. frame_len - 1 { + + for i in 1 .. frame_len - 1 { self[RegType::Temp(i)] = self.and_stack[e][i].clone(); - } - + } + if let &Addr::Con(Constant::Usize(b0)) = &self.and_stack[e][frame_len - 1] { self.b0 = b0; } @@ -468,7 +472,7 @@ impl MachineState { self.p = CodePtr::Local(self.and_stack[e].special_form_cp); self.deallocate(); - + return Ok(()); }, &SystemClauseType::RestoreCutPolicy => { @@ -643,7 +647,7 @@ impl MachineState { } let mut output = printer.print(addr); - println!("{}", output.result()); + print!("{}", output.result()); } }; diff --git a/src/prolog/write.rs b/src/prolog/write.rs index 239feb4f..aae16284 100644 --- a/src/prolog/write.rs +++ b/src/prolog/write.rs @@ -360,18 +360,20 @@ pub fn print(wam: &mut Machine, result: EvalSession) { write!(stdout, "{}", bindings).unwrap(); stdout.flush().unwrap(); + wam.attribute_goals(&heap_locs); + if !wam.or_stack_is_empty() { stdout.flush().unwrap(); for c in stdin.keys() { match c.unwrap() { Key::Char(' ') | Key::Char(';') => { - write!(stdout, " ;\n\r").unwrap(); + write!(stdout, " ;\r\n").unwrap(); result = wam.continue_query(&alloc_locs, &mut heap_locs); break; }, Key::Char('.') => { - write!(stdout, " .\n\r").unwrap(); + write!(stdout, " .\r\n").unwrap(); return; }, _ => {} @@ -380,14 +382,14 @@ pub fn print(wam: &mut Machine, result: EvalSession) { if let &EvalSession::Error(SessionError::QueryFailure) = &result { - write!(stdout, "false.\n\r").unwrap(); + write!(stdout, "false.\r\n").unwrap(); stdout.flush().unwrap(); return; } if let &EvalSession::Error(SessionError::QueryFailureWithException(ref e)) = &result { - write!(stdout, "{}\n\r", error_string(e)).unwrap(); + write!(stdout, "{}\r\n", error_string(e)).unwrap(); stdout.flush().unwrap(); return; }