@@ -272,16 +272,10 @@ enum SystemClauseType {
|
||||
PathCanonical,
|
||||
#[strum_discriminants(strum(props(Arity = "3", Name = "$file_time")))]
|
||||
FileTime,
|
||||
#[strum_discriminants(strum(props(Arity = "1", Name = "$del_attr_non_head")))]
|
||||
DeleteAttribute,
|
||||
#[strum_discriminants(strum(props(Arity = "1", Name = "$del_attr_head")))]
|
||||
DeleteHeadAttribute,
|
||||
#[strum_discriminants(strum(props(Arity = "arity", Name = "$module_call")))]
|
||||
DynamicModuleResolution(usize),
|
||||
#[strum_discriminants(strum(props(Arity = "arity", Name = "$prepare_call_clause")))]
|
||||
PrepareCallClause(usize),
|
||||
#[strum_discriminants(strum(props(Arity = "1", Name = "$enqueue_attr_var")))]
|
||||
EnqueueAttributedVar,
|
||||
#[strum_discriminants(strum(props(Arity = "2", Name = "$fetch_global_var")))]
|
||||
FetchGlobalVar,
|
||||
#[strum_discriminants(strum(props(Arity = "1", Name = "$first_stream")))]
|
||||
@@ -566,8 +560,12 @@ enum SystemClauseType {
|
||||
GetClauseP,
|
||||
#[strum_discriminants(strum(props(Arity = "6", Name = "$invoke_clause_at_p")))]
|
||||
InvokeClauseAtP,
|
||||
#[strum_discriminants(strum(props(Arity = "2", Name = "$get_from_attr_list")))]
|
||||
#[strum_discriminants(strum(props(Arity = "3", Name = "$get_from_attr_list")))]
|
||||
GetFromAttributedVarList,
|
||||
#[strum_discriminants(strum(props(Arity = "3", Name = "$put_to_attr_list")))]
|
||||
PutToAttributedVarList,
|
||||
#[strum_discriminants(strum(props(Arity = "3", Name = "$del_from_attr_list")))]
|
||||
DeleteFromAttributedVarList,
|
||||
REPL(REPLCodePtr),
|
||||
}
|
||||
|
||||
@@ -1620,8 +1618,6 @@ fn generate_instruction_preface() -> TokenStream {
|
||||
&Instruction::CallDeleteDirectory(_) |
|
||||
&Instruction::CallPathCanonical(_) |
|
||||
&Instruction::CallFileTime(_) |
|
||||
&Instruction::CallDeleteAttribute(_) |
|
||||
&Instruction::CallDeleteHeadAttribute(_) |
|
||||
&Instruction::CallDynamicModuleResolution(..) |
|
||||
&Instruction::CallPrepareCallClause(..) |
|
||||
&Instruction::CallCompileInlineOrExpandedGoal(..) |
|
||||
@@ -1629,7 +1625,8 @@ fn generate_instruction_preface() -> TokenStream {
|
||||
&Instruction::CallGetClauseP(_) |
|
||||
&Instruction::CallInvokeClauseAtP(_) |
|
||||
&Instruction::CallGetFromAttributedVarList(_) |
|
||||
&Instruction::CallEnqueueAttributedVar(_) |
|
||||
&Instruction::CallPutToAttributedVarList(_) |
|
||||
&Instruction::CallDeleteFromAttributedVarList(_) |
|
||||
&Instruction::CallFetchGlobalVar(_) |
|
||||
&Instruction::CallFirstStream(_) |
|
||||
&Instruction::CallFlushOutput(_) |
|
||||
@@ -1836,8 +1833,6 @@ fn generate_instruction_preface() -> TokenStream {
|
||||
&Instruction::ExecuteDeleteDirectory(_) |
|
||||
&Instruction::ExecutePathCanonical(_) |
|
||||
&Instruction::ExecuteFileTime(_) |
|
||||
&Instruction::ExecuteDeleteAttribute(_) |
|
||||
&Instruction::ExecuteDeleteHeadAttribute(_) |
|
||||
&Instruction::ExecuteDynamicModuleResolution(..) |
|
||||
&Instruction::ExecutePrepareCallClause(..) |
|
||||
&Instruction::ExecuteCompileInlineOrExpandedGoal(..) |
|
||||
@@ -1845,7 +1840,8 @@ fn generate_instruction_preface() -> TokenStream {
|
||||
&Instruction::ExecuteGetClauseP(_) |
|
||||
&Instruction::ExecuteInvokeClauseAtP(_) |
|
||||
&Instruction::ExecuteGetFromAttributedVarList(_) |
|
||||
&Instruction::ExecuteEnqueueAttributedVar(_) |
|
||||
&Instruction::ExecutePutToAttributedVarList(_) |
|
||||
&Instruction::ExecuteDeleteFromAttributedVarList(_) |
|
||||
&Instruction::ExecuteFetchGlobalVar(_) |
|
||||
&Instruction::ExecuteFirstStream(_) |
|
||||
&Instruction::ExecuteFlushOutput(_) |
|
||||
|
||||
@@ -19,76 +19,12 @@
|
||||
'$default_attr_list'(PGs, Module, AttrVar).
|
||||
'$default_attr_list'([], _, _) --> [].
|
||||
|
||||
'$absent_attr'(V, Attr) :-
|
||||
'$get_attr_list'(V, Ls),
|
||||
'$absent_from_list'(Ls, Attr).
|
||||
|
||||
'$absent_from_list'(X, Attr) :-
|
||||
( var(X) ->
|
||||
true
|
||||
; X = [L|Ls],
|
||||
L \= Attr ->
|
||||
'$absent_from_list'(Ls, Attr)
|
||||
).
|
||||
|
||||
'$get_attr'(V, Attr) :-
|
||||
'$get_attr_list'(V, Ls),
|
||||
nonvar(Ls),
|
||||
'$get_from_attr_list'(Ls, Attr).
|
||||
|
||||
/*
|
||||
'$get_from_list'([L|Ls], V, Attr) :-
|
||||
nonvar(L),
|
||||
( L \= Attr ->
|
||||
nonvar(Ls),
|
||||
'$get_from_list'(Ls, V, Attr)
|
||||
; L = Attr
|
||||
).
|
||||
*/
|
||||
|
||||
'$put_attr'(V, Attr) :-
|
||||
'$get_attr_list'(V, Ls),
|
||||
'$add_to_list'(Ls, V, Attr).
|
||||
|
||||
'$add_to_list'(Ls, V, Attr) :-
|
||||
( var(Ls) ->
|
||||
Ls = [Attr | _],
|
||||
'$enqueue_attr_var'(V)
|
||||
; Ls = [_ | Ls0],
|
||||
'$add_to_list'(Ls0, V, Attr)
|
||||
).
|
||||
|
||||
'$del_attr'(Ls0, _, _) :-
|
||||
var(Ls0),
|
||||
!.
|
||||
'$del_attr'(Ls0, V, Attr) :-
|
||||
Ls0 = [Att | Ls1],
|
||||
nonvar(Att),
|
||||
( Att \= Attr ->
|
||||
'$del_attr_buried'(Ls0, Ls1, V, Attr)
|
||||
; '$del_attr_head'(V),
|
||||
'$del_attr'(Ls1, V, Attr)
|
||||
).
|
||||
|
||||
'$del_attr_step'(Ls1, V, Attr) :-
|
||||
( nonvar(Ls1) ->
|
||||
Ls1 = [_ | Ls2],
|
||||
'$del_attr_buried'(Ls1, Ls2, V, Attr)
|
||||
'$absent_attr'(V, Module, Attr) :-
|
||||
( '$get_from_attr_list'(V, Module, Attr) ->
|
||||
false
|
||||
; true
|
||||
).
|
||||
|
||||
%% assumptions: Ls0 is a list, Ls1 is its tail;
|
||||
%% the head of Ls0 can be ignored.
|
||||
'$del_attr_buried'(Ls0, Ls1, V, Attr) :-
|
||||
( var(Ls1) -> true
|
||||
; Ls1 = [Att | Ls2] ->
|
||||
( Att \= Attr ->
|
||||
'$del_attr_buried'(Ls1, Ls2, V, Attr)
|
||||
; '$del_attr_non_head'(Ls0), %% set tail of Ls0 = tail of Ls1. can be undone by backtracking.
|
||||
'$del_attr_step'(Ls1, V, Attr)
|
||||
)
|
||||
).
|
||||
|
||||
'$copy_attr_list'(L, _Module, []) :- var(L), !.
|
||||
'$copy_attr_list'([Module0:Att|Atts], Module, CopiedAtts) :-
|
||||
( Module0 == Module ->
|
||||
@@ -144,38 +80,28 @@ put_attr(Name, Arity, Module) -->
|
||||
{ functor(Attr, Name, Arity) },
|
||||
[(put_atts(V, +Attr) :-
|
||||
!,
|
||||
functor(Attr, Head, Arity),
|
||||
functor(AttrForm, Head, Arity),
|
||||
'$get_attr_list'(V, Ls),
|
||||
atts:'$del_attr'(Ls, V, Module:AttrForm),
|
||||
atts:'$put_attr'(V, Module:Attr)),
|
||||
'$put_to_attr_list'(V, Module, Attr)),
|
||||
(put_atts(V, Attr) :-
|
||||
!,
|
||||
functor(Attr, Head, Arity),
|
||||
functor(AttrForm, Head, Arity),
|
||||
'$get_attr_list'(V, Ls),
|
||||
atts:'$del_attr'(Ls, V, Module:AttrForm),
|
||||
atts:'$put_attr'(V, Module:Attr)),
|
||||
'$put_to_attr_list'(V, Module, Attr)),
|
||||
(put_atts(V, -Attr) :-
|
||||
!,
|
||||
functor(Attr, _, _),
|
||||
'$get_attr_list'(V, Ls),
|
||||
atts:'$del_attr'(Ls, V, Module:Attr))].
|
||||
'$del_from_attr_list'(V, Module, Attr))].
|
||||
|
||||
get_attr(Name, Arity, Module) -->
|
||||
{ functor(Attr, Name, Arity) },
|
||||
[(get_atts(V, +Attr) :-
|
||||
!,
|
||||
functor(Attr, _, _),
|
||||
atts:'$get_attr'(V, Module:Attr)),
|
||||
atts:'$get_from_attr_list'(V, Module, Attr)),
|
||||
(get_atts(V, Attr) :-
|
||||
!,
|
||||
functor(Attr, _, _),
|
||||
atts:'$get_attr'(V, Module:Attr)),
|
||||
atts:'$get_from_attr_list'(V, Module, Attr)),
|
||||
(get_atts(V, -Attr) :-
|
||||
!,
|
||||
functor(Attr, _, _),
|
||||
atts:'$absent_attr'(V, Module:Attr))].
|
||||
atts:'$absent_attr'(V, Module, Attr))].
|
||||
|
||||
user:goal_expansion(Term, M:put_atts(Var, Attr)) :-
|
||||
nonvar(Term),
|
||||
|
||||
@@ -52,6 +52,7 @@ impl MachineState {
|
||||
self.cp = INSTALL_VERIFY_ATTR_INTERRUPT;
|
||||
}
|
||||
|
||||
debug_assert_eq!(self.heap[h].get_tag(), HeapCellValueTag::AttrVar);
|
||||
self.attr_var_init.bindings.push((h, addr));
|
||||
}
|
||||
|
||||
@@ -63,10 +64,9 @@ impl MachineState {
|
||||
.map(|(ref h, _)| attr_var_as_cell!(*h));
|
||||
|
||||
let var_list_addr = heap_loc_as_cell!(iter_to_heap_list(&mut self.heap, iter));
|
||||
|
||||
let iter = self.attr_var_init.bindings.drain(0..).map(|(_, ref v)| *v);
|
||||
|
||||
let value_list_addr = heap_loc_as_cell!(iter_to_heap_list(&mut self.heap, iter));
|
||||
|
||||
(var_list_addr, value_list_addr)
|
||||
}
|
||||
|
||||
|
||||
@@ -3570,22 +3570,6 @@ impl Machine {
|
||||
self.file_time();
|
||||
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
|
||||
}
|
||||
&Instruction::CallDeleteAttribute(_) => {
|
||||
self.delete_attribute();
|
||||
self.machine_st.p += 1;
|
||||
}
|
||||
&Instruction::ExecuteDeleteAttribute(_) => {
|
||||
self.delete_attribute();
|
||||
self.machine_st.p = self.machine_st.cp;
|
||||
}
|
||||
&Instruction::CallDeleteHeadAttribute(_) => {
|
||||
self.delete_head_attribute();
|
||||
self.machine_st.p += 1;
|
||||
}
|
||||
&Instruction::ExecuteDeleteHeadAttribute(_) => {
|
||||
self.delete_head_attribute();
|
||||
self.machine_st.p = self.machine_st.cp;
|
||||
}
|
||||
&Instruction::CallDynamicModuleResolution(arity, _) => {
|
||||
let (module_name, key) = try_or_throw!(
|
||||
self.machine_st,
|
||||
@@ -3616,14 +3600,6 @@ impl Machine {
|
||||
self.machine_st.backtrack();
|
||||
}
|
||||
}
|
||||
&Instruction::CallEnqueueAttributedVar(_) => {
|
||||
self.enqueue_attributed_var();
|
||||
self.machine_st.p += 1;
|
||||
}
|
||||
&Instruction::ExecuteEnqueueAttributedVar(_) => {
|
||||
self.enqueue_attributed_var();
|
||||
self.machine_st.p = self.machine_st.cp;
|
||||
}
|
||||
&Instruction::CallFetchGlobalVar(_) => {
|
||||
self.fetch_global_var();
|
||||
step_or_fail!(self, self.machine_st.p += 1);
|
||||
@@ -5215,6 +5191,22 @@ impl Machine {
|
||||
self.get_from_attributed_variable_list();
|
||||
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
|
||||
}
|
||||
&Instruction::CallPutToAttributedVarList(_) => {
|
||||
self.put_to_attributed_variable_list();
|
||||
step_or_fail!(self, self.machine_st.p += 1);
|
||||
}
|
||||
&Instruction::ExecutePutToAttributedVarList(_) => {
|
||||
self.put_to_attributed_variable_list();
|
||||
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
|
||||
}
|
||||
&Instruction::CallDeleteFromAttributedVarList(_) => {
|
||||
self.delete_from_attributed_variable_list();
|
||||
step_or_fail!(self, self.machine_st.p += 1);
|
||||
}
|
||||
&Instruction::ExecuteDeleteFromAttributedVarList(_) => {
|
||||
self.delete_from_attributed_variable_list();
|
||||
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -870,7 +870,18 @@ impl Machine {
|
||||
let l = self.machine_st.trail[i + 1].get_value() as usize;
|
||||
|
||||
if l < self.machine_st.hb {
|
||||
if h == l {
|
||||
self.machine_st.heap[h] = heap_loc_as_cell!(h);
|
||||
} else {
|
||||
read_heap_cell!(self.machine_st.heap[l],
|
||||
(HeapCellValueTag::Var) => {
|
||||
self.machine_st.heap[h] = list_loc_as_cell!(l);
|
||||
}
|
||||
_ => {
|
||||
self.machine_st.heap[h] = heap_loc_as_cell!(l);
|
||||
}
|
||||
);
|
||||
}
|
||||
} else {
|
||||
self.machine_st.heap[h] = heap_loc_as_cell!(h);
|
||||
}
|
||||
|
||||
@@ -456,7 +456,41 @@ impl BrentAlgState {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum MatchSite {
|
||||
NoMatchVarTail(usize), // no match, we refer to the location of the uninstantiated tail instead.
|
||||
Match(usize), // a match
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct AttrListMatch {
|
||||
match_site: MatchSite,
|
||||
prev_tail: Option<usize>,
|
||||
}
|
||||
|
||||
impl MachineState {
|
||||
pub(crate) fn get_attr_var_list(&mut self, attr_var: HeapCellValue) -> Option<usize> {
|
||||
read_heap_cell!(attr_var,
|
||||
(HeapCellValueTag::AttrVar, h) => {
|
||||
Some(h + 1)
|
||||
}
|
||||
(HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
|
||||
// create an AttrVar in the heap.
|
||||
let h = self.heap.len();
|
||||
|
||||
self.heap.push(attr_var_as_cell!(h));
|
||||
self.heap.push(heap_loc_as_cell!(h+1));
|
||||
|
||||
self.bind(Ref::attr_var(h), attr_var);
|
||||
|
||||
Some(h + 1)
|
||||
}
|
||||
_ => {
|
||||
None
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn name_and_arity_from_heap(&self, cell: HeapCellValue) -> Option<PredicateKey> {
|
||||
read_heap_cell!(self.store(self.deref(cell)),
|
||||
(HeapCellValueTag::Str, s) => {
|
||||
@@ -4308,15 +4342,8 @@ impl Machine {
|
||||
(HeapCellValueTag::AttrVar, h) => {
|
||||
h+1
|
||||
}
|
||||
(HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
|
||||
// create an AttrVar in the heap.
|
||||
let h = self.machine_st.heap.len();
|
||||
|
||||
self.machine_st.heap.push(attr_var_as_cell!(h));
|
||||
self.machine_st.heap.push(heap_loc_as_cell!(h+1));
|
||||
|
||||
self.machine_st.bind(Ref::attr_var(h), attr_var);
|
||||
h + 1
|
||||
(HeapCellValueTag::Var, h) => {
|
||||
h
|
||||
}
|
||||
_ => {
|
||||
self.machine_st.fail = true;
|
||||
@@ -4330,67 +4357,40 @@ impl Machine {
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn get_from_attributed_variable_list(&mut self) {
|
||||
let mut attrs_list = self.deref_register(1);
|
||||
let attr = self.deref_register(2);
|
||||
|
||||
let (name, arity) = match self.machine_st.name_and_arity_from_heap(attr) {
|
||||
Some(key) => key,
|
||||
None => {
|
||||
self.machine_st.fail = true;
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
while let HeapCellValueTag::Lis = attrs_list.get_tag() {
|
||||
let mut list_head = self.machine_st.heap[attrs_list.get_value()];
|
||||
|
||||
loop {
|
||||
read_heap_cell!(list_head,
|
||||
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
|
||||
if list_head != self.machine_st.heap[h] {
|
||||
list_head = self.machine_st.heap[h];
|
||||
} else {
|
||||
self.machine_st.fail = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
(HeapCellValueTag::Str | HeapCellValueTag::Atom) => {
|
||||
let (t_name, t_arity) = self.machine_st
|
||||
.name_and_arity_from_heap(list_head)
|
||||
.unwrap();
|
||||
|
||||
if name == t_name && arity == t_arity {
|
||||
let old_tr = self.machine_st.tr;
|
||||
|
||||
unify!(self.machine_st, list_head, attr);
|
||||
|
||||
if self.machine_st.fail {
|
||||
let curr_tr = self.machine_st.trail.len();
|
||||
|
||||
self.unwind_trail(old_tr, curr_tr);
|
||||
self.machine_st.tr = old_tr;
|
||||
|
||||
self.machine_st.pdl.clear();
|
||||
self.machine_st.fail = false;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
let attr_var = self.deref_register(1);
|
||||
let attr = self.deref_register(3);
|
||||
let attr_var_list = read_heap_cell!(attr_var,
|
||||
(HeapCellValueTag::AttrVar, h) => {
|
||||
self.machine_st.heap[h+1]
|
||||
}
|
||||
_ => {
|
||||
break;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
attrs_list = self.machine_st.store(
|
||||
self.machine_st.deref(self.machine_st.heap[attrs_list.get_value()+1])
|
||||
);
|
||||
}
|
||||
|
||||
self.machine_st.fail = true;
|
||||
return;
|
||||
}
|
||||
);
|
||||
|
||||
let module = self.deref_register(2);
|
||||
|
||||
match self.match_attribute(attr_var_list, module, attr) {
|
||||
Some(AttrListMatch { match_site: MatchSite::Match(match_site), .. }) => {
|
||||
let list_head = self.machine_st.heap[match_site];
|
||||
|
||||
if list_head.get_value() == match_site {
|
||||
// at the end of the list, no match found in this case.
|
||||
self.machine_st.fail = true;
|
||||
} else {
|
||||
let (_, qualified_goal) = self.machine_st.strip_module(
|
||||
list_head,
|
||||
empty_list_as_cell!(),
|
||||
);
|
||||
|
||||
unify!(self.machine_st, qualified_goal, attr);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
self.machine_st.fail = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
@@ -4427,81 +4427,202 @@ impl Machine {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn enqueue_attributed_var(&mut self) {
|
||||
let addr = self.deref_register(1);
|
||||
|
||||
read_heap_cell!(addr,
|
||||
pub(crate) fn delete_from_attributed_variable_list(&mut self) {
|
||||
let attr_var = self.deref_register(1);
|
||||
let attr = self.deref_register(3);
|
||||
let attr_var_list = read_heap_cell!(attr_var,
|
||||
(HeapCellValueTag::AttrVar, h) => {
|
||||
self.machine_st.attr_var_init.attr_var_queue.push(h);
|
||||
h + 1
|
||||
}
|
||||
_ => {
|
||||
return;
|
||||
}
|
||||
);
|
||||
|
||||
let module = self.deref_register(2);
|
||||
|
||||
match self.match_attribute(self.machine_st.heap[attr_var_list], module, attr) {
|
||||
Some(AttrListMatch { prev_tail, match_site: MatchSite::Match(match_site) }) => {
|
||||
let prev_tail = if let Some(prev_tail) = prev_tail {
|
||||
// not at the head.
|
||||
prev_tail
|
||||
} else {
|
||||
if self.machine_st.heap[match_site + 1].is_var() {
|
||||
let h = attr_var.get_value();
|
||||
|
||||
self.machine_st.heap[h] = heap_loc_as_cell!(h);
|
||||
self.machine_st.trail(TrailRef::Ref(Ref::attr_var(h)));
|
||||
}
|
||||
|
||||
// at the head.
|
||||
attr_var_list
|
||||
};
|
||||
|
||||
if self.machine_st.heap[match_site + 1].get_tag() == HeapCellValueTag::Lis {
|
||||
let prev_tail_value = self.machine_st.heap[match_site + 1].get_value();
|
||||
self.machine_st.heap[prev_tail].set_value(prev_tail_value);
|
||||
} else {
|
||||
self.machine_st.heap[prev_tail] = heap_loc_as_cell!(prev_tail);
|
||||
}
|
||||
|
||||
self.machine_st.trail(TrailRef::AttrVarListLink(prev_tail, match_site));
|
||||
}
|
||||
_ => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn put_to_attributed_variable_list(&mut self) {
|
||||
let attr_var = self.deref_register(1);
|
||||
let attr = self.deref_register(3);
|
||||
let attr_var_list = match self.machine_st.get_attr_var_list(attr_var) {
|
||||
Some(h) => h,
|
||||
None => {
|
||||
self.machine_st.fail = true;
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let module = self.deref_register(2);
|
||||
|
||||
/*
|
||||
* How to handle attribute trailing using just AttrVarListLink (which
|
||||
* should be re-named to something more general) in unwind_trail:
|
||||
*
|
||||
* Given AttrVarListLink(h, l):
|
||||
*
|
||||
* 1. Check cell at offset l.
|
||||
* 2. If h == l, set heap[h] = heap_loc_as_cell!(h).
|
||||
* 3. If cell is a Var, set heap[h] = list_loc_as_cell!(l).
|
||||
* 4. Otherwise, cell points to an element of the list which is therefore
|
||||
* an atom or str. Set heap[h] accordingly.
|
||||
*
|
||||
* For this to work, all elements of attributed variable lists must be
|
||||
* heap cell locs pointing to later elements in the heap, either atoms (0-arity)
|
||||
* or str cells (> 0-arity).
|
||||
*/
|
||||
|
||||
let h = self.machine_st.heap.len();
|
||||
|
||||
self.machine_st.heap.push(str_loc_as_cell!(h+1));
|
||||
self.machine_st.heap.extend(functor!(atom!(":"), [cell(module), cell(attr)]));
|
||||
|
||||
match self.match_attribute(self.machine_st.heap[attr_var_list], module, attr) {
|
||||
Some(AttrListMatch { match_site, .. }) => {
|
||||
let (match_site, l) = match match_site {
|
||||
MatchSite::NoMatchVarTail(match_site) => {
|
||||
let l = self.machine_st.heap[match_site].get_value();
|
||||
|
||||
// at the end of the (non-empty) list here.
|
||||
self.machine_st.heap[match_site] = list_loc_as_cell!(h+4);
|
||||
self.machine_st.heap.push(heap_loc_as_cell!(h));
|
||||
self.machine_st.heap.push(heap_loc_as_cell!(h+5));
|
||||
|
||||
(match_site, l)
|
||||
}
|
||||
MatchSite::Match(match_site) => {
|
||||
let l = self.machine_st.heap[match_site].get_value();
|
||||
self.machine_st.heap[match_site].set_value(h);
|
||||
|
||||
(match_site, l)
|
||||
}
|
||||
};
|
||||
|
||||
self.machine_st.trail(TrailRef::AttrVarListLink(match_site, l));
|
||||
}
|
||||
None => {
|
||||
// the list is empty.
|
||||
self.machine_st.heap[attr_var_list] = list_loc_as_cell!(h+4);
|
||||
self.machine_st.heap.push(heap_loc_as_cell!(h));
|
||||
self.machine_st.heap.push(heap_loc_as_cell!(h+5));
|
||||
|
||||
self.machine_st.attr_var_init.attr_var_queue.push(attr_var_list - 1);
|
||||
self.machine_st.trail(TrailRef::AttrVarListLink(attr_var_list, attr_var_list));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn match_attribute(
|
||||
&self,
|
||||
mut attrs_list: HeapCellValue,
|
||||
module: HeapCellValue,
|
||||
attr: HeapCellValue,
|
||||
) -> Option<AttrListMatch> {
|
||||
let (name, arity) = match self.machine_st.name_and_arity_from_heap(attr) {
|
||||
Some(key) => key,
|
||||
None => {
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
let mut prev_tail = None;
|
||||
|
||||
while let HeapCellValueTag::Lis = attrs_list.get_tag() {
|
||||
let mut list_head = self.machine_st.heap[attrs_list.get_value()];
|
||||
|
||||
loop {
|
||||
read_heap_cell!(list_head,
|
||||
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
|
||||
debug_assert!(list_head != self.machine_st.heap[h]);
|
||||
list_head = self.machine_st.heap[h];
|
||||
}
|
||||
(HeapCellValueTag::Str | HeapCellValueTag::Atom) => {
|
||||
let (module_loc, qualified_goal) = self.machine_st.strip_module(
|
||||
list_head,
|
||||
empty_list_as_cell!(),
|
||||
);
|
||||
|
||||
let (t_name, t_arity) = self.machine_st
|
||||
.name_and_arity_from_heap(qualified_goal)
|
||||
.unwrap();
|
||||
|
||||
if module == module_loc && name == t_name && arity == t_arity {
|
||||
return Some(AttrListMatch {
|
||||
match_site: MatchSite::Match(attrs_list.get_value()),
|
||||
prev_tail,
|
||||
});
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
_ => {
|
||||
break;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn delete_attribute(&mut self) {
|
||||
let ls0 = self.deref_register(1);
|
||||
let tail_loc = attrs_list.get_value() + 1;
|
||||
prev_tail = Some(tail_loc);
|
||||
|
||||
if let HeapCellValueTag::Lis = ls0.get_tag() {
|
||||
let l1 = ls0.get_value();
|
||||
let ls1 = self.machine_st.store(self.machine_st.deref(heap_loc_as_cell!(l1 + 1)));
|
||||
// do the work of self.store(self.deref(...)) but inline it
|
||||
// for speed and simplify it.
|
||||
let mut list_tail = self.machine_st.heap[tail_loc];
|
||||
|
||||
if let HeapCellValueTag::Lis = ls1.get_tag() {
|
||||
let l2 = ls1.get_value();
|
||||
|
||||
let old_addr = self.machine_st.store(self.machine_st.deref(self.machine_st.heap[l1+1]));
|
||||
let tail = self.machine_st.store(self.machine_st.deref(heap_loc_as_cell!(l2 + 1)));
|
||||
|
||||
let tail = if tail.is_var() {
|
||||
heap_loc_as_cell!(l1 + 1)
|
||||
loop {
|
||||
read_heap_cell!(list_tail,
|
||||
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
|
||||
if list_tail != self.machine_st.heap[h] {
|
||||
list_tail = self.machine_st.heap[h];
|
||||
} else {
|
||||
tail
|
||||
};
|
||||
|
||||
let trail_ref = read_heap_cell!(old_addr,
|
||||
(HeapCellValueTag::Var, h) => {
|
||||
TrailRef::AttrVarHeapLink(h)
|
||||
return Some(AttrListMatch {
|
||||
match_site: MatchSite::NoMatchVarTail(h),
|
||||
prev_tail,
|
||||
});
|
||||
}
|
||||
(HeapCellValueTag::Lis, l) => {
|
||||
TrailRef::AttrVarListLink(l1 + 1, l)
|
||||
}
|
||||
(HeapCellValueTag::Lis) => {
|
||||
attrs_list = list_tail;
|
||||
break;
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
);
|
||||
|
||||
self.machine_st.heap[l1 + 1] = tail;
|
||||
self.machine_st.trail(trail_ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn delete_head_attribute(&mut self) {
|
||||
let addr = self.deref_register(1);
|
||||
|
||||
debug_assert_eq!(addr.get_tag(), HeapCellValueTag::AttrVar);
|
||||
|
||||
let h = addr.get_value();
|
||||
let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.heap[h + 1]));
|
||||
|
||||
debug_assert_eq!(addr.get_tag(), HeapCellValueTag::Lis);
|
||||
|
||||
let l = addr.get_value();
|
||||
let tail = self.machine_st.store(self.machine_st.deref(self.machine_st.heap[l + 1]));
|
||||
|
||||
let tail = if tail.is_var() {
|
||||
self.machine_st.heap[h] = heap_loc_as_cell!(h);
|
||||
self.machine_st.trail(TrailRef::Ref(Ref::attr_var(h)));
|
||||
|
||||
heap_loc_as_cell!(h + 1)
|
||||
} else {
|
||||
tail
|
||||
};
|
||||
|
||||
self.machine_st.heap[h + 1] = tail;
|
||||
self.machine_st.trail(TrailRef::AttrVarListLink(h + 1, l));
|
||||
None
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
||||
Reference in New Issue
Block a user