eyeprolog 1.3.68 → 1.3.69
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -7
- package/package.json +1 -1
- package/src/ARCHITECTURE.md +7 -0
- package/src/CLPZ-MIGRATION.md +27 -9
- package/src/lib/arithmetic.pl +36 -0
- package/src/lib/assoc.pl +42 -0
- package/src/lib/between.pl +54 -0
- package/src/lib/dcgs.pl +23 -0
- package/src/lib/debug.pl +17 -0
- package/src/lib/error.pl +123 -0
- package/src/lib/format.pl +35 -0
- package/src/lib/freeze.pl +28 -0
- package/src/lib/pairs.pl +36 -0
- package/src/lib/si.pl +62 -0
- package/src/lib/terms.pl +18 -0
- package/src/scryer-compat.js +39 -0
- package/src/standard-library.js +13 -0
- package/src/term.js +13 -0
- package/test/run-regression.mjs +74 -1
- package/the-art-of-eyeprolog.md +6 -3
package/README.md
CHANGED
|
@@ -159,15 +159,17 @@ variable representatives and ordinary Prolog backtracking, and the REPL projects
|
|
|
159
159
|
module `attribute_goals//1` hooks as residual goals. See
|
|
160
160
|
[`examples/attributed-variables.pl`](examples/attributed-variables.pl).
|
|
161
161
|
|
|
162
|
-
The
|
|
162
|
+
The next two migration stages toward reusing Markus Triska's MIT-licensed
|
|
163
163
|
[Scryer `library(clpz)`](https://github.com/mthom/scryer-prolog/blob/master/src/lib/clpz.pl)
|
|
164
|
-
|
|
164
|
+
are now in place as well. Normal-profile loading supports user-defined
|
|
165
165
|
`term_expansion/2` and `goal_expansion/2`, clause-list generation, and
|
|
166
|
-
`expand_term/2` for processor DCG lowering
|
|
167
|
-
used by Scryer
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
166
|
+
`expand_term/2` for processor DCG lowering. EyeProlog also ships the support
|
|
167
|
+
modules used by Scryer's CLP(Z) source (`assoc`, `pairs`, `between`, `dcgs`,
|
|
168
|
+
`terms`, `error`, `si`, `freeze`, `arithmetic`, `debug`, and `format`) together
|
|
169
|
+
with generic backtrackable blackboard primitives. The current CLP(Z) engine
|
|
170
|
+
remains active while the upstream solver itself is integrated and checked for
|
|
171
|
+
behavioral and performance parity. The staged plan and exact compatibility
|
|
172
|
+
boundary are documented in [`src/CLPZ-MIGRATION.md`](src/CLPZ-MIGRATION.md).
|
|
171
173
|
|
|
172
174
|
Recursion through negation is explicit. EyeProlog provides `tnot/1` for
|
|
173
175
|
well-founded negation over finite, range-restricted, function-free Datalog
|
package/package.json
CHANGED
package/src/ARCHITECTURE.md
CHANGED
|
@@ -48,6 +48,13 @@ needed by Scryer's `library(atts)` and `library(clpz)`. The current CLP(Z)-speci
|
|
|
48
48
|
`Env._clpz` store remains transitional until the Scryer Prolog implementation can
|
|
49
49
|
replace it without losing test or performance parity; see `src/CLPZ-MIGRATION.md`.
|
|
50
50
|
|
|
51
|
+
`Env` also owns the small generic backtrackable blackboard used by Scryer-style
|
|
52
|
+
libraries. Blackboard maps are shared by clones and copied only on write, so
|
|
53
|
+
`bb_b_put/2` follows ordinary Prolog backtracking without any CLP(Z)-specific
|
|
54
|
+
state in the VM. `scryer-compat.js` exposes the private host bridge used by
|
|
55
|
+
`library(debug)`; the rest of the Stage 3 compatibility surface lives as Prolog
|
|
56
|
+
modules under `src/lib/`.
|
|
57
|
+
|
|
51
58
|
`source-expansion.js` is the explicit compile-time execution boundary. When an
|
|
52
59
|
already-loaded `term_expansion/2` or `goal_expansion/2` hook exists, program
|
|
53
60
|
preparation invokes it with a fresh bounded `Solver` against the partially built
|
package/src/CLPZ-MIGRATION.md
CHANGED
|
@@ -55,17 +55,35 @@ The regression corpus covers clause-list generation, variable-sharing goal
|
|
|
55
55
|
expansion, qualified hook lexical context, and the Scryer pattern where a
|
|
56
56
|
`term_expansion/2` hook calls `expand_term/2` to generate a DCG predicate.
|
|
57
57
|
|
|
58
|
-
##
|
|
58
|
+
## Stage 3: Scryer support-library surface
|
|
59
59
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
`arithmetic`, `debug`, and `format
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
60
|
+
This stage is implemented. EyeProlog now registers the library names imported by
|
|
61
|
+
Scryer's current `clpz.pl`: `assoc`, `pairs`, `between`, `dcgs`, `terms`,
|
|
62
|
+
`error`, `si`, `freeze`, `arithmetic`, `debug`, and `format`. The implementations
|
|
63
|
+
are deliberately small compatibility layers where CLP(Z) needs only a subset of
|
|
64
|
+
the upstream module, while observable predicate contracts stay at the Prolog
|
|
65
|
+
library boundary. In particular, `library(freeze)` is implemented with the same
|
|
66
|
+
attributed-variable `verify_attributes/3` protocol introduced in Stage 1.
|
|
66
67
|
|
|
67
|
-
|
|
68
|
-
|
|
68
|
+
Two remaining Scryer runtime facilities are generic rather than constraint
|
|
69
|
+
specific. `Env` now carries a copy-on-write backtrackable blackboard, exposed to
|
|
70
|
+
Prolog through `bb_get/2` and `bb_b_put/2` compatibility wrappers, and
|
|
71
|
+
`library(terms)` provides `copy_term_nat/2` using EyeProlog's attribute-free
|
|
72
|
+
logical copy semantics. Regression coverage exercises the support modules,
|
|
73
|
+
blackboard rollback, attribute-free copying, and the exact import/attribute
|
|
74
|
+
prelude used by upstream CLP(Z).
|
|
75
|
+
|
|
76
|
+
## What still prevents replacing `src/clpz.js`
|
|
77
|
+
|
|
78
|
+
The VM/compiler and named support-library blockers are now closed. The remaining
|
|
79
|
+
work is direct upstream-source integration: vendor a pinned Scryer `clpz.pl`,
|
|
80
|
+
apply only the small compatibility patches exposed by loading the complete file,
|
|
81
|
+
and run it side-by-side against EyeProlog's existing CLP(Z) corpus plus selected
|
|
82
|
+
Scryer regressions. Only after behavioral and performance parity should the
|
|
83
|
+
`eyeprolog__clpz_*` adapters and `Env._clpz` store be removed.
|
|
84
|
+
|
|
85
|
+
This boundary is intentional: Stage 3 does not claim that the complete upstream
|
|
86
|
+
solver is active merely because its dependency prelude loads.
|
|
69
87
|
|
|
70
88
|
## Migration rule
|
|
71
89
|
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/** Integer arithmetic helpers used by Scryer's CLP(Z) source. */
|
|
2
|
+
|
|
3
|
+
:- module(arithmetic, [lsb/2, msb/2, popcount/2]).
|
|
4
|
+
|
|
5
|
+
:- use_module(library(error), [must_be/2, domain_error/3]).
|
|
6
|
+
|
|
7
|
+
lsb(X, N) :-
|
|
8
|
+
must_be(integer, X),
|
|
9
|
+
( X < 1 -> domain_error(not_less_than_one, X, lsb/2)
|
|
10
|
+
; Low is X /\ (-X), arithmetic__msb(Low, -1, N)
|
|
11
|
+
).
|
|
12
|
+
|
|
13
|
+
msb(X, N) :-
|
|
14
|
+
must_be(integer, X),
|
|
15
|
+
( X < 1 -> domain_error(not_less_than_one, X, msb/2)
|
|
16
|
+
; Shifted is X >> 1, arithmetic__msb(Shifted, 0, N)
|
|
17
|
+
).
|
|
18
|
+
|
|
19
|
+
arithmetic__msb(0, N, N) :- !.
|
|
20
|
+
arithmetic__msb(X, N0, N) :-
|
|
21
|
+
X1 is X >> 1,
|
|
22
|
+
N1 is N0 + 1,
|
|
23
|
+
arithmetic__msb(X1, N1, N).
|
|
24
|
+
|
|
25
|
+
popcount(X, Count) :-
|
|
26
|
+
must_be(integer, X),
|
|
27
|
+
( X < 0 -> domain_error(not_less_than_zero, X, popcount/2)
|
|
28
|
+
; arithmetic__popcount(X, 0, Count)
|
|
29
|
+
).
|
|
30
|
+
|
|
31
|
+
arithmetic__popcount(0, Count, Count) :- !.
|
|
32
|
+
arithmetic__popcount(X, Count0, Count) :-
|
|
33
|
+
Bit is X /\ 1,
|
|
34
|
+
Count1 is Count0 + Bit,
|
|
35
|
+
X1 is X >> 1,
|
|
36
|
+
arithmetic__popcount(X1, Count1, Count).
|
package/src/lib/assoc.pl
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/** Minimal Scryer-compatible association maps.
|
|
2
|
+
|
|
3
|
+
The public operations used by library(clpz) are represented as a sorted
|
|
4
|
+
list wrapped in assoc/1. The representation is intentionally private: the
|
|
5
|
+
predicates preserve the observable assoc contracts while keeping the
|
|
6
|
+
compatibility layer small and declarative.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
:- module(assoc, [
|
|
10
|
+
empty_assoc/1,
|
|
11
|
+
assoc_to_list/2,
|
|
12
|
+
get_assoc/3,
|
|
13
|
+
put_assoc/4
|
|
14
|
+
]).
|
|
15
|
+
|
|
16
|
+
empty_assoc(assoc([])).
|
|
17
|
+
|
|
18
|
+
assoc_to_list(assoc(Pairs), Pairs).
|
|
19
|
+
|
|
20
|
+
get_assoc(Key, assoc(Pairs), Value) :-
|
|
21
|
+
assoc__get(Pairs, Key, Value).
|
|
22
|
+
|
|
23
|
+
assoc__get([K-V|Pairs], Key, Value) :-
|
|
24
|
+
compare(Order, Key, K),
|
|
25
|
+
assoc__get(Order, Key, Value, V, Pairs).
|
|
26
|
+
|
|
27
|
+
assoc__get(=, _, Value, Value, _).
|
|
28
|
+
assoc__get(>, Key, Value, _, Pairs) :-
|
|
29
|
+
assoc__get(Pairs, Key, Value).
|
|
30
|
+
|
|
31
|
+
put_assoc(Key, assoc(Pairs0), Value, assoc(Pairs)) :-
|
|
32
|
+
assoc__put(Pairs0, Key, Value, Pairs).
|
|
33
|
+
|
|
34
|
+
assoc__put([], Key, Value, [Key-Value]).
|
|
35
|
+
assoc__put([K-V|Pairs0], Key, Value, Pairs) :-
|
|
36
|
+
compare(Order, Key, K),
|
|
37
|
+
assoc__put(Order, Key, Value, K, V, Pairs0, Pairs).
|
|
38
|
+
|
|
39
|
+
assoc__put(=, Key, Value, _, _, Pairs, [Key-Value|Pairs]).
|
|
40
|
+
assoc__put(<, Key, Value, K, V, Pairs, [Key-Value,K-V|Pairs]).
|
|
41
|
+
assoc__put(>, Key, Value, K, V, Pairs0, [K-V|Pairs]) :-
|
|
42
|
+
assoc__put(Pairs0, Key, Value, Pairs).
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/** Scryer-compatible integer generators needed by CLP(Z). */
|
|
2
|
+
|
|
3
|
+
:- module(between, [between/3, gen_int/1, gen_nat/1, numlist/2, numlist/3, repeat/1]).
|
|
4
|
+
|
|
5
|
+
:- use_module(library(error), [must_be/2, can_be/2]).
|
|
6
|
+
|
|
7
|
+
between(Lower, Upper, X) :-
|
|
8
|
+
must_be(integer, Lower),
|
|
9
|
+
must_be(integer, Upper),
|
|
10
|
+
can_be(integer, X),
|
|
11
|
+
( nonvar(X) -> Lower =< X, X =< Upper
|
|
12
|
+
; Lower =< Upper, between__from(Lower, Upper, X)
|
|
13
|
+
).
|
|
14
|
+
|
|
15
|
+
between__from(Lower, Upper, Lower).
|
|
16
|
+
between__from(Lower, Upper, X) :-
|
|
17
|
+
Lower < Upper,
|
|
18
|
+
Next is Lower + 1,
|
|
19
|
+
between__from(Next, Upper, X).
|
|
20
|
+
|
|
21
|
+
gen_nat(N) :-
|
|
22
|
+
can_be(integer, N),
|
|
23
|
+
( var(N) -> between__nats(0, N) ; N >= 0 ).
|
|
24
|
+
|
|
25
|
+
between__nats(N, N).
|
|
26
|
+
between__nats(N0, N) :- N1 is N0 + 1, between__nats(N1, N).
|
|
27
|
+
|
|
28
|
+
gen_int(N) :-
|
|
29
|
+
can_be(integer, N),
|
|
30
|
+
( var(N) -> between__ints(0, N) ; true ).
|
|
31
|
+
|
|
32
|
+
between__ints(0, 0).
|
|
33
|
+
between__ints(I, I) :- I > 0.
|
|
34
|
+
between__ints(I, N) :- I > 0, N is -I.
|
|
35
|
+
between__ints(I0, N) :- I1 is I0 + 1, between__ints(I1, N).
|
|
36
|
+
|
|
37
|
+
repeat(N) :-
|
|
38
|
+
must_be(integer, N), N > 0,
|
|
39
|
+
between__repeat(N).
|
|
40
|
+
between__repeat(_).
|
|
41
|
+
between__repeat(N0) :- N0 > 1, N is N0 - 1, between__repeat(N).
|
|
42
|
+
|
|
43
|
+
numlist(Upper, List) :- numlist(1, Upper, List).
|
|
44
|
+
|
|
45
|
+
numlist(Lower, Upper, List) :-
|
|
46
|
+
must_be(integer, Lower),
|
|
47
|
+
must_be(integer, Upper),
|
|
48
|
+
between__numlist(Lower, Upper, List).
|
|
49
|
+
|
|
50
|
+
between__numlist(Lower, Upper, []) :- Lower > Upper, !.
|
|
51
|
+
between__numlist(Lower, Upper, [Lower|Rest]) :-
|
|
52
|
+
Lower =< Upper,
|
|
53
|
+
Next is Lower + 1,
|
|
54
|
+
between__numlist(Next, Upper, Rest).
|
package/src/lib/dcgs.pl
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** Scryer-compatible DCG helpers.
|
|
2
|
+
|
|
3
|
+
EyeProlog already provides phrase/2-3 and ISO-style grammar expansion in the
|
|
4
|
+
runtime. This module supplies the sequence combinators used by Scryer's
|
|
5
|
+
declarative libraries and exports the built-in phrase predicates under the
|
|
6
|
+
expected module name.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
:- module(dcgs, [
|
|
10
|
+
phrase/2,
|
|
11
|
+
phrase/3,
|
|
12
|
+
seq//1,
|
|
13
|
+
seqq//1
|
|
14
|
+
]).
|
|
15
|
+
|
|
16
|
+
seq([]) --> [].
|
|
17
|
+
seq([Element|Elements]) --> [Element], seq(Elements).
|
|
18
|
+
|
|
19
|
+
seqq([]) --> [].
|
|
20
|
+
seqq([Elements|Sequences]) --> seq(Elements), seqq(Sequences).
|
|
21
|
+
|
|
22
|
+
'...' --> [].
|
|
23
|
+
'...' --> [_], '...'.
|
package/src/lib/debug.pl
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** Compatibility hooks for Scryer libraries.
|
|
2
|
+
|
|
3
|
+
CLP(Z) only needs the backtrackable blackboard operations; the debugging
|
|
4
|
+
predicates are deliberately harmless no-ops unless EyeProlog grows a debug
|
|
5
|
+
topic UI later.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
:- module(debug, [debug/1, debug/3, nodebug/1, bb_get/2, bb_b_put/2]).
|
|
9
|
+
|
|
10
|
+
:- meta_predicate(debug(+, +, +)).
|
|
11
|
+
|
|
12
|
+
debug(_).
|
|
13
|
+
debug(_, _, _).
|
|
14
|
+
nodebug(_).
|
|
15
|
+
|
|
16
|
+
bb_get(Key, Value) :- eyeprolog__bb_get(Key, Value).
|
|
17
|
+
bb_b_put(Key, Value) :- eyeprolog__bb_b_put(Key, Value).
|
package/src/lib/error.pl
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/** Small Scryer-compatible error/type layer used by reusable libraries. */
|
|
2
|
+
|
|
3
|
+
:- module(error, [
|
|
4
|
+
must_be/2,
|
|
5
|
+
can_be/2,
|
|
6
|
+
instantiation_error/0,
|
|
7
|
+
instantiation_error/1,
|
|
8
|
+
domain_error/2,
|
|
9
|
+
domain_error/3,
|
|
10
|
+
type_error/2,
|
|
11
|
+
type_error/3,
|
|
12
|
+
representation_error/1,
|
|
13
|
+
resource_error/1,
|
|
14
|
+
call_with_error_context/2
|
|
15
|
+
]).
|
|
16
|
+
|
|
17
|
+
:- meta_predicate(call_with_error_context(0, +)).
|
|
18
|
+
|
|
19
|
+
must_be(Type, Term) :-
|
|
20
|
+
( var(Type) -> instantiation_error(must_be/2)
|
|
21
|
+
; error__must_be(Type, Term)
|
|
22
|
+
).
|
|
23
|
+
|
|
24
|
+
error__must_be(integer, Term) :- !,
|
|
25
|
+
( var(Term) -> instantiation_error(must_be/2)
|
|
26
|
+
; integer(Term) -> true
|
|
27
|
+
; type_error(integer, Term, must_be/2)
|
|
28
|
+
).
|
|
29
|
+
error__must_be(atom, Term) :- !,
|
|
30
|
+
( var(Term) -> instantiation_error(must_be/2)
|
|
31
|
+
; atom(Term) -> true
|
|
32
|
+
; type_error(atom, Term, must_be/2)
|
|
33
|
+
).
|
|
34
|
+
error__must_be(number, Term) :- !,
|
|
35
|
+
( var(Term) -> instantiation_error(must_be/2)
|
|
36
|
+
; number(Term) -> true
|
|
37
|
+
; type_error(number, Term, must_be/2)
|
|
38
|
+
).
|
|
39
|
+
error__must_be(var, Term) :- !,
|
|
40
|
+
( var(Term) -> true
|
|
41
|
+
; throw(error(uninstantiation_error(Term), must_be/2))
|
|
42
|
+
).
|
|
43
|
+
error__must_be(ground, Term) :- !,
|
|
44
|
+
( ground(Term) -> true ; instantiation_error(must_be/2) ).
|
|
45
|
+
error__must_be(acyclic, Term) :- !,
|
|
46
|
+
( acyclic_term(Term) -> true ; type_error(acyclic_term, Term, must_be/2) ).
|
|
47
|
+
error__must_be(list, Term) :- !,
|
|
48
|
+
error__proper_list(Term).
|
|
49
|
+
error__must_be(list(Type), Term) :- !,
|
|
50
|
+
error__proper_list_of(Term, Type).
|
|
51
|
+
error__must_be(pair, Term) :- !,
|
|
52
|
+
( var(Term) -> instantiation_error(must_be/2)
|
|
53
|
+
; Term = _-_ -> true
|
|
54
|
+
; type_error(pair, Term, must_be/2)
|
|
55
|
+
).
|
|
56
|
+
error__must_be(not_less_than_zero, Term) :- !,
|
|
57
|
+
must_be(integer, Term),
|
|
58
|
+
( Term >= 0 -> true ; domain_error(not_less_than_zero, Term, must_be/2) ).
|
|
59
|
+
error__must_be(Type, Term) :-
|
|
60
|
+
( var(Term) -> instantiation_error(must_be/2)
|
|
61
|
+
; type_error(Type, Term, must_be/2)
|
|
62
|
+
).
|
|
63
|
+
|
|
64
|
+
error__proper_list([]).
|
|
65
|
+
error__proper_list([_|Tail]) :- !, error__proper_list(Tail).
|
|
66
|
+
error__proper_list(Term) :-
|
|
67
|
+
( var(Term) -> instantiation_error(must_be/2)
|
|
68
|
+
; type_error(list, Term, must_be/2)
|
|
69
|
+
).
|
|
70
|
+
|
|
71
|
+
error__proper_list_of([], _).
|
|
72
|
+
error__proper_list_of([Head|Tail], Type) :- !,
|
|
73
|
+
must_be(Type, Head),
|
|
74
|
+
error__proper_list_of(Tail, Type).
|
|
75
|
+
error__proper_list_of(Term, _) :-
|
|
76
|
+
( var(Term) -> instantiation_error(must_be/2)
|
|
77
|
+
; type_error(list, Term, must_be/2)
|
|
78
|
+
).
|
|
79
|
+
|
|
80
|
+
can_be(Type, Term) :-
|
|
81
|
+
( var(Type) -> instantiation_error(can_be/2)
|
|
82
|
+
; var(Term) -> true
|
|
83
|
+
; error__can_be(Type, Term)
|
|
84
|
+
).
|
|
85
|
+
|
|
86
|
+
error__can_be(integer, Term) :- !,
|
|
87
|
+
( integer(Term) -> true ; type_error(integer, Term, can_be/2) ).
|
|
88
|
+
error__can_be(atom, Term) :- !,
|
|
89
|
+
( atom(Term) -> true ; type_error(atom, Term, can_be/2) ).
|
|
90
|
+
error__can_be(number, Term) :- !,
|
|
91
|
+
( number(Term) -> true ; type_error(number, Term, can_be/2) ).
|
|
92
|
+
error__can_be(list, Term) :- !, error__partial_list(Term).
|
|
93
|
+
error__can_be(list(Type), Term) :- !, error__partial_list_of(Term, Type).
|
|
94
|
+
error__can_be(not_less_than_zero, Term) :- !,
|
|
95
|
+
( integer(Term) ->
|
|
96
|
+
( Term >= 0 -> true ; domain_error(not_less_than_zero, Term, can_be/2) )
|
|
97
|
+
; type_error(integer, Term, can_be/2)
|
|
98
|
+
).
|
|
99
|
+
error__can_be(Type, Term) :- error__must_be(Type, Term).
|
|
100
|
+
|
|
101
|
+
error__partial_list(Term) :- var(Term), !.
|
|
102
|
+
error__partial_list([]) :- !.
|
|
103
|
+
error__partial_list([_|Tail]) :- !, error__partial_list(Tail).
|
|
104
|
+
error__partial_list(Term) :- type_error(list, Term, can_be/2).
|
|
105
|
+
|
|
106
|
+
error__partial_list_of(Term, _) :- var(Term), !.
|
|
107
|
+
error__partial_list_of([], _) :- !.
|
|
108
|
+
error__partial_list_of([Head|Tail], Type) :- !,
|
|
109
|
+
can_be(Type, Head),
|
|
110
|
+
error__partial_list_of(Tail, Type).
|
|
111
|
+
error__partial_list_of(Term, _) :- type_error(list, Term, can_be/2).
|
|
112
|
+
|
|
113
|
+
instantiation_error :- throw(error(instantiation_error, [])).
|
|
114
|
+
instantiation_error(Context) :- throw(error(instantiation_error, Context)).
|
|
115
|
+
domain_error(Type, Term) :- throw(error(domain_error(Type, Term), [])).
|
|
116
|
+
domain_error(Type, Term, Context) :- throw(error(domain_error(Type, Term), Context)).
|
|
117
|
+
type_error(Type, Term) :- throw(error(type_error(Type, Term), [])).
|
|
118
|
+
type_error(Type, Term, Context) :- throw(error(type_error(Type, Term), Context)).
|
|
119
|
+
representation_error(Flag) :- throw(error(representation_error(Flag), [])).
|
|
120
|
+
resource_error(Resource) :- throw(error(resource_error(Resource), [])).
|
|
121
|
+
|
|
122
|
+
call_with_error_context(Goal, Pair) :-
|
|
123
|
+
catch(Goal, error(Error, Context), throw(error(Error, [Pair|Context]))).
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/** Small format/2 compatibility layer covering the controls used by CLP(Z). */
|
|
2
|
+
|
|
3
|
+
:- module(format, [format/2]).
|
|
4
|
+
|
|
5
|
+
format(Template, Arguments) :-
|
|
6
|
+
format__chars(Template, Chars),
|
|
7
|
+
format__emit(Chars, Arguments).
|
|
8
|
+
|
|
9
|
+
format__chars(Template, Chars) :-
|
|
10
|
+
atom(Template), !,
|
|
11
|
+
atom_chars(Template, Chars).
|
|
12
|
+
format__chars(Chars, Chars).
|
|
13
|
+
|
|
14
|
+
format__emit([], []).
|
|
15
|
+
format__emit(['~','~'|Chars], Args) :- !,
|
|
16
|
+
put_char('~'),
|
|
17
|
+
format__emit(Chars, Args).
|
|
18
|
+
format__emit(['~',n|Chars], Args) :- !,
|
|
19
|
+
nl,
|
|
20
|
+
format__emit(Chars, Args).
|
|
21
|
+
format__emit(['~',w|Chars], [Arg|Args]) :- !,
|
|
22
|
+
write(Arg),
|
|
23
|
+
format__emit(Chars, Args).
|
|
24
|
+
format__emit(['~',q|Chars], [Arg|Args]) :- !,
|
|
25
|
+
writeq(Arg),
|
|
26
|
+
format__emit(Chars, Args).
|
|
27
|
+
format__emit(['~',a|Chars], [Arg|Args]) :- !,
|
|
28
|
+
write(Arg),
|
|
29
|
+
format__emit(Chars, Args).
|
|
30
|
+
format__emit(['~',d|Chars], [Arg|Args]) :- !,
|
|
31
|
+
write(Arg),
|
|
32
|
+
format__emit(Chars, Args).
|
|
33
|
+
format__emit([Char|Chars], Args) :-
|
|
34
|
+
put_char(Char),
|
|
35
|
+
format__emit(Chars, Args).
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/** Attributed-variable implementation of Scryer-compatible freeze/2. */
|
|
2
|
+
|
|
3
|
+
:- module(freeze, [freeze/2]).
|
|
4
|
+
|
|
5
|
+
:- use_module(library(atts)).
|
|
6
|
+
:- meta_predicate(freeze(-, 0)).
|
|
7
|
+
:- attribute frozen/1.
|
|
8
|
+
|
|
9
|
+
verify_attributes(Var, Other, Goals) :-
|
|
10
|
+
get_atts(Var, frozen(FrozenA)), !,
|
|
11
|
+
( var(Other) ->
|
|
12
|
+
( get_atts(Other, frozen(FrozenB)) ->
|
|
13
|
+
put_atts(Other, frozen((FrozenB,FrozenA)))
|
|
14
|
+
; put_atts(Other, frozen(FrozenA))
|
|
15
|
+
),
|
|
16
|
+
Goals = []
|
|
17
|
+
; Goals = [FrozenA]
|
|
18
|
+
).
|
|
19
|
+
verify_attributes(_, _, []).
|
|
20
|
+
|
|
21
|
+
freeze(X, Goal) :-
|
|
22
|
+
put_atts(Fresh, frozen(Goal)),
|
|
23
|
+
Fresh = X.
|
|
24
|
+
|
|
25
|
+
attribute_goals(Var) -->
|
|
26
|
+
{ get_atts(Var, frozen(Goals)),
|
|
27
|
+
put_atts(Var, -frozen(_)) },
|
|
28
|
+
[freeze:freeze(Var, Goals)].
|
package/src/lib/pairs.pl
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/** Scryer-compatible pair helpers used by CLP(Z). */
|
|
2
|
+
|
|
3
|
+
:- module(pairs, [
|
|
4
|
+
pairs_keys_values/3,
|
|
5
|
+
pairs_keys/2,
|
|
6
|
+
pairs_values/2,
|
|
7
|
+
group_pairs_by_key/2,
|
|
8
|
+
map_list_to_pairs/3
|
|
9
|
+
]).
|
|
10
|
+
|
|
11
|
+
:- meta_predicate(map_list_to_pairs(2, ?, ?)).
|
|
12
|
+
|
|
13
|
+
pairs_keys_values([], [], []).
|
|
14
|
+
pairs_keys_values([A-B|ABs], [A|As], [B|Bs]) :-
|
|
15
|
+
pairs_keys_values(ABs, As, Bs).
|
|
16
|
+
|
|
17
|
+
pairs_keys(Pairs, Keys) :- pairs_keys_values(Pairs, Keys, _).
|
|
18
|
+
pairs_values(Pairs, Values) :- pairs_keys_values(Pairs, _, Values).
|
|
19
|
+
|
|
20
|
+
map_list_to_pairs(Pred, List, Pairs) :-
|
|
21
|
+
pairs__map_list_to_pairs(List, Pred, Pairs).
|
|
22
|
+
|
|
23
|
+
pairs__map_list_to_pairs([], _, []).
|
|
24
|
+
pairs__map_list_to_pairs([Head|Tail0], Pred, [Key-Head|Tail]) :-
|
|
25
|
+
call(Pred, Head, Key),
|
|
26
|
+
pairs__map_list_to_pairs(Tail0, Pred, Tail).
|
|
27
|
+
|
|
28
|
+
group_pairs_by_key([], []).
|
|
29
|
+
group_pairs_by_key([K-V|Pairs0], [K-[V|Values]|Pairs]) :-
|
|
30
|
+
pairs__same_key(K, Pairs0, Values, Pairs1),
|
|
31
|
+
group_pairs_by_key(Pairs1, Pairs).
|
|
32
|
+
|
|
33
|
+
pairs__same_key(K0, [K1-V|Pairs0], [V|Values], Pairs) :-
|
|
34
|
+
K0 == K1, !,
|
|
35
|
+
pairs__same_key(K0, Pairs0, Values, Pairs).
|
|
36
|
+
pairs__same_key(_, Pairs, [], Pairs).
|
package/src/lib/si.pl
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/** Sufficient-instantiation tests compatible with Scryer library(si). */
|
|
2
|
+
|
|
3
|
+
:- module(si, [
|
|
4
|
+
atom_si/1,
|
|
5
|
+
integer_si/1,
|
|
6
|
+
atomic_si/1,
|
|
7
|
+
list_si/1,
|
|
8
|
+
character_si/1,
|
|
9
|
+
term_si/1,
|
|
10
|
+
chars_si/1,
|
|
11
|
+
dif_si/2,
|
|
12
|
+
not_si/1,
|
|
13
|
+
when_si/2
|
|
14
|
+
]).
|
|
15
|
+
|
|
16
|
+
:- meta_predicate(not_si(0)).
|
|
17
|
+
:- meta_predicate(when_si(+, 0)).
|
|
18
|
+
|
|
19
|
+
atom_si(A) :- ( var(A) -> throw(error(instantiation_error, atom_si/1)) ; atom(A) ).
|
|
20
|
+
integer_si(I) :- ( var(I) -> throw(error(instantiation_error, integer_si/1)) ; integer(I) ).
|
|
21
|
+
atomic_si(A) :- ( var(A) -> throw(error(instantiation_error, atomic_si/1)) ; atomic(A) ).
|
|
22
|
+
|
|
23
|
+
list_si(List) :- si__list(List).
|
|
24
|
+
si__list([]).
|
|
25
|
+
si__list([_|Tail]) :- !, si__list(Tail).
|
|
26
|
+
si__list(Term) :-
|
|
27
|
+
( var(Term) -> throw(error(instantiation_error, list_si/1)) ; fail ).
|
|
28
|
+
|
|
29
|
+
character_si(C) :-
|
|
30
|
+
( var(C) -> throw(error(instantiation_error, character_si/1))
|
|
31
|
+
; atom(C), atom_length(C, 1)
|
|
32
|
+
).
|
|
33
|
+
|
|
34
|
+
term_si(Term) :-
|
|
35
|
+
( ground(Term) -> acyclic_term(Term)
|
|
36
|
+
; throw(error(instantiation_error, term_si/1))
|
|
37
|
+
).
|
|
38
|
+
|
|
39
|
+
chars_si(Chars) :-
|
|
40
|
+
list_si(Chars),
|
|
41
|
+
si__chars(Chars).
|
|
42
|
+
si__chars([]).
|
|
43
|
+
si__chars([C|Cs]) :- character_si(C), si__chars(Cs).
|
|
44
|
+
|
|
45
|
+
dif_si(X, Y) :-
|
|
46
|
+
X \== Y,
|
|
47
|
+
( X \= Y -> true ; throw(error(instantiation_error, dif_si/2)) ).
|
|
48
|
+
|
|
49
|
+
not_si(Goal) :- term_si(Goal), \+ Goal.
|
|
50
|
+
|
|
51
|
+
when_si(Condition, Goal) :-
|
|
52
|
+
( si__condition(Condition) ->
|
|
53
|
+
( call(Condition) -> call(Goal)
|
|
54
|
+
; throw(error(instantiation_error, when_si/2)) )
|
|
55
|
+
; throw(error(domain_error(when_condition_si, Condition), when_si/2))
|
|
56
|
+
).
|
|
57
|
+
|
|
58
|
+
si__condition(Condition) :- var(Condition), !, throw(error(instantiation_error, when_si/2)).
|
|
59
|
+
si__condition(ground(_)).
|
|
60
|
+
si__condition(nonvar(_)).
|
|
61
|
+
si__condition((A,B)) :- si__condition(A), si__condition(B).
|
|
62
|
+
si__condition((A;B)) :- si__condition(A), si__condition(B).
|
package/src/lib/terms.pl
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** Term helpers compatible with the Scryer library surface used by CLP(Z). */
|
|
2
|
+
|
|
3
|
+
:- module(terms, [numbervars/3, copy_term_nat/2]).
|
|
4
|
+
|
|
5
|
+
:- use_module(library(error), [must_be/2, can_be/2]).
|
|
6
|
+
|
|
7
|
+
copy_term_nat(Term, Copy) :- copy_term(Term, Copy).
|
|
8
|
+
|
|
9
|
+
numbervars(Term, N0, N) :-
|
|
10
|
+
must_be(integer, N0),
|
|
11
|
+
can_be(integer, N),
|
|
12
|
+
term_variables(Term, Variables),
|
|
13
|
+
terms__numbervars(Variables, N0, N).
|
|
14
|
+
|
|
15
|
+
terms__numbervars([], N, N).
|
|
16
|
+
terms__numbervars(['$VAR'(N0)|Variables], N0, N) :-
|
|
17
|
+
N1 is N0 + 1,
|
|
18
|
+
terms__numbervars(Variables, N1, N).
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// Small host primitives needed by Scryer-style declarative libraries.
|
|
2
|
+
//
|
|
3
|
+
// Keep these facilities generic: they are not part of the CLP(Z) engine. The
|
|
4
|
+
// backtrackable blackboard lives in Env so ordinary Prolog choice points undo
|
|
5
|
+
// writes automatically.
|
|
6
|
+
|
|
7
|
+
import { ATOM, NUMBER, STRING, deref, unify } from './term.js';
|
|
8
|
+
import { PrologError } from './errors.js';
|
|
9
|
+
|
|
10
|
+
function blackboardKey(term, env) {
|
|
11
|
+
const value = deref(term, env);
|
|
12
|
+
if (value.type === ATOM) return `a:${value.name}`;
|
|
13
|
+
if (value.type === NUMBER) return `n:${value.name}`;
|
|
14
|
+
if (value.type === STRING) return `s:${value.name}`;
|
|
15
|
+
if (value.type === 'var') throw new PrologError('instantiation_error');
|
|
16
|
+
throw new PrologError('type_error(atomic)', value);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function* bbGetBuiltin({ goal, env }) {
|
|
20
|
+
const key = blackboardKey(goal.args[0], env);
|
|
21
|
+
const stored = env.getBacktrackableBlackboard(key);
|
|
22
|
+
if (stored === undefined) return;
|
|
23
|
+
const next = env.clone();
|
|
24
|
+
if (unify(goal.args[1], stored, next)) yield next;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function* bbPutBuiltin({ goal, env }) {
|
|
28
|
+
const next = env.clone();
|
|
29
|
+
const key = blackboardKey(goal.args[0], next);
|
|
30
|
+
next.putBacktrackableBlackboard(key, deref(goal.args[1], next));
|
|
31
|
+
yield next;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export const scryerCompatibilityBuiltins = {
|
|
35
|
+
register(registry) {
|
|
36
|
+
registry.add('eyeprolog__bb_get', 2, bbGetBuiltin, { eyePrologLibrary: true });
|
|
37
|
+
registry.add('eyeprolog__bb_b_put', 2, bbPutBuiltin, { deterministic: true, eyePrologLibrary: true });
|
|
38
|
+
},
|
|
39
|
+
};
|
package/src/standard-library.js
CHANGED
|
@@ -6,23 +6,35 @@ import { PrologError, createDefaultRegistry, eyePrologLibraryBuiltins } from './
|
|
|
6
6
|
import { clpzBuiltins } from './clpz.js';
|
|
7
7
|
import { attsBuiltins } from './atts.js';
|
|
8
8
|
import { expansionBuiltins } from './expansion-builtins.js';
|
|
9
|
+
import { scryerCompatibilityBuiltins } from './scryer-compat.js';
|
|
9
10
|
import { registerCleanupBuiltins } from './cleanup.js';
|
|
10
11
|
import { fs, isNode, memoryStatistics } from './platform.js';
|
|
11
12
|
import { ATOM, VAR, atom, deref, numberTerm, unify } from './term.js';
|
|
12
13
|
|
|
13
14
|
const moduleFiles = Object.freeze({
|
|
14
15
|
aggregate: 'aggregate.pl',
|
|
16
|
+
arithmetic: 'arithmetic.pl',
|
|
17
|
+
assoc: 'assoc.pl',
|
|
15
18
|
atts: 'atts.pl',
|
|
19
|
+
between: 'between.pl',
|
|
16
20
|
clpz: 'clpz.pl',
|
|
17
21
|
comparison: 'comparison.pl',
|
|
18
22
|
dates: 'dates.pl',
|
|
23
|
+
dcgs: 'dcgs.pl',
|
|
24
|
+
debug: 'debug.pl',
|
|
25
|
+
error: 'error.pl',
|
|
26
|
+
format: 'format.pl',
|
|
27
|
+
freeze: 'freeze.pl',
|
|
19
28
|
iso_ext: 'iso_ext.pl',
|
|
20
29
|
lambda: 'lambda.pl',
|
|
21
30
|
lists: 'lists.pl',
|
|
31
|
+
pairs: 'pairs.pl',
|
|
22
32
|
primes: 'primes.pl',
|
|
23
33
|
prologue: 'prologue.pl',
|
|
24
34
|
random: 'random.pl',
|
|
35
|
+
si: 'si.pl',
|
|
25
36
|
strings: 'strings.pl',
|
|
37
|
+
terms: 'terms.pl',
|
|
26
38
|
uuid: 'uuid.pl',
|
|
27
39
|
});
|
|
28
40
|
|
|
@@ -190,6 +202,7 @@ export function createEyePrologRegistry() {
|
|
|
190
202
|
eyePrologLibraryBuiltins.register(registry);
|
|
191
203
|
attsBuiltins.register(registry);
|
|
192
204
|
expansionBuiltins.register(registry);
|
|
205
|
+
scryerCompatibilityBuiltins.register(registry);
|
|
193
206
|
clpzBuiltins.register(registry);
|
|
194
207
|
registry.eyePrologLibrary = true;
|
|
195
208
|
return registry;
|
package/src/term.js
CHANGED
|
@@ -109,6 +109,9 @@ export class Env {
|
|
|
109
109
|
this._prologAttributes = null;
|
|
110
110
|
this._attributeHookRunner = null;
|
|
111
111
|
this._pendingAttributeGoals = null;
|
|
112
|
+
// Backtrackable blackboard entries used by Scryer-compatible libraries.
|
|
113
|
+
// Values are logical terms and the map is copy-on-write across Env clones.
|
|
114
|
+
this._backtrackableBlackboard = null;
|
|
112
115
|
this._clpz = null;
|
|
113
116
|
this._occursCheckHandler = null;
|
|
114
117
|
this._localVariables = null;
|
|
@@ -127,6 +130,7 @@ export class Env {
|
|
|
127
130
|
clone._prologAttributes = this._prologAttributes;
|
|
128
131
|
clone._attributeHookRunner = this._attributeHookRunner;
|
|
129
132
|
clone._pendingAttributeGoals = this._pendingAttributeGoals;
|
|
133
|
+
clone._backtrackableBlackboard = this._backtrackableBlackboard;
|
|
130
134
|
clone._clpz = this._clpz;
|
|
131
135
|
clone._occursCheckHandler = this._occursCheckHandler;
|
|
132
136
|
clone._localVariables = this._localVariables;
|
|
@@ -148,12 +152,21 @@ export class Env {
|
|
|
148
152
|
this._variableAnnotations = other._variableAnnotations;
|
|
149
153
|
this._prologAttributes = other._prologAttributes;
|
|
150
154
|
this._pendingAttributeGoals = other._pendingAttributeGoals;
|
|
155
|
+
this._backtrackableBlackboard = other._backtrackableBlackboard;
|
|
151
156
|
this._clpz = other._clpz;
|
|
152
157
|
// Execution callbacks belong to the Solver driving this Env, not to the
|
|
153
158
|
// logical branch being adopted from an inner attribute-hook call.
|
|
154
159
|
this._localVariables = other._localVariables;
|
|
155
160
|
return this;
|
|
156
161
|
}
|
|
162
|
+
getBacktrackableBlackboard(key) {
|
|
163
|
+
return this._backtrackableBlackboard?.get(key);
|
|
164
|
+
}
|
|
165
|
+
putBacktrackableBlackboard(key, value) {
|
|
166
|
+
const next = new Map(this._backtrackableBlackboard ?? []);
|
|
167
|
+
next.set(key, value);
|
|
168
|
+
this._backtrackableBlackboard = next;
|
|
169
|
+
}
|
|
157
170
|
hasLocalVariables() {
|
|
158
171
|
return this._localVariables != null && this._localVariables.size !== 0;
|
|
159
172
|
}
|
package/test/run-regression.mjs
CHANGED
|
@@ -229,6 +229,77 @@ check :- old(X), X = ok.
|
|
|
229
229
|
'a user hook defined by a library module executes in its lexical module');
|
|
230
230
|
},
|
|
231
231
|
},
|
|
232
|
+
{
|
|
233
|
+
name: 'Scryer CLP(Z) support libraries provide the dependency surface',
|
|
234
|
+
run: () => {
|
|
235
|
+
const source = `:- module(scryer_support, [snapshot/6, blackboard_rollback/1, copy_drops_attrs/0]).
|
|
236
|
+
:- use_module(library(assoc)).
|
|
237
|
+
:- use_module(library(pairs)).
|
|
238
|
+
:- use_module(library(between)).
|
|
239
|
+
:- use_module(library(dcgs)).
|
|
240
|
+
:- use_module(library(terms)).
|
|
241
|
+
:- use_module(library(error)).
|
|
242
|
+
:- use_module(library(si)).
|
|
243
|
+
:- use_module(library(freeze)).
|
|
244
|
+
:- use_module(library(arithmetic)).
|
|
245
|
+
:- use_module(library(debug)).
|
|
246
|
+
:- use_module(library(format)).
|
|
247
|
+
:- use_module(library(atts)).
|
|
248
|
+
snapshot(Pairs, Keys, Values, Ns, Bits, Wake) :-
|
|
249
|
+
empty_assoc(A0),
|
|
250
|
+
put_assoc(2, A0, b, A1),
|
|
251
|
+
put_assoc(1, A1, a, A2),
|
|
252
|
+
assoc_to_list(A2, Pairs),
|
|
253
|
+
pairs_keys_values(Pairs, Keys, Values),
|
|
254
|
+
numlist(1, 3, Ns),
|
|
255
|
+
list_si(Ns),
|
|
256
|
+
arithmetic:popcount(13, Bits),
|
|
257
|
+
freeze(X, Wake = awake),
|
|
258
|
+
X = go.
|
|
259
|
+
blackboard_rollback(Value) :-
|
|
260
|
+
bb_b_put(k, base),
|
|
261
|
+
( bb_b_put(k, temporary), fail ; bb_get(k, Value) ).
|
|
262
|
+
copy_drops_attrs :-
|
|
263
|
+
put_attr(X, probe, value),
|
|
264
|
+
copy_term_nat(X, Copy),
|
|
265
|
+
term_attributed_variables(Copy, []).
|
|
266
|
+
`;
|
|
267
|
+
const snapshot = run(source, { goal: 'scryer_support:snapshot(Pairs,Keys,Values,Ns,Bits,Wake)' });
|
|
268
|
+
assertIncludes(snapshot.stdout,
|
|
269
|
+
'scryer_support:snapshot([1 - a, 2 - b], [1, 2], "ab", [1, 2, 3], 3, awake).',
|
|
270
|
+
'assoc, pairs, between, si, freeze, and arithmetic compatibility');
|
|
271
|
+
assertIncludes(run(source, { goal: 'scryer_support:blackboard_rollback(V)' }).stdout,
|
|
272
|
+
'scryer_support:blackboard_rollback(base).',
|
|
273
|
+
'backtrackable blackboard writes roll back with Env branches');
|
|
274
|
+
assertIncludes(run(source, { goal: 'scryer_support:copy_drops_attrs' }).stdout,
|
|
275
|
+
'scryer_support:copy_drops_attrs.',
|
|
276
|
+
'copy_term_nat/2 omits attributed-variable state');
|
|
277
|
+
assertEqual(run(source, { goal: 'debug:bb_get(missing,_V)' }).stats.completed_goal_lists, 0,
|
|
278
|
+
'bb_get/2 is semidet for an absent key');
|
|
279
|
+
const prelude = `:- module(scryer_clpz_prelude, [probe/0]).
|
|
280
|
+
:- use_module(library(assoc)).
|
|
281
|
+
:- use_module(library(pairs)).
|
|
282
|
+
:- use_module(library(between)).
|
|
283
|
+
:- use_module(library(lists)).
|
|
284
|
+
:- use_module(library(atts)).
|
|
285
|
+
:- use_module(library(iso_ext)).
|
|
286
|
+
:- use_module(library(dcgs)).
|
|
287
|
+
:- use_module(library(terms)).
|
|
288
|
+
:- use_module(library(error), [domain_error/3, type_error/3, can_be/2]).
|
|
289
|
+
:- use_module(library(si)).
|
|
290
|
+
:- use_module(library(freeze)).
|
|
291
|
+
:- use_module(library(arithmetic)).
|
|
292
|
+
:- use_module(library(debug)).
|
|
293
|
+
:- use_module(library(format)).
|
|
294
|
+
:- attribute clpz/1, clpz_aux/1, clpz_relation/1, edges/1, flow/1,
|
|
295
|
+
parent/1, free/1, queue/2, disabled/0.
|
|
296
|
+
probe :- empty_assoc(A), copy_term_nat(A, _), bb_b_put(current, ok), bb_get(current, ok).
|
|
297
|
+
`;
|
|
298
|
+
assertIncludes(run(prelude, { goal: 'scryer_clpz_prelude:probe' }).stdout,
|
|
299
|
+
'scryer_clpz_prelude:probe.',
|
|
300
|
+
'the dependency and attribute prelude used by upstream clpz.pl loads unchanged');
|
|
301
|
+
},
|
|
302
|
+
},
|
|
232
303
|
{
|
|
233
304
|
name: 'write_term variable_names/1 errors preserve the instantiated option culprit (issue #69)',
|
|
234
305
|
run: () => {
|
|
@@ -4829,7 +4900,7 @@ answer(ok) :-
|
|
|
4829
4900
|
assertEqual(Boolean(registry.get('is', 2)), true, 'ISO is/2 exists');
|
|
4830
4901
|
assertEqual(Boolean(registry.get('append', 3)), false, 'append/3 is not ISO core');
|
|
4831
4902
|
assertEqual(library.eyePrologLibrary, true, 'complete registry marker');
|
|
4832
|
-
assertEqual(library.defs.size,
|
|
4903
|
+
assertEqual(library.defs.size, 175, 'EyeProlog registry contains ISO definitions, cleanup controls, observability extensions, WFS tnot/1, and private library adapters');
|
|
4833
4904
|
assertEqual(Boolean(registry.get('phrase', 2)), true, 'Part 3 phrase/2 exists');
|
|
4834
4905
|
assertEqual(Boolean(registry.get('phrase', 3)), true, 'Part 3 phrase/3 exists');
|
|
4835
4906
|
assertEqual(registry.get('statistics', 0), null, 'statistics/0 is absent from the ISO registry');
|
|
@@ -4872,6 +4943,8 @@ answer(ok) :-
|
|
|
4872
4943
|
assertEqual(registry.get('put_atts', 2), null, 'put_atts/2 is absent from the ISO registry');
|
|
4873
4944
|
assertEqual(Boolean(library.get('put_atts', 2)), true, 'put_atts/2 is registered for attributed-variable libraries');
|
|
4874
4945
|
assertEqual(Boolean(library.get('$put_to_attr_list', 3)), true, 'private attribute-list adapter is registered');
|
|
4946
|
+
assertEqual(Boolean(library.get('eyeprolog__bb_get', 2)), true, 'private backtrackable blackboard reader is registered');
|
|
4947
|
+
assertEqual(Boolean(library.get('eyeprolog__bb_b_put', 2)), true, 'private backtrackable blackboard writer is registered');
|
|
4875
4948
|
assertEqual(library.get('between', 3), null, 'between/3 remains portable Prolog');
|
|
4876
4949
|
assertEqual(library.get('smallest_divisor_from', 3), null, 'smallest_divisor_from/3 remains portable Prolog');
|
|
4877
4950
|
assertEqual(library.get('random', 3), null, 'random/3 remains portable Prolog');
|
package/the-art-of-eyeprolog.md
CHANGED
|
@@ -6427,9 +6427,12 @@ is intended to support staged reuse of Markus Triska's MIT-licensed
|
|
|
6427
6427
|
The generic compile-time expansion blocker is now closed: normal-profile source
|
|
6428
6428
|
loading runs module-local and `user` `term_expansion/2` and `goal_expansion/2`
|
|
6429
6429
|
hooks, accepts clause-list expansions, preserves surrounding variable sharing,
|
|
6430
|
-
and provides `expand_term/2` for processor DCG lowering.
|
|
6431
|
-
Scryer
|
|
6432
|
-
|
|
6430
|
+
and provides `expand_term/2` for processor DCG lowering. EyeProlog now also
|
|
6431
|
+
registers the Scryer support modules needed by that source (`assoc`, `pairs`,
|
|
6432
|
+
`between`, `dcgs`, `terms`, `error`, `si`, `freeze`, `arithmetic`, `debug`, and
|
|
6433
|
+
`format`) and supplies a generic copy-on-write backtrackable blackboard. The
|
|
6434
|
+
remaining migration step is to vendor and load a pinned upstream `clpz.pl`, then
|
|
6435
|
+
establish behavioral and performance parity before removing the JS kernel. The
|
|
6433
6436
|
migration state is tracked in [`src/CLPZ-MIGRATION.md`](src/CLPZ-MIGRATION.md).
|
|
6434
6437
|
Until parity is reached, the JS kernel remains the active implementation so
|
|
6435
6438
|
existing CLP(Z) behavior does not regress.
|