eyeprolog 1.5.55 → 1.5.56
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/examples/combinatorics-findall-sort.pl +4 -4
- package/examples/d3-group.pl +37 -37
- package/examples/eulerian-path.pl +4 -4
- package/examples/graph-reachability.pl +4 -4
- package/examples/monkey-bananas.pl +4 -4
- package/examples/proof/graph-reachability.pl +8 -8
- package/package.json +1 -1
- package/src/cli.js +12 -0
- package/src/program.js +45 -0
- package/test/conformance/ISO-PROLOG-TEXT-EXECUTION-MATRIX.md +1 -1
- package/test/regression/cases-api.mjs +1677 -0
- package/test/regression/cases-documentation-sync.mjs +717 -0
- package/test/regression/cases-regression.mjs +5250 -0
- package/test/regression/cases-white-box.mjs +938 -0
- package/test/regression/support.mjs +770 -0
- package/test/run-all.mjs +0 -0
- package/test/run-architecture.mjs +0 -0
- package/test/run-book-examples.mjs +0 -0
- package/test/run-cleanup.mjs +0 -0
- package/test/run-conformance-all.mjs +0 -0
- package/test/run-conformance-report.mjs +0 -0
- package/test/run-conformance.mjs +0 -0
- package/test/run-examples.mjs +0 -0
- package/test/run-http-json.mjs +0 -0
- package/test/run-interop.mjs +0 -0
- package/test/run-iso-part2-amendment.mjs +0 -0
- package/test/run-iso-strict.mjs +0 -0
- package/test/run-neumerkel-tests.mjs +0 -0
- package/test/run-neumerkel.mjs +0 -0
- package/test/run-openrulebench.mjs +0 -0
- package/test/run-playground.mjs +0 -0
- package/test/run-regression.mjs +28 -9240
- package/test/run-wg17.mjs +0 -0
- package/tools/extract-book-examples.mjs +0 -0
- package/tools/report-wg17-syntax-coverage.mjs +0 -0
|
@@ -14,16 +14,16 @@
|
|
|
14
14
|
|
|
15
15
|
% select/3 nondeterministically removes one item from a list; because it is an
|
|
16
16
|
% ordinary rule, the example also demonstrates user-level list recursion.
|
|
17
|
-
|
|
17
|
+
select_item(Item, [Item | Rest], Rest).
|
|
18
18
|
% The recursive clause keeps the non-selected head and searches the tail.
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
select_item(Item, [Head | Tail], [Head | Rest]) :-
|
|
20
|
+
select_item(Item, Tail, Rest).
|
|
21
21
|
|
|
22
22
|
% combination/3 builds an unordered K-combination by repeated selection.
|
|
23
23
|
combination(0, _items, []).
|
|
24
24
|
combination(I, Items, Combination) :-
|
|
25
25
|
(I > 0),
|
|
26
|
-
|
|
26
|
+
select_item(Item, Items, Remaining),
|
|
27
27
|
(J is I - 1),
|
|
28
28
|
combination(J, Remaining, Partial),
|
|
29
29
|
sort([Item | Partial], Combination).
|
package/examples/d3-group.pl
CHANGED
|
@@ -21,42 +21,42 @@ symmetry(reflection_b).
|
|
|
21
21
|
symmetry(reflection_c).
|
|
22
22
|
|
|
23
23
|
% Cayley table for D3 composition.
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
24
|
+
compose_op(identity, identity, identity).
|
|
25
|
+
compose_op(identity, rotation_120, rotation_120).
|
|
26
|
+
compose_op(identity, rotation_240, rotation_240).
|
|
27
|
+
compose_op(identity, reflection_a, reflection_a).
|
|
28
|
+
compose_op(identity, reflection_b, reflection_b).
|
|
29
|
+
compose_op(identity, reflection_c, reflection_c).
|
|
30
|
+
compose_op(rotation_120, identity, rotation_120).
|
|
31
|
+
compose_op(rotation_120, rotation_120, rotation_240).
|
|
32
|
+
compose_op(rotation_120, rotation_240, identity).
|
|
33
|
+
compose_op(rotation_120, reflection_a, reflection_b).
|
|
34
|
+
compose_op(rotation_120, reflection_b, reflection_c).
|
|
35
|
+
compose_op(rotation_120, reflection_c, reflection_a).
|
|
36
|
+
compose_op(rotation_240, identity, rotation_240).
|
|
37
|
+
compose_op(rotation_240, rotation_120, identity).
|
|
38
|
+
compose_op(rotation_240, rotation_240, rotation_120).
|
|
39
|
+
compose_op(rotation_240, reflection_a, reflection_c).
|
|
40
|
+
compose_op(rotation_240, reflection_b, reflection_a).
|
|
41
|
+
compose_op(rotation_240, reflection_c, reflection_b).
|
|
42
|
+
compose_op(reflection_a, identity, reflection_a).
|
|
43
|
+
compose_op(reflection_a, rotation_120, reflection_c).
|
|
44
|
+
compose_op(reflection_a, rotation_240, reflection_b).
|
|
45
|
+
compose_op(reflection_a, reflection_a, identity).
|
|
46
|
+
compose_op(reflection_a, reflection_b, rotation_240).
|
|
47
|
+
compose_op(reflection_a, reflection_c, rotation_120).
|
|
48
|
+
compose_op(reflection_b, identity, reflection_b).
|
|
49
|
+
compose_op(reflection_b, rotation_120, reflection_a).
|
|
50
|
+
compose_op(reflection_b, rotation_240, reflection_c).
|
|
51
|
+
compose_op(reflection_b, reflection_a, rotation_120).
|
|
52
|
+
compose_op(reflection_b, reflection_b, identity).
|
|
53
|
+
compose_op(reflection_b, reflection_c, rotation_240).
|
|
54
|
+
compose_op(reflection_c, identity, reflection_c).
|
|
55
|
+
compose_op(reflection_c, rotation_120, reflection_b).
|
|
56
|
+
compose_op(reflection_c, rotation_240, reflection_a).
|
|
57
|
+
compose_op(reflection_c, reflection_a, rotation_240).
|
|
58
|
+
compose_op(reflection_c, reflection_b, rotation_120).
|
|
59
|
+
compose_op(reflection_c, reflection_c, identity).
|
|
60
60
|
% Each candidate subgroup must also contain inverses.
|
|
61
61
|
inverse(identity, identity).
|
|
62
62
|
inverse(rotation_120, rotation_240).
|
|
@@ -78,7 +78,7 @@ all_symmetries(Symmetries) :-
|
|
|
78
78
|
|
|
79
79
|
% A valid subgroup is closed under both composition and inverse.
|
|
80
80
|
closed_under_composition(Group) :-
|
|
81
|
-
\+ (member(X, Group), member(Y, Group),
|
|
81
|
+
\+ (member(X, Group), member(Y, Group), compose_op(X, Y, Z), \+ member(Z, Group)).
|
|
82
82
|
|
|
83
83
|
closed_under_inverse(Group) :-
|
|
84
84
|
\+ (member(X, Group), inverse(X, Y), \+ member(Y, Group)).
|
|
@@ -39,9 +39,9 @@ incident(V, E) :- edge(E, _u, V).
|
|
|
39
39
|
adjacent_by_edge(V, U, E) :- edge(E, V, U).
|
|
40
40
|
adjacent_by_edge(V, U, E) :- edge(E, U, V).
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
select_item(Item, [Item | Rest], Rest).
|
|
43
|
+
select_item(Item, [Head | Tail], [Head | Rest]) :-
|
|
44
|
+
select_item(Item, Tail, Rest).
|
|
45
45
|
|
|
46
46
|
% Eulerian paths start at an odd-degree vertex when exactly two exist.
|
|
47
47
|
odd_degree(V) :-
|
|
@@ -77,7 +77,7 @@ eulerian_path(Path) :-
|
|
|
77
77
|
dfs_euler(_current, Path, [], Path).
|
|
78
78
|
dfs_euler(Current, Visited, Remaining, Path) :-
|
|
79
79
|
adjacent_by_edge(Current, Next, Edge),
|
|
80
|
-
|
|
80
|
+
select_item(Edge, Remaining, Newremaining),
|
|
81
81
|
dfs_euler(Next, [Next | Visited], Newremaining, Path).
|
|
82
82
|
|
|
83
83
|
oddVertices(eulerian_path_case, Odds) :-
|
|
@@ -18,14 +18,14 @@ edge(d, f).
|
|
|
18
18
|
edge(e, f).
|
|
19
19
|
edge(f, g).
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
reachable_via(Node, Node, _visited).
|
|
22
|
+
reachable_via(Start, Goal, Visited) :-
|
|
23
23
|
edge(Start, Next),
|
|
24
24
|
\+ member(Next, Visited),
|
|
25
|
-
|
|
25
|
+
reachable_via(Next, Goal, [Next|Visited]).
|
|
26
26
|
|
|
27
27
|
is_reachable(Start, Goal) :-
|
|
28
|
-
|
|
28
|
+
reachable_via(Start, Goal, [Start]).
|
|
29
29
|
|
|
30
30
|
reachable(reachability_case, path(a, f)) :-
|
|
31
31
|
is_reachable(a, f).
|
|
@@ -20,16 +20,16 @@ plan(Moves) :-
|
|
|
20
20
|
candidate_plan(Moves),
|
|
21
21
|
initial_state(I),
|
|
22
22
|
goal_state(G),
|
|
23
|
-
|
|
23
|
+
reachable_state(I, Moves, G).
|
|
24
24
|
|
|
25
25
|
candidate_plan([_, _, _]).
|
|
26
26
|
candidate_plan([_, _, _, _]).
|
|
27
27
|
candidate_plan([_, _, _, _, _]).
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
reachable_state(S, [], S).
|
|
30
|
+
reachable_state(S1, [M|L], S3) :-
|
|
31
31
|
legal_move(S1, M, S2),
|
|
32
|
-
|
|
32
|
+
reachable_state(S2, L, S3).
|
|
33
33
|
|
|
34
34
|
initial_state([loc1, loc2, loc3, n, n]).
|
|
35
35
|
goal_state([_, _, _, _, y]).
|
|
@@ -11,7 +11,7 @@ why(
|
|
|
11
11
|
bindings([binding("Start", a), binding("Goal", f)]),
|
|
12
12
|
uses([
|
|
13
13
|
proof(
|
|
14
|
-
goal(
|
|
14
|
+
goal(reachable_via(a, f, "a")),
|
|
15
15
|
by(rule("graph-reachability.pl", clause(9))),
|
|
16
16
|
bindings([binding("Start", a), binding("Goal", f), binding("Visited", "a"), binding("Next", b)]),
|
|
17
17
|
uses([
|
|
@@ -24,7 +24,7 @@ why(
|
|
|
24
24
|
by(builtin('\\+', 1))
|
|
25
25
|
),
|
|
26
26
|
proof(
|
|
27
|
-
goal(
|
|
27
|
+
goal(reachable_via(b, f, "ba")),
|
|
28
28
|
by(rule("graph-reachability.pl", clause(9))),
|
|
29
29
|
bindings([binding("Start", b), binding("Goal", f), binding("Visited", "ba"), binding("Next", d)]),
|
|
30
30
|
uses([
|
|
@@ -37,7 +37,7 @@ why(
|
|
|
37
37
|
by(builtin('\\+', 1))
|
|
38
38
|
),
|
|
39
39
|
proof(
|
|
40
|
-
goal(
|
|
40
|
+
goal(reachable_via(d, f, "dba")),
|
|
41
41
|
by(rule("graph-reachability.pl", clause(9))),
|
|
42
42
|
bindings([binding("Start", d), binding("Goal", f), binding("Visited", "dba"), binding("Next", f)]),
|
|
43
43
|
uses([
|
|
@@ -50,7 +50,7 @@ why(
|
|
|
50
50
|
by(builtin('\\+', 1))
|
|
51
51
|
),
|
|
52
52
|
proof(
|
|
53
|
-
goal(
|
|
53
|
+
goal(reachable_via(f, f, "fdba")),
|
|
54
54
|
by(fact("graph-reachability.pl", clause(8))),
|
|
55
55
|
bindings([binding("Node", f), binding("_visited", "fdba")])
|
|
56
56
|
)
|
|
@@ -79,7 +79,7 @@ why(
|
|
|
79
79
|
bindings([binding("Start", c), binding("Goal", g)]),
|
|
80
80
|
uses([
|
|
81
81
|
proof(
|
|
82
|
-
goal(
|
|
82
|
+
goal(reachable_via(c, g, "c")),
|
|
83
83
|
by(rule("graph-reachability.pl", clause(9))),
|
|
84
84
|
bindings([binding("Start", c), binding("Goal", g), binding("Visited", "c"), binding("Next", e)]),
|
|
85
85
|
uses([
|
|
@@ -92,7 +92,7 @@ why(
|
|
|
92
92
|
by(builtin('\\+', 1))
|
|
93
93
|
),
|
|
94
94
|
proof(
|
|
95
|
-
goal(
|
|
95
|
+
goal(reachable_via(e, g, "ec")),
|
|
96
96
|
by(rule("graph-reachability.pl", clause(9))),
|
|
97
97
|
bindings([binding("Start", e), binding("Goal", g), binding("Visited", "ec"), binding("Next", f)]),
|
|
98
98
|
uses([
|
|
@@ -105,7 +105,7 @@ why(
|
|
|
105
105
|
by(builtin('\\+', 1))
|
|
106
106
|
),
|
|
107
107
|
proof(
|
|
108
|
-
goal(
|
|
108
|
+
goal(reachable_via(f, g, "fec")),
|
|
109
109
|
by(rule("graph-reachability.pl", clause(9))),
|
|
110
110
|
bindings([binding("Start", f), binding("Goal", g), binding("Visited", "fec"), binding("Next", g)]),
|
|
111
111
|
uses([
|
|
@@ -118,7 +118,7 @@ why(
|
|
|
118
118
|
by(builtin('\\+', 1))
|
|
119
119
|
),
|
|
120
120
|
proof(
|
|
121
|
-
goal(
|
|
121
|
+
goal(reachable_via(g, g, "gfec")),
|
|
122
122
|
by(fact("graph-reachability.pl", clause(8))),
|
|
123
123
|
bindings([binding("Node", g), binding("_visited", "gfec")])
|
|
124
124
|
)
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -196,6 +196,10 @@ export async function main(argv) {
|
|
|
196
196
|
});
|
|
197
197
|
|
|
198
198
|
const portabilityFailures = program.interopPortabilityWarnings ?? [];
|
|
199
|
+
// Shadowing is reported unconditionally: silently replacing a library
|
|
200
|
+
// predicate for the whole program is the failure mode this diagnostic exists
|
|
201
|
+
// to surface, so it must not depend on opting in to --warnings.
|
|
202
|
+
printLibraryShadowingWarnings(program);
|
|
199
203
|
if (options.warnings || (options.portable && portabilityFailures.length > 0)) printWarnings(program);
|
|
200
204
|
if (options.portable && portabilityFailures.length > 0) {
|
|
201
205
|
process.exitCode = 1;
|
|
@@ -364,6 +368,14 @@ function printSourceWarning(warning) {
|
|
|
364
368
|
`);
|
|
365
369
|
}
|
|
366
370
|
|
|
371
|
+
function printLibraryShadowingWarnings(program) {
|
|
372
|
+
for (const warning of program.libraryShadowingWarnings ?? []) {
|
|
373
|
+
process.stderr.write('eyeprolog warning: user definition shadows a bundled library predicate\n');
|
|
374
|
+
process.stderr.write(` ${warning.indicator} replaces library(${warning.library}) ${warning.indicator} for all user code in this program\n`);
|
|
375
|
+
process.stderr.write(` import it explicitly with :- use_module(library(${warning.library}), [${warning.indicator}]). to make this an error\n`);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
367
379
|
function printWarnings(program) {
|
|
368
380
|
for (const warning of program.interopPortabilityWarnings ?? []) {
|
|
369
381
|
if (warning.kind === 'library') {
|
package/src/program.js
CHANGED
|
@@ -153,6 +153,7 @@ export class Program {
|
|
|
153
153
|
this.autoloadedPredicates = [];
|
|
154
154
|
this.libraryImports = [];
|
|
155
155
|
this.interopPortabilityWarnings = [];
|
|
156
|
+
this.libraryShadowingWarnings = [];
|
|
156
157
|
this.dynamicPredicates = new Set();
|
|
157
158
|
// ISO 7.5.3 notes that a public/1 directive declaring user-defined
|
|
158
159
|
// procedures to be public would be an extension. Such a procedure stays
|
|
@@ -1428,6 +1429,50 @@ function analyzeInteropPortability(program, extraGoals = []) {
|
|
|
1428
1429
|
});
|
|
1429
1430
|
}
|
|
1430
1431
|
program.interopPortabilityWarnings = [...warnings.values()];
|
|
1432
|
+
analyzeLibraryShadowing(program);
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
// A user-defined procedure replaces the bundled-library procedure of the same
|
|
1436
|
+
// name and arity: the library clauses are never autoloaded, so other parts of
|
|
1437
|
+
// the same program that expected the library behaviour just see the user's
|
|
1438
|
+
// clauses. Bundled library modules keep resolving their own internal calls, so
|
|
1439
|
+
// this only affects user code, but within user code it acts at a distance
|
|
1440
|
+
// across included files.
|
|
1441
|
+
//
|
|
1442
|
+
// How strictly this is treated depends on how explicit the program was, which
|
|
1443
|
+
// follows the graded scheme SWI-Prolog uses for the same situation:
|
|
1444
|
+
//
|
|
1445
|
+
// implicit autoload -> warning
|
|
1446
|
+
// use_module(library(L)) -> warning
|
|
1447
|
+
// use_module(library(L), [Name/Arity]) -> permission_error
|
|
1448
|
+
//
|
|
1449
|
+
// Only the last case is an outright contradiction: the program asked for that
|
|
1450
|
+
// exact predicate to be imported and then supplied clauses for it. The first
|
|
1451
|
+
// two stay warnings so that flat, module-free programs -- which load unchanged
|
|
1452
|
+
// on Scryer and Trealla, where the library is simply never imported -- keep
|
|
1453
|
+
// working. Note that ISO reserves permission_error(modify, static_procedure)
|
|
1454
|
+
// for built-in predicates (7.5.3); library predicates are not built-ins, so
|
|
1455
|
+
// this error is raised only where the program's own import list demands it.
|
|
1456
|
+
function analyzeLibraryShadowing(program) {
|
|
1457
|
+
const explicitlyImported = new Map();
|
|
1458
|
+
for (const entry of program.libraryImports) {
|
|
1459
|
+
if (entry.imports == null) continue;
|
|
1460
|
+
for (const indicator of entry.imports) {
|
|
1461
|
+
explicitlyImported.set(`${entry.targetModule}:${indicator.key}`, entry.library);
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
const shadowed = new Map();
|
|
1466
|
+
for (const group of program.groups.values()) {
|
|
1467
|
+
if (group.module !== 'user') continue;
|
|
1468
|
+
const key = `${group.name}/${group.arity}`;
|
|
1469
|
+
const explicitLibrary = explicitlyImported.get(`${group.module}:${key}`);
|
|
1470
|
+
if (explicitLibrary != null) throw staticProcedureModificationError(group.name, group.arity);
|
|
1471
|
+
const library = eyePrologLibraryAutoload[key];
|
|
1472
|
+
if (library == null || shadowed.has(key)) continue;
|
|
1473
|
+
shadowed.set(key, { kind: 'shadowed-library-predicate', indicator: key, library });
|
|
1474
|
+
}
|
|
1475
|
+
program.libraryShadowingWarnings = [...shadowed.values()];
|
|
1431
1476
|
}
|
|
1432
1477
|
|
|
1433
1478
|
function sourceOptionsFor(source, options) {
|
|
@@ -23,7 +23,7 @@ chosen behavior is also indexed by `ISO-IMPLEMENTATION-DEFINED.md`.
|
|
|
23
23
|
| 7.4.2.7 `include/1` | covered | The included text is prepared at the directive position and shares operator/character/flag preparation state with its parent. |
|
|
24
24
|
| 7.4.2.8 `ensure_loaded/1` | covered | A source is prepared at most once in the current load graph, including repeated references and self/top-level references. |
|
|
25
25
|
| 7.4.2.9 `set_prolog_flag/2` | covered | Preparation-time flag changes affect subsequent text and are replayed into execution state; strict flag names/values/changeability remain governed by the closed 7.11 review. |
|
|
26
|
-
| 7.4.3 source clauses | covered | Source heads/bodies are validated like program clauses, standardized static/control procedures are protected, declarations can create empty procedures, and body conversion follows 7.6.2 while preserving head/body variable identity. The built-in restriction applies in every execution mode, so consulting a clause for a built-in predicate or control construct reports the same `permission_error(modify, static_procedure)` as `assert`ing one; EyeProlog's own library and extension predicates are not standard built-ins
|
|
26
|
+
| 7.4.3 source clauses | covered | Source heads/bodies are validated like program clauses, standardized static/control procedures are protected, declarations can create empty procedures, and body conversion follows 7.6.2 while preserving head/body variable identity. The built-in restriction applies in every execution mode, so consulting a clause for a built-in predicate or control construct reports the same `permission_error(modify, static_procedure)` as `assert`ing one; EyeProlog's own library and extension predicates are not standard built-ins, so ISO does not protect them. They stay redefinable when they reach the program implicitly, through autoloading or a whole-module `use_module(library(L))`, but the redefinition is reported as a shadowing warning because it replaces the library predicate for all user code in the program. Naming a predicate in an explicit import list, `use_module(library(L), [Name/Arity])`, and then supplying clauses for it is a contradiction and reports `permission_error(modify, static_procedure)`. Bundled library modules keep resolving their own internal calls, so a user redefinition never changes library behaviour. Corpus: `error/iso/consult_redefines_builtin`. |
|
|
27
27
|
|
|
28
28
|
The strict release test `closes ISO 7.4 Prolog-text preparation and directive
|
|
29
29
|
rows` exercises the cross-text operator/character/flag state, include and
|