]> Repositorios git - scryer-prolog.git/commitdiff
correct project_attributes, correct compare_term_test and eq_test, polish attribute_g...
authorMark Thom <[email protected]>
Fri, 15 Feb 2019 04:59:24 +0000 (21:59 -0700)
committerMark Thom <[email protected]>
Fri, 15 Feb 2019 04:59:24 +0000 (21:59 -0700)
README.md
src/prolog/heap_iter.rs
src/prolog/instructions.rs
src/prolog/lib/dif.pl
src/prolog/machine/attributed_variables.pl
src/prolog/machine/attributed_variables.rs
src/prolog/machine/machine_state_impl.rs
src/prolog/machine/project_attributes.pl
src/prolog/machine/system_calls.rs

index e4517e85ae9cda3536726ab987a19eef626fc391..3e2f199622481960aa494d38ec2c97f63c8a73cc 100644 (file)
--- 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
index 2b96ff6931578d7e99388a70e28469b9963756bd..4847a4a3642f8c61b236e5b7f2f7ac0f9612bc5d 100644 (file)
@@ -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<HCIter> Iterator for HCAcyclicIterator<HCIter>
 pub struct HCZippedAcyclicIterator<HCIter> {
     i1: HCIter,
     i2: HCIter,
-    seen: HashSet<(Addr, Addr)>
+    seen: HashSet<(Addr, Addr)>,
+    pub first_to_expire: Ordering
 }
 
 impl<HCIter: MutStackHCIterator> HCZippedAcyclicIterator<HCIter>
 {
     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<HCIter> Iterator for HCZippedAcyclicIterator<HCIter>
             }
         }
 
-        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
         }
-    }
+    }    
 }
index d44fbdd03a3cbcce16a7a629de651d06948bdccd..a20f50d7ddc260fa232788991ac3221ba39ca17a 100644 (file)
@@ -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<SystemClauseType> {
         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),
index 7199ea8841abc21982e5a3617dbf9eacaeb98e0d..c2097fd4d478e9b096f7550ebd0d6adb57da52fd 100644 (file)
@@ -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),
index 90c041362ddffcda485945be30c216a4e721883f..f7b5493c5e49e084a1e18de602b2f1f4a98b7bee 100644 (file)
@@ -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),
index b1b56fc7fd07cf038f28bfc90df5ddfe30288bfb..bd7ec478feb516420e38e1eacc0742df9e3d5b9b 100644 (file)
@@ -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<Addr>,
     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<Addr> {
+        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);
     }
 }
index e9feda1a922027c7f65403861e7020dd04973c3d..34d4a8d8beedaf8fa5a08156d9d39c96fd5c2996 100644 (file)
@@ -149,7 +149,7 @@ impl MachineState {
     }
 
     pub(super)
-    fn print_var_eq<Outputter>(&self, var: Rc<Var>, addr: Addr, var_dir: &HeapVarDict,
+    fn print_var_eq<Outputter>(&self, var: Rc<Var>, 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<Outputter>(&self, addr: Addr, var_dir: &HeapVarDict, output: Outputter)
+    fn print_exception<Outputter>(&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) {
index d163aa27087efb3066ed15f51d2adf5cf449a122..a642ffa52afacb06a3c45de31b5b9f97180a5535 100644 (file)
@@ -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).
index 5dec796294515aeeb07ccfe08258baf8d2f19151..c3b4c9fe24f2fdfb86fce4143a9ee04560140fd6 100644 (file)
@@ -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();