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
use prolog::instructions::*;
use prolog::machine::machine_state::*;
+use std::cmp::Ordering;
use std::collections::HashSet;
use std::ops::Deref;
use std::vec::Vec;
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 }
}
}
}
}
- 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
}
- }
+ }
}
#[derive(Copy, Clone, PartialEq)]
pub enum SystemClauseType {
CheckCutPoint,
- Deallocate,
DeleteAttribute,
DeleteHeadAttribute,
DynamicModuleResolution,
+ EnqueueAttributeGoal,
ExpandGoal,
ExpandTerm,
GetAttributedVariableList,
GetDoubleQuotes,
InstallNewBlock,
ResetBlock,
- RestoreCodePtrFromSpecialFormCP,
+ ReturnFromAttributeGoals,
+ ReturnFromVerifyAttr,
SetBall,
SetCutPointByDefault(RegType),
SetDoubleQuotes,
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"),
&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"),
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),
("$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),
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),
'$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),
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");
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,
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());
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)
}
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)
{
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);
}
}
}
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
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;
}
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)
}
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 {
}
}
- 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(_)))
}
};
- Ordering::Equal
+ iter.first_to_expire
}
pub(super) fn reset_block(&mut self, addr: Addr) {
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) :-
( 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).
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()));
}
};
},
+ &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(());
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();