eyeprolog 1.5.25 → 1.5.27
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/odrl-policy-reasoning.pl +2 -5
- package/package.json +1 -1
- package/src/cli.js +8 -4
- package/src/program.js +10 -1
- package/src/solver.js +26 -13
- package/src/standard-library.js +8 -0
- package/test/conformance/ISO-BUILTIN-MODE-ERROR-MATRIX.md +7 -3
- package/test/conformance/ISO-COMPLIANCE.md +19 -13
- package/test/conformance/ISO-CORRIGENDA-MATRIX.md +93 -0
- package/test/conformance/ISO-IMPLEMENTATION-DEFINED.md +1 -1
- package/test/conformance/ISO-PROCESSOR-REQUIREMENTS.md +2 -2
- package/test/conformance/README.md +6 -2
- package/test/run-iso-strict.mjs +44 -0
- package/test/run-regression.mjs +100 -2
- package/the-art-of-eyeprolog.md +19 -5
|
@@ -345,11 +345,8 @@ profile_prohibition(Request) :-
|
|
|
345
345
|
cycle_request(Request),
|
|
346
346
|
tnot(profile_permission(Request)).
|
|
347
347
|
|
|
348
|
-
%
|
|
349
|
-
%
|
|
350
|
-
wfs_truth(Claim, true) :- call(Claim), \+ tnot(Claim).
|
|
351
|
-
wfs_truth(Claim, false) :- tnot(Claim), \+ call(Claim).
|
|
352
|
-
wfs_truth(Claim, undefined) :- \+ call(Claim), \+ tnot(Claim).
|
|
348
|
+
% The normal-profile wfs_truth/2 predicate reports the three-valued result of
|
|
349
|
+
% each ground claim without treating an undefined claim as ordinary success.
|
|
353
350
|
|
|
354
351
|
% --- Curated questions -----------------------------------------------------
|
|
355
352
|
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -28,6 +28,7 @@ export async function main(argv) {
|
|
|
28
28
|
proofDetail: 'abstract',
|
|
29
29
|
verifyProof: null,
|
|
30
30
|
quads: false,
|
|
31
|
+
quiet: false,
|
|
31
32
|
stats: false,
|
|
32
33
|
isoStrict: false,
|
|
33
34
|
portable: false,
|
|
@@ -60,6 +61,8 @@ export async function main(argv) {
|
|
|
60
61
|
options.verifyProof = file;
|
|
61
62
|
} else if (!endOptions && (arg === '--quads' || arg === '-q')) {
|
|
62
63
|
options.quads = true;
|
|
64
|
+
} else if (!endOptions && arg === '--quiet') {
|
|
65
|
+
options.quiet = true;
|
|
63
66
|
} else if (!endOptions && (arg === '--stats' || arg === '-s')) {
|
|
64
67
|
options.stats = true;
|
|
65
68
|
} else if (!endOptions && arg === '--iso-strict') {
|
|
@@ -116,7 +119,7 @@ export async function main(argv) {
|
|
|
116
119
|
}
|
|
117
120
|
|
|
118
121
|
if (options.isoStrict && options.files.length === 0 && options.goals.length === 0 &&
|
|
119
|
-
options.verifyProof == null && !options.proof && !options.stats && !options.warnings) {
|
|
122
|
+
options.verifyProof == null && !options.proof && !options.quiet && !options.stats && !options.warnings) {
|
|
120
123
|
const engine = await loadEngine();
|
|
121
124
|
const { runRepl } = await import('./repl.js');
|
|
122
125
|
const exitCode = await runRepl(engine, {
|
|
@@ -251,8 +254,8 @@ async function runForwardDefault(engine, program, options) {
|
|
|
251
254
|
});
|
|
252
255
|
try {
|
|
253
256
|
const result = engine.executeForwardRules(program, solver, {
|
|
254
|
-
onAnswer: (line) => process.stdout.write(line),
|
|
255
|
-
onFuse: (line) => process.stdout.write(line),
|
|
257
|
+
onAnswer: (line) => { if (!options.quiet) process.stdout.write(line); },
|
|
258
|
+
onFuse: (line) => { if (!options.quiet) process.stdout.write(line); },
|
|
256
259
|
onDiagnostic: (line) => process.stderr.write(line),
|
|
257
260
|
});
|
|
258
261
|
if (result.haltCode != null) process.exitCode = result.haltCode;
|
|
@@ -277,7 +280,7 @@ async function runDefault(engine, program, options) {
|
|
|
277
280
|
try {
|
|
278
281
|
const { haltCode } = engine.executeGoals(program, solver, goals, {
|
|
279
282
|
onAnswer: (line, resolved) => {
|
|
280
|
-
process.stdout.write(line);
|
|
283
|
+
if (!options.quiet) process.stdout.write(line);
|
|
281
284
|
if (options.proof) writeExplanation(explanation, program, resolved, registry, options);
|
|
282
285
|
},
|
|
283
286
|
});
|
|
@@ -313,6 +316,7 @@ Options:
|
|
|
313
316
|
--proof-detail mode Use abstract or expanded proof detail (implies --proof).
|
|
314
317
|
--verify-proof file Verify why/2 proof certificates against the input program.
|
|
315
318
|
-q, --quads Run embedded quad tests and fail if any do not hold.
|
|
319
|
+
--quiet Suppress answer terms while preserving Prolog output.
|
|
316
320
|
-s, --stats Print solver and memory statistics to stderr after execution.
|
|
317
321
|
--iso-strict Use ISO/IEC 13211-1 core + Corrigenda 1-3 only;
|
|
318
322
|
reject EyeProlog language extensions.
|
package/src/program.js
CHANGED
|
@@ -57,6 +57,10 @@ function collectMultiplicitySensitiveDependencies(goal, out = []) {
|
|
|
57
57
|
collectMultiplicitySensitiveDependencies(goal.args[0], out);
|
|
58
58
|
return out;
|
|
59
59
|
}
|
|
60
|
+
if (goal.name === 'wfs_truth' && goal.arity === 2) {
|
|
61
|
+
collectMultiplicitySensitiveDependencies(goal.args[0], out);
|
|
62
|
+
return out;
|
|
63
|
+
}
|
|
60
64
|
if (goal.name === 'forall' && goal.arity === 2) {
|
|
61
65
|
collectMultiplicitySensitiveDependencies(goal.args[0], out);
|
|
62
66
|
collectMultiplicitySensitiveDependencies(goal.args[1], out);
|
|
@@ -1134,6 +1138,10 @@ function collectAutoloadGoalDependencies(goal, out = []) {
|
|
|
1134
1138
|
collectAutoloadGoalDependencies(goal.args[0], out);
|
|
1135
1139
|
return out;
|
|
1136
1140
|
}
|
|
1141
|
+
if (goal.name === 'wfs_truth' && goal.arity === 2) {
|
|
1142
|
+
collectAutoloadGoalDependencies(goal.args[0], out);
|
|
1143
|
+
return out;
|
|
1144
|
+
}
|
|
1137
1145
|
|
|
1138
1146
|
out.push({ key: `${goal.name}/${goal.arity}`, name: goal.name, arity: goal.arity, module: goal.module });
|
|
1139
1147
|
|
|
@@ -1687,7 +1695,8 @@ function annotateGoalModule(term, module) {
|
|
|
1687
1695
|
if (!term || (term.type !== ATOM && term.type !== COMPOUND)) return term;
|
|
1688
1696
|
term.module = module;
|
|
1689
1697
|
const callableArguments = (term.name === ',' || term.name === ';' || term.name === '->') ? term.args
|
|
1690
|
-
: (
|
|
1698
|
+
: (term.name === 'wfs_truth' && term.arity === 2) ? [term.args[0]]
|
|
1699
|
+
: (['call', 'once', '\\+', 'not', 'tnot', 'catch', 'call_cleanup', 'setup_call_cleanup',
|
|
1691
1700
|
'forall', 'findall', 'bagof', 'setof', 'countall', 'sumall',
|
|
1692
1701
|
'aggregate_min', 'aggregate_max', 'maplist', 'phrase'].includes(term.name)
|
|
1693
1702
|
? term.args
|
package/src/solver.js
CHANGED
|
@@ -919,7 +919,27 @@ export class Solver {
|
|
|
919
919
|
}
|
|
920
920
|
|
|
921
921
|
*solveTabledNegation(argument, env) {
|
|
922
|
-
const
|
|
922
|
+
const truth = this.groundGoalTruth(argument, env);
|
|
923
|
+
if (truth === 'true') return;
|
|
924
|
+
if (truth === 'undefined') {
|
|
925
|
+
this.stats.wfs_undefined_answers++;
|
|
926
|
+
return;
|
|
927
|
+
}
|
|
928
|
+
yield env;
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
groundGoalTruth(argument, env) {
|
|
932
|
+
let invoked = copyResolved(argument, env);
|
|
933
|
+
while (invoked.type === COMPOUND && invoked.name === ':' && invoked.arity === 2) {
|
|
934
|
+
const module = invoked.args[0];
|
|
935
|
+
if (module.type === VAR) throw new PrologError('instantiation_error');
|
|
936
|
+
if (module.type !== 'atom') throw new PrologError('type_error(atom)', module);
|
|
937
|
+
invoked = invoked.args[1];
|
|
938
|
+
if (invoked.type !== COMPOUND && invoked.type !== 'atom') {
|
|
939
|
+
throw new PrologError('type_error(callable)', invoked);
|
|
940
|
+
}
|
|
941
|
+
qualifyTerm(invoked, module.name);
|
|
942
|
+
}
|
|
923
943
|
if (invoked.type === VAR) throw new PrologError('instantiation_error');
|
|
924
944
|
if (invoked.type !== COMPOUND && invoked.type !== 'atom') {
|
|
925
945
|
throw new PrologError('type_error(callable)', invoked);
|
|
@@ -928,25 +948,18 @@ export class Solver {
|
|
|
928
948
|
const group = this.program.findGroup(invoked.name, invoked.arity, invoked.module ?? 'user');
|
|
929
949
|
if (group?.wfsDatalog === true) {
|
|
930
950
|
const model = this.wfsModelFor(group);
|
|
931
|
-
|
|
932
|
-
if (truth === 'true') return;
|
|
933
|
-
if (truth === 'undefined') {
|
|
934
|
-
this.stats.wfs_undefined_answers++;
|
|
935
|
-
return;
|
|
936
|
-
}
|
|
937
|
-
yield env;
|
|
938
|
-
return;
|
|
951
|
+
return truthOfGroundGoal(model, invoked);
|
|
939
952
|
}
|
|
940
953
|
|
|
941
|
-
// Outside an unstratified WFS component, a ground
|
|
942
|
-
//
|
|
954
|
+
// Outside an unstratified WFS component, a ground goal has the ordinary
|
|
955
|
+
// two-valued result after the positive goal is evaluated.
|
|
943
956
|
const child = this.cloneForInnerGoal(1);
|
|
944
957
|
for (const _ of child.solve([invoked], env.clone(), 0)) {
|
|
945
958
|
this.absorbStatsFrom(child);
|
|
946
|
-
return;
|
|
959
|
+
return 'true';
|
|
947
960
|
}
|
|
948
961
|
this.absorbStatsFrom(child);
|
|
949
|
-
|
|
962
|
+
return 'false';
|
|
950
963
|
}
|
|
951
964
|
|
|
952
965
|
activeVariant(goal, env) {
|
package/src/standard-library.js
CHANGED
|
@@ -310,6 +310,13 @@ function* tabledNegationBuiltin({ solver, goal, env }) {
|
|
|
310
310
|
yield* solver.solveTabledNegation(goal.args[0], env);
|
|
311
311
|
}
|
|
312
312
|
|
|
313
|
+
function* wfsTruthBuiltin({ solver, goal, env }) {
|
|
314
|
+
const truth = solver.groundGoalTruth(goal.args[0], env);
|
|
315
|
+
if (truth === 'undefined') solver.stats.wfs_undefined_answers++;
|
|
316
|
+
const next = env.clone();
|
|
317
|
+
if (unify(goal.args[1], atom(truth), next)) yield next;
|
|
318
|
+
}
|
|
319
|
+
|
|
313
320
|
function runtimeStatistics(solver) {
|
|
314
321
|
return { ...solver.stats, ...memoryStatistics() };
|
|
315
322
|
}
|
|
@@ -361,6 +368,7 @@ export function createEyePrologRegistry() {
|
|
|
361
368
|
registry.add('statistics', 0, statisticsBuiltin, { deterministic: true });
|
|
362
369
|
registry.add('statistics', 2, statisticsValueBuiltin);
|
|
363
370
|
registry.add('tnot', 1, tabledNegationBuiltin, { deterministic: true });
|
|
371
|
+
registry.add('wfs_truth', 2, wfsTruthBuiltin, { deterministic: true });
|
|
364
372
|
attsHostBuiltins.register(registry);
|
|
365
373
|
expansionBuiltins.register(registry);
|
|
366
374
|
arithmeticHostBuiltins.register(registry);
|
|
@@ -17,11 +17,13 @@ table.
|
|
|
17
17
|
The table is intentionally explicit about what has and has not been closed.
|
|
18
18
|
The current audit now covers the complete 8.2-8.17 built-in family at the
|
|
19
19
|
level of prescribed modes, success/failure behavior, individual error
|
|
20
|
-
conditions, and explicit not-applicable processor branches.
|
|
21
|
-
|
|
20
|
+
conditions, and explicit not-applicable processor branches. Closely related
|
|
21
|
+
conditions may share a row only when that row names every condition and the
|
|
22
|
+
executable evidence for each. Higher-level Clause 7 and Clause 9 semantics
|
|
23
|
+
remain tracked separately.
|
|
22
24
|
|
|
23
25
|
The focused assertions added for this matrix live in `test/run-iso-strict.mjs`;
|
|
24
|
-
existing file-based cases remain additional
|
|
26
|
+
existing file-based cases remain additional regression evidence.
|
|
25
27
|
|
|
26
28
|
## 8.2 — term unification
|
|
27
29
|
|
|
@@ -369,6 +371,8 @@ built-in matrix does not have a gap at 8.17.
|
|
|
369
371
|
The built-in **8.2-8.17 row audit is complete** at the level tracked by this
|
|
370
372
|
file: prescribed modes, success/failure behavior, individual error conditions,
|
|
371
373
|
and conditional/not-applicable processor branches all have explicit outcomes.
|
|
374
|
+
“Row audit” means condition-by-condition accounting; it does not promise one
|
|
375
|
+
Markdown table row per condition when a grouped row enumerates them all.
|
|
372
376
|
ISO 7.12 simultaneous-error selection remains an implementation-dependent
|
|
373
377
|
processor choice unless more specific normative text constrains it.
|
|
374
378
|
|
|
@@ -5,12 +5,16 @@ EyeProlog's ISO/IEC 13211-1 core. The normative baseline is ISO/IEC 13211-1:1995
|
|
|
5
5
|
together with Technical Corrigenda 1:2007, 2:2012, and 3:2017. Detailed
|
|
6
6
|
row-level evidence lives only where it adds information: the built-in, processor,
|
|
7
7
|
term-semantics, Prolog-text/execution, evaluable-functor, implementation-defined,
|
|
8
|
-
WG17-syntax, and STC draft ledgers in this directory. The generated
|
|
8
|
+
published-Corrigenda, WG17-syntax, and STC draft ledgers in this directory. The generated
|
|
9
9
|
[`conformance-report.md`](../../conformance-report.md) gives the current executable WG17 syntax result together with file-based case totals.
|
|
10
10
|
|
|
11
11
|
The ledger deliberately does **not** claim independent certification. A row
|
|
12
12
|
marked `covered` means EyeProlog has implementation and executable tests for
|
|
13
|
-
that family
|
|
13
|
+
that family, an explicit disposition for every requirement accounted for by
|
|
14
|
+
the linked audit rows, and no known open defect in the listed behavior. An
|
|
15
|
+
audit row may group closely related modes or error conditions, but it must name
|
|
16
|
+
each grouped condition and its evidence; `covered` does not imply one Markdown
|
|
17
|
+
row per occurrence of the word `shall`. A row marked
|
|
14
18
|
`audit` means the family is implemented and tested, but the project has not yet
|
|
15
19
|
mapped every normative `shall`, option combination, prescribed error, and
|
|
16
20
|
relevant implementation-dependent overlap choice to an explicit audit outcome.
|
|
@@ -23,7 +27,7 @@ relevant implementation-dependent overlap choice to an explicit audit outcome.
|
|
|
23
27
|
| 5.1(b) execute conforming Prolog goals | covered | Clause 7 term/control/execution semantics, the higher-level 7.10 stream model, 7.11 flags, the 7.12 error envelope, all 8.2-8.17 built-in rows, and Clause 9 arithmetic have explicit executable dispositions. |
|
|
24
28
|
| 5.1(c) reject nonconforming text/read-terms | covered | WG17 negative syntax cases, focused malformed-production/escape/comment/operator cases, read-term syntax errors, and strict rejection of implementation-specific syntax provide explicit rejection evidence across the Clause 6 families. |
|
|
25
29
|
| 5.1(d) document permitted variations | covered | The clause-by-clause [ISO 5.4 decision index](ISO-IMPLEMENTATION-DEFINED.md) records every explicit implementation-defined decision found in the Part 1 + Corrigenda baseline and separately inventories implementation-specific extension families. The index retains an `audit gap` category for future discoveries; no current release-facing row depends on one. |
|
|
26
|
-
| 5.1(e) offer a strictly conforming mode | covered | `--iso-strict` and API option `isoStrict: true` restrict the processor to the Part 1 + Corrigenda 1-3 core language surface, remove EyeProlog-only registry/flag/operator features, reject explicit tabling and other normal-profile extensions, and reject the normal-profile host `stringTerm
|
|
30
|
+
| 5.1(e) offer a strictly conforming mode | covered | `--iso-strict` and API option `isoStrict: true` restrict the processor to the Part 1 + Corrigenda 1-3 core language surface, remove EyeProlog-only registry/flag/operator features, reject explicit tabling and other normal-profile extensions, and reject the normal-profile host `stringTerm(Text)` term type at strict program/goal entry. |
|
|
27
31
|
| 5.4 accompanying documentation | covered | *The Art of EyeProlog* remains the implementation reference; [ISO-IMPLEMENTATION-DEFINED.md](ISO-IMPLEMENTATION-DEFINED.md) is the closed clause-by-clause 5.4 decision index and points each decision to implementation evidence. |
|
|
28
32
|
| 5.5 extension boundaries | covered | [ISO-PROCESSOR-REQUIREMENTS.md](ISO-PROCESSOR-REQUIREMENTS.md) gives an explicit disposition for every 5.5 extension hook. The Clause 6 cross-profile gate verifies that normal-mode syntax extensions do not reinterpret standard text accepted by the strict reader. |
|
|
29
33
|
|
|
@@ -31,7 +35,7 @@ relevant implementation-dependent overlap choice to an explicit audit outcome.
|
|
|
31
35
|
|
|
32
36
|
| Standard area | Status | Current evidence |
|
|
33
37
|
| --- | --- | --- |
|
|
34
|
-
| Clause 6 — tokens, terms, lists, operators, quoted text | covered | The strict Clause 6 gate maps atomic/variable/compound/operator/list/curly/double-quoted term forms, layout/comments, quoted escapes, integer bases/character codes, floating tokens, and solo/meta token boundaries, with malformed counterparts rejected. The complete 366-case WG17 syntax matrix provides
|
|
38
|
+
| Clause 6 — tokens, terms, lists, operators, quoted text | covered | The strict Clause 6 gate maps atomic/variable/compound/operator/list/curly/double-quoted term forms, layout/comments, quoted escapes, integer bases/character codes, floating tokens, and solo/meta token boundaries, with malformed counterparts rejected. The complete 366-case WG17 syntax matrix provides externally sourced production-level expectations, and a cross-profile gate verifies that normal syntax extensions preserve every strict-accepted standard observation. The implementation-defined 6.5/6.6 PCS/collation choices are documented separately. |
|
|
35
39
|
| 7.1-7.3 — term types, term order, unification | covered | [ISO-TERM-SEMANTICS-MATRIX.md](ISO-TERM-SEMANTICS-MATRIX.md) records the five mutually exclusive strict term types, derived variable/compound/list notions, the complete standard-order classes and implementation-dependent variable-order choice, NSTO MGU/failure behavior, and EyeProlog's permitted consistent occurs-check failure for Part 1's undefined STO ordinary-unification cases. The normal JavaScript API string term is documented as a 5.5.4 extension and rejected at strict program/goal entry. |
|
|
36
40
|
| 7.4 — Prolog text and directives | covered | [ISO-PROLOG-TEXT-EXECUTION-MATRIX.md](ISO-PROLOG-TEXT-EXECUTION-MATRIX.md) closes the preparation/directive rows: declaration semantics, source clauses, cross-text operators/character conversion/flags, initialization order/lifetime, `include/1`, and one-time `ensure_loaded/1`, with implementation-defined cross-text choices indexed under 5.4. |
|
|
37
41
|
| 7.5-7.6 — database and term/clause conversion | covered | [ISO-PROLOG-TEXT-EXECUTION-MATRIX.md](ISO-PROLOG-TEXT-EXECUTION-MATRIX.md) closes static/dynamic and private/public procedure semantics, clause order, logical-update visibility, empty/unknown lifetime, and term/body/clause conversion. Source and runtime assertion conversion recurse through `,/2`, `;/2`, and `->/2`, preserve variable identity, and protect standardized static/control procedures. |
|
|
@@ -41,11 +45,11 @@ relevant implementation-dependent overlap choice to an explicit audit outcome.
|
|
|
41
45
|
| 7.10 — input/output concepts | covered | Higher-level stream semantics are pinned for non-atom ground stream terms, alias lifetime, current/target stream selection and fallback, write truncation, append positioning, contradictory stream options, exact binary round-tripping, flushing, standard-stream close behavior, and repositioned overwrite. Term-output spelling is also checked lexically where ISO distinguishes token forms: Corrigendum 2 bar operators are written with bare `|`, ordinary atom/functor `|` remains quoted, and the semicolon name token is emitted bare by canonical output. The complete 8.11-8.14 built-in mode/error family remains row-audited in [ISO-BUILTIN-MODE-ERROR-MATRIX.md](ISO-BUILTIN-MODE-ERROR-MATRIX.md), while all implementation-defined stream choices are indexed in [ISO-IMPLEMENTATION-DEFINED.md](ISO-IMPLEMENTATION-DEFINED.md). |
|
|
42
46
|
| 7.11 — flags | covered | The complete Part 1 flag set, selected defaults, standard value domains, changeability, `current_prolog_flag/2`, and `set_prolog_flag/2` error behavior have dedicated strict tests. EyeProlog selects `bounded=false` and `integer_rounding_function=toward_zero`; valid alternative values of those fixed flags reach `permission_error(modify,flag,...)`, while `max_integer` and `min_integer` have no current value. STC #70 is recorded explicitly: EyeProlog has no separate finite procedure-arity ceiling, so the optional `max_procedure_arity` flag is absent while `max_arity` remains `unbounded`. Strict mode excludes the EyeProlog `occurs_check` extension. |
|
|
43
47
|
| 7.12 — errors | covered | The strict error-envelope gate exercises instantiation, type, domain, existence, permission, representation, evaluation, resource, syntax, and system errors through `error(Error, Context)`. Built-in rows provide the individual prescribed conditions, implementation-defined representation/context choices are documented, and simultaneous-error regressions pin deterministic EyeProlog choices without treating textual table order as normative. |
|
|
44
|
-
| 8.2-8.17 — built-in predicates | covered | [ISO-BUILTIN-MODE-ERROR-MATRIX.md](ISO-BUILTIN-MODE-ERROR-MATRIX.md)
|
|
48
|
+
| 8.2-8.17 — built-in predicates | covered | [ISO-BUILTIN-MODE-ERROR-MATRIX.md](ISO-BUILTIN-MODE-ERROR-MATRIX.md) accounts for the complete Part 1 + Corrigenda built-in family across prescribed modes, success/failure behavior, individual error conditions, and conditional/not-applicable branches. Closely related conditions may share a row when every condition and its executable evidence are named. The audit exposed and fixed source/runtime 7.6.2 body conversion/variable sharing, strict host-string leakage, input-code error timing, `close/2` force handling, and closed-stream `stream_property/2` behavior. Simultaneous-error choices are documented as implementation dependent under 7.12 unless separately constrained. |
|
|
45
49
|
| Clause 9 — evaluable functors | covered | [ISO-EVALUABLE-FUNCTOR-MATRIX.md](ISO-EVALUABLE-FUNCTOR-MATRIX.md) records the published Part 1 + Corrigenda arithmetic templates and exceptional branches across 9.1, 9.3, and 9.4. It pins the unbounded integer model, `rndI`/`rndF`/`resultF` choices, float-only conversion rules, I->F overflow, explicit `exp/1` and power underflow, Corrigendum 2 additions and mixed-type `max/2`/`min/2` implementation-dependent choice, Corrigendum 3 negative-power correction, signed bitwise/shift choices, and resource-error translation. Post-N289 STC #75 remains a separately tracked draft proposal rather than a silent change to the published baseline. |
|
|
46
|
-
| Corrigendum 1 | covered |
|
|
47
|
-
| Corrigendum 2 | covered |
|
|
48
|
-
| Corrigendum 3 | covered |
|
|
50
|
+
| Corrigendum 1 | covered | [ISO-CORRIGENDA-MATRIX.md](ISO-CORRIGENDA-MATRIX.md) dispositions every amendment cluster, including the square-root boundary, double-quoted operator atoms, typed expression errors, clause/operator enumeration, and atomic-conversion corrections; editorial items and the later-superseded set-order example are identified explicitly. |
|
|
51
|
+
| Corrigendum 2 | covered | [ISO-CORRIGENDA-MATRIX.md](ISO-CORRIGENDA-MATRIX.md) tracks the bar/operator changes, new predicates and evaluable functors, catch and uninstantiation corrections, atomic-conversion errors, and every other amendment cluster to executable evidence or an explicit editorial disposition. |
|
|
52
|
+
| Corrigendum 3 | covered | [ISO-CORRIGENDA-MATRIX.md](ISO-CORRIGENDA-MATRIX.md) tracks option-extension/error rules, final layout, term-to-body conversion, metadata traversal, writing rules, stream/built-in corrections, and negative integer powers; editorial changes are dispositioned separately. |
|
|
49
53
|
|
|
50
54
|
## Conformance corrections and audit closure
|
|
51
55
|
|
|
@@ -248,8 +252,10 @@ not interpret the following as core-language features:
|
|
|
248
252
|
- the implementation-specific `occurs_check` Prolog flag;
|
|
249
253
|
- Part 2 module directives (`module/2`, `use_module/1-2`, `meta_predicate/1`);
|
|
250
254
|
- Part 3 grammar-rule expansion and `phrase/2-3`;
|
|
251
|
-
- explicit tabling,
|
|
252
|
-
|
|
255
|
+
- explicit tabling, EyeProlog well-founded evaluation via `tnot/1` and
|
|
256
|
+
`wfs_truth/2`, WFS runtime statistics, and recursive numeric execution shortcuts;
|
|
257
|
+
- normal-profile integer digit separators and Trealla-compatible
|
|
258
|
+
`"text"||Tail` double-quoted-list splicing;
|
|
253
259
|
- the JavaScript API `stringTerm(Text)` additional term type (normal mode only).
|
|
254
260
|
|
|
255
261
|
The predefined Part 1 `1200 fx` `?-` operator and `1200 xfx` `-->` operator
|
|
@@ -288,13 +294,13 @@ post-N289 STC drafts remain review input until standardized.
|
|
|
288
294
|
| Clause 5 processor obligations have explicit dispositions | covered | `ISO-PROCESSOR-REQUIREMENTS.md` gives explicit outcomes for 5.1-5.5, including the strict/normal extension boundary. |
|
|
289
295
|
| Clause 6 lexical/syntactic requirements have explicit dispositions | covered | the strict Clause 6 production/rejection gate and the 366-case vendored WG17 matrix cover the standard families; cross-profile preservation verifies that normal extensions do not reinterpret strict-accepted text. |
|
|
290
296
|
| Clause 7 semantic requirements have explicit dispositions | covered | 7.1-7.12 now have explicit semantic, implementation-defined, or error-envelope dispositions backed by strict tests and the specialized matrices. |
|
|
291
|
-
| Clause 8 built-in modes/errors have explicit dispositions | covered | `ISO-BUILTIN-MODE-ERROR-MATRIX.md`
|
|
297
|
+
| Clause 8 built-in modes/errors have explicit dispositions | covered | `ISO-BUILTIN-MODE-ERROR-MATRIX.md` accounts for 8.2-8.17 condition by condition, using grouped rows only where every grouped condition and its evidence are named |
|
|
292
298
|
| Clause 9 evaluable-functor requirements have explicit dispositions | covered | `ISO-EVALUABLE-FUNCTOR-MATRIX.md` plus the strict arithmetic regression closes the published Part 1 + Corrigenda arithmetic rows |
|
|
293
299
|
| Implementation-defined choices are documented | covered | `ISO-IMPLEMENTATION-DEFINED.md` is the Clause 5.4 decision index and strict tests pin execution-visible choices |
|
|
294
300
|
| Implementation-specific strict/normal boundary is documented and tested | covered | all 5.5 hooks have explicit dispositions; the WG17 cross-profile gate verifies syntax-preservation for standard text accepted by the strict reader. |
|
|
295
|
-
| Published Corrigenda 1-3 are incorporated | covered |
|
|
301
|
+
| Published Corrigenda 1-3 are incorporated | covered | `ISO-CORRIGENDA-MATRIX.md` inventories every published amendment cluster with executable, editorial, or superseded disposition |
|
|
296
302
|
| Current post-N289 draft is tracked without silently changing the published baseline | covered | `STC-DRAFT-STATUS.md` tracks reviewed draft items separately from normative requirements |
|
|
297
|
-
|
|
|
303
|
+
| Externally sourced syntax corpus is an offline release gate | covered | the vendored WG17 syntax matrix has 366 executable dispositions checked against its upstream expectations; this is external review evidence, not certification |
|
|
298
304
|
| Third-party standard-core regression provenance is retained | covered | adapted Logtalk, Scryer, Trealla, and SWI-Prolog cases retain source identifiers and licenses in `THIRD_PARTY.md` |
|
|
299
305
|
| No unexplained deviation remains in the release-facing ledger | covered | the release-facing ledger contains no remaining `audit` rows; documented variation points are implementation-defined/specific or draft-only rather than unexplained deviations. |
|
|
300
306
|
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# ISO/IEC 13211-1 published Corrigenda audit
|
|
2
|
+
|
|
3
|
+
This matrix records every amendment cluster in Technical Corrigenda 1:2007,
|
|
4
|
+
2:2012, and 3:2017 against EyeProlog's published Part 1 baseline. It separates
|
|
5
|
+
behavior-changing requirements from editorial/example-only corrections and
|
|
6
|
+
from text superseded by a later Corrigendum. A `covered` behavior row names
|
|
7
|
+
executable evidence; an `editorial` row records that no processor behavior was
|
|
8
|
+
changed; a `superseded` row points to the later published amendment.
|
|
9
|
+
|
|
10
|
+
The stable audit IDs are checked by the documentation regression suite. They
|
|
11
|
+
make omission detectable without reproducing the licensed standard text here.
|
|
12
|
+
|
|
13
|
+
## Technical Corrigendum 1:2007
|
|
14
|
+
|
|
15
|
+
| Audit ID | Clauses / amendment cluster | Disposition | EyeProlog evidence |
|
|
16
|
+
| --- | --- | --- | --- |
|
|
17
|
+
| C1-01 | 3.106, 3.108, 3.125, 3.148 terminology and typography | editorial | Definitions/source typography; no processor behavior changes. |
|
|
18
|
+
| C1-02 | 4.1.3.5 non-negative square-root axiom | covered | Strict test `pins behavior-changing Technical Corrigendum 1 corrections` checks `sqrt(0)`. |
|
|
19
|
+
| C1-03 | 6.3.7 priority of a double-quoted atom that names an operator | covered | Same strict test plus `iso/corrigendum1_double_quote_operator`. |
|
|
20
|
+
| C1-04 | 7.2.5 compound-term ordering wording | editorial | The corrected condition is represented by the Clause 7.2 standard-order tests. |
|
|
21
|
+
| C1-05 | 7.8.5.4, table 35, and 7.8.8.4 control-model/example corrections | editorial | Corrected notation; conjunction and if-then-else behavior is independently covered by the strict 7.8 audit. |
|
|
22
|
+
| C1-06 | 7.9.2 integer- and float-operand type errors | covered | Strict Clause 7.9 tests exercise integer-only and float-only templates. |
|
|
23
|
+
| C1-07 | 7.12.2 representation-error metavariable capitalization | editorial | Error-term representation is covered by the 7.12 envelope; this amendment changes notation only. |
|
|
24
|
+
| C1-08 | 8.8.1.1 selected `clause/2` result is unified with head/body | covered | Strict test `pins behavior-changing Technical Corrigendum 1 corrections`. |
|
|
25
|
+
| C1-09 | 8.9.4.1 `abolish/1` note wording | editorial | Singular/plural note correction only. |
|
|
26
|
+
| C1-10 | 8.10.3.4 set-order example | superseded | Corrigendum 3 explicitly restores the original example; current behavior follows Corrigendum 3. |
|
|
27
|
+
| C1-11 | 8.13.3.4 `put_byte/1-2` example values | editorial | Examples corrected; byte-output semantics are covered by the strict 8.13 audit. |
|
|
28
|
+
| C1-12 | 8.14.1.4 input-stream names and post-syntax-error example state | editorial | Examples corrected; read-stream behavior is covered by strict term-I/O tests. |
|
|
29
|
+
| C1-13 | 8.14.4.1 selected `current_op/3` result is unified with its arguments | covered | Strict test `pins behavior-changing Technical Corrigendum 1 corrections`. |
|
|
30
|
+
| C1-14 | 8.16.4 `atom_chars/2` accepts a matching supplied list prefix | covered | Strict test `pins behavior-changing Technical Corrigendum 1 corrections`. |
|
|
31
|
+
| C1-15 | 8.16.5 `atom_codes/2` accepts a matching supplied list prefix | covered | Strict test `pins behavior-changing Technical Corrigendum 1 corrections`. |
|
|
32
|
+
| C1-16 | 9.1.4.1 and 9.1.7 arithmetic notes/examples | editorial | Corrected examples and reference; corresponding arithmetic operations are covered by the Clause 9 matrix. |
|
|
33
|
+
| C1-17 | 9.3.5.4 and 9.3.6.4 transcendental example constants | editorial | Example constants only; `exp/1` and `log/1` have executable strict coverage. |
|
|
34
|
+
| C1-18 | 9.4.1-9.4.4 example error terms | editorial | Corrected examples; evaluable-functor and integer-operand errors are covered by strict Clause 9 tests. |
|
|
35
|
+
|
|
36
|
+
## Technical Corrigendum 2:2012
|
|
37
|
+
|
|
38
|
+
| Audit ID | Clauses / amendment cluster | Disposition | EyeProlog evidence |
|
|
39
|
+
| --- | --- | --- | --- |
|
|
40
|
+
| C2-01 | 6.3.4, 6.4, 6.5 bar token/operator rules and protected `[]`/`{}` operators | covered | WG17 lexical output cases, `corrigenda_bar_operator`, and strict `op/3` tests. |
|
|
41
|
+
| C2-02 | 6.3.4.4 predefined unary plus and `div` operators | covered | Strict predefined-operator and arithmetic tests. |
|
|
42
|
+
| C2-03 | 7.1.1.5 witness-variable list | covered | `term_variables/2`, read-option traversal, and variable-order tests. |
|
|
43
|
+
| C2-04 | 7.1.6.9 list-prefix definition | covered | Atomic-conversion partial/improper-list tests. |
|
|
44
|
+
| C2-05 | 7.8.3.4 complete term-to-body error culprit for `call/1` | covered | Strict 7.8 callability and recursive body-conversion tests. |
|
|
45
|
+
| C2-06 | 7.8.9 `catch/3` catches errors arising from its protected goal | covered | `corrigenda_catch_callability` and strict exception tests. |
|
|
46
|
+
| C2-07 | 7.9 typed evaluable-operand error selection | covered | Strict Clause 7.9/9 operand-template tests. |
|
|
47
|
+
| C2-08 | 7.12.2 pair/order domains and uninstantiation error class | covered | Strict error envelope and Corrigendum-specific output-argument tests. |
|
|
48
|
+
| C2-09 | 8.1.3 output-mode arguments use uninstantiation errors | covered | Strict `open/4` output argument test. |
|
|
49
|
+
| C2-10 | 8.2.4 `subsumes_term/2` | covered | Strict registry and Corrigendum term-predicate tests. |
|
|
50
|
+
| C2-11 | 8.3.9-8.3.11 `callable/1`, `ground/1`, `acyclic_term/1` | covered | Strict registry/type tests and `corrigenda_term_predicates`. |
|
|
51
|
+
| C2-12 | 8.4.2-8.4.4 `compare/3`, `sort/2`, `keysort/2` | covered | Strict mode/error rows and `corrigenda_sort_keysort`. |
|
|
52
|
+
| C2-13 | 8.5.5 `term_variables/2` | covered | Strict mode/error rows and `corrigenda_term_predicates`. |
|
|
53
|
+
| C2-14 | 8.9.3 static `retract/1` uses modify permission | covered | Strict database predicate error tests. |
|
|
54
|
+
| C2-15 | 8.9.5 `retractall/1` | covered | Strict lifetime/error tests and `corrigenda_retractall`. |
|
|
55
|
+
| C2-16 | 8.11.5 non-variable `open/4` stream result | covered | Strict uninstantiation-error test. |
|
|
56
|
+
| C2-17 | 8.14.3 protected operator priority/specifier combinations | covered | Strict `op/3` row audit and bar-operator cases. |
|
|
57
|
+
| C2-18 | 8.15.4 `call/2..8` and implementation-dependent higher arities | covered | Strict closure expansion, error, and selected ceiling tests. |
|
|
58
|
+
| C2-19 | 8.15.5 `false/0` | covered | Strict registry, execution, and static-procedure protection tests. |
|
|
59
|
+
| C2-20 | 8.16.4-8.16.8 atomic/number conversion partial-list errors | covered | Individual strict mode/error assertions for all four predicates. |
|
|
60
|
+
| C2-21 | 9.1 unary plus and flooring integer `div/2` | covered | Strict arithmetic matrix and negative-operand distinction from `//2`. |
|
|
61
|
+
| C2-22 | 9.3 `max/2`, `min/2`, `^/2`, inverse trig, `atan2/2`, `tan/1`, and `pi/0` | covered | Strict evaluable-functor matrix and exceptional-value tests. |
|
|
62
|
+
| C2-23 | 9.4.6 `xor/2` | covered | Strict signed bitwise and operand-type tests. |
|
|
63
|
+
|
|
64
|
+
## Technical Corrigendum 3:2017
|
|
65
|
+
|
|
66
|
+
| Audit ID | Clauses / amendment cluster | Disposition | EyeProlog evidence |
|
|
67
|
+
| --- | --- | --- | --- |
|
|
68
|
+
| C3-01 | 5.5.12 implementation-specific options and their error classification | covered | Strict option surfaces reject normal-only options and exercise variable/domain distinctions. |
|
|
69
|
+
| C3-02 | 6.2.1 optional final layout text | covered | Strict test `pins behavior-changing Technical Corrigendum 3 corrections`. |
|
|
70
|
+
| C3-03 | 7.1.6.3 iterated-goal term uses structural form rather than unification | covered | Strict `bagof/3`/`setof/3` grouping and error tests. |
|
|
71
|
+
| C3-04 | 7.8.3 `call/1` applies term-to-body conversion before execution | covered | Strict call/cut-scope and variable-body conversion regressions. |
|
|
72
|
+
| C3-05 | 7.10.3 read-option unification and left-to-right variable traversal | covered | Corrigendum 3 metadata traversal tests. |
|
|
73
|
+
| C3-06 | 7.10.4 `variable_names/1` write option | covered | Strict test `pins behavior-changing Technical Corrigendum 3 corrections` and file-based writer case. |
|
|
74
|
+
| C3-07 | 7.10.5 variable, list, curly, functional, and operator writing rules | covered | Strict writer suite and exact WG17 writer assertions. |
|
|
75
|
+
| C3-08 | 7.12.2 error-classification set corrections | editorial | Corrected type/domain/permission enumerations are reflected by individual strict errors. |
|
|
76
|
+
| C3-09 | 8.1.2/8.1.3 option-list modes and component-variable errors | covered | Strict open/close/read/write option-list assertions. |
|
|
77
|
+
| C3-10 | 8.5.1.4 conditional `max_arity` example | editorial | Example disposition is documented; EyeProlog selects `max_arity=unbounded`. |
|
|
78
|
+
| C3-11 | 8.9.2.1 assertion-description variable correction | editorial | Metavariable typo only; `assertz/1` conversion behavior is strictly tested. |
|
|
79
|
+
| C3-12 | 8.10.3.4 restores the original set-order example | superseded | Supersedes C1-10; current grouped-solution order is tested and documented as implementation dependent where permitted. |
|
|
80
|
+
| C3-13 | 8.11.4.1 explicit success of `set_output/1` | covered | Strict stream-selection success test. |
|
|
81
|
+
| C3-14 | 8.11.5, 8.11.6, 8.14.1, 8.14.2 option-list error rewrites | covered | Individual strict option instantiation/list/domain assertions. |
|
|
82
|
+
| C3-15 | 8.14.1.1 corrected syntax reference | editorial | Reference correction only; read-term syntax errors are executable. |
|
|
83
|
+
| C3-16 | 8.14.2.4 canonical-list and option-error examples | covered | Canonical list output, variable option, and invalid option tests. |
|
|
84
|
+
| C3-17 | 8.17.1.4 unknown flag uses the `prolog_flag` domain | covered | Strict `set_prolog_flag/2` unknown-flag test. |
|
|
85
|
+
| C3-18 | 9.3.1.3 arithmetic metavariable correction | editorial | Metavariable typo only. |
|
|
86
|
+
| C3-19 | 9.3.10 negative integer exponent requires a float base | covered | Strict test `pins behavior-changing Technical Corrigendum 3 corrections`. |
|
|
87
|
+
|
|
88
|
+
## Closure rule
|
|
89
|
+
|
|
90
|
+
The three Corrigenda rows in `ISO-COMPLIANCE.md` may be marked `covered` only
|
|
91
|
+
while this complete stable-ID inventory passes its structural regression and
|
|
92
|
+
every behavior-changing row retains executable evidence. Editorial and
|
|
93
|
+
superseded rows are explicit dispositions rather than silently omitted tests.
|
|
@@ -119,7 +119,7 @@ families; `--iso-strict` is intended to remove their Part 1 interpretation.
|
|
|
119
119
|
| 5.5.4 Types | The normal JavaScript API exposes an implementation-specific string term `stringTerm(Text)`. It is disjoint from the five Part 1 term types; normal term order places it after atoms and before compound terms, and normal `atomic/1` treats it as atomic. It has no Prolog source token syntax (double-quoted source still follows `double_quotes`), is non-callable for term-to-clause conversion, is not evaluable as an arithmetic expression, and writes as a double-quoted host string. | Strict mode rejects a programmatic string term at program/goal entry with `representation_error(term)`, so the additional type cannot enter the Part 1 execution domain. **defined** — `src/term.js`, `src/program.js`, `src/solver.js`; strict API-boundary regression. |
|
|
120
120
|
| 5.5.5 Directives | `module/2`, `use_module/1-2`, `meta_predicate/1` and normal-profile library behavior | Rejected as implementation-specific Part 1 directives. |
|
|
121
121
|
| 5.5.6 Side effects | Normal mode adds `statistics/0-2`, cleanup/library state, and optional proof/statistics host instrumentation. | The strict registry excludes Prolog-visible statistics/cleanup/library adapters; ordinary Part 1 I/O/database/flag/operator side effects remain. Host proof/statistics collection observes execution through the embedding API rather than adding a strict Prolog goal effect. **covered** — strict registry/execution regression. |
|
|
122
|
-
| 5.5.7 Control constructs | `tnot/1` and normal-profile execution optimizations | `tnot/1` and the normal-profile explicit `table` declaration are absent. |
|
|
122
|
+
| 5.5.7 Control constructs | `tnot/1`, `wfs_truth/2`, and normal-profile execution optimizations | `tnot/1`, `wfs_truth/2`, and the normal-profile explicit `table` declaration are absent. |
|
|
123
123
|
| 5.5.8 Flags | `occurs_check` | Absent in strict mode. |
|
|
124
124
|
| 5.5.9 Built-in predicates | EyeProlog libraries, CLP(Z), statistics, Part 3 `phrase/2-3`, and bundled-library autoloaded predicates | Strict registry contains only the Part 1 + Corrigenda core registry. |
|
|
125
125
|
| 5.5.10 Evaluable functors | Normal mode additionally accepts the EyeProlog evaluable atom `e`; the remaining arithmetic functors accepted by strict mode are the Part 1 + Corrigenda set. | Strict mode rejects `e/0` as non-evaluable and retains the Corrigendum arithmetic additions. **covered** — strict extension-boundary regression plus `src/iso-arithmetic.js`. |
|
|
@@ -40,7 +40,7 @@ certification claim.
|
|
|
40
40
|
| 5.5.4 additional term types | covered | the normal JavaScript API's `stringTerm(Text)` is documented as an implementation-specific sixth term type, including disjointness, ordering, clause conversion, lack of source token syntax, expression behavior, and writing; strict program/goal entry rejects that type with `representation_error(term)` |
|
|
41
41
|
| 5.5.5 additional directives | covered | normal module/library directives are documented implementation-specific features and are rejected by strict mode |
|
|
42
42
|
| 5.5.6 additional side effects | covered | normal-profile `statistics/0-2`, cleanup/library state, proof/statistics host instrumentation, and other extension effects are documented outside the Part 1 core; strict registry tests exclude the Prolog-visible statistics/cleanup extensions. Host instrumentation is an embedding observation rather than an extra strict Prolog goal effect |
|
|
43
|
-
| 5.5.7 additional control constructs | covered | `tnot/1` and implementation-specific execution optimizations are absent/disabled in strict mode; standard control constructs remain separately audited |
|
|
43
|
+
| 5.5.7 additional control constructs | covered | `tnot/1`, `wfs_truth/2`, and implementation-specific execution optimizations are absent/disabled in strict mode; standard control constructs remain separately audited |
|
|
44
44
|
| 5.5.8 additional flags | covered | normal `occurs_check` extension is absent from strict mode; the Part 1 flag family is fully audited |
|
|
45
45
|
| 5.5.9 additional built-in predicates and error forms | covered | strict registry excludes normal-profile library/native additions; `ISO-BUILTIN-MODE-ERROR-MATRIX.md` closes the complete 8.2-8.17 family row-by-row; simultaneous-error choices are documented per 7.12 rather than treated as a global table-order mandate |
|
|
46
46
|
| 5.5.10 additional evaluable functors/types | covered | strict mode rejects the normal-profile evaluable `e` extension while retaining the full Part 1 + Corrigenda arithmetic set. `ISO-EVALUABLE-FUNCTOR-MATRIX.md` now closes the Clause 9 semantic/error audit and pins the 9.1.4.2 `resultF`, mixed-type `max/2`/`min/2`, and signed bitwise/shift choices. Post-N289 STC #75 remains separate from the published baseline |
|
|
@@ -50,7 +50,7 @@ certification claim.
|
|
|
50
50
|
|
|
51
51
|
The production audit is kept here rather than in another status file. The strict
|
|
52
52
|
regression gate covers the following families directly, while the complete WG17
|
|
53
|
-
matrix supplies
|
|
53
|
+
matrix supplies detailed externally sourced syntax expectations.
|
|
54
54
|
|
|
55
55
|
| Clause family | Disposition | Executable evidence |
|
|
56
56
|
| --- | --- | --- |
|
|
@@ -14,6 +14,10 @@ tracks the row-by-row built-in audit,
|
|
|
14
14
|
closes 7.4-7.8, [ISO-EVALUABLE-FUNCTOR-MATRIX.md](ISO-EVALUABLE-FUNCTOR-MATRIX.md)
|
|
15
15
|
closes 7.9/Clause 9, and [ISO-PROCESSOR-REQUIREMENTS.md](ISO-PROCESSOR-REQUIREMENTS.md)
|
|
16
16
|
decomposes the Clause 5 processor obligations.
|
|
17
|
+
[ISO-CORRIGENDA-MATRIX.md](ISO-CORRIGENDA-MATRIX.md) gives every published
|
|
18
|
+
Corrigenda amendment cluster an executable, editorial, or superseded
|
|
19
|
+
disposition. Built-in rows may group closely related conditions only when the
|
|
20
|
+
row names every grouped condition and its executable evidence.
|
|
17
21
|
The exit checklist is embedded in [ISO-COMPLIANCE.md](ISO-COMPLIANCE.md). [WG17-SYNTAX-STATUS.md](WG17-SYNTAX-STATUS.md) records the
|
|
18
22
|
complete one-to-one trace for the vendored active upstream WG17 syntax cases.
|
|
19
23
|
[STC-DRAFT-STATUS.md](STC-DRAFT-STATUS.md) separately tracks executable
|
|
@@ -31,9 +35,9 @@ Clause 9 evaluable functors. Public comparison material remains supporting revie
|
|
|
31
35
|
evidence rather than a duplicated vendored corpus. Cases under `iso/`
|
|
32
36
|
identify standards-derived behavior; other directories cover EyeProlog host
|
|
33
37
|
contracts and extensions. EyeProlog-only execution features such as explicit
|
|
34
|
-
tabling
|
|
38
|
+
tabling, `tnot/1` well-founded negation, and `wfs_truth/2` inspection are outside the Part 1 strict-core
|
|
35
39
|
claim. Their focused semantic coverage lives primarily in regression tests;
|
|
36
|
-
`tnot/1`
|
|
40
|
+
`tnot/1` and `wfs_truth/2` are absent from the strict ISO registry. The processor character set is documented as the Unicode scalar repertoire with
|
|
37
41
|
scalar-value collation in both normal and strict profiles; `--iso-strict`
|
|
38
42
|
therefore changes only implementation-specific language facilities, not this
|
|
39
43
|
implementation-defined processor choice.
|
package/test/run-iso-strict.mjs
CHANGED
|
@@ -28,6 +28,50 @@ export function runIsoStrict(reporter = new TestReporter()) {
|
|
|
28
28
|
equal(result.stdout, 'p(1).\n', 'stdout');
|
|
29
29
|
});
|
|
30
30
|
|
|
31
|
+
reporter.test('pins behavior-changing Technical Corrigendum 1 corrections', () => {
|
|
32
|
+
equal(run('', { isoStrict: true, goal: 'X is sqrt(0), X =:= 0.0' }).stats.completed_goal_lists,
|
|
33
|
+
1, 'non-negative square-root boundary');
|
|
34
|
+
equal(run('', {
|
|
35
|
+
isoStrict: true,
|
|
36
|
+
goal: "atom_chars('North',['N'|Tail]), Tail == [o,r,t,h]",
|
|
37
|
+
}).stats.completed_goal_lists, 1, 'atom_chars/2 accepts a supplied list prefix');
|
|
38
|
+
equal(run('', {
|
|
39
|
+
isoStrict: true,
|
|
40
|
+
goal: "atom_codes('North',[78|Tail]), Tail == [111,114,116,104]",
|
|
41
|
+
}).stats.completed_goal_lists, 1, 'atom_codes/2 accepts a supplied list prefix');
|
|
42
|
+
|
|
43
|
+
const source = [
|
|
44
|
+
':- dynamic(p/1).',
|
|
45
|
+
'p(a).',
|
|
46
|
+
'p(b).',
|
|
47
|
+
':- op(500, xfy, likes).',
|
|
48
|
+
':- set_prolog_flag(double_quotes, atom).',
|
|
49
|
+
'double_quote_operator :- (alice "likes" bob) = likes(alice,bob).',
|
|
50
|
+
'',
|
|
51
|
+
].join('\n');
|
|
52
|
+
equal(run(source, { isoStrict: true, goal: 'clause(p(X),true), X == a' }).stats.completed_goal_lists,
|
|
53
|
+
1, 'clause/2 unifies the selected clause');
|
|
54
|
+
equal(run(source, { isoStrict: true, goal: 'current_op(500,xfy,likes)' }).stats.completed_goal_lists,
|
|
55
|
+
1, 'current_op/3 unifies the selected operator');
|
|
56
|
+
equal(run(source, { isoStrict: true, goal: 'double_quote_operator' }).stats.completed_goal_lists,
|
|
57
|
+
1, 'double-quoted atom receives its operator priority');
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
reporter.test('pins behavior-changing Technical Corrigendum 3 corrections', () => {
|
|
61
|
+
const trailingLayout = Program.parse('p.\n % trailing layout is a complete Prolog text\n', {
|
|
62
|
+
isoStrict: true,
|
|
63
|
+
});
|
|
64
|
+
equal(Boolean(trailingLayout.findGroup('p', 0)), true, 'optional final layout text');
|
|
65
|
+
|
|
66
|
+
const written = run('', {
|
|
67
|
+
isoStrict: true,
|
|
68
|
+
goal: "write_term(pair(X,X),[variable_names(['Named'=X])])",
|
|
69
|
+
});
|
|
70
|
+
includes(written.stdout, 'pair(Named,Named)', 'write variable_names/1');
|
|
71
|
+
equal(capture(() => run('', { isoStrict: true, goal: 'X is 2^(-1)' })).formal,
|
|
72
|
+
'type_error(float)', 'negative integer exponent correction');
|
|
73
|
+
});
|
|
74
|
+
|
|
31
75
|
reporter.test('keeps Corrigendum 2 core predicates and excludes Part 3 phrase', () => {
|
|
32
76
|
const registry = createStrictIsoRegistry();
|
|
33
77
|
equal(Boolean(registry.get('subsumes_term', 2)), true, 'subsumes_term/2');
|
package/test/run-regression.mjs
CHANGED
|
@@ -2404,6 +2404,7 @@ c4 ?- call((!;1)).
|
|
|
2404
2404
|
assertIncludes(result.stdout, '-g, --goal goal', 'stdout');
|
|
2405
2405
|
assertIncludes(result.stdout, '-p, --proof', 'stdout');
|
|
2406
2406
|
assertIncludes(result.stdout, '-q, --quads', 'stdout');
|
|
2407
|
+
assertIncludes(result.stdout, '--quiet', 'stdout');
|
|
2407
2408
|
assertIncludes(result.stdout, '-s, --stats', 'stdout');
|
|
2408
2409
|
assertIncludes(result.stdout, '--portable', 'stdout');
|
|
2409
2410
|
assertIncludes(result.stdout, '--no-autoload', 'stdout');
|
|
@@ -3821,6 +3822,19 @@ child.stdin.write(\`consult(${consultedAtom}).\\n\`);
|
|
|
3821
3822
|
assertEqual(result.stderr, '', 'stderr');
|
|
3822
3823
|
},
|
|
3823
3824
|
},
|
|
3825
|
+
{
|
|
3826
|
+
name: '--quiet preserves goal side effects without printing answer terms',
|
|
3827
|
+
run: () => {
|
|
3828
|
+
const input = 'emit :- write(side_effect), nl.\n';
|
|
3829
|
+
const quiet = runCli(['--quiet', '--goal', 'emit', '-'], { input });
|
|
3830
|
+
assertEqual(quiet.status, 0, 'quiet exit status');
|
|
3831
|
+
assertEqual(quiet.stdout, 'side_effect\n', 'quiet stdout');
|
|
3832
|
+
assertEqual(quiet.stderr, '', 'quiet stderr');
|
|
3833
|
+
|
|
3834
|
+
const ordinary = runCli(['--goal', 'emit', '-'], { input });
|
|
3835
|
+
assertEqual(ordinary.stdout, 'side_effect\nemit.\n', 'ordinary answer output remains unchanged');
|
|
3836
|
+
},
|
|
3837
|
+
},
|
|
3824
3838
|
{
|
|
3825
3839
|
name: '-g requires a goal argument',
|
|
3826
3840
|
run: () => {
|
|
@@ -5271,6 +5285,34 @@ ${profile}`;
|
|
|
5271
5285
|
assertIncludes(arithmetic, '`float_integer_part/1`, `float_fractional_part/1`', 'float-only conversion row');
|
|
5272
5286
|
},
|
|
5273
5287
|
},
|
|
5288
|
+
{
|
|
5289
|
+
name: 'published ISO Corrigenda have a complete stable audit inventory',
|
|
5290
|
+
run: () => {
|
|
5291
|
+
const compliance = fs.readFileSync(path.join(testRoot, 'conformance', 'ISO-COMPLIANCE.md'), 'utf8');
|
|
5292
|
+
const matrix = fs.readFileSync(path.join(testRoot, 'conformance', 'ISO-CORRIGENDA-MATRIX.md'), 'utf8');
|
|
5293
|
+
const expected = [
|
|
5294
|
+
...Array.from({ length: 18 }, (_, index) => `C1-${String(index + 1).padStart(2, '0')}`),
|
|
5295
|
+
...Array.from({ length: 23 }, (_, index) => `C2-${String(index + 1).padStart(2, '0')}`),
|
|
5296
|
+
...Array.from({ length: 19 }, (_, index) => `C3-${String(index + 1).padStart(2, '0')}`),
|
|
5297
|
+
];
|
|
5298
|
+
const rows = matrix.split('\n')
|
|
5299
|
+
.filter((line) => /^\| C[123]-\d\d \|/.test(line))
|
|
5300
|
+
.map((line) => line.split('|').slice(1, -1).map((cell) => cell.trim()));
|
|
5301
|
+
assertEqual(rows.map(([id]) => id).join(','), expected.join(','), 'Corrigenda stable audit IDs');
|
|
5302
|
+
for (const [id, clauses, disposition, evidence] of rows) {
|
|
5303
|
+
assertEqual(Boolean(clauses), true, `${id} clause/amendment cluster`);
|
|
5304
|
+
assertEqual(['covered', 'editorial', 'superseded'].includes(disposition), true, `${id} disposition`);
|
|
5305
|
+
assertEqual(Boolean(evidence), true, `${id} evidence`);
|
|
5306
|
+
if (disposition === 'covered') {
|
|
5307
|
+
assertEqual(/test|WG17|strict|case/i.test(evidence), true, `${id} executable evidence`);
|
|
5308
|
+
}
|
|
5309
|
+
}
|
|
5310
|
+
assertIncludes(compliance, '[ISO-CORRIGENDA-MATRIX.md](ISO-CORRIGENDA-MATRIX.md)', 'Corrigenda matrix link');
|
|
5311
|
+
for (const corrigendum of ['Corrigendum 1', 'Corrigendum 2', 'Corrigendum 3']) {
|
|
5312
|
+
assertIncludes(compliance, `| ${corrigendum} | covered |`, `${corrigendum} covered row`);
|
|
5313
|
+
}
|
|
5314
|
+
},
|
|
5315
|
+
},
|
|
5274
5316
|
{
|
|
5275
5317
|
name: 'ISO 7.4-7.8 execution matrix is closed',
|
|
5276
5318
|
run: () => {
|
|
@@ -5299,6 +5341,16 @@ ${profile}`;
|
|
|
5299
5341
|
]) assertIncludes(compliance, row, row);
|
|
5300
5342
|
assertIncludes(processor, '## Clause 6 syntax-preservation closure', 'Clause 6 closure map');
|
|
5301
5343
|
assertIncludes(processor, '| 5.5.1 syntax extensions preserve standard token/text meaning | covered |', '5.5.1 covered');
|
|
5344
|
+
|
|
5345
|
+
const boundary = compliance.slice(
|
|
5346
|
+
compliance.indexOf('## Strict-core boundary'),
|
|
5347
|
+
compliance.indexOf('## Release gate'),
|
|
5348
|
+
);
|
|
5349
|
+
assertIncludes(boundary, '`wfs_truth/2`', 'strict boundary includes wfs_truth/2');
|
|
5350
|
+
assertIncludes(boundary, 'integer digit separators', 'strict boundary includes digit separators');
|
|
5351
|
+
assertIncludes(boundary, '`"text"||Tail`', 'strict boundary includes double-bar list splicing');
|
|
5352
|
+
assertEqual((boundary.match(/`tnot\/1`/g) ?? []).length, 1, 'strict boundary lists tnot/1 once');
|
|
5353
|
+
assertEqual(compliance.includes('`stringTerm/1` term type'), false, 'JavaScript stringTerm uses call notation');
|
|
5302
5354
|
},
|
|
5303
5355
|
},
|
|
5304
5356
|
{
|
|
@@ -5311,7 +5363,7 @@ ${profile}`;
|
|
|
5311
5363
|
'| Clause 7 semantic requirements have explicit dispositions | covered |',
|
|
5312
5364
|
'| Clause 8 built-in modes/errors have explicit dispositions | covered |',
|
|
5313
5365
|
'| Clause 9 evaluable-functor requirements have explicit dispositions | covered |',
|
|
5314
|
-
'|
|
|
5366
|
+
'| Externally sourced syntax corpus is an offline release gate | covered |',
|
|
5315
5367
|
'| No unexplained deviation remains in the release-facing ledger | covered |',
|
|
5316
5368
|
]) assertIncludes(exit, item, item);
|
|
5317
5369
|
assertNotIncludes(exit, '| audit |', 'no release-facing audit rows remain');
|
|
@@ -6726,7 +6778,7 @@ answer(ok) :-
|
|
|
6726
6778
|
assertEqual(Boolean(registry.get('is', 2)), true, 'ISO is/2 exists');
|
|
6727
6779
|
assertEqual(Boolean(registry.get('append', 3)), false, 'append/3 is not ISO core');
|
|
6728
6780
|
assertEqual(library.eyePrologLibrary, true, 'complete registry marker');
|
|
6729
|
-
assertEqual(library.defs.size,
|
|
6781
|
+
assertEqual(library.defs.size, 222, 'EyeProlog registry contains ISO definitions, cleanup controls, observability extensions, WFS predicates, and generic library adapters');
|
|
6730
6782
|
assertEqual(registry.get('eyeprolog__dynify', 1), null, 'Eyelet dynify adapter is absent from the ISO registry');
|
|
6731
6783
|
assertEqual(Boolean(library.get('eyeprolog__dynify', 1)), true, 'Eyelet dynify adapter is an internal EyeProlog library primitive');
|
|
6732
6784
|
assertEqual(registry.get('eyeprolog__eyelet_emit', 2), null, 'Eyelet event adapter is absent from the ISO registry');
|
|
@@ -6743,6 +6795,8 @@ answer(ok) :-
|
|
|
6743
6795
|
assertEqual(Boolean(library.get('statistics', 2)), true, 'statistics/2 is an EyeProlog observability extension');
|
|
6744
6796
|
assertEqual(registry.get('tnot', 1), null, 'tnot/1 is absent from the ISO registry');
|
|
6745
6797
|
assertEqual(Boolean(library.get('tnot', 1)), true, 'tnot/1 is an EyeProlog WFS extension');
|
|
6798
|
+
assertEqual(registry.get('wfs_truth', 2), null, 'wfs_truth/2 is absent from the ISO registry');
|
|
6799
|
+
assertEqual(Boolean(library.get('wfs_truth', 2)), true, 'wfs_truth/2 is an EyeProlog WFS extension');
|
|
6746
6800
|
assertEqual(registry.get('time', 1), null, 'time/1 is absent from the ISO registry');
|
|
6747
6801
|
assertEqual(Boolean(library.get('time', 1)), true, 'time/1 is an EyeProlog timing extension');
|
|
6748
6802
|
assertEqual(registry.get('dif', 2), null, 'dif/2 is absent from the strict ISO core registry');
|
|
@@ -7807,6 +7861,50 @@ undefined_case :- tnot(win(c)).
|
|
|
7807
7861
|
assertEqual(run(source, { goal: 'undefined_case' }).stdout, '', 'tnot of an undefined WFS atom is not a successful answer');
|
|
7808
7862
|
},
|
|
7809
7863
|
},
|
|
7864
|
+
{
|
|
7865
|
+
name: 'wfs_truth exposes three-valued results without executing undefined goals',
|
|
7866
|
+
run: () => {
|
|
7867
|
+
const source = `
|
|
7868
|
+
:- use_module(library(tabling)).
|
|
7869
|
+
:- table(win/1).
|
|
7870
|
+
move(a, b).
|
|
7871
|
+
move(c, d).
|
|
7872
|
+
move(d, c).
|
|
7873
|
+
win(X) :- move(X, Y), tnot(win(Y)).
|
|
7874
|
+
`;
|
|
7875
|
+
assertEqual(run(source, { goal: 'wfs_truth(win(a), Truth)' }).stdout,
|
|
7876
|
+
'wfs_truth(win(a), true).\n', 'true WFS atom');
|
|
7877
|
+
assertEqual(run(source, { goal: 'wfs_truth(win(b), Truth)' }).stdout,
|
|
7878
|
+
'wfs_truth(win(b), false).\n', 'false WFS atom');
|
|
7879
|
+
const undefinedResult = run(source, { goal: 'wfs_truth(win(c), Truth)' });
|
|
7880
|
+
assertEqual(undefinedResult.stdout, 'wfs_truth(win(c), undefined).\n', 'undefined WFS atom');
|
|
7881
|
+
assertEqual(undefinedResult.stats.wfs_undefined_answers, 1, 'undefined truth inspection is counted');
|
|
7882
|
+
assertEqual(run(source, { goal: 'wfs_truth(win(c), true)' }).stdout, '', 'truth filter can reject undefined');
|
|
7883
|
+
let nongroundError = null;
|
|
7884
|
+
try {
|
|
7885
|
+
run(source, { goal: 'wfs_truth(win(X), Truth)' });
|
|
7886
|
+
} catch (error) {
|
|
7887
|
+
nongroundError = error;
|
|
7888
|
+
}
|
|
7889
|
+
assertEqual(nongroundError?.formal, 'instantiation_error', 'inspected goal must be ground');
|
|
7890
|
+
|
|
7891
|
+
const moduleSource = `
|
|
7892
|
+
:- module(cycle, [status/1]).
|
|
7893
|
+
:- use_module(library(tabling)).
|
|
7894
|
+
:- table(a/0).
|
|
7895
|
+
:- table(b/0).
|
|
7896
|
+
a :- tnot(b).
|
|
7897
|
+
b :- tnot(a).
|
|
7898
|
+
status(Truth) :- wfs_truth(a, Truth).
|
|
7899
|
+
`;
|
|
7900
|
+
assertEqual(run(moduleSource, { goal: 'cycle:status(Truth)' }).stdout,
|
|
7901
|
+
'cycle:status(undefined).\n', 'lexical module qualification');
|
|
7902
|
+
assertEqual(run(moduleSource, { goal: 'wfs_truth(cycle:a, Truth)' }).stdout,
|
|
7903
|
+
'wfs_truth(cycle:a, undefined).\n', 'explicit module qualification');
|
|
7904
|
+
assertEqual(run(moduleSource, { goal: 'tnot(cycle:a)' }).stdout, '',
|
|
7905
|
+
'qualified tnot preserves undefined failure');
|
|
7906
|
+
},
|
|
7907
|
+
},
|
|
7810
7908
|
{
|
|
7811
7909
|
name: 'undefined WFS goals do not run continuations or print CLI answers',
|
|
7812
7910
|
run: () => {
|
package/the-art-of-eyeprolog.md
CHANGED
|
@@ -1147,6 +1147,16 @@ Here neither `win(a)` nor `win(b)` is unconditionally established; both belong
|
|
|
1147
1147
|
to the undefined part of the well-founded model. EyeProlog retains that state
|
|
1148
1148
|
internally but does not expose undefined atoms as successful query answers or
|
|
1149
1149
|
run the remaining goals of a conjunction through them.
|
|
1150
|
+
Use `wfs_truth/2` when the truth state itself is data:
|
|
1151
|
+
|
|
1152
|
+
```text
|
|
1153
|
+
?- wfs_truth(win(a), Truth).
|
|
1154
|
+
Truth = undefined.
|
|
1155
|
+
```
|
|
1156
|
+
|
|
1157
|
+
The inspected goal must be ground. The predicate reports `true`, `false`, or
|
|
1158
|
+
`undefined`; reporting `undefined` is a successful result of `wfs_truth/2`, not
|
|
1159
|
+
a successful execution of the inspected goal.
|
|
1150
1160
|
Direct calls to `tnot/1` must be ground. In WFS rules, variables occurring in
|
|
1151
1161
|
the head or a negated literal must be range-restricted by positive body
|
|
1152
1162
|
literals. Ordinary `\+/1` is unchanged, and strict ISO mode does not provide
|
|
@@ -5951,8 +5961,9 @@ declaration; they never opt an undeclared predicate into tabling.
|
|
|
5951
5961
|
|
|
5952
5962
|
Ordinary `\+/1` remains ISO-style negation as failure. The separate `tnot/1`
|
|
5953
5963
|
extension explicitly requests well-founded evaluation for eligible finite,
|
|
5954
|
-
range-restricted Datalog dependencies.
|
|
5955
|
-
|
|
5964
|
+
range-restricted Datalog dependencies. `wfs_truth/2` reports the three-valued
|
|
5965
|
+
state of a ground callable as `true`, `false`, or `undefined`. Strict ISO mode
|
|
5966
|
+
exposes none of `table`, `tnot/1`, or `wfs_truth/2`.
|
|
5956
5967
|
|
|
5957
5968
|
#### Query execution
|
|
5958
5969
|
|
|
@@ -6359,9 +6370,9 @@ or observability. The ISO and library catalogs therefore cover **523 distinct pr
|
|
|
6359
6370
|
re-exported by a compatibility module is counted once in this library surface:
|
|
6360
6371
|
for example `call_cleanup/2` and `setup_call_cleanup/3` are exported by
|
|
6361
6372
|
`library(iso_ext)`, while `time/1` and `statistics/2` are available from
|
|
6362
|
-
`library(time)`. `statistics/0` and `
|
|
6363
|
-
outside the library catalog. These additions are
|
|
6364
|
-
registry.
|
|
6373
|
+
`library(time)`. `statistics/0`, `tnot/1`, and `wfs_truth/2` remain
|
|
6374
|
+
normal-runtime extensions outside the library catalog. These additions are
|
|
6375
|
+
absent from the strict ISO registry.
|
|
6365
6376
|
|
|
6366
6377
|
The sources are `src/lib/aggregate.pl`, `src/lib/arithmetic.pl`,
|
|
6367
6378
|
`src/lib/assoc.pl`, `src/lib/atts.pl`, `src/lib/between.pl`,
|
|
@@ -9375,6 +9386,8 @@ eyeprolog --goal 'ancestor(ada, Who)' examples/ancestor.pl
|
|
|
9375
9386
|
|
|
9376
9387
|
Repeat `-g` or `--goal` to request several result relations in one run. EyeProlog prints
|
|
9377
9388
|
their ground answers in the order the goals were supplied.
|
|
9389
|
+
Use `--quiet` for command-style goals: Prolog output such as `write/1` remains
|
|
9390
|
+
visible, while the resolved answer terms are suppressed.
|
|
9378
9391
|
|
|
9379
9392
|
For a self-running example, place the host goal in an ordinary comment:
|
|
9380
9393
|
|
|
@@ -9396,6 +9409,7 @@ make the observed question explicit.
|
|
|
9396
9409
|
| `--proof-detail abstract|expanded` | Select library abstraction for proof output; implies `--proof` |
|
|
9397
9410
|
| `--verify-proof File` | Verify saved `why/2` proof certificates against the input program without proof search |
|
|
9398
9411
|
| `-q`, `--quads` | Run embedded quad tests and fail if any do not hold |
|
|
9412
|
+
| `--quiet` | Suppress resolved answer terms while preserving Prolog output and diagnostics |
|
|
9399
9413
|
| `--iso-strict` | Restrict parsing and execution to ISO/IEC 13211-1:1995 + Corrigenda 1–3; reject EyeProlog language extensions (including `table` and `:+`) and disable bundled-library autoloading |
|
|
9400
9414
|
| `--portable` | Enforce the conservative EyeProlog/Trealla/Scryer interoperability profile |
|
|
9401
9415
|
| `--no-autoload` | Disable bundled-library predicate autoloading |
|