From: Mark Thom Date: Fri, 15 Feb 2019 04:59:24 +0000 (-0700) Subject: correct project_attributes, correct compare_term_test and eq_test, polish attribute_g... X-Git-Tag: v0.8.110~253 X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=9abe70113a66caabb237cf0f85d030ce8bf09861;p=scryer-prolog.git correct project_attributes, correct compare_term_test and eq_test, polish attribute_goals/2 --- diff --git a/README.md b/README.md index e4517e85..3e2f1996 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ Extend rusty-wam to include the following, among other features: semantics. Adding coroutines like `dif/2`, `freeze/2`, etc. is straightforward with attributed variables (_in progress_). - [x] Support for `verify_attributes/3` in modules - - [ ] Support for `attribute_goals/2` at toplevel and + - [x] Support for `attribute_goals/2` at toplevel and `project_attributes/2` in modules - [ ] `call_residue_vars/2` * `if_` and related predicates, following the developments of the diff --git a/src/prolog/heap_iter.rs b/src/prolog/heap_iter.rs index 2b96ff69..4847a4a3 100644 --- a/src/prolog/heap_iter.rs +++ b/src/prolog/heap_iter.rs @@ -3,6 +3,7 @@ use prolog_parser::ast::*; use prolog::instructions::*; use prolog::machine::machine_state::*; +use std::cmp::Ordering; use std::collections::HashSet; use std::ops::Deref; use std::vec::Vec; @@ -216,13 +217,15 @@ impl Iterator for HCAcyclicIterator pub struct HCZippedAcyclicIterator { i1: HCIter, i2: HCIter, - seen: HashSet<(Addr, Addr)> + seen: HashSet<(Addr, Addr)>, + pub first_to_expire: Ordering } impl HCZippedAcyclicIterator { pub fn new(i1: HCIter, i2: HCIter) -> Self { - HCZippedAcyclicIterator { i1, i2, seen: HashSet::new() } + HCZippedAcyclicIterator { i1, i2, seen: HashSet::new(), + first_to_expire: Ordering::Equal } } } @@ -242,10 +245,18 @@ impl Iterator for HCZippedAcyclicIterator } } - if let (Some(v1), Some(v2)) = (self.i1.next(), self.i2.next()) { - Some((v1, v2)) - } else { - None + match (self.i1.next(), self.i2.next()) { + (Some(v1), Some(v2)) => + Some((v1, v2)), + (Some(_), None) => { + self.first_to_expire = Ordering::Greater; + None + }, + (None, Some(_)) => { + self.first_to_expire = Ordering::Less; + None + }, + _ => None } - } + } } diff --git a/src/prolog/instructions.rs b/src/prolog/instructions.rs index d44fbdd0..a20f50d7 100644 --- a/src/prolog/instructions.rs +++ b/src/prolog/instructions.rs @@ -238,10 +238,10 @@ pub struct Module { #[derive(Copy, Clone, PartialEq)] pub enum SystemClauseType { CheckCutPoint, - Deallocate, DeleteAttribute, DeleteHeadAttribute, DynamicModuleResolution, + EnqueueAttributeGoal, ExpandGoal, ExpandTerm, GetAttributedVariableList, @@ -265,7 +265,8 @@ pub enum SystemClauseType { GetDoubleQuotes, InstallNewBlock, ResetBlock, - RestoreCodePtrFromSpecialFormCP, + ReturnFromAttributeGoals, + ReturnFromVerifyAttr, SetBall, SetCutPointByDefault(RegType), SetDoubleQuotes, @@ -280,10 +281,10 @@ 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"), + &SystemClauseType::EnqueueAttributeGoal => clause_name!("$enqueue_attribute_goal"), &SystemClauseType::ExpandTerm => clause_name!("$expand_term"), &SystemClauseType::ExpandGoal => clause_name!("$expand_goal"), &SystemClauseType::GetAttributedVariableList => clause_name!("$get_attr_list"), @@ -307,7 +308,8 @@ impl SystemClauseType { &SystemClauseType::GetCurrentBlock => clause_name!("$get_current_block"), &SystemClauseType::InstallNewBlock => clause_name!("$install_new_block"), &SystemClauseType::ResetBlock => clause_name!("$reset_block"), - &SystemClauseType::RestoreCodePtrFromSpecialFormCP => clause_name!("$restore_p_from_sfcp"), + &SystemClauseType::ReturnFromAttributeGoals => clause_name!("$return_from_attribute_goals"), + &SystemClauseType::ReturnFromVerifyAttr => clause_name!("$return_from_verify_attr"), &SystemClauseType::SetBall => clause_name!("$set_ball"), &SystemClauseType::SetCutPointByDefault(_) => clause_name!("$set_cp_by_default"), &SystemClauseType::SetDoubleQuotes => clause_name!("$set_double_quotes"), @@ -322,10 +324,10 @@ 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), + ("$enqueue_attribute_goal", 1) => Some(SystemClauseType::EnqueueAttributeGoal), ("$expand_term", 2) => Some(SystemClauseType::ExpandTerm), ("$expand_goal", 2) => Some(SystemClauseType::ExpandGoal), ("$get_attr_list", 2) => Some(SystemClauseType::GetAttributedVariableList), @@ -349,7 +351,8 @@ impl SystemClauseType { ("$get_cp", 1) => Some(SystemClauseType::GetCutPoint), ("$install_new_block", 1) => Some(SystemClauseType::InstallNewBlock), ("$reset_block", 1) => Some(SystemClauseType::ResetBlock), - ("$restore_p_from_sfcp", 0) => Some(SystemClauseType::RestoreCodePtrFromSpecialFormCP), + ("$return_from_attribute_goals", 0) => Some(SystemClauseType::ReturnFromAttributeGoals), + ("$return_from_verify_attr", 0) => Some(SystemClauseType::ReturnFromVerifyAttr), ("$set_ball", 1) => Some(SystemClauseType::SetBall), ("$set_cp_by_default", 1) => Some(SystemClauseType::SetCutPointByDefault(temp_v!(1))), ("$set_double_quotes", 1) => Some(SystemClauseType::SetDoubleQuotes), diff --git a/src/prolog/lib/dif.pl b/src/prolog/lib/dif.pl index 7199ea88..c2097fd4 100644 --- a/src/prolog/lib/dif.pl +++ b/src/prolog/lib/dif.pl @@ -44,13 +44,10 @@ dif(X, Y) :- X \== Y, gather_dif_goals(Attrs, _) :- var(Attrs), !. -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). +gather_dif_goals([dif(X, Y) | Attrs], [dif(X, Y) | Goals]) :- + gather_dif_goals(Attrs, Goals). +gather_dif_goals([_ | Attrs], Goals) :- + gather_dif_goals(Attrs, Goals). attribute_goals(X, Goal) :- '$get_attr_list'(X, Attrs), diff --git a/src/prolog/machine/attributed_variables.pl b/src/prolog/machine/attributed_variables.pl index 90c04136..f7b5493c 100644 --- a/src/prolog/machine/attributed_variables.pl +++ b/src/prolog/machine/attributed_variables.pl @@ -3,7 +3,7 @@ driver(Vars, Values) :- '$redo_attr_var_bindings', % the bindings list is emptied here. !, call_goals(ListOfListsOfGoalLists), - '$restore_p_from_sfcp'. + '$return_from_verify_attr'. iterate([Var|VarBindings], [Value|ValueBindings], [ListOfGoalLists | ListsCubed]) :- '$get_attr_list'(Var, Ls), diff --git a/src/prolog/machine/attributed_variables.rs b/src/prolog/machine/attributed_variables.rs index b1b56fc7..bd7ec478 100644 --- a/src/prolog/machine/attributed_variables.rs +++ b/src/prolog/machine/attributed_variables.rs @@ -2,6 +2,7 @@ use prolog::heap_iter::*; use prolog::machine::*; use std::collections::HashSet; +use std::collections::hash_set::IntoIter; pub static VERIFY_ATTRS: &str = include_str!("attributed_variables.pl"); pub static PROJECT_ATTRS: &str = include_str!("project_attributes.pl"); @@ -9,15 +10,17 @@ pub static PROJECT_ATTRS: &str = include_str!("project_attributes.pl"); pub(super) type Bindings = Vec<(usize, Addr)>; pub(super) struct AttrVarInitializer { + pub(super) attribute_goals: Vec, pub(super) bindings: Bindings, pub(super) cp: LocalCodePtr, pub(super) verify_attrs_loc: usize, - pub(super) project_attrs_loc: usize + pub(super) project_attrs_loc: usize, } impl AttrVarInitializer { pub(super) fn new(verify_attrs_loc: usize, project_attrs_loc: usize) -> Self { AttrVarInitializer { + attribute_goals: vec![], bindings: vec![], cp: LocalCodePtr::default(), verify_attrs_loc, @@ -70,33 +73,37 @@ impl MachineState { pub(super) fn verify_attributes(&mut self) { - /* STEP 1: Undo bindings in machine. - STEP 2: Write the list of bindings to two lists in the heap, one for vars, one for values. - STEP 3: Pass the addresses of the lists to iterate in the attr_vars special form. - Call verify_attributes/3 wherever applicable. - STEP 4: Redo the bindings. - STEP 5: Call the goals. - STEP 6: Pop the top of AttrVarInitializer::cp_stack to self.p. - STEP 7: Swap the AttrVarInitializer's Registers back for the machine's Registers. - */ - - // STEP 1. for (h, _) in &self.attr_var_init.bindings { self.heap[*h] = HeapCellValue::Addr(Addr::AttrVar(*h)); } - // STEP 2. let (var_list_addr, value_list_addr) = self.populate_var_and_value_lists(); - // STEP 3. self[temp_v!(1)] = var_list_addr; self[temp_v!(2)] = value_list_addr; } + fn gather_attr_vars_created_since(&mut self, h: usize) -> IntoIter { + let mut attr_vars = HashSet::new(); + + for i in h .. self.heap.len() { + let addr = self.heap[i].as_addr(i); + + match self.store(self.deref(addr)) { + Addr::AttrVar(h) => { + attr_vars.insert(Addr::AttrVar(h)); + }, + _ => {} + } + } + + attr_vars.into_iter() + } + fn populate_project_attr_lists(&mut self, var_dict: &HeapVarDict) -> (Addr, Addr) { let mut query_vars = HashSet::new(); - let mut attr_vars = HashSet::new(); + let attr_vars = self.gather_attr_vars_created_since(0); for (_, addr) in var_dict { let iter = HCPreOrderIterator::new(&self, addr.clone()); @@ -109,16 +116,13 @@ impl MachineState { 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())); + let attr_var_list = Addr::HeapCell(self.heap.to_list(attr_vars)); (query_var_list, attr_var_list) } @@ -150,9 +154,37 @@ impl MachineState { self.b0 = self.b; self.p = CodePtr::Local(LocalCodePtr::DirEntry(p)); } + + fn print_attribute_goals(&mut self, var_dict: &HeapVarDict) + { + let attr_goals = mem::replace(&mut self.attr_var_init.attribute_goals, vec![]); + + if attr_goals.is_empty() { + return; + } + + let mut output = PrinterOutputter::new(); + + for goal_addr in attr_goals { + let mut printer = HCPrinter::from_heap_locs(&self, output, var_dict); + printer.see_all_locs(); + + printer.numbervars = false; + printer.quoted = true; + + output = printer.print(goal_addr); + output.append(", "); + } + + // cut trailing ", " + let output_len = output.len(); + output.truncate(output_len - 2); + + println!("\r\n{}\r", output.result()); + } } -impl Machine { +impl Machine { pub fn attribute_goals(&mut self, var_dict: &HeapVarDict) { @@ -166,5 +198,7 @@ impl Machine { self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(p)); self.machine_st.query_stepper(&mut self.indices, &mut self.policies, &mut self.code_repo); + + self.machine_st.print_attribute_goals(var_dict); } } diff --git a/src/prolog/machine/machine_state_impl.rs b/src/prolog/machine/machine_state_impl.rs index e9feda1a..34d4a8d8 100644 --- a/src/prolog/machine/machine_state_impl.rs +++ b/src/prolog/machine/machine_state_impl.rs @@ -149,7 +149,7 @@ impl MachineState { } pub(super) - fn print_var_eq(&self, var: Rc, addr: Addr, var_dir: &HeapVarDict, + fn print_var_eq(&self, var: Rc, addr: Addr, var_dict: &HeapVarDict, mut output: Outputter) -> Outputter where Outputter: HCValueOutputter @@ -161,7 +161,7 @@ impl MachineState { output.append(var.as_str()); output.append(" = "); - let mut printer = HCPrinter::from_heap_locs(&self, output, var_dir); + let mut printer = HCPrinter::from_heap_locs(&self, output, var_dict); printer.numbervars = false; printer.quoted = true; @@ -178,11 +178,11 @@ impl MachineState { } pub(super) - fn print_exception(&self, addr: Addr, var_dir: &HeapVarDict, output: Outputter) + fn print_exception(&self, addr: Addr, var_dict: &HeapVarDict, output: Outputter) -> Outputter where Outputter: HCValueOutputter { - let printer = HCPrinter::from_heap_locs(&self, output, var_dir); + let printer = HCPrinter::from_heap_locs(&self, output, var_dict); printer.print(addr) } @@ -1562,9 +1562,9 @@ impl MachineState { let a1 = self[temp_v!(1)].clone(); let a2 = self[temp_v!(2)].clone(); - let iter = self.zipped_acyclic_pre_order_iter(a1, a2); + let mut iter = self.zipped_acyclic_pre_order_iter(a1, a2); - for (v1, v2) in iter { + while let Some((v1, v2)) = iter.next() { match (v1, v2) { (HeapCellValue::NamedStr(ar1, n1, _), HeapCellValue::NamedStr(ar2, n2, _)) => if ar1 != ar2 || n1 != n2 { @@ -1580,13 +1580,14 @@ impl MachineState { } } - false + // did the two iterators expire at the same step? + iter.first_to_expire != Ordering::Equal } pub(super) fn compare_term_test(&self, a1: &Addr, a2: &Addr) -> Ordering { - let iter = self.zipped_acyclic_pre_order_iter(a1.clone(), a2.clone()); + let mut iter = self.zipped_acyclic_pre_order_iter(a1.clone(), a2.clone()); - for (v1, v2) in iter { + while let Some((v1, v2)) = iter.next() { match (v1, v2) { (HeapCellValue::Addr(Addr::Lis(_)), HeapCellValue::Addr(Addr::Con(Constant::String(_)))) | (HeapCellValue::Addr(Addr::Con(Constant::String(_))), HeapCellValue::Addr(Addr::Lis(_))) @@ -1742,7 +1743,7 @@ impl MachineState { } }; - Ordering::Equal + iter.first_to_expire } pub(super) fn reset_block(&mut self, addr: Addr) { diff --git a/src/prolog/machine/project_attributes.pl b/src/prolog/machine/project_attributes.pl index d163aa27..a642ffa5 100644 --- a/src/prolog/machine/project_attributes.pl +++ b/src/prolog/machine/project_attributes.pl @@ -4,7 +4,23 @@ driver(QueryVars, AttrVars) :- call_project_attributes(Modules, QueryVars, AttrVars), call_attribute_goals(Modules, QueryVars), call_attribute_goals(Modules, AttrVars), - '$deallocate'. + '$return_from_attribute_goals'. + +enqueue_goal(Goals0) :- + nonvar(Goals0), Goals0 = [Goal | Goals], !, + enqueue_goals(Goals0). % enqueue lists of goals separately. +enqueue_goal(Goal) :- + nonvar(Goal), + '$enqueue_attribute_goal'(Goal). % enqueue the goal for printing to the toplevel. + +enqueue_goals(Goals0) :- + nonvar(Goals0), + Goals0 = [Goal | Goals], + nonvar(Goal), + !, + '$enqueue_attribute_goal'(Goal), + enqueue_goals(Goals). +enqueue_goals(_). call_project_attributes([], _, _). call_project_attributes([Module|Modules], QueryVars, AttrVars) :- @@ -25,7 +41,7 @@ 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) + nonvar(Goal) -> enqueue_goal(Goal) ; true ), call_goals(AttrVars, Module). diff --git a/src/prolog/machine/system_calls.rs b/src/prolog/machine/system_calls.rs index 5dec7962..c3b4c9fe 100644 --- a/src/prolog/machine/system_calls.rs +++ b/src/prolog/machine/system_calls.rs @@ -203,11 +203,7 @@ impl MachineState { Addr::Con(Constant::Usize(old_b)) if self.b <= old_b + 2 => {}, _ => self.fail = true }; - }, - &SystemClauseType::Deallocate => { - self.deallocate(); - return Ok(()); - }, + }, &SystemClauseType::DeleteAttribute => { let ls0 = self.store(self.deref(self[temp_v!(1)].clone())); @@ -264,6 +260,10 @@ impl MachineState { } }; }, + &SystemClauseType::EnqueueAttributeGoal => { + let addr = self[temp_v!(1)].clone(); + self.attr_var_init.attribute_goals.push(addr); + }, &SystemClauseType::ExpandGoal => { self.p = CodePtr::Local(LocalCodePtr::UserGoalExpansion(0)); return Ok(()); @@ -453,7 +453,12 @@ impl MachineState { None => panic!("remove_inference_counter: requires \\ CWILCallPolicy.") }, - &SystemClauseType::RestoreCodePtrFromSpecialFormCP => { + &SystemClauseType::ReturnFromAttributeGoals => { + self.deallocate(); + self.p = CodePtr::Local(LocalCodePtr::TopLevel(0, 0)); + return Ok(()); + }, + &SystemClauseType::ReturnFromVerifyAttr => { let e = self.e; let frame_len = self.and_stack[e].len();