fix attribute_goals/2 display bugs, cycle detection bug

This commit is contained in:
Mark Thom
2019-02-14 01:12:52 -07:00
parent f616b4ddfd
commit cd5549ee5b
12 changed files with 176 additions and 107 deletions

View File

@@ -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);
}
}

View File

@@ -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) => {

View File

@@ -152,7 +152,7 @@ impl MachineState {
fn print_var_eq<Outputter>(&self, var: Rc<Var>, 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<Outputter>(&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();

View File

@@ -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)

View File

@@ -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)
call_attribute_goals([], _).
call_attribute_goals([Module | Modules], AttrVars) :-
call_goals(AttrVars, Module),
call_attribute_goals(Modules, AttrVars).
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_attribute_goals(AttrVars).
call_goals(AttrVars, Module).
call_goals(Ls, _) :- var(Ls), !.
call_goals([Attr|Attrs], X) :-
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, Modules, Modules) :-
var(Attrs), !.
gather_modules_for_attrs([Attr|Attrs], [Module|Modules], Modules0) :-
'$module_of'(Module, Attr),
( catch(Module:attribute_goals(X, Goal),
error(evaluation_error((Module:attribute_goals/2), attribute_goals/2)),
writeq(Goal)) -> true
; true
),
call_goals(Attrs, X).
gather_modules([]) --> [].
gather_modules([AttrVar|AttrVars]) -->
{ '$get_attr_list'(AttrVar, Attrs) },
gather_modules_for_attrs(Attrs),
gather_modules(AttrVars).
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, Modules0).

View File

@@ -30,20 +30,7 @@ impl MachineState {
// a step in Brent's algorithm.
fn brents_alg_step(&self, brent_st: &mut BrentAlgState) -> Option<CycleSearchResult>
{
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());
}
};