eyeprolog 1.1.8 → 1.1.10
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 +6 -6
- package/package.json +1 -1
- package/src/lib/prologue.pl +87 -0
- package/src/solver.js +2 -0
- package/src/standard-library.js +3 -2
- package/test/conformance/expected/iso/exceptions_and_flags.pl +1 -1
- package/test/fixtures/README.md +23 -0
- package/test/fixtures/phrase_quad.pl +195 -0
- package/test/fixtures/prologue_quad.pl +134 -0
- package/test/fixtures/prologue_quad_runner.pl +2 -0
- package/test/run-regression.mjs +32 -3
- package/the-art-of-eyeprolog.md +14 -8
package/README.md
CHANGED
|
@@ -66,12 +66,12 @@ noun --> [world] | [prolog].
|
|
|
66
66
|
%% goal: phrase(sentence, Words)
|
|
67
67
|
```
|
|
68
68
|
|
|
69
|
-
EyeProlog also adds
|
|
70
|
-
**All
|
|
71
|
-
`src/lib/lists.pl`. They are ISO/IEC 13211-2 modules,
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
predicates use ISO atoms or character lists.
|
|
69
|
+
EyeProlog also adds 46 public library predicates to its 129-entry ISO registry.
|
|
70
|
+
**All 46 are ordinary Prolog clauses** in `src/lib/eyeprolog.pl`,
|
|
71
|
+
`src/lib/lists.pl`, and `src/lib/prologue.pl`. They are ISO/IEC 13211-2 modules,
|
|
72
|
+
loaded explicitly with `use_module(library(eyeprolog))`,
|
|
73
|
+
`use_module(library(lists))`, or `use_module(library(prologue))`. None requires
|
|
74
|
+
host support. Portable text predicates use ISO atoms or character lists.
|
|
75
75
|
|
|
76
76
|
## Development
|
|
77
77
|
|
package/package.json
CHANGED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/** Predicates proposed by the ISO Prolog Prologue working draft. */
|
|
2
|
+
|
|
3
|
+
:- module(prologue, [
|
|
4
|
+
member/2,
|
|
5
|
+
append/3,
|
|
6
|
+
length/2,
|
|
7
|
+
between/3,
|
|
8
|
+
select/3,
|
|
9
|
+
succ/2,
|
|
10
|
+
maplist/2
|
|
11
|
+
]).
|
|
12
|
+
|
|
13
|
+
:- meta_predicate(maplist(1, '?')).
|
|
14
|
+
|
|
15
|
+
member(X, [X|_]).
|
|
16
|
+
member(X, [_|Xs]) :- member(X, Xs).
|
|
17
|
+
|
|
18
|
+
append([], Ys, Ys).
|
|
19
|
+
append([X|Xs], Ys, [X|Zs]) :- append(Xs, Ys, Zs).
|
|
20
|
+
|
|
21
|
+
length(List, Length) :-
|
|
22
|
+
nonvar(Length), !,
|
|
23
|
+
prologue__integer(Length),
|
|
24
|
+
prologue__not_less_than_zero(Length),
|
|
25
|
+
prologue__length_fixed(Length, List).
|
|
26
|
+
length(List, Length) :-
|
|
27
|
+
prologue__length_generate(List, 0, Length).
|
|
28
|
+
|
|
29
|
+
prologue__length_fixed(0, []).
|
|
30
|
+
prologue__length_fixed(N, [_|Xs]) :-
|
|
31
|
+
N > 0,
|
|
32
|
+
Next is N - 1,
|
|
33
|
+
prologue__length_fixed(Next, Xs).
|
|
34
|
+
|
|
35
|
+
prologue__length_generate([], N, N).
|
|
36
|
+
prologue__length_generate([_|Xs], N0, N) :-
|
|
37
|
+
N1 is N0 + 1,
|
|
38
|
+
prologue__length_generate(Xs, N1, N).
|
|
39
|
+
|
|
40
|
+
between(Lower, Upper, X) :-
|
|
41
|
+
prologue__integer(Lower),
|
|
42
|
+
prologue__integer(Upper),
|
|
43
|
+
prologue__integer_or_variable(X),
|
|
44
|
+
prologue__between(Lower, Upper, X).
|
|
45
|
+
|
|
46
|
+
prologue__between(Lower, Upper, Lower) :- Lower =< Upper.
|
|
47
|
+
prologue__between(Lower, Upper, X) :-
|
|
48
|
+
Lower < Upper,
|
|
49
|
+
Next is Lower + 1,
|
|
50
|
+
prologue__between(Next, Upper, X).
|
|
51
|
+
|
|
52
|
+
select(X, [X|Xs], Xs).
|
|
53
|
+
select(X, [Y|Ys], [Y|Zs]) :- select(X, Ys, Zs).
|
|
54
|
+
|
|
55
|
+
succ(X, S) :-
|
|
56
|
+
var(X), !,
|
|
57
|
+
( var(S) -> 0 is S
|
|
58
|
+
; prologue__integer(S),
|
|
59
|
+
prologue__not_less_than_zero(S),
|
|
60
|
+
S > 0,
|
|
61
|
+
X is S - 1
|
|
62
|
+
).
|
|
63
|
+
succ(X, S) :-
|
|
64
|
+
prologue__integer(X),
|
|
65
|
+
prologue__not_less_than_zero(X),
|
|
66
|
+
( var(S) -> S is X + 1
|
|
67
|
+
; prologue__integer(S),
|
|
68
|
+
prologue__not_less_than_zero(S),
|
|
69
|
+
S =:= X + 1
|
|
70
|
+
).
|
|
71
|
+
|
|
72
|
+
maplist(_, []).
|
|
73
|
+
maplist(Closure, [X|Xs]) :-
|
|
74
|
+
call(Closure, X),
|
|
75
|
+
maplist(Closure, Xs).
|
|
76
|
+
|
|
77
|
+
prologue__integer_or_variable(X) :- var(X), !.
|
|
78
|
+
prologue__integer_or_variable(X) :- prologue__integer(X).
|
|
79
|
+
|
|
80
|
+
prologue__integer(X) :- integer(X), !.
|
|
81
|
+
prologue__integer(X) :- var(X), !, 0 is X.
|
|
82
|
+
% arg/3 performs the required integer type check before inspecting its term.
|
|
83
|
+
prologue__integer(X) :- arg(X, type_check, _).
|
|
84
|
+
|
|
85
|
+
prologue__not_less_than_zero(X) :- X >= 0, !.
|
|
86
|
+
% atom_length/2 reports domain_error(not_less_than_zero) for a negative value.
|
|
87
|
+
prologue__not_less_than_zero(X) :- atom_length('', X).
|
package/src/solver.js
CHANGED
|
@@ -431,6 +431,8 @@ function defaultPrologFlags(unknown = 'error') {
|
|
|
431
431
|
['integer_rounding_function', { value: compound('toward_zero', []), allowed: ['toward_zero'], changeable: false }],
|
|
432
432
|
['char_conversion', { value: compound('on', []), allowed: ['on', 'off'], changeable: true }],
|
|
433
433
|
['debug', { value: compound('off', []), allowed: ['on', 'off'], changeable: true }],
|
|
434
|
+
['max_integer', { value: compound('unbounded', []), allowed: ['unbounded'], changeable: false }],
|
|
435
|
+
['min_integer', { value: compound('unbounded', []), allowed: ['unbounded'], changeable: false }],
|
|
434
436
|
['max_arity', { value: compound('unbounded', []), allowed: ['unbounded'], changeable: false }],
|
|
435
437
|
['unknown', { value: compound(unknown, []), allowed: ['error', 'fail', 'warning'], changeable: true }],
|
|
436
438
|
['double_quotes', { value: compound('chars', []), allowed: ['chars', 'codes', 'atom'], changeable: true }],
|
package/src/standard-library.js
CHANGED
|
@@ -8,6 +8,7 @@ import { fs, isNode } from './platform.js';
|
|
|
8
8
|
const moduleFiles = Object.freeze({
|
|
9
9
|
eyeprolog: 'eyeprolog.pl',
|
|
10
10
|
lists: 'lists.pl',
|
|
11
|
+
prologue: 'prologue.pl',
|
|
11
12
|
});
|
|
12
13
|
|
|
13
14
|
const cacheKey = isNode
|
|
@@ -36,14 +37,14 @@ function libraryUrl(filename) {
|
|
|
36
37
|
|
|
37
38
|
export const eyePrologNativeLibraryIndicators = Object.freeze([]);
|
|
38
39
|
export const eyePrologPortableLibraryIndicators = Object.freeze([
|
|
39
|
-
'uuid/3', 'difference/3', 'maplist/3', 'lt/2', 'gt/2', 'le/2', 'ge/2',
|
|
40
|
+
'uuid/3', 'difference/3', 'maplist/2', 'maplist/3', 'lt/2', 'gt/2', 'le/2', 'ge/2',
|
|
40
41
|
'between/3', 'smallest_divisor_from/3', 'random/3', 'matches/3', 'split/3',
|
|
41
42
|
'replace/4', 'lowercase/2', 'uppercase/2', 'trim/2', 'number_string/2',
|
|
42
43
|
'atom_string/2', 'term_string/2', 'append/3', 'string_concat/3', 'contains/2',
|
|
43
44
|
'matches/2', 'join/3', 'substring/4', 'member/2', 'select/3', 'last/2',
|
|
44
45
|
'nth0/3', 'nth1/3', 'set_nth0/4', 'take/3', 'drop/3', 'slice/4', 'reverse/2',
|
|
45
46
|
'length/2', 'sum_list/2', 'min_list/2', 'max_list/2', 'list_to_set/2',
|
|
46
|
-
'countall/2', 'sumall/3', 'aggregate_min/5', 'aggregate_max/5',
|
|
47
|
+
'countall/2', 'succ/2', 'sumall/3', 'aggregate_min/5', 'aggregate_max/5',
|
|
47
48
|
]);
|
|
48
49
|
export const eyePrologLibraryIndicators = Object.freeze([...eyePrologPortableLibraryIndicators]);
|
|
49
50
|
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
answer(7, red, caught(eyeprolog), first, caught(eyeprolog)).
|
|
2
2
|
answer(7, red, caught(eyeprolog), second, caught(eyeprolog)).
|
|
3
|
-
flags(off, on, [pair(bounded, false), pair(integer_rounding_function, toward_zero), pair(char_conversion, on), pair(debug, off), pair(max_arity, unbounded), pair(unknown, fail), pair(double_quotes, chars)]).
|
|
3
|
+
flags(off, on, [pair(bounded, false), pair(integer_rounding_function, toward_zero), pair(char_conversion, on), pair(debug, off), pair(max_integer, unbounded), pair(min_integer, unbounded), pair(max_arity, unbounded), pair(unknown, fail), pair(double_quotes, chars)]).
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Regression fixtures
|
|
2
|
+
|
|
3
|
+
`phrase_quad.pl` is an unmodified snapshot of Ulrich Neumerkel's ISO Prolog
|
|
4
|
+
`phrase/2-3` quad corpus:
|
|
5
|
+
|
|
6
|
+
<https://www.complang.tuwien.ac.at/ulrich/iso-prolog/phrase_quad.pl>
|
|
7
|
+
|
|
8
|
+
Retrieved on 2026-08-11. It is vendored so the regression suite exercises all
|
|
9
|
+
58 quads without depending on network access or availability of the source
|
|
10
|
+
server.
|
|
11
|
+
|
|
12
|
+
`prologue_quad.pl` is an unmodified snapshot of the 33 machine-readable quads
|
|
13
|
+
for the predicates proposed by the Prolog Prologue working draft:
|
|
14
|
+
|
|
15
|
+
<https://www.complang.tuwien.ac.at/ulrich/iso-prolog/prologue_quad.pl>
|
|
16
|
+
|
|
17
|
+
The corresponding working draft is at
|
|
18
|
+
<https://www.complang.tuwien.ac.at/ulrich/iso-prolog/prologue>.
|
|
19
|
+
The corpus snapshot was retrieved on 2026-08-11.
|
|
20
|
+
|
|
21
|
+
`prologue_quad_runner.pl` loads EyeProlog's `library(prologue)` and includes
|
|
22
|
+
the unmodified corpus, mirroring the draft's requirement that a Prologue be
|
|
23
|
+
included before its examples are run.
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
c1 ?- call(1).
|
|
2
|
+
type_error(callable,1).
|
|
3
|
+
|
|
4
|
+
c2 ?- call((1,fail)).
|
|
5
|
+
type_error(callable,(1,fail)).
|
|
6
|
+
|
|
7
|
+
c3 ?- call((fail,1)).
|
|
8
|
+
type_error(callable,(fail,1)).
|
|
9
|
+
|
|
10
|
+
c4 ?- call((!;1)).
|
|
11
|
+
type_error(callable,(!;1)).
|
|
12
|
+
|
|
13
|
+
c5 ?- call((!;\+1)).
|
|
14
|
+
true.
|
|
15
|
+
|
|
16
|
+
c6 ?- call((!;call(1))).
|
|
17
|
+
true.
|
|
18
|
+
|
|
19
|
+
c7 ?- call((\+!;X=a)).
|
|
20
|
+
X=a.
|
|
21
|
+
|
|
22
|
+
f1 ?- functor(T,F,A).
|
|
23
|
+
instantiation_error.
|
|
24
|
+
|
|
25
|
+
f2 ?- functor(T,1,2).
|
|
26
|
+
type_error(atom,1).
|
|
27
|
+
|
|
28
|
+
f3 ?- functor([_],.,2).
|
|
29
|
+
true.
|
|
30
|
+
|
|
31
|
+
1 ?- phrase(=,L).
|
|
32
|
+
L = []
|
|
33
|
+
| existence_error(non_terminal,(=)//0).
|
|
34
|
+
|
|
35
|
+
2 ?- phrase(1,L).
|
|
36
|
+
type_error(callable,1).
|
|
37
|
+
|
|
38
|
+
39 ?- phrase(K,L).
|
|
39
|
+
instantiation_error.
|
|
40
|
+
|
|
41
|
+
40 ?- K = [], phrase(K,L).
|
|
42
|
+
K = [], L = [].
|
|
43
|
+
|
|
44
|
+
24 ?- asserta((a-->b)).
|
|
45
|
+
permission_error(modify,static_procedure,(-->)/2).
|
|
46
|
+
|
|
47
|
+
25 ?- clause((a-->b),B).
|
|
48
|
+
permission_error(access,private_procedure,(-->)/2).
|
|
49
|
+
|
|
50
|
+
26 ?- (X-->Y).
|
|
51
|
+
existence_error(procedure,(-->)/2).
|
|
52
|
+
|
|
53
|
+
3 ?- phrase(!,L).
|
|
54
|
+
L = [].
|
|
55
|
+
|
|
56
|
+
4 ?- phrase([a],L).
|
|
57
|
+
L = [a].
|
|
58
|
+
|
|
59
|
+
5 ?- phrase([a|b],L).
|
|
60
|
+
type_error(list,[a|b]).
|
|
61
|
+
|
|
62
|
+
6 ?- phrase([a|L],K).
|
|
63
|
+
instantiation_error.
|
|
64
|
+
|
|
65
|
+
38 ?- phrase([a|L],L).
|
|
66
|
+
instantiation_error.
|
|
67
|
+
|
|
68
|
+
7 ?- phrase([a|L],[a,b]).
|
|
69
|
+
instantiation_error.
|
|
70
|
+
|
|
71
|
+
8 ?- phrase([a|L],[]).
|
|
72
|
+
instantiation_error.
|
|
73
|
+
|
|
74
|
+
9 ?- phrase(([a],[]),[a]).
|
|
75
|
+
true.
|
|
76
|
+
|
|
77
|
+
10 ?- phrase(([a],{1}),[]).
|
|
78
|
+
type_error(callable,(...,...)).
|
|
79
|
+
|
|
80
|
+
37 ?- phrase((!,[a],{1}),[]).
|
|
81
|
+
type_error(callable,(...,...)).
|
|
82
|
+
|
|
83
|
+
11 ?- phrase(({!,fail};[]),L).
|
|
84
|
+
false.
|
|
85
|
+
|
|
86
|
+
12 ?- phrase('|'([],[a]),[a]).
|
|
87
|
+
true.
|
|
88
|
+
|
|
89
|
+
13 ?- phrase(({fail},1),L).
|
|
90
|
+
type_error(callable,1).
|
|
91
|
+
|
|
92
|
+
14 ?- phrase(([a];[]),L).
|
|
93
|
+
L = [a] ; L = [].
|
|
94
|
+
|
|
95
|
+
15 ?- phrase({fail,1},L).
|
|
96
|
+
type_error(callable,((fail,1),[]=_A))
|
|
97
|
+
| type_error(callable,((fail,1),...)).
|
|
98
|
+
|
|
99
|
+
16 ?- phrase({throw(h)},[a]).
|
|
100
|
+
throw(h).
|
|
101
|
+
|
|
102
|
+
17 ?- phrase(({L=[]},[a|L]),[a]).
|
|
103
|
+
instantiation_error.
|
|
104
|
+
|
|
105
|
+
18 ?- phrase([a|L],K), L=[b].
|
|
106
|
+
instantiation_error.
|
|
107
|
+
|
|
108
|
+
19 ?- phrase(([a|L],1),[]).
|
|
109
|
+
type_error(callable,1)
|
|
110
|
+
| instantiation_error.
|
|
111
|
+
|
|
112
|
+
20 ?- phrase((1,[a|L]),[]).
|
|
113
|
+
type_error(callable,1)
|
|
114
|
+
| instantiation_error.
|
|
115
|
+
|
|
116
|
+
21 ?- phrase((1,[a|b]),[]).
|
|
117
|
+
type_error(callable,1)
|
|
118
|
+
| type_error(list,[a|b]).
|
|
119
|
+
|
|
120
|
+
46 ?- phrase((1,{2}),[]).
|
|
121
|
+
type_error(callable,1).
|
|
122
|
+
|
|
123
|
+
47 ?- phrase(({2},1),[]).
|
|
124
|
+
type_error(callable,1).
|
|
125
|
+
|
|
126
|
+
48 ?- phrase((1,(2,[_|_],3),4),[]).
|
|
127
|
+
type_error(callable,1)
|
|
128
|
+
| type_error(callable,2)
|
|
129
|
+
| instantiation_error
|
|
130
|
+
| type_error(callable,3)
|
|
131
|
+
| type_error(callable,4).
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
22 ?- phrase('|'(([x]->[y]),[z]),L).
|
|
135
|
+
representation_error(dcg_body)
|
|
136
|
+
| L=[x,y].
|
|
137
|
+
|
|
138
|
+
23 ?- phrase(;(([x]->[y]),[z]),L).
|
|
139
|
+
L=[x,y].
|
|
140
|
+
|
|
141
|
+
45 ?- phrase(([a],phrase(2)),[]).
|
|
142
|
+
false.
|
|
143
|
+
|
|
144
|
+
27 ?- phrase(\+[a],[]).
|
|
145
|
+
representation_error(dcg_body)
|
|
146
|
+
| true.
|
|
147
|
+
|
|
148
|
+
28 ?- phrase(\+1,L).
|
|
149
|
+
representation_error(dcg_body)
|
|
150
|
+
| type_error(callable,1).
|
|
151
|
+
|
|
152
|
+
29 ?- phrase(([a],\+1),[]).
|
|
153
|
+
representation_error(dcg_body)
|
|
154
|
+
| false.
|
|
155
|
+
|
|
156
|
+
30 ?- phrase(([a],\+1;[]),[]).
|
|
157
|
+
representation_error(dcg_body)
|
|
158
|
+
| true.
|
|
159
|
+
|
|
160
|
+
31 ?- phrase(phrase(phrase,[]),L).
|
|
161
|
+
existence_error(procedure,phrase/4)
|
|
162
|
+
| existence_error(non_terminal,phrase//2)
|
|
163
|
+
| L = [].
|
|
164
|
+
|
|
165
|
+
32 ?- phrase(call([]),[]).
|
|
166
|
+
existence_error(procedure,[]/2)
|
|
167
|
+
| true.
|
|
168
|
+
|
|
169
|
+
33 ?- L=[],phrase([a|L],[b]).
|
|
170
|
+
false.
|
|
171
|
+
|
|
172
|
+
36 ?- L=[],phrase([a|L],[a]).
|
|
173
|
+
L=[].
|
|
174
|
+
|
|
175
|
+
34 ?- phrase([a],[b]).
|
|
176
|
+
false.
|
|
177
|
+
|
|
178
|
+
35 ?- phrase(!,[_]) ; L=1.
|
|
179
|
+
L=1.
|
|
180
|
+
|
|
181
|
+
41 ?- phrase([], non_list).
|
|
182
|
+
false
|
|
183
|
+
| type_error(list,non_list).
|
|
184
|
+
|
|
185
|
+
42 ?- phrase([], [a|non_list]).
|
|
186
|
+
false
|
|
187
|
+
| type_error(list,[a|non_list]).
|
|
188
|
+
|
|
189
|
+
43 ?- phrase([], L,non_list).
|
|
190
|
+
L = non_list
|
|
191
|
+
| type_error(list,non_list).
|
|
192
|
+
|
|
193
|
+
44 ?- phrase([], L,[a|non_list]).
|
|
194
|
+
L = [a|non_list]
|
|
195
|
+
| type_error(list,[a|non_list]).
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
% p.p.1 member/2
|
|
2
|
+
|
|
3
|
+
?- member(X, [1,2]).
|
|
4
|
+
X = 1
|
|
5
|
+
; X = 2.
|
|
6
|
+
|
|
7
|
+
?- member(1, L).
|
|
8
|
+
L = [1|_]
|
|
9
|
+
; L = [_,1|_]
|
|
10
|
+
; L = [_,_,1|_]
|
|
11
|
+
; ... . % Ad infinitum.
|
|
12
|
+
|
|
13
|
+
?- member(X, [Y,Z|nonlist]).
|
|
14
|
+
X = Y
|
|
15
|
+
; X = Z.
|
|
16
|
+
|
|
17
|
+
?- member(X, nonlist).
|
|
18
|
+
false.
|
|
19
|
+
|
|
20
|
+
?- member(X, X).
|
|
21
|
+
sto, % undefined, STO 7.3.3
|
|
22
|
+
true
|
|
23
|
+
| sto,
|
|
24
|
+
loops.
|
|
25
|
+
|
|
26
|
+
% p.p.2 append/3
|
|
27
|
+
|
|
28
|
+
?- append([a,b],[c,d], Xs).
|
|
29
|
+
Xs = [a,b,c,d].
|
|
30
|
+
|
|
31
|
+
?- append([a], nonlist, Xs).
|
|
32
|
+
Xs = [a|nonlist].
|
|
33
|
+
|
|
34
|
+
?- append([a], Ys, Zs).
|
|
35
|
+
Zs = [a|Ys].
|
|
36
|
+
|
|
37
|
+
?- append(Xs, Ys, [a,b,c]).
|
|
38
|
+
Xs = [], Ys = [a,b,c]
|
|
39
|
+
; Xs = [a], Ys = [b,c]
|
|
40
|
+
; Xs = [a,b], Ys = [c]
|
|
41
|
+
; Xs = [a,b,c], Ys = [].
|
|
42
|
+
|
|
43
|
+
% p.p.3 length/2
|
|
44
|
+
|
|
45
|
+
?- length([a,b,c], Length).
|
|
46
|
+
Length = 3.
|
|
47
|
+
|
|
48
|
+
?- length(List, 5).
|
|
49
|
+
List = [_,_,_,_,_].
|
|
50
|
+
|
|
51
|
+
?- length(List, Length).
|
|
52
|
+
List = [], Length = 0
|
|
53
|
+
; List = [_], Length = 1
|
|
54
|
+
; List = [_,_], Length = 2
|
|
55
|
+
; ... . % Ad infinitum.
|
|
56
|
+
|
|
57
|
+
% p.p.4 between/3
|
|
58
|
+
|
|
59
|
+
?- between(1, 2, 0).
|
|
60
|
+
false.
|
|
61
|
+
|
|
62
|
+
?- between(1, 2, I).
|
|
63
|
+
I = 1
|
|
64
|
+
; I = 2.
|
|
65
|
+
|
|
66
|
+
?- between(2, 1, I).
|
|
67
|
+
false.
|
|
68
|
+
|
|
69
|
+
?- between(I, I, 0).
|
|
70
|
+
instantiation_error.
|
|
71
|
+
|
|
72
|
+
?- between(1, I, 0).
|
|
73
|
+
instantiation_error.
|
|
74
|
+
|
|
75
|
+
?- between(I, -1, 0).
|
|
76
|
+
instantiation_error.
|
|
77
|
+
|
|
78
|
+
?- between(1, c, 0).
|
|
79
|
+
type_error(integer,c).
|
|
80
|
+
|
|
81
|
+
?- between(1+1,2,I).
|
|
82
|
+
type_error(integer,1+1).
|
|
83
|
+
|
|
84
|
+
% p.p.5 select/3
|
|
85
|
+
|
|
86
|
+
?- select(X, [1,2], Xs).
|
|
87
|
+
X = 1, Xs = [2]
|
|
88
|
+
; X = 2, Xs = [1].
|
|
89
|
+
|
|
90
|
+
?- select(X, [Y|nonlist], Xs).
|
|
91
|
+
X = Y, Xs = nonlist.
|
|
92
|
+
|
|
93
|
+
?- select(E, Xs, Xs).
|
|
94
|
+
sto.
|
|
95
|
+
|
|
96
|
+
% p.p.6 succ/2
|
|
97
|
+
|
|
98
|
+
?- succ(X, S).
|
|
99
|
+
instantiation_error.
|
|
100
|
+
|
|
101
|
+
?- succ(X, X).
|
|
102
|
+
instantiation_error.
|
|
103
|
+
|
|
104
|
+
?- succ(0, S).
|
|
105
|
+
S = 1.
|
|
106
|
+
|
|
107
|
+
?- succ(1, 1+1).
|
|
108
|
+
type_error(integer, 1+1).
|
|
109
|
+
|
|
110
|
+
?- succ(X, 0).
|
|
111
|
+
false.
|
|
112
|
+
|
|
113
|
+
?- succ(-1, S).
|
|
114
|
+
domain_error(not_less_than_zero, -1).
|
|
115
|
+
|
|
116
|
+
?- current_prolog_flag(max_integer, Max),
|
|
117
|
+
( integer(Max) -> succ(Max, S) ; true ).
|
|
118
|
+
evaluation_error(int_overflow)
|
|
119
|
+
| Max = unbounded.
|
|
120
|
+
|
|
121
|
+
% p.p.7
|
|
122
|
+
|
|
123
|
+
?- maplist(>(3), [1, 2]).
|
|
124
|
+
true.
|
|
125
|
+
|
|
126
|
+
?- maplist(>(3), [1, 2, 3]).
|
|
127
|
+
false.
|
|
128
|
+
|
|
129
|
+
?- maplist(=(X), Xs).
|
|
130
|
+
Xs = []
|
|
131
|
+
; Xs = [X]
|
|
132
|
+
; Xs = [X, X]
|
|
133
|
+
; Xs = [X, X, X]
|
|
134
|
+
; ... . % Ad infinitum.
|
package/test/run-regression.mjs
CHANGED
|
@@ -309,6 +309,34 @@ c4 ?- call((!;1)).
|
|
|
309
309
|
assertEqual(result.stdout, 'quads: 22 run, 22 passed, 0 failed.\n', 'quad report');
|
|
310
310
|
},
|
|
311
311
|
},
|
|
312
|
+
{
|
|
313
|
+
name: 'runQuads passes the complete vendored ISO phrase quad corpus',
|
|
314
|
+
run: () => {
|
|
315
|
+
const source = fs.readFileSync(path.join(testRoot, 'fixtures', 'phrase_quad.pl'), 'utf8');
|
|
316
|
+
const result = publicApi.runQuads(Program.parseSources([{
|
|
317
|
+
text: source,
|
|
318
|
+
filename: 'test/fixtures/phrase_quad.pl',
|
|
319
|
+
}]));
|
|
320
|
+
assertEqual(result.total, 58, 'quad total');
|
|
321
|
+
assertEqual(result.passed, 58, 'quad passed');
|
|
322
|
+
assertEqual(result.stdout, 'quads: 58 run, 58 passed, 0 failed.\n', 'quad report');
|
|
323
|
+
},
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
name: 'runQuads passes the complete vendored Prolog Prologue quad corpus',
|
|
327
|
+
run: () => {
|
|
328
|
+
const filename = path.join(testRoot, 'fixtures', 'prologue_quad_runner.pl');
|
|
329
|
+
const source = fs.readFileSync(filename, 'utf8');
|
|
330
|
+
const result = publicApi.runQuads(Program.parseSources([{
|
|
331
|
+
text: source,
|
|
332
|
+
filename,
|
|
333
|
+
baseDir: path.dirname(filename),
|
|
334
|
+
}]));
|
|
335
|
+
assertEqual(result.total, 33, 'quad total');
|
|
336
|
+
assertEqual(result.passed, 33, 'quad passed');
|
|
337
|
+
assertEqual(result.stdout, 'quads: 33 run, 33 passed, 0 failed.\n', 'quad report');
|
|
338
|
+
},
|
|
339
|
+
},
|
|
312
340
|
{
|
|
313
341
|
name: 'runQuads rejects malformed answer substitutions',
|
|
314
342
|
run: () => {
|
|
@@ -848,7 +876,7 @@ function documentationSyncCases() {
|
|
|
848
876
|
'<a href="https://eyereasoner.github.io/eyeprolog/the-art-of-eyeprolog">\n <img src="book-assets/title-page.svg" alt="Read The Art of EyeProlog"',
|
|
849
877
|
'README cover links to the book',
|
|
850
878
|
);
|
|
851
|
-
for (const filename of ['src/iso.js', 'src/dcg.js', 'src/standard-library.js', 'src/lib/eyeprolog.pl', 'src/lib/lists.pl', 'src/playground-worker.js']) {
|
|
879
|
+
for (const filename of ['src/iso.js', 'src/dcg.js', 'src/standard-library.js', 'src/lib/eyeprolog.pl', 'src/lib/lists.pl', 'src/lib/prologue.pl', 'src/playground-worker.js']) {
|
|
852
880
|
assertEqual(fs.existsSync(path.join(packageRoot, filename)), true, `${filename} exists`);
|
|
853
881
|
assertIncludes(book, filename, `book documents ${filename}`);
|
|
854
882
|
}
|
|
@@ -1287,10 +1315,10 @@ open(X) :- candidate(X), \\+ closed(X).
|
|
|
1287
1315
|
assertEqual(Boolean(registry.get('phrase', 2)), true, 'Part 3 phrase/2 exists');
|
|
1288
1316
|
assertEqual(Boolean(registry.get('phrase', 3)), true, 'Part 3 phrase/3 exists');
|
|
1289
1317
|
assertEqual(registeredNativeEyePrologLibraryNames().length, 0, 'public native EyeProlog builtin count');
|
|
1290
|
-
assertEqual(eyePrologPortableLibraryIndicators.length,
|
|
1318
|
+
assertEqual(eyePrologPortableLibraryIndicators.length, 46, 'portable Prolog library count');
|
|
1291
1319
|
assertEqual(eyePrologNativeLibraryIndicators.length, 0, 'native host library count');
|
|
1292
1320
|
assertEqual(eyePrologNativeLibraryIndicators.join(','), '', 'no EyeProlog library predicate requires host support');
|
|
1293
|
-
assertEqual(eyePrologLibraryIndicators.length,
|
|
1321
|
+
assertEqual(eyePrologLibraryIndicators.length, 46, 'complete EyeProlog library surface');
|
|
1294
1322
|
assertEqual(library.get('between', 3), null, 'between/3 remains portable Prolog');
|
|
1295
1323
|
assertEqual(library.get('smallest_divisor_from', 3), null, 'smallest_divisor_from/3 remains portable Prolog');
|
|
1296
1324
|
assertEqual(library.get('random', 3), null, 'random/3 remains portable Prolog');
|
|
@@ -1318,6 +1346,7 @@ open(X) :- candidate(X), \\+ closed(X).
|
|
|
1318
1346
|
assertEqual(fs.existsSync(path.join(packageRoot, 'src', 'lib', 'eyeprolog.pl')), true, 'portable module exists');
|
|
1319
1347
|
assertEqual(fs.existsSync(path.join(packageRoot, 'src', 'standard-library.js')), true, 'standard module registry exists');
|
|
1320
1348
|
assertEqual(fs.existsSync(path.join(packageRoot, 'src', 'lib', 'lists.pl')), true, 'lists module exists');
|
|
1349
|
+
assertEqual(fs.existsSync(path.join(packageRoot, 'src', 'lib', 'prologue.pl')), true, 'Prologue module exists');
|
|
1321
1350
|
assertEqual(fs.existsSync(path.join(packageRoot, 'src', 'eyeprolog-autoload.js')), false, 'obsolete autoloader is absent');
|
|
1322
1351
|
assertEqual(fs.existsSync(path.join(packageRoot, 'src', 'library-source.js')), false, 'duplicate source loader is absent');
|
|
1323
1352
|
assertEqual(fs.existsSync(path.join(packageRoot, 'src', 'portable-library.js')), false, 'obsolete duplicate module remains absent');
|
package/the-art-of-eyeprolog.md
CHANGED
|
@@ -5580,6 +5580,8 @@ silently changing a static program.
|
|
|
5580
5580
|
| `integer_rounding_function` | `toward_zero` | `toward_zero` | no |
|
|
5581
5581
|
| `char_conversion` | `on` | `on`, `off` | yes |
|
|
5582
5582
|
| `debug` | `off` | `on`, `off` | yes |
|
|
5583
|
+
| `max_integer` | `unbounded` | `unbounded` | no |
|
|
5584
|
+
| `min_integer` | `unbounded` | `unbounded` | no |
|
|
5583
5585
|
| `max_arity` | `unbounded` | `unbounded` | no |
|
|
5584
5586
|
| `unknown` | `fail` | `error`, `fail`, `warning` | yes |
|
|
5585
5587
|
| `double_quotes` | `chars` | `chars`, `codes`, `atom` | yes |
|
|
@@ -5735,17 +5737,20 @@ so side effects occur in Prolog execution order.
|
|
|
5735
5737
|
|
|
5736
5738
|
### The EyeProlog library
|
|
5737
5739
|
|
|
5738
|
-
EyeProlog exposes **
|
|
5739
|
-
indicators in its isolated ISO profile. **All
|
|
5740
|
-
across `src/lib/eyeprolog.pl` and `src/lib/
|
|
5740
|
+
EyeProlog exposes **46 library predicate indicators** in addition to the 129
|
|
5741
|
+
indicators in its isolated ISO profile. **All 46 are ordinary Prolog clauses**
|
|
5742
|
+
across `src/lib/eyeprolog.pl`, `src/lib/lists.pl`, and `src/lib/prologue.pl`; none
|
|
5741
5743
|
is a native host predicate. The resulting
|
|
5742
|
-
normal EyeProlog language surface is therefore **
|
|
5744
|
+
normal EyeProlog language surface is therefore **175 public predicate
|
|
5743
5745
|
indicators**. Internally, the runtime registry contains only the 129 ISO
|
|
5744
5746
|
definitions; the EyeProlog relations are module source clauses.
|
|
5745
5747
|
|
|
5746
|
-
The
|
|
5747
|
-
loads them explicitly with
|
|
5748
|
-
`use_module(library(
|
|
5748
|
+
The three Prolog files declare `eyeprolog`, `lists`, and `prologue` with
|
|
5749
|
+
`module/2`. A program loads them explicitly with
|
|
5750
|
+
`use_module(library(eyeprolog))`, `use_module(library(lists))`, or
|
|
5751
|
+
`use_module(library(prologue))`; `use_module/2` can select a smaller import
|
|
5752
|
+
list. The last module implements the predicates exercised by the working-draft
|
|
5753
|
+
Prologue quad corpus.
|
|
5749
5754
|
`src/standard-library.js` only registers the module sources for Node and browser
|
|
5750
5755
|
resolution and never adds clauses implicitly.
|
|
5751
5756
|
The isolated ISO-only registry remains
|
|
@@ -5759,6 +5764,7 @@ private helpers and same-named predicates in different modules separate.
|
|
|
5759
5764
|
| --- | --- |
|
|
5760
5765
|
| `library(lists)` | `maplist/3`, `append/3`, `member/2`, `select/3`, `last/2`, `nth0/3`, `nth1/3`, `reverse/2`, `length/2`, `sum_list/2`, `min_list/2`, `max_list/2`, `list_to_set/2`, `countall/2` |
|
|
5761
5766
|
| `library(eyeprolog)` | `uuid/3`, `difference/3`, `lt/2`, `le/2`, `gt/2`, `ge/2`, `between/3`, `smallest_divisor_from/3`, `random/3`, `matches/3`, `split/3`, `replace/4`, `lowercase/2`, `uppercase/2`, `trim/2`, `number_string/2`, `atom_string/2`, `term_string/2`, `string_concat/3`, `contains/2`, `matches/2`, `join/3`, `substring/4`, `set_nth0/4`, `take/3`, `drop/3`, `slice/4`, `sumall/3`, `aggregate_min/5`, `aggregate_max/5` |
|
|
5767
|
+
| `library(prologue)` | `member/2`, `append/3`, `length/2`, `between/3`, `select/3`, `succ/2`, `maplist/2` |
|
|
5762
5768
|
|
|
5763
5769
|
<!-- eyeprolog-library-catalog:end -->
|
|
5764
5770
|
|
|
@@ -5885,7 +5891,7 @@ eyeprolog --goal 'answer(Kind, Value)' program.pl
|
|
|
5885
5891
|
The portable text API uses **ISO atoms or proper lists of one-character atoms**.
|
|
5886
5892
|
A generated text result defaults to an atom. Double-quoted source text uses the
|
|
5887
5893
|
ISO representation selected by `double_quotes`; with the default `chars`, it is
|
|
5888
|
-
already a proper character list accepted by this API. The
|
|
5894
|
+
already a proper character list accepted by this API. The 46-predicate portable
|
|
5889
5895
|
library itself has no STRING or JavaScript dependency.
|
|
5890
5896
|
|
|
5891
5897
|
| Predicate and principal mode | Behavior |
|