Merge branch 'master' into ffi
This commit is contained in:
12
Cargo.lock
generated
12
Cargo.lock
generated
@@ -367,6 +367,17 @@ dependencies = [
|
|||||||
"syn 1.0.103",
|
"syn 1.0.103",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "derive_deref"
|
||||||
|
version = "1.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dcdbcee2d9941369faba772587a565f4f534e42cb8d17e5295871de730163b2b"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2 1.0.47",
|
||||||
|
"quote 1.0.21",
|
||||||
|
"syn 1.0.103",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "difflib"
|
name = "difflib"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
@@ -1850,6 +1861,7 @@ dependencies = [
|
|||||||
"crossterm",
|
"crossterm",
|
||||||
"crrl",
|
"crrl",
|
||||||
"ctrlc",
|
"ctrlc",
|
||||||
|
"derive_deref",
|
||||||
"dirs-next",
|
"dirs-next",
|
||||||
"divrem",
|
"divrem",
|
||||||
"futures",
|
"futures",
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ tokio = { version = "1.24.2", features = ["full"] }
|
|||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
libffi = "3.1.0"
|
libffi = "3.1.0"
|
||||||
libloading = "0.7"
|
libloading = "0.7"
|
||||||
|
derive_deref = "1.1.1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
assert_cmd = "1.0.3"
|
assert_cmd = "1.0.3"
|
||||||
|
|||||||
17
README.md
17
README.md
@@ -6,14 +6,15 @@ source industrial strength production environment that is also a
|
|||||||
testbed for bleeding edge research in logic and constraint
|
testbed for bleeding edge research in logic and constraint
|
||||||
programming, which is itself written in a high-level language.
|
programming, which is itself written in a high-level language.
|
||||||
|
|
||||||
|
The homepage of the project is: [**https://www.scryer.pl**](https://www.scryer.pl)
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## Phase 1
|
## Phase 1
|
||||||
|
|
||||||
Produce an implementation of the Warren Abstract Machine in Rust, done
|
Produce an implementation of the Warren Abstract Machine in Rust, done
|
||||||
according to the progression of languages in [Warren's Abstract
|
according to the progression of languages in [Warren's Abstract
|
||||||
Machine: A Tutorial
|
Machine: A Tutorial Reconstruction](https://github.com/mthom/scryer-prolog/blob/master/wambook/wambook.pdf).
|
||||||
Reconstruction](https://github.com/mthom/scryer-prolog/blob/master/wambook/wambook.pdf).
|
|
||||||
|
|
||||||
Phase 1 has been completed in that Scryer Prolog implements in some form
|
Phase 1 has been completed in that Scryer Prolog implements in some form
|
||||||
all of the WAM book, including lists, cuts, Debray allocation, first
|
all of the WAM book, including lists, cuts, Debray allocation, first
|
||||||
@@ -52,9 +53,9 @@ Extend Scryer Prolog to include the following, among other features:
|
|||||||
`bb_put/2` (non-backtrackable) and `bb_b_put/2`
|
`bb_put/2` (non-backtrackable) and `bb_b_put/2`
|
||||||
(backtrackable).
|
(backtrackable).
|
||||||
- [x] Delimited continuations based on reset/3, shift/1 (documented in
|
- [x] Delimited continuations based on reset/3, shift/1 (documented in
|
||||||
"Delimited Continuations for Prolog").
|
"[Delimited Continuations for Prolog](https://biblio.ugent.be/publication/5646080/file/5646081)").
|
||||||
- [x] Tabling library based on delimited continuations
|
- [x] Tabling library based on delimited continuations
|
||||||
(documented in "Tabling as a Library with Delimited Control").
|
(documented in "[Tabling as a Library with Delimited Control](https://biblio.ugent.be/publication/6880648/file/6885145.pdf)").
|
||||||
- [x] A _redone_ representation of strings as difference lists of
|
- [x] A _redone_ representation of strings as difference lists of
|
||||||
characters, using a packed internal representation.
|
characters, using a packed internal representation.
|
||||||
- [x] clp(B) and clp(ℤ) as builtin libraries.
|
- [x] clp(B) and clp(ℤ) as builtin libraries.
|
||||||
@@ -69,7 +70,7 @@ Extend Scryer Prolog to include the following, among other features:
|
|||||||
- [ ] Greatly reducing the number of instructions used to compile disjunctives.
|
- [ ] Greatly reducing the number of instructions used to compile disjunctives.
|
||||||
- [ ] Storing short atoms to heap cells without writing them to the atom table.
|
- [ ] Storing short atoms to heap cells without writing them to the atom table.
|
||||||
- [ ] A compacting garbage collector satisfying the five properties of
|
- [ ] A compacting garbage collector satisfying the five properties of
|
||||||
"Precise Garbage Collection in Prolog." (_in progress_)
|
"[Precise Garbage Collection in Prolog](https://www.complang.tuwien.ac.at/ulrich/papers/PDF/2008-ciclops.pdf)." (_in progress_)
|
||||||
- [ ] Mode declarations.
|
- [ ] Mode declarations.
|
||||||
|
|
||||||
## Phase 3
|
## Phase 3
|
||||||
@@ -88,12 +89,12 @@ nice to have in the future. They'd make a good project for anyone wanting
|
|||||||
to contribute code to Scryer Prolog.
|
to contribute code to Scryer Prolog.
|
||||||
|
|
||||||
1. Implement the global analysis techniques described in Peter van
|
1. Implement the global analysis techniques described in Peter van
|
||||||
Roy's thesis, "Can Logic Programming Execute as Fast as Imperative
|
Roy's thesis, "[Can Logic Programming Execute as Fast as Imperative
|
||||||
Programming?"
|
Programming?](https://www.info.ucl.ac.be/~pvr/Peter.thesis/Peter.thesis.html)"
|
||||||
|
|
||||||
2. Add unum representation and arithmetic, using either an existing
|
2. Add unum representation and arithmetic, using either an existing
|
||||||
unum implementation or an ad hoc one. Unums are described in
|
unum implementation or an ad hoc one. Unums are described in
|
||||||
Gustafson's book "The End of Error."
|
Gustafson's book "[The End of Error](http://www.johngustafson.net/unums.html)."
|
||||||
|
|
||||||
3. Add concurrent tables to manage shared references to atoms and
|
3. Add concurrent tables to manage shared references to atoms and
|
||||||
strings.
|
strings.
|
||||||
|
|||||||
@@ -272,16 +272,10 @@ enum SystemClauseType {
|
|||||||
PathCanonical,
|
PathCanonical,
|
||||||
#[strum_discriminants(strum(props(Arity = "3", Name = "$file_time")))]
|
#[strum_discriminants(strum(props(Arity = "3", Name = "$file_time")))]
|
||||||
FileTime,
|
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")))]
|
#[strum_discriminants(strum(props(Arity = "arity", Name = "$module_call")))]
|
||||||
DynamicModuleResolution(usize),
|
DynamicModuleResolution(usize),
|
||||||
#[strum_discriminants(strum(props(Arity = "arity", Name = "$prepare_call_clause")))]
|
#[strum_discriminants(strum(props(Arity = "arity", Name = "$prepare_call_clause")))]
|
||||||
PrepareCallClause(usize),
|
PrepareCallClause(usize),
|
||||||
#[strum_discriminants(strum(props(Arity = "1", Name = "$enqueue_attr_var")))]
|
|
||||||
EnqueueAttributedVar,
|
|
||||||
#[strum_discriminants(strum(props(Arity = "2", Name = "$fetch_global_var")))]
|
#[strum_discriminants(strum(props(Arity = "2", Name = "$fetch_global_var")))]
|
||||||
FetchGlobalVar,
|
FetchGlobalVar,
|
||||||
#[strum_discriminants(strum(props(Arity = "1", Name = "$first_stream")))]
|
#[strum_discriminants(strum(props(Arity = "1", Name = "$first_stream")))]
|
||||||
@@ -572,6 +566,14 @@ enum SystemClauseType {
|
|||||||
GetClauseP,
|
GetClauseP,
|
||||||
#[strum_discriminants(strum(props(Arity = "6", Name = "$invoke_clause_at_p")))]
|
#[strum_discriminants(strum(props(Arity = "6", Name = "$invoke_clause_at_p")))]
|
||||||
InvokeClauseAtP,
|
InvokeClauseAtP,
|
||||||
|
#[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,
|
||||||
|
#[strum_discriminants(strum(props(Arity = "1", Name = "$delete_all_attributes_from_var")))]
|
||||||
|
DeleteAllAttributesFromVar,
|
||||||
REPL(REPLCodePtr),
|
REPL(REPLCodePtr),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1624,15 +1626,16 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
&Instruction::CallDeleteDirectory(_) |
|
&Instruction::CallDeleteDirectory(_) |
|
||||||
&Instruction::CallPathCanonical(_) |
|
&Instruction::CallPathCanonical(_) |
|
||||||
&Instruction::CallFileTime(_) |
|
&Instruction::CallFileTime(_) |
|
||||||
&Instruction::CallDeleteAttribute(_) |
|
|
||||||
&Instruction::CallDeleteHeadAttribute(_) |
|
|
||||||
&Instruction::CallDynamicModuleResolution(..) |
|
&Instruction::CallDynamicModuleResolution(..) |
|
||||||
&Instruction::CallPrepareCallClause(..) |
|
&Instruction::CallPrepareCallClause(..) |
|
||||||
&Instruction::CallCompileInlineOrExpandedGoal(..) |
|
&Instruction::CallCompileInlineOrExpandedGoal(..) |
|
||||||
&Instruction::CallIsExpandedOrInlined(_) |
|
&Instruction::CallIsExpandedOrInlined(_) |
|
||||||
&Instruction::CallGetClauseP(_) |
|
&Instruction::CallGetClauseP(_) |
|
||||||
&Instruction::CallInvokeClauseAtP(_) |
|
&Instruction::CallInvokeClauseAtP(_) |
|
||||||
&Instruction::CallEnqueueAttributedVar(_) |
|
&Instruction::CallGetFromAttributedVarList(_) |
|
||||||
|
&Instruction::CallPutToAttributedVarList(_) |
|
||||||
|
&Instruction::CallDeleteFromAttributedVarList(_) |
|
||||||
|
&Instruction::CallDeleteAllAttributesFromVar(_) |
|
||||||
&Instruction::CallFetchGlobalVar(_) |
|
&Instruction::CallFetchGlobalVar(_) |
|
||||||
&Instruction::CallFirstStream(_) |
|
&Instruction::CallFirstStream(_) |
|
||||||
&Instruction::CallFlushOutput(_) |
|
&Instruction::CallFlushOutput(_) |
|
||||||
@@ -1842,15 +1845,16 @@ fn generate_instruction_preface() -> TokenStream {
|
|||||||
&Instruction::ExecuteDeleteDirectory(_) |
|
&Instruction::ExecuteDeleteDirectory(_) |
|
||||||
&Instruction::ExecutePathCanonical(_) |
|
&Instruction::ExecutePathCanonical(_) |
|
||||||
&Instruction::ExecuteFileTime(_) |
|
&Instruction::ExecuteFileTime(_) |
|
||||||
&Instruction::ExecuteDeleteAttribute(_) |
|
|
||||||
&Instruction::ExecuteDeleteHeadAttribute(_) |
|
|
||||||
&Instruction::ExecuteDynamicModuleResolution(..) |
|
&Instruction::ExecuteDynamicModuleResolution(..) |
|
||||||
&Instruction::ExecutePrepareCallClause(..) |
|
&Instruction::ExecutePrepareCallClause(..) |
|
||||||
&Instruction::ExecuteCompileInlineOrExpandedGoal(..) |
|
&Instruction::ExecuteCompileInlineOrExpandedGoal(..) |
|
||||||
&Instruction::ExecuteIsExpandedOrInlined(_) |
|
&Instruction::ExecuteIsExpandedOrInlined(_) |
|
||||||
&Instruction::ExecuteGetClauseP(_) |
|
&Instruction::ExecuteGetClauseP(_) |
|
||||||
&Instruction::ExecuteInvokeClauseAtP(_) |
|
&Instruction::ExecuteInvokeClauseAtP(_) |
|
||||||
&Instruction::ExecuteEnqueueAttributedVar(_) |
|
&Instruction::ExecuteGetFromAttributedVarList(_) |
|
||||||
|
&Instruction::ExecutePutToAttributedVarList(_) |
|
||||||
|
&Instruction::ExecuteDeleteFromAttributedVarList(_) |
|
||||||
|
&Instruction::ExecuteDeleteAllAttributesFromVar(_) |
|
||||||
&Instruction::ExecuteFetchGlobalVar(_) |
|
&Instruction::ExecuteFetchGlobalVar(_) |
|
||||||
&Instruction::ExecuteFirstStream(_) |
|
&Instruction::ExecuteFirstStream(_) |
|
||||||
&Instruction::ExecuteFlushOutput(_) |
|
&Instruction::ExecuteFlushOutput(_) |
|
||||||
|
|||||||
@@ -812,8 +812,9 @@ impl PredicateInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn must_retract_local_clauses(&self) -> bool {
|
pub(crate) fn must_retract_local_clauses(&self, is_cross_module_clause: bool) -> bool {
|
||||||
self.is_extensible && self.has_clauses && !self.is_discontiguous
|
self.is_extensible && self.has_clauses && !self.is_discontiguous &&
|
||||||
|
!(self.is_multifile && is_cross_module_clause)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,74 +19,12 @@
|
|||||||
'$default_attr_list'(PGs, Module, AttrVar).
|
'$default_attr_list'(PGs, Module, AttrVar).
|
||||||
'$default_attr_list'([], _, _) --> [].
|
'$default_attr_list'([], _, _) --> [].
|
||||||
|
|
||||||
'$absent_attr'(V, Attr) :-
|
'$absent_attr'(V, Module, Attr) :-
|
||||||
'$get_attr_list'(V, Ls),
|
( '$get_from_attr_list'(V, Module, Attr) ->
|
||||||
'$absent_from_list'(Ls, Attr).
|
false
|
||||||
|
|
||||||
'$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_list'(Ls, V, 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)
|
|
||||||
; true
|
; 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'(L, _Module, []) :- var(L), !.
|
||||||
'$copy_attr_list'([Module0:Att|Atts], Module, CopiedAtts) :-
|
'$copy_attr_list'([Module0:Att|Atts], Module, CopiedAtts) :-
|
||||||
( Module0 == Module ->
|
( Module0 == Module ->
|
||||||
@@ -142,38 +80,28 @@ put_attr(Name, Arity, Module) -->
|
|||||||
{ functor(Attr, Name, Arity) },
|
{ functor(Attr, Name, Arity) },
|
||||||
[(put_atts(V, +Attr) :-
|
[(put_atts(V, +Attr) :-
|
||||||
!,
|
!,
|
||||||
functor(Attr, Head, Arity),
|
'$put_to_attr_list'(V, Module, Attr)),
|
||||||
functor(AttrForm, Head, Arity),
|
(put_atts(V, Attr) :-
|
||||||
'$get_attr_list'(V, Ls),
|
|
||||||
atts:'$del_attr'(Ls, V, Module:AttrForm),
|
|
||||||
atts:'$put_attr'(V, Module:Attr)),
|
|
||||||
(put_atts(V, Attr) :-
|
|
||||||
!,
|
!,
|
||||||
functor(Attr, Head, Arity),
|
'$put_to_attr_list'(V, Module, Attr)),
|
||||||
functor(AttrForm, Head, Arity),
|
|
||||||
'$get_attr_list'(V, Ls),
|
|
||||||
atts:'$del_attr'(Ls, V, Module:AttrForm),
|
|
||||||
atts:'$put_attr'(V, Module:Attr)),
|
|
||||||
(put_atts(V, -Attr) :-
|
(put_atts(V, -Attr) :-
|
||||||
!,
|
!,
|
||||||
functor(Attr, _, _),
|
'$del_from_attr_list'(V, Module, Attr))].
|
||||||
'$get_attr_list'(V, Ls),
|
|
||||||
atts:'$del_attr'(Ls, V, Module:Attr))].
|
|
||||||
|
|
||||||
get_attr(Name, Arity, Module) -->
|
get_attr(Name, Arity, Module) -->
|
||||||
{ functor(Attr, Name, Arity) },
|
{ functor(Attr, Name, Arity) },
|
||||||
[(get_atts(V, +Attr) :-
|
[(get_atts(V, +Attr) :-
|
||||||
!,
|
!,
|
||||||
functor(Attr, _, _),
|
functor(Attr, _, _),
|
||||||
atts:'$get_attr'(V, Module:Attr)),
|
atts:'$get_from_attr_list'(V, Module, Attr)),
|
||||||
(get_atts(V, Attr) :-
|
(get_atts(V, Attr) :-
|
||||||
!,
|
!,
|
||||||
functor(Attr, _, _),
|
functor(Attr, _, _),
|
||||||
atts:'$get_attr'(V, Module:Attr)),
|
atts:'$get_from_attr_list'(V, Module, Attr)),
|
||||||
(get_atts(V, -Attr) :-
|
(get_atts(V, -Attr) :-
|
||||||
!,
|
!,
|
||||||
functor(Attr, _, _),
|
functor(Attr, _, _),
|
||||||
atts:'$absent_attr'(V, Module:Attr))].
|
atts:'$absent_attr'(V, Module, Attr))].
|
||||||
|
|
||||||
user:goal_expansion(Term, M:put_atts(Var, Attr)) :-
|
user:goal_expansion(Term, M:put_atts(Var, Attr)) :-
|
||||||
nonvar(Term),
|
nonvar(Term),
|
||||||
|
|||||||
@@ -211,7 +211,7 @@ Here is an example session with a few queries and their answers:
|
|||||||
T = 1, clpb:sat(X=:=X*Y), clpb:sat(Y=:=Y*Z).
|
T = 1, clpb:sat(X=:=X*Y), clpb:sat(Y=:=Y*Z).
|
||||||
|
|
||||||
?- sat(1#X#a#b).
|
?- sat(1#X#a#b).
|
||||||
sat(X=:=a#b).
|
clpb:sat(X=:=a#b).
|
||||||
```
|
```
|
||||||
|
|
||||||
The pending residual goals constrain remaining variables to Boolean
|
The pending residual goals constrain remaining variables to Boolean
|
||||||
@@ -348,7 +348,7 @@ does compute =|XOR|= as intended:
|
|||||||
|
|
||||||
```
|
```
|
||||||
?- xor(x, y, Z).
|
?- xor(x, y, Z).
|
||||||
sat(Z=:=x#y).
|
clpb:sat(Z=:=x#y).
|
||||||
```
|
```
|
||||||
|
|
||||||
## Acknowledgments
|
## Acknowledgments
|
||||||
|
|||||||
@@ -220,31 +220,23 @@ partition_([X|Xs], Pred, Ls0, Es0, Gs0) :-
|
|||||||
|
|
||||||
:- meta_predicate(include(1, ?, ?)).
|
:- meta_predicate(include(1, ?, ?)).
|
||||||
|
|
||||||
include(Goal, Ls0, Ls) :-
|
include(_, [], []).
|
||||||
include_(Ls0, Goal, Ls).
|
include(Goal, [L|Ls0], Ls) :-
|
||||||
|
|
||||||
include_([], _, []).
|
|
||||||
include_([L|Ls0], Goal, Ls) :-
|
|
||||||
( call(Goal, L) ->
|
( call(Goal, L) ->
|
||||||
Ls = [L|Rest]
|
Ls = [L|Rest]
|
||||||
; Ls = Rest
|
; Ls = Rest
|
||||||
),
|
),
|
||||||
include_(Ls0, Goal, Rest).
|
include(Goal, Ls0, Rest).
|
||||||
|
|
||||||
|
|
||||||
:- meta_predicate(exclude(1, ?, ?)).
|
:- meta_predicate(exclude(1, ?, ?)).
|
||||||
|
|
||||||
exclude(Goal, Ls0, Ls) :-
|
exclude(_, [], []).
|
||||||
exclude_(Ls0, Goal, Ls).
|
exclude(Goal, [L|Ls0], Ls) :-
|
||||||
|
|
||||||
exclude_([], _, []).
|
|
||||||
exclude_([L|Ls0], Goal, Ls) :-
|
|
||||||
( call(Goal, L) ->
|
( call(Goal, L) ->
|
||||||
Ls = Rest
|
Ls = Rest
|
||||||
; Ls = [L|Rest]
|
; Ls = [L|Rest]
|
||||||
),
|
),
|
||||||
exclude_(Ls0, Goal, Rest).
|
exclude(Goal, Ls0, Rest).
|
||||||
|
|
||||||
|
|
||||||
%:- discontiguous clpz:goal_expansion/5.
|
%:- discontiguous clpz:goal_expansion/5.
|
||||||
|
|
||||||
@@ -7711,7 +7703,7 @@ attributes_goals([]) --> [].
|
|||||||
attributes_goals([propagator(P, State)|As]) -->
|
attributes_goals([propagator(P, State)|As]) -->
|
||||||
( { ground(State) } -> []
|
( { ground(State) } -> []
|
||||||
; { phrase(attribute_goal_(P), Gs) } ->
|
; { phrase(attribute_goal_(P), Gs) } ->
|
||||||
{ % del_attr(State, clpz_aux), State = processed,
|
{ del_attr(State, clpz_aux), State = processed,
|
||||||
( monotonic ->
|
( monotonic ->
|
||||||
maplist(unwrap_with(bare_integer), Gs, Gs1)
|
maplist(unwrap_with(bare_integer), Gs, Gs1)
|
||||||
; maplist(unwrap_with(=), Gs, Gs1)
|
; maplist(unwrap_with(=), Gs, Gs1)
|
||||||
@@ -7822,7 +7814,7 @@ conjunction(A, B, G, D) -->
|
|||||||
|
|
||||||
original_goal(original_goal(State, Goal)) -->
|
original_goal(original_goal(State, Goal)) -->
|
||||||
( { var(State) } ->
|
( { var(State) } ->
|
||||||
% { State = processed },
|
{ State = processed },
|
||||||
[Goal]
|
[Goal]
|
||||||
; []
|
; []
|
||||||
).
|
).
|
||||||
|
|||||||
@@ -75,13 +75,6 @@ phrase(GRBody, S0, S) :-
|
|||||||
; call(M:GRBody1, S0, S)
|
; call(M:GRBody1, S0, S)
|
||||||
).
|
).
|
||||||
|
|
||||||
|
|
||||||
module_call_qualified(M, Call, Call1) :-
|
|
||||||
( nonvar(M) -> Call1 = M:Call
|
|
||||||
; Call = Call1
|
|
||||||
).
|
|
||||||
|
|
||||||
|
|
||||||
% The same version of the below two dcg_rule clauses, but with module scoping.
|
% The same version of the below two dcg_rule clauses, but with module scoping.
|
||||||
dcg_rule(( M:NonTerminal, Terminals --> GRBody ), ( M:Head :- Body )) :-
|
dcg_rule(( M:NonTerminal, Terminals --> GRBody ), ( M:Head :- Body )) :-
|
||||||
dcg_non_terminal(NonTerminal, S0, S, Head),
|
dcg_non_terminal(NonTerminal, S0, S, Head),
|
||||||
@@ -127,7 +120,10 @@ dcg_body(NonTerminal, S0, S, Goal1) :-
|
|||||||
NonTerminal \= ( \+ _ ),
|
NonTerminal \= ( \+ _ ),
|
||||||
loader:strip_module(NonTerminal, M, NonTerminal0),
|
loader:strip_module(NonTerminal, M, NonTerminal0),
|
||||||
dcg_non_terminal(NonTerminal0, S0, S, Goal0),
|
dcg_non_terminal(NonTerminal0, S0, S, Goal0),
|
||||||
module_call_qualified(M, Goal0, Goal1).
|
( functor(NonTerminal, (:), 2) ->
|
||||||
|
Goal1 = M:Goal0
|
||||||
|
; Goal1 = Goal0
|
||||||
|
).
|
||||||
|
|
||||||
% The following constructs in a grammar rule body
|
% The following constructs in a grammar rule body
|
||||||
% are defined in the corresponding subclauses.
|
% are defined in the corresponding subclauses.
|
||||||
@@ -215,6 +211,9 @@ user:goal_expansion(phrase(GRBody, S, S0), GRBody2) :-
|
|||||||
E,
|
E,
|
||||||
dcgs:error_goal(E, GRBody1)
|
dcgs:error_goal(E, GRBody1)
|
||||||
),
|
),
|
||||||
module_call_qualified(M, GRBody1, GRBody2).
|
( GRBody = (_:_) ->
|
||||||
|
GRBody2 = M:GRBody1
|
||||||
|
; GRBody2 = GRBody1
|
||||||
|
).
|
||||||
|
|
||||||
user:goal_expansion(phrase(GRBody, S), phrase(GRBody, S, [])).
|
user:goal_expansion(phrase(GRBody, S), phrase(GRBody, S, [])).
|
||||||
|
|||||||
@@ -40,9 +40,6 @@ verify_attributes(Var, Value, Goals) :-
|
|||||||
; Goals = []
|
; Goals = []
|
||||||
).
|
).
|
||||||
|
|
||||||
% Probably the world's worst dif/2 implementation. I'm open to
|
|
||||||
% suggestions for improvement.
|
|
||||||
|
|
||||||
%% dif(?X, ?Y).
|
%% dif(?X, ?Y).
|
||||||
%
|
%
|
||||||
% True iff X and Y are different terms. Unlike `\=/2`, `dif/2` is more declarative because if X and Y can
|
% True iff X and Y are different terms. Unlike `\=/2`, `dif/2` is more declarative because if X and Y can
|
||||||
@@ -69,12 +66,16 @@ dif(X, Y) :-
|
|||||||
)
|
)
|
||||||
).
|
).
|
||||||
|
|
||||||
gather_dif_goals([]) --> [].
|
gather_dif_goals(_, []) --> [].
|
||||||
gather_dif_goals([(X \== Y) | Goals]) -->
|
gather_dif_goals(V, [(X \== Y) | Goals]) -->
|
||||||
[dif:dif(X, Y)],
|
( { term_variables(X, [V0 | _]),
|
||||||
gather_dif_goals(Goals).
|
V == V0 } ->
|
||||||
|
[dif:dif(X, Y)]
|
||||||
|
; []
|
||||||
|
),
|
||||||
|
gather_dif_goals(V, Goals).
|
||||||
|
|
||||||
attribute_goals(X) -->
|
attribute_goals(X) -->
|
||||||
{ get_atts(X, +dif(Goals)) },
|
{ get_atts(X, +dif(Goals)) },
|
||||||
gather_dif_goals(Goals),
|
gather_dif_goals(X, Goals),
|
||||||
{ put_atts(X, -dif(_)) }.
|
{ put_atts(X, -dif(_)) }.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
Written 2018-2022 by Markus Triska (triska@metalevel.at)
|
Written 2018-2023 by Markus Triska (triska@metalevel.at)
|
||||||
I place this code in the public domain. Use it in any way you want.
|
I place this code in the public domain. Use it in any way you want.
|
||||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
@@ -85,11 +85,11 @@ must_be_(list, Term) :- check_(error:ilist, list, Term).
|
|||||||
must_be_(type, Term) :- check_(error:type, type, Term).
|
must_be_(type, Term) :- check_(error:type, type, Term).
|
||||||
must_be_(boolean, Term) :- check_(error:boolean, boolean, Term).
|
must_be_(boolean, Term) :- check_(error:boolean, boolean, Term).
|
||||||
must_be_(term, Term) :-
|
must_be_(term, Term) :-
|
||||||
( \+ ground(Term) ->
|
( acyclic_term(Term) ->
|
||||||
instantiation_error(must_be/2)
|
( ground(Term) -> true
|
||||||
; \+ acyclic_term(Term) ->
|
; instantiation_error(must_be/2)
|
||||||
type_error(term, Term, must_be/2)
|
)
|
||||||
; true
|
; type_error(term, Term, must_be/2)
|
||||||
).
|
).
|
||||||
|
|
||||||
% We cannot use maplist(must_be(character), Cs), because library(lists)
|
% We cannot use maplist(must_be(character), Cs), because library(lists)
|
||||||
|
|||||||
@@ -38,5 +38,5 @@ freeze(X, Goal) :-
|
|||||||
attribute_goals(Var) -->
|
attribute_goals(Var) -->
|
||||||
{ get_atts(Var, frozen(Goals)),
|
{ get_atts(Var, frozen(Goals)),
|
||||||
put_atts(Var, -frozen(_)) },
|
put_atts(Var, -frozen(_)) },
|
||||||
[freeze(Var, Goals)].
|
[freeze:freeze(Var, Goals)].
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
current_module/1
|
current_module/1
|
||||||
]).
|
]).
|
||||||
|
|
||||||
|
|
||||||
:- use_module(library(error)).
|
:- use_module(library(error)).
|
||||||
:- use_module(library(lists)).
|
:- use_module(library(lists)).
|
||||||
:- use_module(library(pairs)).
|
:- use_module(library(pairs)).
|
||||||
@@ -221,7 +220,12 @@ complete_partial_goal(N, HeadArg, InnerHeadArgs, SuppArgs, CompleteHeadArg) :-
|
|||||||
integer(N),
|
integer(N),
|
||||||
N >= 0,
|
N >= 0,
|
||||||
HeadArg =.. [Functor | InnerHeadArgs],
|
HeadArg =.. [Functor | InnerHeadArgs],
|
||||||
length(SuppArgs, N),
|
% the next two lines are equivalent to length(SuppArgs, N) but
|
||||||
|
% avoid length/2 so that copy_term/3 (which is invoked by
|
||||||
|
% length/2) can be bootstrapped without self-reference.
|
||||||
|
functor(SuppArgsFunctor, '.', N),
|
||||||
|
SuppArgsFunctor =.. [_ | SuppArgs],
|
||||||
|
% length(SuppArgs, N),
|
||||||
append(InnerHeadArgs, SuppArgs, InnerHeadArgs0),
|
append(InnerHeadArgs, SuppArgs, InnerHeadArgs0),
|
||||||
CompleteHeadArg =.. [Functor | InnerHeadArgs0].
|
CompleteHeadArg =.. [Functor | InnerHeadArgs0].
|
||||||
|
|
||||||
@@ -620,7 +624,7 @@ strip_module(Goal, M, G) :-
|
|||||||
|
|
||||||
strip_subst_module(Goal, M1, M2, G) :-
|
strip_subst_module(Goal, M1, M2, G) :-
|
||||||
'$strip_module'(Goal, M2, G),
|
'$strip_module'(Goal, M2, G),
|
||||||
( var(M2) ->
|
( var(M2), \+ functor(Goal, (:), 2) ->
|
||||||
M2 = M1
|
M2 = M1
|
||||||
; true
|
; true
|
||||||
).
|
).
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ impl MachineState {
|
|||||||
self.cp = INSTALL_VERIFY_ATTR_INTERRUPT;
|
self.cp = INSTALL_VERIFY_ATTR_INTERRUPT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debug_assert_eq!(self.heap[h].get_tag(), HeapCellValueTag::AttrVar);
|
||||||
self.attr_var_init.bindings.push((h, addr));
|
self.attr_var_init.bindings.push((h, addr));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,10 +64,9 @@ impl MachineState {
|
|||||||
.map(|(ref h, _)| attr_var_as_cell!(*h));
|
.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 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 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));
|
let value_list_addr = heap_loc_as_cell!(iter_to_heap_list(&mut self.heap, iter));
|
||||||
|
|
||||||
(var_list_addr, value_list_addr)
|
(var_list_addr, value_list_addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2280,14 +2280,17 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
.ok_or(SessionError::NamelessEntry)?;
|
.ok_or(SessionError::NamelessEntry)?;
|
||||||
|
|
||||||
let listing_src_file_name = self.listing_src_file_name();
|
let listing_src_file_name = self.listing_src_file_name();
|
||||||
let payload_compilation_target = self.payload.compilation_target;
|
|
||||||
|
|
||||||
let mut predicate_info = self
|
// payload_compilation_target describes the compilation context,
|
||||||
.wam_prelude
|
// e.g. compiling
|
||||||
.indices
|
//
|
||||||
.get_predicate_skeleton(&self.payload.predicates.compilation_target, &key)
|
// table_wrapper:tabled(get_node(A), b).
|
||||||
.map(|skeleton| skeleton.predicate_info())
|
//
|
||||||
.unwrap_or_default();
|
// without a module declaration means self.payload.compilation_target
|
||||||
|
// is CompilationTarget::User while self.payload.predicates.compilation_target
|
||||||
|
// is CompilationTarget::Module(atom!("table_wrapper")).
|
||||||
|
|
||||||
|
let payload_compilation_target = self.payload.compilation_target;
|
||||||
|
|
||||||
let local_predicate_info = self
|
let local_predicate_info = self
|
||||||
.wam_prelude
|
.wam_prelude
|
||||||
@@ -2301,34 +2304,37 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
.map(|skeleton| skeleton.predicate_info())
|
.map(|skeleton| skeleton.predicate_info())
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
if local_predicate_info.must_retract_local_clauses() {
|
let mut predicate_info = self
|
||||||
|
.wam_prelude
|
||||||
|
.indices
|
||||||
|
.get_predicate_skeleton(&self.payload.predicates.compilation_target, &key)
|
||||||
|
.map(|skeleton| skeleton.predicate_info())
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
let is_cross_module_clause =
|
||||||
|
payload_compilation_target != self.payload.predicates.compilation_target;
|
||||||
|
|
||||||
|
if local_predicate_info.must_retract_local_clauses(is_cross_module_clause) {
|
||||||
self.retract_local_clauses(&key, predicate_info.is_dynamic);
|
self.retract_local_clauses(&key, predicate_info.is_dynamic);
|
||||||
}
|
}
|
||||||
|
|
||||||
let do_incremental_compile =
|
|
||||||
if payload_compilation_target == self.payload.predicates.compilation_target {
|
|
||||||
predicate_info.compile_incrementally()
|
|
||||||
} else {
|
|
||||||
local_predicate_info.is_multifile && predicate_info.compile_incrementally()
|
|
||||||
};
|
|
||||||
|
|
||||||
let predicates_len = self.payload.predicates.len();
|
let predicates_len = self.payload.predicates.len();
|
||||||
let non_counted_bt = self.payload.non_counted_bt_preds.contains(&key);
|
let non_counted_bt = self.payload.non_counted_bt_preds.contains(&key);
|
||||||
|
|
||||||
if do_incremental_compile {
|
if predicate_info.compile_incrementally() {
|
||||||
let predicates = self.payload.predicates.take();
|
let predicates = self.payload.predicates.take();
|
||||||
|
|
||||||
for term in predicates.predicates {
|
for term in predicates.predicates {
|
||||||
self.incremental_compile_clause(
|
self.incremental_compile_clause(
|
||||||
key,
|
key,
|
||||||
term,
|
term,
|
||||||
payload_compilation_target,
|
self.payload.predicates.compilation_target,
|
||||||
non_counted_bt,
|
non_counted_bt,
|
||||||
AppendOrPrepend::Append,
|
AppendOrPrepend::Append,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if payload_compilation_target != self.payload.predicates.compilation_target {
|
if is_cross_module_clause {
|
||||||
if !local_predicate_info.is_extensible {
|
if !local_predicate_info.is_extensible {
|
||||||
if predicate_info.is_multifile {
|
if predicate_info.is_multifile {
|
||||||
println!(
|
println!(
|
||||||
@@ -2343,9 +2349,11 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
.indices
|
.indices
|
||||||
.remove_predicate_skeleton(&self.payload.predicates.compilation_target, &key)
|
.remove_predicate_skeleton(&self.payload.predicates.compilation_target, &key)
|
||||||
{
|
{
|
||||||
|
let compilation_target = self.payload.predicates.compilation_target;
|
||||||
|
|
||||||
if predicate_info.is_dynamic {
|
if predicate_info.is_dynamic {
|
||||||
let clause_clause_compilation_target =
|
let clause_clause_compilation_target =
|
||||||
match self.payload.predicates.compilation_target {
|
match compilation_target {
|
||||||
CompilationTarget::User => {
|
CompilationTarget::User => {
|
||||||
CompilationTarget::Module(atom!("builtins"))
|
CompilationTarget::Module(atom!("builtins"))
|
||||||
}
|
}
|
||||||
@@ -2364,7 +2372,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
|
|
||||||
self.payload.retraction_info.push_record(
|
self.payload.retraction_info.push_record(
|
||||||
RetractionRecord::RemovedSkeleton(
|
RetractionRecord::RemovedSkeleton(
|
||||||
payload_compilation_target,
|
compilation_target,
|
||||||
key,
|
key,
|
||||||
skeleton,
|
skeleton,
|
||||||
),
|
),
|
||||||
@@ -2415,9 +2423,11 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
|||||||
.clause_clauses.drain(0..std::cmp::min(predicates_len, clause_clauses_len))
|
.clause_clauses.drain(0..std::cmp::min(predicates_len, clause_clauses_len))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
let compilation_target = self.payload.predicates.compilation_target;
|
||||||
|
|
||||||
self.compile_clause_clauses(
|
self.compile_clause_clauses(
|
||||||
key,
|
key,
|
||||||
payload_compilation_target,
|
compilation_target,
|
||||||
clauses_vec.into_iter(),
|
clauses_vec.into_iter(),
|
||||||
AppendOrPrepend::Append,
|
AppendOrPrepend::Append,
|
||||||
)?;
|
)?;
|
||||||
|
|||||||
@@ -28,7 +28,10 @@ pub(crate) fn copy_term<T: CopierTarget>(
|
|||||||
attr_var_policy: AttrVarPolicy,
|
attr_var_policy: AttrVarPolicy,
|
||||||
) {
|
) {
|
||||||
let mut copy_term_state = CopyTermState::new(target, attr_var_policy);
|
let mut copy_term_state = CopyTermState::new(target, attr_var_policy);
|
||||||
|
|
||||||
copy_term_state.copy_term_impl(addr);
|
copy_term_state.copy_term_impl(addr);
|
||||||
|
copy_term_state.copy_attr_var_lists();
|
||||||
|
copy_term_state.unwind_trail();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -38,6 +41,7 @@ struct CopyTermState<T: CopierTarget> {
|
|||||||
old_h: usize,
|
old_h: usize,
|
||||||
target: T,
|
target: T,
|
||||||
attr_var_policy: AttrVarPolicy,
|
attr_var_policy: AttrVarPolicy,
|
||||||
|
attr_var_list_locs: Vec<(usize, HeapCellValue)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: CopierTarget> CopyTermState<T> {
|
impl<T: CopierTarget> CopyTermState<T> {
|
||||||
@@ -48,6 +52,7 @@ impl<T: CopierTarget> CopyTermState<T> {
|
|||||||
old_h: target.threshold(),
|
old_h: target.threshold(),
|
||||||
target,
|
target,
|
||||||
attr_var_policy,
|
attr_var_policy,
|
||||||
|
attr_var_list_locs: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,16 +91,12 @@ impl<T: CopierTarget> CopyTermState<T> {
|
|||||||
self.target.push(hcv);
|
self.target.push(hcv);
|
||||||
}
|
}
|
||||||
|
|
||||||
let cdr = self
|
let cdr = self.target.store(self.target.deref(heap_loc_as_cell!(addr + 1)));
|
||||||
.target
|
|
||||||
.store(self.target.deref(heap_loc_as_cell!(addr + 1)));
|
|
||||||
|
|
||||||
if !cdr.is_var() {
|
if !cdr.is_var() {
|
||||||
self.trail_list_cell(addr + 1, threshold);
|
self.trail_list_cell(addr + 1, threshold);
|
||||||
} else {
|
} else {
|
||||||
let car = self
|
let car = self.target.store(self.target.deref(heap_loc_as_cell!(addr)));
|
||||||
.target
|
|
||||||
.store(self.target.deref(heap_loc_as_cell!(addr)));
|
|
||||||
|
|
||||||
if !car.is_var() {
|
if !car.is_var() {
|
||||||
self.trail_list_cell(addr, threshold);
|
self.trail_list_cell(addr, threshold);
|
||||||
@@ -167,6 +168,51 @@ impl<T: CopierTarget> CopyTermState<T> {
|
|||||||
self.trail.push((Ref::heap_cell(pstr_loc), trail_item));
|
self.trail.push((Ref::heap_cell(pstr_loc), trail_item));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn copy_attr_var_lists(&mut self) {
|
||||||
|
while !self.attr_var_list_locs.is_empty() {
|
||||||
|
let iter = mem::replace(&mut self.attr_var_list_locs, vec![]);
|
||||||
|
|
||||||
|
for (threshold, list_loc) in iter {
|
||||||
|
self.target[threshold] = list_loc_as_cell!(self.target.threshold());
|
||||||
|
self.copy_attr_var_list(list_loc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Attributed variable attribute lists adhere to a particular
|
||||||
|
* structure which is ensured by this function and not at all by
|
||||||
|
* the vanilla copier.
|
||||||
|
*/
|
||||||
|
fn copy_attr_var_list(&mut self, mut list_addr: HeapCellValue) {
|
||||||
|
while let HeapCellValueTag::Lis = list_addr.get_tag() {
|
||||||
|
let threshold = self.target.threshold();
|
||||||
|
let heap_loc = list_addr.get_value();
|
||||||
|
let str_loc = self.target[heap_loc].get_value();
|
||||||
|
|
||||||
|
self.target.push(heap_loc_as_cell!(threshold+2));
|
||||||
|
self.target.push(heap_loc_as_cell!(threshold+1));
|
||||||
|
|
||||||
|
read_heap_cell!(self.target[str_loc],
|
||||||
|
(HeapCellValueTag::Atom) => {
|
||||||
|
self.target.push(self.target[str_loc]);
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Str) => {
|
||||||
|
self.copy_term_impl(self.target[str_loc]);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
list_addr = self.target[heap_loc + 1];
|
||||||
|
|
||||||
|
if HeapCellValueTag::Lis == list_addr.get_tag() {
|
||||||
|
self.target[threshold + 1] = list_loc_as_cell!(self.target.threshold());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn reinstantiate_var(&mut self, addr: HeapCellValue, frontier: usize) {
|
fn reinstantiate_var(&mut self, addr: HeapCellValue, frontier: usize) {
|
||||||
read_heap_cell!(addr,
|
read_heap_cell!(addr,
|
||||||
(HeapCellValueTag::Var, h) => {
|
(HeapCellValueTag::Var, h) => {
|
||||||
@@ -195,9 +241,15 @@ impl<T: CopierTarget> CopyTermState<T> {
|
|||||||
|
|
||||||
if let AttrVarPolicy::DeepCopy = self.attr_var_policy {
|
if let AttrVarPolicy::DeepCopy = self.attr_var_policy {
|
||||||
self.target.push(attr_var_as_cell!(threshold));
|
self.target.push(attr_var_as_cell!(threshold));
|
||||||
|
self.target.push(heap_loc_as_cell!(threshold + 1));
|
||||||
|
|
||||||
let list_val = self.target[h + 1];
|
let old_list_link = self.target[h + 1];
|
||||||
self.target.push(list_val);
|
self.trail.push((Ref::heap_cell(h + 1), old_list_link));
|
||||||
|
self.target[h + 1] = heap_loc_as_cell!(threshold + 1);
|
||||||
|
|
||||||
|
if old_list_link.get_tag() == HeapCellValueTag::Lis {
|
||||||
|
self.attr_var_list_locs.push((threshold + 1, old_list_link));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@@ -298,8 +350,6 @@ impl<T: CopierTarget> CopyTermState<T> {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.unwind_trail();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unwind_trail(&mut self) {
|
fn unwind_trail(&mut self) {
|
||||||
|
|||||||
@@ -3570,22 +3570,6 @@ impl Machine {
|
|||||||
self.file_time();
|
self.file_time();
|
||||||
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
|
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, _) => {
|
&Instruction::CallDynamicModuleResolution(arity, _) => {
|
||||||
let (module_name, key) = try_or_throw!(
|
let (module_name, key) = try_or_throw!(
|
||||||
self.machine_st,
|
self.machine_st,
|
||||||
@@ -3616,14 +3600,6 @@ impl Machine {
|
|||||||
self.machine_st.backtrack();
|
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(_) => {
|
&Instruction::CallFetchGlobalVar(_) => {
|
||||||
self.fetch_global_var();
|
self.fetch_global_var();
|
||||||
step_or_fail!(self, self.machine_st.p += 1);
|
step_or_fail!(self, self.machine_st.p += 1);
|
||||||
@@ -5231,6 +5207,38 @@ impl Machine {
|
|||||||
|
|
||||||
self.machine_st.execute_at_index(2, p);
|
self.machine_st.execute_at_index(2, p);
|
||||||
}
|
}
|
||||||
|
&Instruction::CallGetFromAttributedVarList(_) => {
|
||||||
|
self.get_from_attributed_variable_list();
|
||||||
|
step_or_fail!(self, self.machine_st.p += 1);
|
||||||
|
}
|
||||||
|
&Instruction::ExecuteGetFromAttributedVarList(_) => {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
&Instruction::CallDeleteAllAttributesFromVar(_) => {
|
||||||
|
self.delete_all_attributes_from_var();
|
||||||
|
self.machine_st.p += 1;
|
||||||
|
}
|
||||||
|
&Instruction::ExecuteDeleteAllAttributesFromVar(_) => {
|
||||||
|
self.delete_all_attributes_from_var();
|
||||||
|
self.machine_st.p = self.machine_st.cp;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -21,6 +21,7 @@ pub mod stack;
|
|||||||
pub mod streams;
|
pub mod streams;
|
||||||
pub mod system_calls;
|
pub mod system_calls;
|
||||||
pub mod term_stream;
|
pub mod term_stream;
|
||||||
|
pub mod unify;
|
||||||
|
|
||||||
use crate::arena::*;
|
use crate::arena::*;
|
||||||
use crate::arithmetic::*;
|
use crate::arithmetic::*;
|
||||||
@@ -257,31 +258,22 @@ impl Machine {
|
|||||||
let mut path_buf = current_dir();
|
let mut path_buf = current_dir();
|
||||||
path_buf.push("machine/attributed_variables.pl");
|
path_buf.push("machine/attributed_variables.pl");
|
||||||
|
|
||||||
bootstrapping_compile(
|
let stream = Stream::from_static_string(
|
||||||
Stream::from_static_string(
|
include_str!("attributed_variables.pl"),
|
||||||
include_str!("attributed_variables.pl"),
|
&mut self.machine_st.arena,
|
||||||
&mut self.machine_st.arena,
|
);
|
||||||
),
|
|
||||||
self,
|
self.load_file(path_buf.to_str().unwrap(), stream);
|
||||||
ListingSource::from_file_and_path(
|
|
||||||
atom!("attributed_variables"),
|
|
||||||
path_buf,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let mut path_buf = current_dir();
|
let mut path_buf = current_dir();
|
||||||
path_buf.push("machine/project_attributes.pl");
|
path_buf.push("machine/project_attributes.pl");
|
||||||
|
|
||||||
bootstrapping_compile(
|
let stream = Stream::from_static_string(
|
||||||
Stream::from_static_string(
|
include_str!("project_attributes.pl"),
|
||||||
include_str!("project_attributes.pl"),
|
&mut self.machine_st.arena,
|
||||||
&mut self.machine_st.arena,
|
);
|
||||||
),
|
|
||||||
self,
|
self.load_file(path_buf.to_str().unwrap(), stream);
|
||||||
ListingSource::from_file_and_path(atom!("project_attributes"), path_buf),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
if let Some(module) = self.indices.modules.get(&atom!("$atts")) {
|
if let Some(module) = self.indices.modules.get(&atom!("$atts")) {
|
||||||
if let Some(code_index) = module.code_dir.get(&(atom!("driver"), 2)) {
|
if let Some(code_index) = module.code_dir.get(&(atom!("driver"), 2)) {
|
||||||
@@ -866,14 +858,22 @@ impl Machine {
|
|||||||
TrailEntryTag::TrailedAttrVar => {
|
TrailEntryTag::TrailedAttrVar => {
|
||||||
self.machine_st.heap[h] = attr_var_as_cell!(h);
|
self.machine_st.heap[h] = attr_var_as_cell!(h);
|
||||||
}
|
}
|
||||||
TrailEntryTag::TrailedAttrVarHeapLink => {
|
|
||||||
self.machine_st.heap[h] = heap_loc_as_cell!(h);
|
|
||||||
}
|
|
||||||
TrailEntryTag::TrailedAttrVarListLink => {
|
TrailEntryTag::TrailedAttrVarListLink => {
|
||||||
let l = self.machine_st.trail[i + 1].get_value() as usize;
|
let l = self.machine_st.trail[i + 1].get_value() as usize;
|
||||||
|
|
||||||
if l < self.machine_st.hb {
|
if l < self.machine_st.hb {
|
||||||
self.machine_st.heap[h] = list_loc_as_cell!(l);
|
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 {
|
} else {
|
||||||
self.machine_st.heap[h] = heap_loc_as_cell!(h);
|
self.machine_st.heap[h] = heap_loc_as_cell!(h);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
:- module('$project_atts', [copy_term/3]).
|
:- module('$project_atts', [copy_term/3]).
|
||||||
|
|
||||||
|
:- use_module(library(dcgs)).
|
||||||
|
:- use_module(library(error), [can_be/2]).
|
||||||
|
:- use_module(library(lambda)).
|
||||||
|
:- use_module(library(lists), [foldl/4, maplist/2]).
|
||||||
|
|
||||||
project_attributes(QueryVars, AttrVars) :-
|
project_attributes(QueryVars, AttrVars) :-
|
||||||
gather_attr_modules(AttrVars, Modules0),
|
phrase(gather_attr_modules(AttrVars), Modules0),
|
||||||
sort(Modules0, Modules),
|
sort(Modules0, Modules),
|
||||||
call_project_attributes(Modules, QueryVars, AttrVars).
|
call_project_attributes(Modules, QueryVars, AttrVars).
|
||||||
|
|
||||||
@@ -17,19 +22,14 @@ project_attributes(QueryVars, AttrVars) :-
|
|||||||
call_project_attributes([], _, _).
|
call_project_attributes([], _, _).
|
||||||
call_project_attributes([Module|Modules], QueryVars, AttrVars) :-
|
call_project_attributes([Module|Modules], QueryVars, AttrVars) :-
|
||||||
( catch(Module:project_attributes(QueryVars, AttrVars),
|
( catch(Module:project_attributes(QueryVars, AttrVars),
|
||||||
E,
|
E,
|
||||||
'$project_atts':'$print_project_attributes_exception'(Module, E)
|
'$project_atts':'$print_project_attributes_exception'(Module, E)
|
||||||
)
|
)
|
||||||
-> true
|
-> true
|
||||||
; true
|
; true
|
||||||
),
|
),
|
||||||
call_project_attributes(Modules, QueryVars, AttrVars).
|
call_project_attributes(Modules, QueryVars, AttrVars).
|
||||||
|
|
||||||
call_attribute_goals([], _, _).
|
|
||||||
call_attribute_goals([Module|Modules], GoalCaller, AttrVars) :-
|
|
||||||
call(GoalCaller, AttrVars, Module, Goals),
|
|
||||||
call_attribute_goals(Modules, GoalCaller, AttrVars).
|
|
||||||
|
|
||||||
'$print_attribute_goals_exception'(Module, E) :-
|
'$print_attribute_goals_exception'(Module, E) :-
|
||||||
( E = error(evaluation_error((Module:attribute_goals)/3), attribute_goals/3)
|
( E = error(evaluation_error((Module:attribute_goals)/3), attribute_goals/3)
|
||||||
; E = error(existence_error(procedure, attribute_goals/3), attribute_goals/3)
|
; E = error(existence_error(procedure, attribute_goals/3), attribute_goals/3)
|
||||||
@@ -38,20 +38,6 @@ call_attribute_goals([Module|Modules], GoalCaller, AttrVars) :-
|
|||||||
nl
|
nl
|
||||||
).
|
).
|
||||||
|
|
||||||
call_query_var_goals([], _, []).
|
|
||||||
call_query_var_goals([AttrVar|AttrVars], Module, Goals) :-
|
|
||||||
( catch(( Module:attribute_goals(AttrVar, Goals, RGoals0),
|
|
||||||
atts:'$default_attr_list'(Module, AttrVar, RGoals0, RGoals)
|
|
||||||
),
|
|
||||||
E,
|
|
||||||
( '$project_atts':'$print_attribute_goals_exception'(Module, E),
|
|
||||||
atts:'$default_attr_list'(Module, AttrVar, Goals, RGoals)
|
|
||||||
))
|
|
||||||
-> true
|
|
||||||
; atts:'$default_attr_list'(Module, AttrVar, Goals, RGoals)
|
|
||||||
),
|
|
||||||
call_query_var_goals(AttrVars, Module, RGoals).
|
|
||||||
|
|
||||||
call_attr_var_goals([], _, []).
|
call_attr_var_goals([], _, []).
|
||||||
call_attr_var_goals([AttrVar|AttrVars], Module, Goals) :-
|
call_attr_var_goals([AttrVar|AttrVars], Module, Goals) :-
|
||||||
( catch(Module:attribute_goals(AttrVar, Goals, RGoals),
|
( catch(Module:attribute_goals(AttrVar, Goals, RGoals),
|
||||||
@@ -77,25 +63,52 @@ call_attribute_goals_with_module_prefix([Module | Modules], GoalCaller, AttrVars
|
|||||||
module_prefixed_goals(Goals0, Module, Goals, Gs),
|
module_prefixed_goals(Goals0, Module, Goals, Gs),
|
||||||
call_attribute_goals_with_module_prefix(Modules, GoalCaller, AttrVars, Gs).
|
call_attribute_goals_with_module_prefix(Modules, GoalCaller, AttrVars, Gs).
|
||||||
|
|
||||||
|
gather_attr_modules([]) --> [].
|
||||||
|
gather_attr_modules([AttrVar|AttrVars]) -->
|
||||||
|
{ '$get_attr_list'(AttrVar, Attrs) },
|
||||||
|
copy_attribute_modules(Attrs),
|
||||||
|
gather_attr_modules(AttrVars).
|
||||||
|
|
||||||
gather_attr_modules([], []).
|
copy_attribute_modules(Attrs) -->
|
||||||
gather_attr_modules([AttrVar|AttrVars], Modules) :-
|
{ var(Attrs) },
|
||||||
'$get_attr_list'(AttrVar, Attrs),
|
!.
|
||||||
copy_attribute_modules(Attrs, Modules, Modules0),
|
copy_attribute_modules([Module:_|Attrs]) -->
|
||||||
gather_attr_modules(AttrVars, Modules0).
|
[Module],
|
||||||
|
copy_attribute_modules(Attrs).
|
||||||
|
|
||||||
copy_attribute_modules(Attrs, Ls, Ls) :-
|
gather_residual_goals_(M, V, V0, V1) :-
|
||||||
var(Attrs), !.
|
( catch(M:attribute_goals(V, V0, V1),
|
||||||
copy_attribute_modules([Module:_|Attrs], [Module|Modules0], Modules1) :-
|
E,
|
||||||
copy_attribute_modules(Attrs, Modules0, Modules1).
|
('$project_atts':'$print_attribute_goals_exception'(M, E),
|
||||||
|
V0 = V1)
|
||||||
|
) ->
|
||||||
|
true
|
||||||
|
; V0 = V1
|
||||||
|
).
|
||||||
|
|
||||||
|
gather_residual_goals(M, V) -->
|
||||||
|
gather_residual_goals_(M, V),
|
||||||
|
atts:'$default_attr_list'(M, V).
|
||||||
|
|
||||||
copy_term(Source, Dest, Goals) :-
|
gather_residual_goals([]) --> [].
|
||||||
'$term_attributed_variables'(Source, AttrVars),
|
gather_residual_goals([V|Vs]) -->
|
||||||
gather_attr_modules(AttrVars, Modules0),
|
{ '$get_attr_list'(V, Attrs),
|
||||||
sort(Modules0, Modules),
|
phrase(copy_attribute_modules(Attrs), Modules0),
|
||||||
call_attribute_goals_with_module_prefix(Modules, '$project_atts':call_query_var_goals,
|
sort(Modules0, Modules) },
|
||||||
AttrVars, Goals0),
|
foldl(V+\M^gather_residual_goals(M, V), Modules),
|
||||||
sort(Goals0, Goals1),
|
gather_residual_goals(Vs).
|
||||||
!,
|
|
||||||
'$copy_term_without_attr_vars'([Source | Goals1], [Dest | Goals]).
|
delete_all_attributes_from_var(V) :- '$delete_all_attributes_from_var'(V).
|
||||||
|
|
||||||
|
copy_term(Term, Copy, Gs) :-
|
||||||
|
can_be(list, Gs),
|
||||||
|
findall(Term-Rs, term_residual_goals(Term,Rs), [Copy-Gs]),
|
||||||
|
( var(Gs) ->
|
||||||
|
Gs = []
|
||||||
|
; true
|
||||||
|
).
|
||||||
|
|
||||||
|
term_residual_goals(Term,Rs) :-
|
||||||
|
'$term_attributed_variables'(Term, Vs),
|
||||||
|
phrase(gather_residual_goals(Vs), Rs),
|
||||||
|
maplist(delete_all_attributes_from_var, Vs).
|
||||||
|
|||||||
@@ -458,7 +458,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 {
|
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> {
|
pub(crate) fn name_and_arity_from_heap(&self, cell: HeapCellValue) -> Option<PredicateKey> {
|
||||||
read_heap_cell!(self.store(self.deref(cell)),
|
read_heap_cell!(self.store(self.deref(cell)),
|
||||||
(HeapCellValueTag::Str, s) => {
|
(HeapCellValueTag::Str, s) => {
|
||||||
@@ -1004,6 +1038,17 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Machine {
|
impl Machine {
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn delete_all_attributes_from_var(&mut self) {
|
||||||
|
let attr_var = self.deref_register(1);
|
||||||
|
|
||||||
|
if let HeapCellValueTag::AttrVar = attr_var.get_tag() {
|
||||||
|
let attr_var_loc = attr_var.get_value();
|
||||||
|
self.machine_st.heap[attr_var_loc] = heap_loc_as_cell!(attr_var_loc);
|
||||||
|
self.machine_st.trail(TrailRef::Ref(Ref::attr_var(attr_var_loc)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn get_clause_p(&self, module_name: Atom) -> (usize, usize) {
|
pub(crate) fn get_clause_p(&self, module_name: Atom) -> (usize, usize) {
|
||||||
use crate::machine::loader::CompilationTarget;
|
use crate::machine::loader::CompilationTarget;
|
||||||
@@ -4467,17 +4512,10 @@ impl Machine {
|
|||||||
let attr_var = self.deref_register(1);
|
let attr_var = self.deref_register(1);
|
||||||
let attr_var_list = read_heap_cell!(attr_var,
|
let attr_var_list = read_heap_cell!(attr_var,
|
||||||
(HeapCellValueTag::AttrVar, h) => {
|
(HeapCellValueTag::AttrVar, h) => {
|
||||||
h + 1
|
h+1
|
||||||
}
|
}
|
||||||
(HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
|
(HeapCellValueTag::Var, h) => {
|
||||||
// create an AttrVar in the heap.
|
h
|
||||||
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
|
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
self.machine_st.fail = true;
|
self.machine_st.fail = true;
|
||||||
@@ -4489,6 +4527,44 @@ impl Machine {
|
|||||||
self.machine_st.bind(Ref::heap_cell(attr_var_list), list_addr);
|
self.machine_st.bind(Ref::heap_cell(attr_var_list), list_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn get_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.heap[h+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)]
|
#[inline(always)]
|
||||||
pub(crate) fn get_attr_var_queue_delimiter(&mut self) {
|
pub(crate) fn get_attr_var_queue_delimiter(&mut self) {
|
||||||
let addr = self.deref_register(1);
|
let addr = self.deref_register(1);
|
||||||
@@ -4523,81 +4599,202 @@ impl Machine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn enqueue_attributed_var(&mut self) {
|
pub(crate) fn delete_from_attributed_variable_list(&mut self) {
|
||||||
let addr = self.deref_register(1);
|
let attr_var = self.deref_register(1);
|
||||||
|
let attr = self.deref_register(3);
|
||||||
read_heap_cell!(addr,
|
let attr_var_list = read_heap_cell!(attr_var,
|
||||||
(HeapCellValueTag::AttrVar, h) => {
|
(HeapCellValueTag::AttrVar, h) => {
|
||||||
self.machine_st.attr_var_init.attr_var_queue.push(h);
|
h + 1
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
let module = self.deref_register(2);
|
||||||
pub(crate) fn delete_attribute(&mut self) {
|
|
||||||
let ls0 = self.deref_register(1);
|
|
||||||
|
|
||||||
if let HeapCellValueTag::Lis = ls0.get_tag() {
|
match self.match_attribute(self.machine_st.heap[attr_var_list], module, attr) {
|
||||||
let l1 = ls0.get_value();
|
Some(AttrListMatch { prev_tail, match_site: MatchSite::Match(match_site) }) => {
|
||||||
let ls1 = self.machine_st.store(self.machine_st.deref(heap_loc_as_cell!(l1 + 1)));
|
let prev_tail = if let Some(prev_tail) = prev_tail {
|
||||||
|
// not at the head.
|
||||||
if let HeapCellValueTag::Lis = ls1.get_tag() {
|
prev_tail
|
||||||
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)
|
|
||||||
} else {
|
} else {
|
||||||
tail
|
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
|
||||||
};
|
};
|
||||||
|
|
||||||
let trail_ref = read_heap_cell!(old_addr,
|
if self.machine_st.heap[match_site + 1].get_tag() == HeapCellValueTag::Lis {
|
||||||
(HeapCellValueTag::Var, h) => {
|
let prev_tail_value = self.machine_st.heap[match_site + 1].get_value();
|
||||||
TrailRef::AttrVarHeapLink(h)
|
self.machine_st.heap[prev_tail].set_value(prev_tail_value);
|
||||||
}
|
} else {
|
||||||
(HeapCellValueTag::Lis, l) => {
|
self.machine_st.heap[prev_tail] = heap_loc_as_cell!(prev_tail);
|
||||||
TrailRef::AttrVarListLink(l1 + 1, l)
|
}
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
self.machine_st.heap[l1 + 1] = tail;
|
self.machine_st.trail(TrailRef::AttrVarListLink(prev_tail, match_site));
|
||||||
self.machine_st.trail(trail_ref);
|
}
|
||||||
|
_ => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn delete_head_attribute(&mut self) {
|
pub(crate) fn put_to_attributed_variable_list(&mut self) {
|
||||||
let addr = self.deref_register(1);
|
let attr_var = self.deref_register(1);
|
||||||
|
let attr = self.deref_register(3);
|
||||||
debug_assert_eq!(addr.get_tag(), HeapCellValueTag::AttrVar);
|
let attr_var_list = match self.machine_st.get_attr_var_list(attr_var) {
|
||||||
|
Some(h) => h,
|
||||||
let h = addr.get_value();
|
None => {
|
||||||
let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.heap[h + 1]));
|
self.machine_st.fail = true;
|
||||||
|
return;
|
||||||
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;
|
let module = self.deref_register(2);
|
||||||
self.machine_st.trail(TrailRef::AttrVarListLink(h + 1, l));
|
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let tail_loc = attrs_list.get_value() + 1;
|
||||||
|
prev_tail = Some(tail_loc);
|
||||||
|
|
||||||
|
// 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];
|
||||||
|
|
||||||
|
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 {
|
||||||
|
return Some(AttrListMatch {
|
||||||
|
match_site: MatchSite::NoMatchVarTail(h),
|
||||||
|
prev_tail,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Lis) => {
|
||||||
|
attrs_list = list_tail;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
@@ -7177,4 +7374,3 @@ impl hkdf::KeyType for MyKey<usize> {
|
|||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
763
src/machine/unify.rs
Normal file
763
src/machine/unify.rs
Normal file
@@ -0,0 +1,763 @@
|
|||||||
|
use crate::arena::*;
|
||||||
|
use crate::forms::*;
|
||||||
|
use crate::heap_iter::stackful_preorder_iter;
|
||||||
|
use crate::machine::*;
|
||||||
|
use crate::machine::machine_state::*;
|
||||||
|
use crate::machine::partial_string::*;
|
||||||
|
use crate::types::*;
|
||||||
|
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
|
use derive_deref::*;
|
||||||
|
use fxhash::FxBuildHasher;
|
||||||
|
use indexmap::IndexSet;
|
||||||
|
|
||||||
|
pub(crate) trait Unifier: DerefMut<Target = MachineState> {
|
||||||
|
fn unify_structure(&mut self, s1: usize, value: HeapCellValue) {
|
||||||
|
// s1 is the value of a STR cell.
|
||||||
|
let (n1, a1) = cell_as_atom_cell!(self.heap[s1]).get_name_and_arity();
|
||||||
|
|
||||||
|
read_heap_cell!(value,
|
||||||
|
(HeapCellValueTag::Str, s2) => {
|
||||||
|
let (n2, a2) = cell_as_atom_cell!(self.heap[s2])
|
||||||
|
.get_name_and_arity();
|
||||||
|
|
||||||
|
if n1 == n2 && a1 == a2 {
|
||||||
|
for idx in (0..a1).rev() {
|
||||||
|
self.pdl.push(heap_loc_as_cell!(s2+1+idx));
|
||||||
|
self.pdl.push(heap_loc_as_cell!(s1+1+idx));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.fail = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Lis, l2) => {
|
||||||
|
if a1 == 2 && n1 == atom!(".") {
|
||||||
|
for idx in (0..2).rev() {
|
||||||
|
self.pdl.push(heap_loc_as_cell!(l2+1+idx));
|
||||||
|
self.pdl.push(heap_loc_as_cell!(s1+1+idx));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.fail = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Atom, (n2, a2)) => {
|
||||||
|
self.fail = !(a1 == 0 && a2 == 0 && n1 == n2);
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::AttrVar, h) => {
|
||||||
|
Self::bind(self, Ref::attr_var(h), str_loc_as_cell!(s1));
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Var, h) => {
|
||||||
|
Self::bind(self, Ref::heap_cell(h), str_loc_as_cell!(s1));
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::StackVar, s) => {
|
||||||
|
Self::bind(self, Ref::stack_cell(s), str_loc_as_cell!(s1));
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.fail = true;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unify_list(&mut self, l1: usize, value: HeapCellValue) {
|
||||||
|
read_heap_cell!(value,
|
||||||
|
(HeapCellValueTag::Lis, l2) => {
|
||||||
|
for idx in (0..2).rev() {
|
||||||
|
self.pdl.push(heap_loc_as_cell!(l2 + idx));
|
||||||
|
self.pdl.push(heap_loc_as_cell!(l1 + idx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Str, s2) => {
|
||||||
|
let (n2, a2) = cell_as_atom_cell!(self.heap[s2])
|
||||||
|
.get_name_and_arity();
|
||||||
|
|
||||||
|
if a2 == 2 && n2 == atom!(".") {
|
||||||
|
for idx in (0..2).rev() {
|
||||||
|
self.pdl.push(heap_loc_as_cell!(s2+1+idx));
|
||||||
|
self.pdl.push(heap_loc_as_cell!(l1+idx));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.fail = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr | HeapCellValueTag::PStr) => {
|
||||||
|
Self::unify_partial_string(self, list_loc_as_cell!(l1), value)
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::AttrVar, h) => {
|
||||||
|
Self::bind(self, Ref::attr_var(h), list_loc_as_cell!(l1));
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Var, h) => {
|
||||||
|
Self::bind(self, Ref::heap_cell(h), list_loc_as_cell!(l1));
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::StackVar, s) => {
|
||||||
|
Self::bind(self, Ref::stack_cell(s), list_loc_as_cell!(l1));
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.fail = true;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unify_complete_string(&mut self, atom: Atom, value: HeapCellValue) {
|
||||||
|
if let Some(r) = value.as_var() {
|
||||||
|
if atom == atom!("") {
|
||||||
|
Self::bind(self, r, atom_as_cell!(atom!("[]")));
|
||||||
|
} else {
|
||||||
|
Self::bind(self, r, atom_as_cstr_cell!(atom));
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
read_heap_cell!(value,
|
||||||
|
(HeapCellValueTag::Atom, (cstr_atom, arity)) if atom == atom!("") => {
|
||||||
|
debug_assert_eq!(arity, 0);
|
||||||
|
self.fail = cstr_atom != atom!("[]");
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Str, s) => {
|
||||||
|
let (name, arity) = cell_as_atom_cell!(self.heap[s])
|
||||||
|
.get_name_and_arity();
|
||||||
|
|
||||||
|
if arity == 0 {
|
||||||
|
self.fail = atom == atom!("") && name != atom!("[]");
|
||||||
|
} else {
|
||||||
|
// this is intentionally the same policy for
|
||||||
|
// value.tag() == Lis and PStrLoc. they're not
|
||||||
|
// grouped together to allow for arity == 0.
|
||||||
|
Self::unify_partial_string(self, atom_as_cstr_cell!(atom), value);
|
||||||
|
|
||||||
|
if !self.pdl.is_empty() {
|
||||||
|
Self::unify_internal(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::CStr, cstr_atom) => {
|
||||||
|
self.fail = atom != cstr_atom;
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc) => {
|
||||||
|
Self::unify_partial_string(self, atom_as_cstr_cell!(atom), value);
|
||||||
|
|
||||||
|
if !self.pdl.is_empty() {
|
||||||
|
Self::unify_internal(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.fail = true;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// the return value of unify_partial_string is interpreted as
|
||||||
|
// follows:
|
||||||
|
//
|
||||||
|
// Some(None) -- the strings are equal, nothing to unify
|
||||||
|
// Some(Some(f2,f1)) -- prefixes equal, try to unify focus values f2, f1
|
||||||
|
// None -- prefixes not equal, unification fails
|
||||||
|
//
|
||||||
|
// d1's tag is assumed to be one of LIS, STR or PSTRLOC.
|
||||||
|
fn unify_partial_string(&mut self, value_1: HeapCellValue, value_2: HeapCellValue) {
|
||||||
|
if let Some(r) = value_2.as_var() {
|
||||||
|
Self::bind(self, r, value_1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let machine_st = self.deref_mut();
|
||||||
|
|
||||||
|
let s1 = machine_st.heap.len();
|
||||||
|
|
||||||
|
machine_st.heap.push(value_1);
|
||||||
|
machine_st.heap.push(value_2);
|
||||||
|
|
||||||
|
let mut pstr_iter1 = HeapPStrIter::new(&machine_st.heap, s1);
|
||||||
|
let mut pstr_iter2 = HeapPStrIter::new(&machine_st.heap, s1 + 1);
|
||||||
|
|
||||||
|
match compare_pstr_prefixes(&mut pstr_iter1, &mut pstr_iter2) {
|
||||||
|
PStrCmpResult::Ordered(Ordering::Equal) => {}
|
||||||
|
PStrCmpResult::Ordered(Ordering::Less) => {
|
||||||
|
if pstr_iter2.focus.as_var().is_none() {
|
||||||
|
machine_st.fail = true;
|
||||||
|
} else {
|
||||||
|
machine_st.pdl.push(empty_list_as_cell!());
|
||||||
|
machine_st.pdl.push(pstr_iter2.focus);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PStrCmpResult::Ordered(Ordering::Greater) => {
|
||||||
|
if pstr_iter1.focus.as_var().is_none() {
|
||||||
|
machine_st.fail = true;
|
||||||
|
} else {
|
||||||
|
machine_st.pdl.push(empty_list_as_cell!());
|
||||||
|
machine_st.pdl.push(pstr_iter1.focus);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continuable @ PStrCmpResult::FirstIterContinuable(iteratee) |
|
||||||
|
continuable @ PStrCmpResult::SecondIterContinuable(iteratee) => {
|
||||||
|
if continuable.is_second_iter() {
|
||||||
|
std::mem::swap(&mut pstr_iter1, &mut pstr_iter2);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut chars_iter = PStrCharsIter {
|
||||||
|
iter: pstr_iter1,
|
||||||
|
item: Some(iteratee),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut focus = pstr_iter2.focus;
|
||||||
|
|
||||||
|
'outer: loop {
|
||||||
|
while let Some(c) = chars_iter.peek() {
|
||||||
|
read_heap_cell!(focus,
|
||||||
|
(HeapCellValueTag::Lis, l) => {
|
||||||
|
let val = pstr_iter2.heap[l];
|
||||||
|
|
||||||
|
machine_st.pdl.push(val);
|
||||||
|
machine_st.pdl.push(char_as_cell!(c));
|
||||||
|
|
||||||
|
focus = pstr_iter2.heap[l+1];
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Str, s) => {
|
||||||
|
let (name, arity) = cell_as_atom_cell!(pstr_iter2.heap[s])
|
||||||
|
.get_name_and_arity();
|
||||||
|
|
||||||
|
if name == atom!(".") && arity == 2 {
|
||||||
|
machine_st.pdl.push(pstr_iter2.heap[s+1]);
|
||||||
|
machine_st.pdl.push(char_as_cell!(c));
|
||||||
|
|
||||||
|
focus = pstr_iter2.heap[s+2];
|
||||||
|
} else {
|
||||||
|
machine_st.fail = true;
|
||||||
|
break 'outer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
|
||||||
|
match chars_iter.item.unwrap() {
|
||||||
|
PStrIteratee::Char(focus, _) => {
|
||||||
|
machine_st.pdl.push(machine_st.heap[focus]);
|
||||||
|
machine_st.pdl.push(heap_loc_as_cell!(h));
|
||||||
|
}
|
||||||
|
PStrIteratee::PStrSegment(focus, _, n) => {
|
||||||
|
read_heap_cell!(machine_st.heap[focus],
|
||||||
|
(HeapCellValueTag::CStr | HeapCellValueTag::PStr, pstr_atom) => {
|
||||||
|
if focus < machine_st.heap.len() - 2 {
|
||||||
|
machine_st.heap.pop();
|
||||||
|
machine_st.heap.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
if n == 0 {
|
||||||
|
let target_cell = match machine_st.heap[focus].get_tag() {
|
||||||
|
HeapCellValueTag::CStr => {
|
||||||
|
atom_as_cstr_cell!(pstr_atom)
|
||||||
|
}
|
||||||
|
HeapCellValueTag::PStr => {
|
||||||
|
pstr_loc_as_cell!(focus)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
machine_st.pdl.push(target_cell);
|
||||||
|
machine_st.pdl.push(heap_loc_as_cell!(h));
|
||||||
|
} else {
|
||||||
|
let h_len = machine_st.heap.len();
|
||||||
|
|
||||||
|
machine_st.heap.push(pstr_offset_as_cell!(focus));
|
||||||
|
machine_st.heap.push(fixnum_as_cell!(
|
||||||
|
Fixnum::build_with(n as i64)
|
||||||
|
));
|
||||||
|
|
||||||
|
machine_st.pdl.push(pstr_loc_as_cell!(h_len));
|
||||||
|
machine_st.pdl.push(heap_loc_as_cell!(h));
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::PStrOffset, pstr_loc) => {
|
||||||
|
let n0 = cell_as_fixnum!(machine_st.heap[focus+1])
|
||||||
|
.get_num() as usize;
|
||||||
|
|
||||||
|
if pstr_loc < machine_st.heap.len() - 2 {
|
||||||
|
machine_st.heap.pop();
|
||||||
|
machine_st.heap.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
if n == n0 {
|
||||||
|
machine_st.pdl.push(pstr_loc_as_cell!(focus));
|
||||||
|
machine_st.pdl.push(heap_loc_as_cell!(h));
|
||||||
|
} else {
|
||||||
|
let h_len = machine_st.heap.len();
|
||||||
|
|
||||||
|
machine_st.heap.push(pstr_offset_as_cell!(pstr_loc));
|
||||||
|
machine_st.heap.push(fixnum_as_cell!(
|
||||||
|
Fixnum::build_with(n as i64)
|
||||||
|
));
|
||||||
|
|
||||||
|
machine_st.pdl.push(pstr_loc_as_cell!(h_len));
|
||||||
|
machine_st.pdl.push(heap_loc_as_cell!(h));
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if focus < machine_st.heap.len() - 2 {
|
||||||
|
machine_st.heap.pop();
|
||||||
|
machine_st.heap.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
machine_st.pdl.push(machine_st.heap[focus]);
|
||||||
|
machine_st.pdl.push(heap_loc_as_cell!(h));
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break 'outer;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
machine_st.fail = true;
|
||||||
|
break 'outer;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
chars_iter.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
chars_iter.iter.next();
|
||||||
|
|
||||||
|
machine_st.pdl.push(focus);
|
||||||
|
machine_st.pdl.push(chars_iter.iter.focus);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PStrCmpResult::Unordered => {
|
||||||
|
machine_st.pdl.push(pstr_iter1.focus);
|
||||||
|
machine_st.pdl.push(pstr_iter2.focus);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
machine_st.heap.pop();
|
||||||
|
machine_st.heap.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unify_atom(&mut self, atom: Atom, value: HeapCellValue) {
|
||||||
|
read_heap_cell!(value,
|
||||||
|
(HeapCellValueTag::Atom, (name, arity)) => {
|
||||||
|
self.fail = !(arity == 0 && name == atom);
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Str, s) => {
|
||||||
|
let (name, arity) = cell_as_atom_cell!(self.heap[s])
|
||||||
|
.get_name_and_arity();
|
||||||
|
|
||||||
|
self.fail = !(arity == 0 && name == atom);
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::CStr, cstr_atom) if atom == atom!("[]") => {
|
||||||
|
self.fail = cstr_atom != atom!("");
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Char, c1) => {
|
||||||
|
if let Some(c2) = atom.as_char() {
|
||||||
|
self.fail = c1 != c2;
|
||||||
|
} else {
|
||||||
|
self.fail = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::AttrVar, h) => {
|
||||||
|
Self::bind(self, Ref::attr_var(h), atom_as_cell!(atom));
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Var, h) => {
|
||||||
|
Self::bind(self, Ref::heap_cell(h), atom_as_cell!(atom));
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::StackVar, s) => {
|
||||||
|
Self::bind(self, Ref::stack_cell(s), atom_as_cell!(atom));
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.fail = true;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unify_char(&mut self, c: char, value: HeapCellValue) {
|
||||||
|
read_heap_cell!(value,
|
||||||
|
(HeapCellValueTag::Atom, (name, arity)) => {
|
||||||
|
if let Some(c2) = name.as_char() {
|
||||||
|
self.fail = !(c == c2 && arity == 0);
|
||||||
|
} else {
|
||||||
|
self.fail = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Str, s) => {
|
||||||
|
let (name, arity) = cell_as_atom_cell!(self.heap[s])
|
||||||
|
.get_name_and_arity();
|
||||||
|
|
||||||
|
if let Some(c2) = name.as_char() {
|
||||||
|
self.fail = !(c == c2 && arity == 0);
|
||||||
|
} else {
|
||||||
|
self.fail = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Char, c2) => {
|
||||||
|
if c != c2 {
|
||||||
|
self.fail = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::AttrVar, h) => {
|
||||||
|
Self::bind(self, Ref::attr_var(h), char_as_cell!(c));
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Var, h) => {
|
||||||
|
Self::bind(self, Ref::heap_cell(h), char_as_cell!(c));
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::StackVar, s) => {
|
||||||
|
Self::bind(self, Ref::stack_cell(s), char_as_cell!(c));
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.fail = true;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unify_fixnum(&mut self, n1: Fixnum, value: HeapCellValue) {
|
||||||
|
if let Some(r) = value.as_var() {
|
||||||
|
Self::bind(self, r, fixnum_as_cell!(n1));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
match Number::try_from(value) {
|
||||||
|
Ok(n2) => match n2 {
|
||||||
|
Number::Fixnum(n2) if n1.get_num() == n2.get_num() => {}
|
||||||
|
Number::Integer(n2) if n1.get_num() == *n2 => {}
|
||||||
|
Number::Rational(n2) if n1.get_num() == *n2 => {}
|
||||||
|
_ => {
|
||||||
|
self.fail = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(_) => {
|
||||||
|
self.fail = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unify_big_num<N>(&mut self, n1: TypedArenaPtr<N>, value: HeapCellValue)
|
||||||
|
where N: PartialEq<Rational>
|
||||||
|
+ PartialEq<Integer>
|
||||||
|
+ PartialEq<i64>
|
||||||
|
+ ArenaAllocated
|
||||||
|
{
|
||||||
|
if let Some(r) = value.as_var() {
|
||||||
|
Self::bind(self, r, typed_arena_ptr_as_cell!(n1));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
match Number::try_from(value) {
|
||||||
|
Ok(n2) => match n2 {
|
||||||
|
Number::Fixnum(n2) if *n1 == n2.get_num() => {}
|
||||||
|
Number::Integer(n2) if *n1 == *n2 => {}
|
||||||
|
Number::Rational(n2) if *n1 == *n2 => {}
|
||||||
|
_ => {
|
||||||
|
self.fail = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(_) => {
|
||||||
|
self.fail = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unify_f64(&mut self, f1: F64Ptr, value: HeapCellValue) {
|
||||||
|
if let Some(r) = value.as_var() {
|
||||||
|
Self::bind(self, r, HeapCellValue::from(f1));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
read_heap_cell!(value,
|
||||||
|
(HeapCellValueTag::F64, f2) => {
|
||||||
|
self.fail = **f1 != **f2;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.fail = true;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unify_constant(&mut self, ptr: UntypedArenaPtr, value: HeapCellValue) {
|
||||||
|
if let Some(ptr2) = value.to_untyped_arena_ptr() {
|
||||||
|
if ptr.get_ptr() == ptr2.get_ptr() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match_untyped_arena_ptr!(ptr,
|
||||||
|
(ArenaHeaderTag::Integer, int_ptr) => {
|
||||||
|
Self::unify_big_num(self, int_ptr, value);
|
||||||
|
}
|
||||||
|
(ArenaHeaderTag::Rational, rat_ptr) => {
|
||||||
|
Self::unify_big_num(self, rat_ptr, value);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
if let Some(r) = value.as_var() {
|
||||||
|
Self::bind(self, r, untyped_arena_ptr_as_cell!(ptr));
|
||||||
|
} else {
|
||||||
|
self.fail = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unify_internal(&mut self) {
|
||||||
|
let mut tabu_list = IndexSet::with_hasher(FxBuildHasher::default());
|
||||||
|
|
||||||
|
while !(self.pdl.is_empty() || self.fail) {
|
||||||
|
let s1 = self.pdl.pop().unwrap();
|
||||||
|
let s1 = (self.deref() as &MachineState).deref(s1);
|
||||||
|
|
||||||
|
let s2 = self.pdl.pop().unwrap();
|
||||||
|
let s2 = (self.deref() as &MachineState).deref(s2);
|
||||||
|
|
||||||
|
if s1 != s2 {
|
||||||
|
let d1 = self.store(s1);
|
||||||
|
let d2 = self.store(s2);
|
||||||
|
|
||||||
|
read_heap_cell!(d1,
|
||||||
|
(HeapCellValueTag::AttrVar, h) => {
|
||||||
|
Self::bind(self, Ref::attr_var(h), d2);
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Var, h) => {
|
||||||
|
Self::bind(self, Ref::heap_cell(h), d2);
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::StackVar, s) => {
|
||||||
|
Self::bind(self, Ref::stack_cell(s), d2);
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Atom, (name, arity)) => {
|
||||||
|
debug_assert_eq!(arity, 0);
|
||||||
|
Self::unify_atom(self, name, d2);
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Str, s1) => {
|
||||||
|
if tabu_list.contains(&(d1, d2)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Self::unify_structure(self, s1, d2);
|
||||||
|
|
||||||
|
if !self.fail {
|
||||||
|
let d2 = self.store(d2);
|
||||||
|
tabu_list.insert((d1, d2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Lis, l1) => {
|
||||||
|
if d2.is_ref() {
|
||||||
|
if tabu_list.contains(&(d1, d2)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Self::unify_list(self, l1, d2);
|
||||||
|
|
||||||
|
if !self.fail {
|
||||||
|
let d2 = self.store(d2);
|
||||||
|
tabu_list.insert((d1, d2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::PStrLoc) => {
|
||||||
|
read_heap_cell!(d2,
|
||||||
|
(HeapCellValueTag::PStrLoc |
|
||||||
|
HeapCellValueTag::Lis |
|
||||||
|
HeapCellValueTag::Str) => {
|
||||||
|
if tabu_list.contains(&(d1, d2)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::CStr |
|
||||||
|
HeapCellValueTag::AttrVar |
|
||||||
|
HeapCellValueTag::Var |
|
||||||
|
HeapCellValueTag::StackVar) => {
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.fail = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
Self::unify_partial_string(self, d1, d2);
|
||||||
|
|
||||||
|
if !self.fail && !d2.is_constant() {
|
||||||
|
let d2 = self.store(d2);
|
||||||
|
tabu_list.insert((d1, d2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::CStr) => {
|
||||||
|
read_heap_cell!(d2,
|
||||||
|
(HeapCellValueTag::AttrVar, h) => {
|
||||||
|
Self::bind(self, Ref::attr_var(h), d1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Var, h) => {
|
||||||
|
Self::bind(self, Ref::heap_cell(h), d1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::StackVar, s) => {
|
||||||
|
Self::bind(self, Ref::stack_cell(s), d1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Str |
|
||||||
|
HeapCellValueTag::Lis |
|
||||||
|
HeapCellValueTag::PStrLoc) => {
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::CStr) => {
|
||||||
|
self.fail = d1 != d2;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.fail = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
Self::unify_partial_string(self, d2, d1);
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::F64, f1) => {
|
||||||
|
Self::unify_f64(self, f1, d2);
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Fixnum, n1) => {
|
||||||
|
Self::unify_fixnum(self, n1, d2);
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Char, c1) => {
|
||||||
|
Self::unify_char(self, c1, d2);
|
||||||
|
}
|
||||||
|
(HeapCellValueTag::Cons, ptr_1) => {
|
||||||
|
Self::unify_constant(self, ptr_1, d2);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bind(&mut self, r: Ref, value: HeapCellValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn bind_with_occurs_check<U: Unifier>(unifier: &mut U, r: Ref, value: HeapCellValue) -> bool {
|
||||||
|
if let RefTag::StackCell = r.get_tag() {
|
||||||
|
// local variable optimization -- r cannot occur in the
|
||||||
|
// heap structure bound to value, so don't bother
|
||||||
|
// traversing value.
|
||||||
|
U::bind(unifier, r, value);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut occurs_triggered = false;
|
||||||
|
|
||||||
|
if !value.is_constant() {
|
||||||
|
for addr in stackful_preorder_iter(&mut unifier.heap, value) {
|
||||||
|
let addr = unmark_cell_bits!(addr);
|
||||||
|
|
||||||
|
if let Some(inner_r) = addr.as_var() {
|
||||||
|
if r == inner_r {
|
||||||
|
occurs_triggered = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if occurs_triggered {
|
||||||
|
unifier.fail = true;
|
||||||
|
} else {
|
||||||
|
U::bind(unifier, r, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return occurs_triggered;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deref, DerefMut)]
|
||||||
|
pub(crate) struct DefaultUnifier<'a> {
|
||||||
|
machine_st: &'a mut MachineState,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a mut MachineState> for DefaultUnifier<'a> {
|
||||||
|
#[inline(always)]
|
||||||
|
fn from(machine_st: &'a mut MachineState) -> Self {
|
||||||
|
Self { machine_st }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Unifier for DefaultUnifier<'a> {
|
||||||
|
fn bind(&mut self, r: Ref, value: HeapCellValue) {
|
||||||
|
self.machine_st.bind(r, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct CompositeUnifierForOccursCheck<U> {
|
||||||
|
unifier: U,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<U: Unifier> Deref for CompositeUnifierForOccursCheck<U> {
|
||||||
|
type Target = MachineState;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
self.unifier.deref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<U: Unifier> DerefMut for CompositeUnifierForOccursCheck<U> {
|
||||||
|
#[inline(always)]
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
self.unifier.deref_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<U: Unifier> From<U> for CompositeUnifierForOccursCheck<U> {
|
||||||
|
#[inline(always)]
|
||||||
|
fn from(unifier: U) -> Self {
|
||||||
|
Self { unifier }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<U: Unifier> Unifier for CompositeUnifierForOccursCheck<U> {
|
||||||
|
fn bind(&mut self, r: Ref, value: HeapCellValue) {
|
||||||
|
bind_with_occurs_check(&mut self.unifier, r, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct CompositeUnifierForOccursCheckWithError<U: Unifier> {
|
||||||
|
unifier: U,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<U: Unifier> Deref for CompositeUnifierForOccursCheckWithError<U> {
|
||||||
|
type Target = MachineState;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
self.unifier.deref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<U: Unifier> DerefMut for CompositeUnifierForOccursCheckWithError<U> {
|
||||||
|
#[inline(always)]
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
self.unifier.deref_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<U: Unifier> From<U> for CompositeUnifierForOccursCheckWithError<U> {
|
||||||
|
#[inline(always)]
|
||||||
|
fn from(unifier: U) -> Self {
|
||||||
|
Self { unifier }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<U: Unifier> Unifier for CompositeUnifierForOccursCheckWithError<U> {
|
||||||
|
fn bind(&mut self, r: Ref, value: HeapCellValue) {
|
||||||
|
if bind_with_occurs_check(&mut self.unifier, r, value) {
|
||||||
|
let err = self.representation_error(RepFlag::Term);
|
||||||
|
let stub = functor_stub(atom!("unify_with_occurs_check"), 2);
|
||||||
|
let err = self.error_form(err, stub);
|
||||||
|
|
||||||
|
self.throw_exception(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -53,7 +53,6 @@ pub enum HeapCellValueView {
|
|||||||
// trail elements.
|
// trail elements.
|
||||||
TrailedHeapVar = 0b011101,
|
TrailedHeapVar = 0b011101,
|
||||||
TrailedStackVar = 0b011111,
|
TrailedStackVar = 0b011111,
|
||||||
TrailedAttrVarHeapLink = 0b100001,
|
|
||||||
TrailedAttrVarListLink = 0b100011,
|
TrailedAttrVarListLink = 0b100011,
|
||||||
TrailedAttachedValue = 0b100101,
|
TrailedAttachedValue = 0b100101,
|
||||||
TrailedBlackboardEntry = 0b100111,
|
TrailedBlackboardEntry = 0b100111,
|
||||||
@@ -182,7 +181,6 @@ impl Ref {
|
|||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum TrailRef {
|
pub enum TrailRef {
|
||||||
Ref(Ref),
|
Ref(Ref),
|
||||||
AttrVarHeapLink(usize),
|
|
||||||
AttrVarListLink(usize, usize),
|
AttrVarListLink(usize, usize),
|
||||||
BlackboardEntry(Atom),
|
BlackboardEntry(Atom),
|
||||||
BlackboardOffset(Atom, HeapCellValue), // key atom, key value
|
BlackboardOffset(Atom, HeapCellValue), // key atom, key value
|
||||||
@@ -194,7 +192,6 @@ pub(crate) enum TrailEntryTag {
|
|||||||
TrailedHeapVar = 0b011110,
|
TrailedHeapVar = 0b011110,
|
||||||
TrailedStackVar = 0b011111,
|
TrailedStackVar = 0b011111,
|
||||||
TrailedAttrVar = 0b101110,
|
TrailedAttrVar = 0b101110,
|
||||||
TrailedAttrVarHeapLink = 0b100010,
|
|
||||||
TrailedAttrVarListLink = 0b100011,
|
TrailedAttrVarListLink = 0b100011,
|
||||||
TrailedAttachedValue = 0b101010,
|
TrailedAttachedValue = 0b101010,
|
||||||
TrailedBlackboardEntry = 0b100110,
|
TrailedBlackboardEntry = 0b100110,
|
||||||
|
|||||||
Reference in New Issue
Block a user