eyeprolog 1.3.55 → 1.3.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/package.json +1 -1
- package/src/iso.js +14 -4
- package/src/program.js +22 -1
- package/src/solver.js +22 -1
- package/test/conformance/ISO-BUILTIN-MODE-ERROR-MATRIX.md +205 -0
- package/test/conformance/ISO-COMPLIANCE.md +36 -10
- package/test/conformance/ISO-IMPLEMENTATION-DEFINED.md +1 -1
- package/test/conformance/ISO-MATRIX.md +5 -5
- package/test/conformance/ISO-PROCESSOR-REQUIREMENTS.md +55 -0
- package/test/conformance/README.md +8 -6
- package/test/run-iso-strict.mjs +170 -0
package/package.json
CHANGED
package/src/iso.js
CHANGED
|
@@ -590,12 +590,22 @@ function requireClauseHead(head) {
|
|
|
590
590
|
if (head.type !== ATOM && head.type !== COMPOUND) throw new PrologError('type_error(callable)', head);
|
|
591
591
|
}
|
|
592
592
|
|
|
593
|
-
function convertAssertedBody(term) {
|
|
593
|
+
function convertAssertedBody(term, culprit = term) {
|
|
594
594
|
if (term.type === VAR) return compound('call', [term]);
|
|
595
|
-
|
|
596
|
-
|
|
595
|
+
// ISO 7.6.2 converts each argument of conjunction, disjunction, and if-then
|
|
596
|
+
// recursively when a term is converted to a clause body. This matters for
|
|
597
|
+
// variables (which become call(Var)) and for invalid nested terms, which
|
|
598
|
+
// must be rejected while assert[az]/1 performs the conversion rather than
|
|
599
|
+
// being stored and failing only if that branch is later executed.
|
|
600
|
+
if (term.type === COMPOUND && [',', ';', '->'].includes(term.name) && term.arity === 2) {
|
|
601
|
+
return compound(term.name, [
|
|
602
|
+
convertAssertedBody(term.args[0], culprit),
|
|
603
|
+
convertAssertedBody(term.args[1], culprit),
|
|
604
|
+
]);
|
|
605
|
+
}
|
|
606
|
+
if (term.type !== ATOM && term.type !== COMPOUND) {
|
|
607
|
+
throw new PrologError('type_error(callable)', culprit);
|
|
597
608
|
}
|
|
598
|
-
if (term.type !== ATOM && term.type !== COMPOUND) throw new PrologError('type_error(callable)', term);
|
|
599
609
|
return term;
|
|
600
610
|
}
|
|
601
611
|
|
package/src/program.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Program representation and clause indexing.
|
|
2
2
|
// Indexes are deliberately conservative: they speed up common scalar arguments but never replace unification as the final check.
|
|
3
|
-
import { ATOM, COMPOUND, VAR, Env, atom, compound, deref, flattenConjunction, isScalar, numberTerm, properListItems, termToString, variable } from './term.js';
|
|
3
|
+
import { ATOM, COMPOUND, STRING, VAR, Env, atom, compound, deref, flattenConjunction, isScalar, numberTerm, properListItems, termToString, variable } from './term.js';
|
|
4
4
|
import { formatTermForWrite } from './write.js';
|
|
5
5
|
import {
|
|
6
6
|
ISO_OPERATOR_DEFINITIONS,
|
|
@@ -33,6 +33,21 @@ import {
|
|
|
33
33
|
const DEFER_PROGRAM_BUILD = Symbol('deferProgramBuild');
|
|
34
34
|
const FAST_PARSE_ABORT = Symbol('fastParseAbort');
|
|
35
35
|
const PROGRAM_BUILD_BATCH_SIZE = 16384;
|
|
36
|
+
|
|
37
|
+
function termContainsStringExtension(term, seen = new Set()) {
|
|
38
|
+
if (term == null || typeof term !== 'object' || seen.has(term)) return false;
|
|
39
|
+
seen.add(term);
|
|
40
|
+
if (term.type === STRING) return true;
|
|
41
|
+
if (term.type === COMPOUND) return term.args.some((arg) => termContainsStringExtension(arg, seen));
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function clauseContainsStringExtension(clause) {
|
|
46
|
+
if (clause == null) return false;
|
|
47
|
+
if (clause.head0Type === STRING || clause.head1Type === STRING) return true;
|
|
48
|
+
if (termContainsStringExtension(clause.head) || termContainsStringExtension(clause.query)) return true;
|
|
49
|
+
return Array.isArray(clause.body) && clause.body.some((goal) => termContainsStringExtension(goal));
|
|
50
|
+
}
|
|
36
51
|
export class Program {
|
|
37
52
|
constructor(clauses = [], options = {}) {
|
|
38
53
|
this.clauses = [];
|
|
@@ -574,6 +589,12 @@ class ProgramBuilder {
|
|
|
574
589
|
let lastGroup = this.lastGroup;
|
|
575
590
|
|
|
576
591
|
for (const clause of clauses) {
|
|
592
|
+
if (program.strictIso && clauseContainsStringExtension(clause)) {
|
|
593
|
+
// Programmatic clauses are part of the public embedding surface. The
|
|
594
|
+
// normal profile permits its host string term extension, but the Part 1
|
|
595
|
+
// strict profile must reject that implementation-specific sixth type.
|
|
596
|
+
throw new PrologError('representation_error(term)');
|
|
597
|
+
}
|
|
577
598
|
if (clause?.kind === 'quad') {
|
|
578
599
|
const module = clause.module ?? 'user';
|
|
579
600
|
annotateGoalModule(clause.query, module);
|
package/src/solver.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Depth-first EyeProlog solver with builtin dispatch, memoization, and guarded recursion handling.
|
|
2
2
|
// Most semantic decisions still flow through unification; optimizations only select candidates earlier.
|
|
3
3
|
import {
|
|
4
|
-
ATOM, COMPOUND, NUMBER, VAR, Env, compactListLength, compactVariableList, compound, cons, copyResolved, deref, emptyList,
|
|
4
|
+
ATOM, COMPOUND, NUMBER, STRING, VAR, Env, compactListLength, compactVariableList, compound, cons, copyResolved, deref, emptyList,
|
|
5
5
|
flattenConjunction, freshTerm, isCons, isDecimalInteger, isEmptyList,
|
|
6
6
|
numberTerm, numberTextFromDouble, termIsGround, termToString, unify, variable, variantTerms,
|
|
7
7
|
} from './term.js';
|
|
@@ -45,6 +45,26 @@ function raiseOccursCheckError(left, right, env) {
|
|
|
45
45
|
throw error;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
|
|
49
|
+
function rejectStrictIsoStringTerms(terms, env) {
|
|
50
|
+
const seen = new Set();
|
|
51
|
+
const visit = (term) => {
|
|
52
|
+
const resolved = deref(term, env);
|
|
53
|
+
if (resolved == null || seen.has(resolved)) return;
|
|
54
|
+
seen.add(resolved);
|
|
55
|
+
if (resolved.type === STRING) {
|
|
56
|
+
// `stringTerm()` is a normal-profile host/API term extension. It has no
|
|
57
|
+
// Part 1 abstract/token syntax, so strict execution must reject it rather
|
|
58
|
+
// than silently introducing a sixth term type through the embedding API.
|
|
59
|
+
throw new PrologError('representation_error(term)');
|
|
60
|
+
}
|
|
61
|
+
if (resolved.type === COMPOUND) {
|
|
62
|
+
for (const arg of resolved.args) visit(arg);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
for (const term of terms) visit(term);
|
|
66
|
+
}
|
|
67
|
+
|
|
48
68
|
export class Solver {
|
|
49
69
|
constructor(program, options = {}) {
|
|
50
70
|
this.program = program;
|
|
@@ -301,6 +321,7 @@ export class Solver {
|
|
|
301
321
|
*solve(goals, env = new Env(), depth = 0) {
|
|
302
322
|
if (!Array.isArray(goals)) goals = [goals];
|
|
303
323
|
env.setOccursCheckHandler(this.occursCheckHandler);
|
|
324
|
+
if (this.isoStrict) rejectStrictIsoStringTerms(goals, env);
|
|
304
325
|
|
|
305
326
|
const writeVariableState = this.writeVariableState;
|
|
306
327
|
if (writeVariableState.depth === 0) {
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
# ISO Part 1 built-in mode/error audit
|
|
2
|
+
|
|
3
|
+
This matrix turns the broad built-in audit in `ISO-COMPLIANCE.md` into smaller,
|
|
4
|
+
release-gated units. The normative baseline is ISO/IEC 13211-1:1995 plus
|
|
5
|
+
Technical Corrigenda 1:2007, 2:2012, and 3:2017.
|
|
6
|
+
|
|
7
|
+
A `covered` row has an executable assertion for the prescribed successful mode,
|
|
8
|
+
failure behavior, or error condition. `not applicable` records a conditional
|
|
9
|
+
standard branch that cannot occur under EyeProlog's documented processor
|
|
10
|
+
choices. The table is intentionally explicit about what has and has not been
|
|
11
|
+
closed: this tranche row-audits 8.2-8.5 and 8.15-8.17; 8.6-8.14 remain under
|
|
12
|
+
the broader audit and will be expanded in later passes.
|
|
13
|
+
|
|
14
|
+
The focused assertions added for this matrix live in `test/run-iso-strict.mjs`;
|
|
15
|
+
existing file-based cases remain additional independent evidence.
|
|
16
|
+
|
|
17
|
+
## 8.2 — term unification
|
|
18
|
+
|
|
19
|
+
| Clause / predicate | Prescribed row | Status | Executable evidence |
|
|
20
|
+
| --- | --- | --- | --- |
|
|
21
|
+
| 8.2.1 `(=)/2` | `?term, ?term`; succeeds/fails according to Prolog unification; no prescribed errors | covered | existing unification corpus and `term_modes_and_ordering` |
|
|
22
|
+
| 8.2.2 `unify_with_occurs_check/2` | `?term, ?term`; succeeds/fails and never reports a prescribed error | covered | strict row-audit success assertion plus unification corpus |
|
|
23
|
+
| 8.2.3 `(\=)/2` | `@term, @term`; succeeds/fails for the defined NSTO cases; no prescribed errors | covered | unification/control corpus |
|
|
24
|
+
| Cor.2 8.2.4 `subsumes_term/2` | `@term, @term`; succeeds/fails without binding its arguments; no prescribed errors | covered | strict row-audit success assertion and Corrigendum 2 term-predicate cases |
|
|
25
|
+
|
|
26
|
+
## 8.3 — type testing
|
|
27
|
+
|
|
28
|
+
All Part 1 type tests have a single input-term mode and no prescribed errors.
|
|
29
|
+
The Corrigendum 2 additions have the same shape.
|
|
30
|
+
|
|
31
|
+
| Predicate | Prescribed row | Status | Executable evidence |
|
|
32
|
+
| --- | --- | --- | --- |
|
|
33
|
+
| `var/1` | input term; semidet; no errors | covered | `type_var_success` and term-mode cases |
|
|
34
|
+
| `atom/1` | input term; semidet; no errors | covered | `type_atom_success` |
|
|
35
|
+
| `integer/1` | input term; semidet; no errors | covered | `type_integer_success` |
|
|
36
|
+
| `float/1` | input term; semidet; no errors | covered | `type_float_success` |
|
|
37
|
+
| `atomic/1` | input term; semidet; no errors | covered | `type_atomic_atom_success`, `type_atomic_number_success` |
|
|
38
|
+
| `compound/1` | input term; semidet; no errors | covered | `type_compound_success` |
|
|
39
|
+
| `nonvar/1` | input term; semidet; no errors | covered | `type_nonvar_success` |
|
|
40
|
+
| `number/1` | input term; semidet; no errors | covered | `type_number_integer_success`, `type_number_float_success` |
|
|
41
|
+
| Cor.2 `callable/1` | input term; semidet; no errors | covered | `type_callable_atom_success`, `type_callable_compound_success` |
|
|
42
|
+
| Cor.2 `ground/1` | input term; semidet; no errors | covered | `type_ground_success` |
|
|
43
|
+
| Cor.2 `acyclic_term/1` | input term; semidet; no errors | covered | Corrigendum 2 term-predicate coverage |
|
|
44
|
+
|
|
45
|
+
## 8.4 — term comparison and sorting
|
|
46
|
+
|
|
47
|
+
| Clause / predicate | Prescribed row | Status | Executable evidence |
|
|
48
|
+
| --- | --- | --- | --- |
|
|
49
|
+
| 8.4.1 `(@<)/2` | two input terms; semidet; no prescribed errors | covered | standard-order corpus and strict type/collation ordering assertions |
|
|
50
|
+
| 8.4.1 `(@=<)/2` | two input terms; semidet; no prescribed errors | covered | standard-order corpus |
|
|
51
|
+
| 8.4.1 `(==)/2` | two input terms; identity test; no prescribed errors | covered | identity/term-mode corpus |
|
|
52
|
+
| 8.4.1 `(\==)/2` | two input terms; non-identity test; no prescribed errors | covered | identity/term-mode corpus |
|
|
53
|
+
| 8.4.1 `(@>)/2` | two input terms; semidet; no prescribed errors | covered | standard-order corpus |
|
|
54
|
+
| 8.4.1 `(@>=)/2` | two input terms; semidet; no prescribed errors | covered | standard-order corpus |
|
|
55
|
+
| Cor.2 8.4.2 `compare/3` | output-order mode | covered | strict `compare(<,a,b)` / comparison cases |
|
|
56
|
+
| Cor.2 8.4.2 `compare/3` | input-order mode | covered | comparison cases |
|
|
57
|
+
| Cor.2 8.4.2 error (a) | non-variable, non-atom `Order` -> atom type error | covered | strict `compare(1,3,3.0)` |
|
|
58
|
+
| Cor.2 8.4.2 error (b) | atom outside `<`, `=`, `>` -> order domain error | covered | strict `compare(>=,3,3.0)` |
|
|
59
|
+
| Cor.2 8.4.3 `sort/2` | input list -> output list | covered | strict `sort([1,1],[1])` and sorting corpus |
|
|
60
|
+
| Cor.2 8.4.3 `sort/2` | input list + input result list | covered | sorting corpus |
|
|
61
|
+
| Cor.2 8.4.3 error (a) | partial input list -> instantiation error | covered | strict `sort([1|T],_)` |
|
|
62
|
+
| Cor.2 8.4.3 error (b) | non-list input -> list type error | covered | strict `sort(foo,_)` |
|
|
63
|
+
| Cor.2 8.4.3 error (c) | non-list result -> list type error | covered | strict `sort([],foo)` |
|
|
64
|
+
| Cor.2 8.4.4 `keysort/2` | input pairs -> output list | covered | strict `keysort([2-b,1-a],[1-a,2-b])` and Corrigendum cases |
|
|
65
|
+
| Cor.2 8.4.4 `keysort/2` | input pairs + input result list | covered | Corrigendum cases |
|
|
66
|
+
| Cor.2 8.4.4 error (a) | partial `Pairs` -> instantiation error | covered | strict `keysort([1-a|T],_)` |
|
|
67
|
+
| Cor.2 8.4.4 error (b) | non-list `Pairs` -> list type error | covered | strict `keysort(foo,_)` |
|
|
68
|
+
| Cor.2 8.4.4 error (c) | non-list `Sorted` -> list type error | covered | strict `keysort([],foo)` |
|
|
69
|
+
| Cor.2 8.4.4 error (d) | variable element in `Pairs` prefix -> instantiation error | covered | strict `keysort([X],_)` |
|
|
70
|
+
| Cor.2 8.4.4 error (e) | non-pair element in `Pairs` prefix -> pair type error | covered | strict `keysort([foo],_)` |
|
|
71
|
+
| Cor.2 8.4.4 error (f) | non-pair element in `Sorted` prefix -> pair type error | covered | strict `keysort([],[foo])` |
|
|
72
|
+
|
|
73
|
+
## 8.5 — term creation and decomposition
|
|
74
|
+
|
|
75
|
+
| Clause / predicate | Prescribed row | Status | Executable evidence |
|
|
76
|
+
| --- | --- | --- | --- |
|
|
77
|
+
| 8.5.1 `functor/3` | decompose a non-variable term | covered | term-construction corpus |
|
|
78
|
+
| 8.5.1 `functor/3` | construct from `Name` and `Arity` | covered | term-construction corpus |
|
|
79
|
+
| 8.5.1 errors (a-b) | missing required `Name` or `Arity` when constructing -> instantiation error | covered | strict `functor(X,Y,3)` and `functor(X,foo,N)` |
|
|
80
|
+
| 8.5.1 error (c) | non-atomic `Name` -> atomic type error | covered | strict `functor(X,foo(a),a)` precedence case |
|
|
81
|
+
| 8.5.1 error (d) | non-integer `Arity` -> integer type error | covered | strict `functor(X,foo,a)` |
|
|
82
|
+
| 8.5.1 error (e) | positive arity with non-atom atomic name -> atom type error | covered | strict `functor(X,1.5,1)` |
|
|
83
|
+
| 8.5.1 error (f) | requested arity above finite `max_arity` | not applicable | EyeProlog selects `max_arity=unbounded`; finite host exhaustion is a resource condition |
|
|
84
|
+
| 8.5.1 error (g) | negative `Arity` -> non-negative domain error | covered | strict `functor(X,foo,-1)` |
|
|
85
|
+
| 8.5.2 `arg/3` | positive integer index + compound term | covered | `logtalk_arg_unification` and strict cases |
|
|
86
|
+
| 8.5.2 error (a) | variable index -> instantiation error | covered | strict `arg(X,foo(a),_)` |
|
|
87
|
+
| 8.5.2 error (b) | variable term -> instantiation error | covered | strict `arg(1,X,_)` |
|
|
88
|
+
| 8.5.2 error (c) | non-integer index -> integer type error | covered | strict `arg(a,foo(a),_)` |
|
|
89
|
+
| 8.5.2 error (d) | non-compound term -> compound type error | covered | strict `arg(0,atom,_)` precedence case |
|
|
90
|
+
| 8.5.2 error (e) | negative index -> non-negative domain error | covered | strict `arg(-1,foo(a),_)` |
|
|
91
|
+
| 8.5.3 `(=..)/2` | term -> list decomposition | covered | `logtalk_univ` and term-construction cases |
|
|
92
|
+
| 8.5.3 `(=..)/2` | list -> term construction | covered | `logtalk_univ` and term-construction cases |
|
|
93
|
+
| 8.5.3 error (a) | both arguments insufficiently instantiated | covered | strict `X=..Y` |
|
|
94
|
+
| 8.5.3 error (b) | partial list in construction direction | covered | strict `X=..[foo|T]` |
|
|
95
|
+
| 8.5.3 error (c) | non-list second argument | covered | strict `X=..foo` |
|
|
96
|
+
| 8.5.3 error (d) | variable list head | covered | strict `X=..[F,a]` |
|
|
97
|
+
| 8.5.3 error (e) | invalid compound functor/list head | covered | strict `X=..[3,a]` and singleton compound-head case |
|
|
98
|
+
| 8.5.3 error (f) | empty construction list | covered | strict `X=..[]` |
|
|
99
|
+
| 8.5.3 finite-arity representation branch | constructed list exceeds finite `max_arity` | not applicable | selected `max_arity=unbounded` |
|
|
100
|
+
| 8.5.4 `copy_term/2` | copy with fresh variables | covered | strict success assertion, `copy_term_fresh_variables`, `logtalk_copy_term_semantics` |
|
|
101
|
+
| Cor.2 8.5.5 `term_variables/2` | output witness-variable list | covered | strict `term_variables(A+B+B,[A,B])`, Logtalk-derived cases |
|
|
102
|
+
| Cor.2 8.5.5 `term_variables/2` | supplied partial/list result | covered | Corrigendum cases |
|
|
103
|
+
| Cor.2 8.5.5 error (a) | second argument neither partial list nor list -> list type error | covered | strict `term_variables(t,[X|foo])` |
|
|
104
|
+
|
|
105
|
+
## 8.15 — logic and control
|
|
106
|
+
|
|
107
|
+
| Clause / predicate | Prescribed row | Status | Executable evidence |
|
|
108
|
+
| --- | --- | --- | --- |
|
|
109
|
+
| 8.15.1 `(\+)/1` | callable goal; semidet | covered | negation corpus |
|
|
110
|
+
| 8.15.1 error (a) | variable goal -> instantiation error | covered | strict `\+(X)` |
|
|
111
|
+
| 8.15.1 error (b) | non-callable goal -> callable type error | covered | strict `\+(3)` |
|
|
112
|
+
| 8.15.2 `once/1` | callable goal; only first solution survives | covered | direct strict solver assertion, `once_commits_first`, `logtalk_once` |
|
|
113
|
+
| 8.15.2 error (a) | variable goal -> instantiation error | covered | strict `once(X)` |
|
|
114
|
+
| 8.15.2 error (b) | non-callable goal -> callable type error | covered | strict `once(3)` |
|
|
115
|
+
| 8.15.3 `repeat/0` | repeatedly succeeds; no prescribed errors | covered | `logtalk_repeat` |
|
|
116
|
+
| Cor.2 8.15.4 `call/2..8` | closure expansion through the standardized maximum arity | covered | direct strict closure assertion and `corrigenda_call_closure` |
|
|
117
|
+
| Cor.2 8.15.4 error (a) | variable closure -> instantiation error | covered | strict `call(X,a)` |
|
|
118
|
+
| Cor.2 8.15.4 error (b) | non-callable closure -> callable type error | covered | strict `call(3,a)` |
|
|
119
|
+
| Cor.2 8.15.4 finite-`max_arity` branch | resulting goal exceeds finite `max_arity` | not applicable | selected `max_arity=unbounded`; branch remains implementation-tested conditionally |
|
|
120
|
+
| Cor.2 8.15.4 implementation-dependent `call/N`, N>=9 | EyeProlog supplies no additional standardized closure arities | covered | strict `call(foo,a,b,c,d,e,f,g,h)` reaches procedure-existence handling rather than an extra call/N built-in |
|
|
121
|
+
| Cor.2 8.15.4 resulting-goal conversion error | expanded goal cannot be converted to a callable goal | covered | strict callability/error tests |
|
|
122
|
+
| Cor.2 8.15.5 `false/0` | always fails; no prescribed errors | covered | strict assertion and `false_builtin` |
|
|
123
|
+
|
|
124
|
+
## 8.16 — atomic term processing
|
|
125
|
+
|
|
126
|
+
| Clause / predicate | Prescribed row | Status | Executable evidence |
|
|
127
|
+
| --- | --- | --- | --- |
|
|
128
|
+
| 8.16.1 `atom_length/2` | atom -> length / check supplied length | covered | `logtalk_atom_length`, strict row audit |
|
|
129
|
+
| 8.16.1 error: atom variable | required atom unavailable -> instantiation error | covered | strict `atom_length(X,4)` |
|
|
130
|
+
| 8.16.1 error: atom type | first argument non-atom -> atom type error | covered | strict `atom_length(1.2,4)` |
|
|
131
|
+
| 8.16.1 error: length type | non-integer length -> integer type error | covered | strict `atom_length(atom,'4')` |
|
|
132
|
+
| 8.16.1 error: length domain | negative length -> non-negative domain error | covered | strict `atom_length(atom,-1)` |
|
|
133
|
+
| 8.16.2 `atom_concat/3` | concatenate known pieces or enumerate splits of known whole | covered | direct strict enumeration assertion and `logtalk_atom_concat` |
|
|
134
|
+
| 8.16.2 errors: insufficient first/whole or second/whole instantiation | instantiation error | covered | strict `atom_concat(X,small,Y)` and `atom_concat(small,X,Y)` |
|
|
135
|
+
| 8.16.2 errors: atom types | non-atom in each fixed position -> atom type error | covered | three strict type assertions |
|
|
136
|
+
| 8.16.3 `sub_atom/5` | enumerate/check source slices | covered | direct strict six-slice assertion and `logtalk_sub_atom` |
|
|
137
|
+
| 8.16.3 error: source variable | instantiation error | covered | strict `sub_atom(X,0,1,0,a)` |
|
|
138
|
+
| 8.16.3 errors: atom types | source/result non-atom -> atom type error | covered | strict source/result assertions |
|
|
139
|
+
| 8.16.3 errors: integer types | fixed Before/Length/After non-integer -> integer type error | covered | three strict assertions |
|
|
140
|
+
| 8.16.3 errors: non-negative domains | fixed Before/Length/After negative -> domain error | covered | three strict assertions |
|
|
141
|
+
| 8.16.4 `atom_chars/2` | atom <-> list of characters | covered | forward/reverse and Logtalk-derived cases |
|
|
142
|
+
| Cor.2 `atom_chars/2`: both insufficiently instantiated | instantiation error | covered | strict `atom_chars(X,Y)` |
|
|
143
|
+
| Cor.2 `atom_chars/2`: atom type | atom side non-atom | covered | strict `atom_chars(1,[])` |
|
|
144
|
+
| Cor.2 `atom_chars/2`: improper list | list type error on complete list culprit | covered | strict `atom_chars(X,[a|foo])` and focused culprit regressions |
|
|
145
|
+
| Cor.2 `atom_chars/2`: variable list-prefix element | instantiation error | covered | strict `atom_chars(X,[Y,a])` |
|
|
146
|
+
| Cor.2 `atom_chars/2`: non-character element | character type error | covered | strict `atom_chars(X,[a,1])` |
|
|
147
|
+
| 8.16.5 `atom_codes/2` | atom <-> list of character codes | covered | forward/reverse and Logtalk-derived cases |
|
|
148
|
+
| Cor.2 `atom_codes/2`: both insufficiently instantiated | instantiation error | covered | strict `atom_codes(X,Y)` |
|
|
149
|
+
| Cor.2 `atom_codes/2`: atom type | atom side non-atom | covered | strict `atom_codes(1,[])` |
|
|
150
|
+
| Cor.2 `atom_codes/2`: improper list | list type error on complete list culprit | covered | strict `atom_codes(X,[97|foo])` |
|
|
151
|
+
| Cor.2 `atom_codes/2`: variable prefix element | instantiation error | covered | strict `atom_codes(X,[Y,97])` |
|
|
152
|
+
| Cor.2 `atom_codes/2`: code type | non-integer code -> integer type error | covered | strict `atom_codes(X,[97,foo])` |
|
|
153
|
+
| Cor.2 `atom_codes/2`: code representation | integer outside processor character-code set -> representation error | covered | strict `atom_codes(X,[97,-1])` |
|
|
154
|
+
| 8.16.6 `char_code/2` | character <-> character code | covered | forward/reverse cases |
|
|
155
|
+
| 8.16.6 under-instantiation | both sides variable -> instantiation error | covered | strict `char_code(X,Y)` |
|
|
156
|
+
| 8.16.6 character type | non-character first argument takes precedence | covered | strict `char_code(ab,foo)` |
|
|
157
|
+
| 8.16.6 code type | non-integer code -> integer type error | covered | strict `char_code(a,foo)` |
|
|
158
|
+
| 8.16.6 code representation | integer outside processor character-code set -> representation error | covered | strict `char_code(a,-1)` |
|
|
159
|
+
| 8.16.7 `number_chars/2` | number <-> character-list number syntax | covered | number conversion corpus |
|
|
160
|
+
| Cor.2 `number_chars/2`: both insufficiently instantiated | instantiation error | covered | strict `number_chars(X,Y)` |
|
|
161
|
+
| Cor.2 `number_chars/2`: number type | fixed non-number -> number type error | covered | strict `number_chars(foo,[])` |
|
|
162
|
+
| Cor.2 `number_chars/2`: improper list | list type error | covered | strict `number_chars(X,[a|foo])` |
|
|
163
|
+
| Cor.2 `number_chars/2`: variable prefix element | instantiation error | covered | strict `number_chars(X,[Y,a])` |
|
|
164
|
+
| Cor.2 `number_chars/2`: non-character element | character type error | covered | strict `number_chars(X,[a,1])` |
|
|
165
|
+
| `number_chars/2`: invalid number syntax | syntax error | covered | strict `number_chars(X,[a])` and parenthesized-number rejection |
|
|
166
|
+
| 8.16.8 `number_codes/2` | number <-> code-list number syntax | covered | number conversion corpus |
|
|
167
|
+
| Cor.2 `number_codes/2`: both insufficiently instantiated | instantiation error | covered | strict `number_codes(X,Y)` |
|
|
168
|
+
| Cor.2 `number_codes/2`: number type | fixed non-number -> number type error | covered | strict `number_codes(foo,[])` |
|
|
169
|
+
| Cor.2 `number_codes/2`: improper list | list type error | covered | strict `number_codes(X,[49|foo])` |
|
|
170
|
+
| Cor.2 `number_codes/2`: variable prefix element | instantiation error | covered | strict `number_codes(X,[Y,49])` |
|
|
171
|
+
| Cor.2 `number_codes/2`: code type | non-integer code -> integer type error | covered | strict `number_codes(X,[49,foo])` |
|
|
172
|
+
| Cor.2 `number_codes/2`: code representation | integer outside processor character-code set -> representation error | covered | strict `number_codes(X,[49,-1])` |
|
|
173
|
+
| `number_codes/2`: invalid number syntax | syntax error | covered | strict `number_codes(X,[97])` |
|
|
174
|
+
|
|
175
|
+
## 8.17 — flags and hooks
|
|
176
|
+
|
|
177
|
+
The complete Part 1 flag family had already been closed before this tranche;
|
|
178
|
+
these rows make the corresponding built-in modes/errors explicit here so the
|
|
179
|
+
built-in matrix does not have a gap at 8.17.
|
|
180
|
+
|
|
181
|
+
| Clause / predicate | Prescribed row | Status | Executable evidence |
|
|
182
|
+
| --- | --- | --- | --- |
|
|
183
|
+
| 8.17.1 `set_prolog_flag/2` | set a supported, changeable flag value | covered | strict flag audit |
|
|
184
|
+
| 8.17.1 errors | variable/name type/domain, value type/domain, and non-changeable-flag permission distinctions | covered | `covers the Part 1 flag defaults, value domains, and changeability` plus file-based flag errors |
|
|
185
|
+
| 8.17.2 `current_prolog_flag/2` | enumerate/query current standard flags | covered | strict complete flag audit |
|
|
186
|
+
| 8.17.2 flag-name type error | fixed non-atom name -> atom type error | covered | strict `current_prolog_flag(1,_)` |
|
|
187
|
+
| 8.17.2 unknown-flag domain error | fixed unsupported flag name -> Prolog-flag domain error | covered | strict `current_prolog_flag(no_such_iso_flag,_)` |
|
|
188
|
+
| 8.17.3 `halt/0` | terminate with implementation-defined successful host status | covered | `halt` conformance case / host runner tests |
|
|
189
|
+
| 8.17.4 `halt/1` | integer host status | covered | halt conformance/runner tests |
|
|
190
|
+
| 8.17.4 variable status | instantiation error | covered | strict `halt(X)` |
|
|
191
|
+
| 8.17.4 non-integer status | integer type error | covered | strict `halt(a)` |
|
|
192
|
+
|
|
193
|
+
## Remaining row-audit work
|
|
194
|
+
|
|
195
|
+
This file deliberately does not relabel the whole 8.2-8.17 family as complete.
|
|
196
|
+
The next row-by-row passes are:
|
|
197
|
+
|
|
198
|
+
- 8.6-8.7 arithmetic predicates and expression-evaluation interactions;
|
|
199
|
+
- 8.8-8.10 database and all-solutions predicates, including all conditional
|
|
200
|
+
static/private/dynamic branches;
|
|
201
|
+
- 8.11-8.14 streams, character/byte I/O, options, and term I/O, including the
|
|
202
|
+
remaining option/mode cross-product.
|
|
203
|
+
|
|
204
|
+
Clause 9 exceptional-value rows and Clause 6/7 processor semantics remain
|
|
205
|
+
tracked separately in `ISO-COMPLIANCE.md` and `ISO-PROCESSOR-REQUIREMENTS.md`.
|
|
@@ -4,8 +4,11 @@ This ledger is the release-facing audit for EyeProlog's ISO/IEC 13211-1 core.
|
|
|
4
4
|
The normative baseline is ISO/IEC 13211-1:1995 together with Technical
|
|
5
5
|
Corrigenda 1:2007, 2:2012, and 3:2017. It complements
|
|
6
6
|
[ISO-MATRIX.md](ISO-MATRIX.md), which maps standard families to representative
|
|
7
|
-
executable tests,
|
|
8
|
-
which
|
|
7
|
+
executable tests, [ISO-BUILTIN-MODE-ERROR-MATRIX.md](ISO-BUILTIN-MODE-ERROR-MATRIX.md),
|
|
8
|
+
which records the row-by-row built-in audit, and
|
|
9
|
+
[ISO-PROCESSOR-REQUIREMENTS.md](ISO-PROCESSOR-REQUIREMENTS.md), which decomposes
|
|
10
|
+
Clause 5 processor obligations. The generated [`conformance-report.md`](../../conformance-report.md)
|
|
11
|
+
gives current case totals.
|
|
9
12
|
|
|
10
13
|
The ledger deliberately does **not** claim independent certification. A row
|
|
11
14
|
marked `covered` means EyeProlog has implementation and executable tests for
|
|
@@ -22,25 +25,25 @@ error-ordering alternative to an individual executable assertion.
|
|
|
22
25
|
| 5.1(b) execute conforming Prolog goals | audit | Clause 7-9 conformance corpus plus regression/API/example gates. A normative goal-semantics ledger is still being expanded. |
|
|
23
26
|
| 5.1(c) reject nonconforming text/read-terms | audit | Dedicated syntax-error cases and strict-core extension rejection. Exhaustive lexical rejection coverage remains open. |
|
|
24
27
|
| 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. Rows marked `audit gap` remain conformance work, but the variation is no longer undocumented. |
|
|
25
|
-
| 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,
|
|
28
|
+
| 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, disable automatic tabling/recursion guards, and reject the normal-profile host `stringTerm/1` term type at strict program/goal entry. |
|
|
26
29
|
| 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 or an explicit audit gap. |
|
|
27
|
-
| 5.5
|
|
30
|
+
| 5.5 extension boundaries | audit | [ISO-PROCESSOR-REQUIREMENTS.md](ISO-PROCESSOR-REQUIREMENTS.md) now splits 5.5 into its individual extension hooks. Operators, character conversion, the normal-profile host string type, directives, control constructs, flags, and reserved atoms have explicit decisions; exhaustive syntax-preservation, side-effect, built-in, and evaluable-functor dependency mapping remains open. |
|
|
28
31
|
|
|
29
32
|
## Normative language families
|
|
30
33
|
|
|
31
34
|
| Standard area | Status | Current evidence |
|
|
32
35
|
| --- | --- | --- |
|
|
33
36
|
| Clause 6 — tokens, terms, lists, operators, quoted text | audit | Complete vendored WG17 syntax matrix, `lexical_and_curly_terms`, `scryer_lexical_terms`, operator suites, syntax-error cases, quoted-layout/escape error cases, writer/read-back regressions, and Unicode-scalar PCS/collation boundary tests. The implementation-defined 6.5/6.6 character-model decisions are now closed; wider shall-by-shall lexical mapping remains open. |
|
|
34
|
-
| 7.1-7.3 — term types, term order, unification | audit | Standard-order, identity, finite-tree and occurs-check suites, Corrigendum 2 term predicates, plus strict checks for the required `variable < float < integer < atom < compound` type order, PCS-based atom collation, and the `max_arity=unbounded` compound-term model. |
|
|
37
|
+
| 7.1-7.3 — term types, term order, unification | audit | Standard-order, identity, finite-tree and occurs-check suites, Corrigendum 2 term predicates, plus strict checks for the required `variable < float < integer < atom < compound` type order, PCS-based atom collation, and the `max_arity=unbounded` compound-term model. The normal JavaScript API string term is now explicitly documented as a 5.5.4 extension and rejected at strict program/goal entry so it cannot add a sixth strict-core type. |
|
|
35
38
|
| 7.4 — Prolog text and directives | audit | All Part 1 directive indicators are parsed; include/ensure-loaded/operator/flag/character-conversion behavior has executable coverage. Preparation-time `char_conversion/2` affects later unquoted source text and respects `char_conversion=off`. Strict preparation now enforces declaration-before-clause ordering for `dynamic/1`, `multifile/1`, and `discontiguous/1`, cross-text `multifile/1`, discontiguous clause grouping, empty declared procedures, include textual-replacement behavior, and one-time initialization per prepared program. The remaining shall-by-shall mapping is still open. |
|
|
36
|
-
| 7.5-7.6 — database and term/clause conversion | audit | Dynamic database and logical-update-view suites. Strict mode restores Part 1 private-static/public-dynamic `clause/2` access; focused strict checks now
|
|
39
|
+
| 7.5-7.6 — database and term/clause conversion | audit | Dynamic database and logical-update-view suites. Strict mode restores Part 1 private-static/public-dynamic `clause/2` access; focused strict checks cover the database built-ins and empty-procedure lifetime. Runtime assertion conversion now applies 7.6.2 recursively through conjunction, disjunction, and if-then: nested variables become `call/1`, and an invalid nested branch is rejected while `asserta/1` or `assertz/1` converts the term instead of being stored for a later execution-time failure. Runtime protection includes the solver-native conjunction control construct `','/2` and, following STC #56's accepted-direction action item, `(:-)/1-2` for database modification/private access while leaving their call behavior distinct. The remaining clause-conversion shall-by-shall mapping is still open. |
|
|
37
40
|
| 7.7 — execution and backtracking | audit | Control/search suites. Strict mode disables EyeProlog automatic tabling, cycle guards, and recursive numeric shortcuts so core execution uses ordinary clause selection/backtracking. |
|
|
38
|
-
| 7.8 — control constructs and exceptions | audit | call, cut, conjunction, disjunction (including failed branches after callee-local cuts), if-then, catch/throw, renamed-copy tests. |
|
|
41
|
+
| 7.8 — control constructs and exceptions | audit | call, cut, conjunction, disjunction (including failed branches after callee-local cuts), if-then, catch/throw, renamed-copy tests. The 8.15 built-in slice (`\+/1`, `once/1`, `repeat/0`, Corrigendum 2 `call/2..8`, `false/0`) is now row-audited in [ISO-BUILTIN-MODE-ERROR-MATRIX.md](ISO-BUILTIN-MODE-ERROR-MATRIX.md); the remaining general control-construct semantics ledger stays open. |
|
|
39
42
|
| 7.9 — expression evaluation | audit | Arithmetic/evaluation/error suites, including Corrigenda. Strict mode now pins direct-variable precedence, 7.9.2 non-evaluable `F/N` errors (including STC #69), arithmetic numeric/integer type errors, float-only rounding conversions, the Part 1 mixed integer/float comparison conversion rule, I->F overflow before floating evaluable functors (STC #42), explicit `exp/1`/power underflow, and prescribed negative/zero power errors before later conversion overflow. Unbounded integer powers/shifts no longer leak host `RangeError`; finite-host exhaustion is normalized to `resource_error(memory)` in line with the Part 1 resource-error note and STC #21. The remaining exceptional-value/error-precedence rows are still being exhaustively enumerated. |
|
|
40
43
|
| 7.10 — input/output concepts | audit | Stream, character/byte I/O, read/write options, operator-sensitive write-back, and Corrigendum 3 writer cases. The audit now also covers write-mode creation/truncation, append creation, repositioned overwrite, flushing, EOF actions, close/current-stream handling, strict stream-position terms, stream-property validation, stream-term requirements, text-vs-binary permission errors, and the prescribed `alias(A)` culprit for `open/4` alias collisions. The latest 8.11/8.12 pass also makes `close/2`'s `force(true)` semantics presence-based and defers `get_code/1-2` / `peek_code/1-2` invalid in-character-code representation errors until after the earlier stream existence/mode/type/EOF/entity conditions. The full option/mode cross-product is still being mapped. |
|
|
41
44
|
| 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. |
|
|
42
|
-
| 7.12 — errors | audit | ISO `error(Error, Context)` envelope, type/domain/permission/representation/evaluation/syntax/resource families and focused error cases.
|
|
43
|
-
| 8.2-8.17 — built-in predicates | audit | Predicate-family coverage is mapped in ISO-MATRIX.md
|
|
45
|
+
| 7.12 — errors | audit | ISO `error(Error, Context)` envelope, type/domain/permission/representation/evaluation/syntax/resource families and focused error cases. [ISO-BUILTIN-MODE-ERROR-MATRIX.md](ISO-BUILTIN-MODE-ERROR-MATRIX.md) now gives explicit prescribed mode/error rows for 8.2-8.5 and 8.15-8.17, including Corrigendum additions and selected not-applicable finite-`max_arity` branches. Exact ISO 8.14.1-8.14.4 precedence and the recent 8.11/8.12 overlaps are also covered. The one-row map remains open for 8.6-8.14 and for the remaining Clause 7/9 exceptional-order interactions. |
|
|
46
|
+
| 8.2-8.17 — built-in predicates | audit | Predicate-family coverage is mapped in ISO-MATRIX.md. The new [ISO-BUILTIN-MODE-ERROR-MATRIX.md](ISO-BUILTIN-MODE-ERROR-MATRIX.md) closes 8.2-8.5 and 8.15-8.17 at one row per prescribed mode/error condition (with finite-`max_arity` branches explicitly marked not applicable under EyeProlog's `unbounded` choice). The still-open row audit is therefore narrowed to 8.6-8.14, especially database/all-solutions and the remaining stream/term-I/O option cross-product. |
|
|
44
47
|
| Clause 9 — evaluable functors | audit | Integer/float/rounding/transcendental/bitwise suites and corrigendum cases. Strict mode excludes the EyeProlog-only evaluable atom `e`, retains Corrigendum 2 arithmetic additions, reports unknown zero-arity evaluables with the required `F/0` culprit shape, distinguishes non-evaluable `F/N` errors from numeric/integer operand errors per 7.9.2 and STC #69, and enforces float-only rounding modes, performs I->F conversion before floating functors (including overflow), reports the explicit `exp/1`, `**/2`, and Corrigendum 2 `^/2` underflow conditions, preserves the power-specific undefined conditions ahead of conversion overflow, and uses the Part 1 integer-to-float rule for mixed arithmetic comparisons. Normal mode retains EyeProlog's exact mixed-type comparison and round-to-zero arithmetic behavior as extensions. Unbounded BigInt resource exhaustion is translated into the Prolog error model rather than leaking host exceptions. Host floating-point representation choices remain documented implementation-defined behavior; the remaining exceptional-value rows are still under audit. |
|
|
45
48
|
| Corrigendum 1 | covered | Double-quoted atom/operator-priority corrections have dedicated cases. |
|
|
46
49
|
| Corrigendum 2 | covered | Added predicates/functors, catch corrections, bar/operator and uninstantiation corrections have dedicated cases. |
|
|
@@ -162,6 +165,28 @@ describes: a later `force(false)` does not cancel an earlier `force(true)` when
|
|
|
162
165
|
a Resource Error or System Error occurs during closure. Focused strict tests
|
|
163
166
|
cover both overlap families.
|
|
164
167
|
|
|
168
|
+
The next row-audit tranche makes the remaining exit criterion concrete rather
|
|
169
|
+
than leaving it as a broad test-count claim.
|
|
170
|
+
[ISO-BUILTIN-MODE-ERROR-MATRIX.md](ISO-BUILTIN-MODE-ERROR-MATRIX.md) now records
|
|
171
|
+
each prescribed mode/error row for the 8.2-8.5 and 8.15-8.17 slices, and
|
|
172
|
+
[ISO-PROCESSOR-REQUIREMENTS.md](ISO-PROCESSOR-REQUIREMENTS.md) decomposes the
|
|
173
|
+
Clause 5 obligations into covered, audit, and not-applicable decisions. While
|
|
174
|
+
doing that mapping, the 7.6.2 term-to-clause conversion audit exposed a runtime
|
|
175
|
+
assertion defect: variables and invalid terms nested under `;/2` or `->/2` were
|
|
176
|
+
not being recursively converted. `asserta/1` and `assertz/1` now convert all
|
|
177
|
+
three standardized binary control forms `,/2`, `;/2`, and `->/2` recursively,
|
|
178
|
+
so nested variables become `call/1` and a non-callable nested branch is rejected
|
|
179
|
+
at assertion time with the complete clause-body culprit.
|
|
180
|
+
|
|
181
|
+
The Clause 5 decomposition also exposed an embedding-only type boundary that
|
|
182
|
+
source-text tests could not see. EyeProlog's normal JavaScript API deliberately
|
|
183
|
+
exports `stringTerm(Text)` as an implementation-specific additional term type.
|
|
184
|
+
Its normal-profile ordering, conversion, evaluation, and writing behavior is
|
|
185
|
+
now documented under 5.5.4, while strict `Program` construction and strict
|
|
186
|
+
`Solver` goal entry reject such terms with `representation_error(term)`. This
|
|
187
|
+
keeps the host extension available in normal mode without allowing it to become
|
|
188
|
+
a sixth term type in the Part 1 strict execution domain.
|
|
189
|
+
|
|
165
190
|
## Post-Corrigendum STC cross-check
|
|
166
191
|
|
|
167
192
|
The public WG17 STC draft is tracked as useful defect-discovery material, but it
|
|
@@ -197,7 +222,8 @@ not interpret the following as core-language features:
|
|
|
197
222
|
- Part 2 module directives (`module/2`, `use_module/1-2`, `meta_predicate/1`);
|
|
198
223
|
- Part 3 grammar-rule expansion and `phrase/2-3`;
|
|
199
224
|
- automatic tabling, cycle guards, and recursive numeric execution shortcuts;
|
|
200
|
-
- EyeProlog well-founded negation via `tnot/1` and its WFS runtime statistics
|
|
225
|
+
- EyeProlog well-founded negation via `tnot/1` and its WFS runtime statistics;
|
|
226
|
+
- the JavaScript API `stringTerm(Text)` additional term type (normal mode only).
|
|
201
227
|
|
|
202
228
|
The predefined Part 1 `1200 fx` `?-` operator and `1200 xfx` `-->` operator
|
|
203
229
|
remain ordinary operator syntax in strict core mode. A conforming `op/3`
|
|
@@ -113,7 +113,7 @@ families; `--iso-strict` is intended to remove their Part 1 interpretation.
|
|
|
113
113
|
| 5.5.1 Syntax | Part 2 modules, Part 3 grammar-rule expansion, and embedded quad syntax | Module directives are rejected; grammar rules remain ordinary `-->/2` terms rather than being expanded; quad syntax is rejected. Unicode PCS membership/classification is implementation defined and therefore shared with normal mode rather than treated as an extension. |
|
|
114
114
|
| 5.5.2 Predefined operators | Part 3 `|` and EyeProlog's labelable infix `(?-)/2`; CLP(Z) operators when that library is imported | Only the Part 1 operator table is predefined; a conforming `op/3` may still add permitted operators. |
|
|
115
115
|
| 5.5.3 Character-conversion mapping | No non-identity initial `Convc` extension | Identity initial mapping. |
|
|
116
|
-
| 5.5.4 Types |
|
|
116
|
+
| 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. |
|
|
117
117
|
| 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. |
|
|
118
118
|
| 5.5.6 Side effects | Host output/statistics, library-specific state, proof/statistics collection | The strict registry excludes library adapters; ordinary Part 1 I/O/database/flag/operator side effects remain. |
|
|
119
119
|
| 5.5.7 Control constructs | `tnot/1` and normal-profile execution optimizations | `tnot/1` is absent; automatic tabling/recursion guards are disabled. |
|
|
@@ -11,13 +11,13 @@ compliance audit and the remaining work before a full conformance claim.
|
|
|
11
11
|
| Clause 6 lexical and term syntax | tokenizer, operator parser, lists, curly terms, quotes, numeric syntax, comments, Unicode-scalar PCS/collation | `scryer_lexical_terms`, `lexical_and_curly_terms`, `double_quoted_lists`, `corrigendum1_double_quote_operator`, `wg17_syntax_high_risk`, `wg17_invalid_octal_escape`, `wg17_unterminated_quoted_token`, `wg17_literal_newline_in_quote`, `wg17_non_iso_escape`, strict PCS/collation tests in `run-iso-strict.mjs`, syntax error cases |
|
|
12
12
|
| Clause 7 term order and unification | finite-tree unification, identity, standard order, errors | `unification_control_information`, `swipl_occurs_check`, `term_modes_and_ordering`, `logtalk_compare_standard_order` |
|
|
13
13
|
| Clause 7 control and exceptions | call, cut, conjunction, disjunction, if-then-else, catch and throw | `cut_control`, `control_and_terms`, `exceptions_and_flags`, `corrigenda_catch_callability`, `throw_copies_ball` |
|
|
14
|
-
| 8.2-8.5 term predicates | unification, Corrigendum 2 tests, comparison, sorting, creation and decomposition | `corrigenda_term_predicates`, `corrigenda_sort_keysort`, `logtalk_arg_unification`, `logtalk_univ`, associated error cases,
|
|
14
|
+
| 8.2-8.5 term predicates | unification, Corrigendum 2 tests, comparison, sorting, creation and decomposition | `corrigenda_term_predicates`, `corrigenda_sort_keysort`, `logtalk_arg_unification`, `logtalk_univ`, associated error cases, and the one-row-per-mode/error 8.2-8.5 slice in `ISO-BUILTIN-MODE-ERROR-MATRIX.md`, including conditional finite-`max_arity` branches |
|
|
15
15
|
| 8.6-8.7 arithmetic predicates | `is/2` and all six arithmetic comparisons | `arithmetic`, comparison cases, isolated evaluation errors |
|
|
16
|
-
| 8.8-8.10 database and solutions | logical update view, dynamic mutation, all-solutions grouping | `dynamic_database`, `trealla_logical_update_view`, `corrigenda_retractall`, `grouped_solutions_and_clauses`, plus strict clause/database error and all-solutions precedence checks,
|
|
16
|
+
| 8.8-8.10 database and solutions | logical update view, dynamic mutation, all-solutions grouping | `dynamic_database`, `trealla_logical_update_view`, `corrigenda_retractall`, `grouped_solutions_and_clauses`, plus strict clause/database error and all-solutions precedence checks, recursive 7.6.2 assertion-body conversion through `,/2`, `;/2`, and `->/2`, runtime static/private protection for conjunction, and STC #56 `(:-)/1-2` database protection |
|
|
17
17
|
| 8.11-8.14 streams and term I/O | text/binary streams, properties, units, read/write options and operators | `streams_and_term_io`, `operators`, Corrigendum 3 option cases, stream error cases, strict 8.14.1-8.14.4 option/error-order tests, Corrigendum 3 variable metadata/write naming checks, and issue #65 checks for stream-term/property validation, text-vs-binary permissions, EOF/flush/position, open/close semantics, presence-based `force(true)` close handling, late `get_code/peek_code` in-character-code representation errors, and the exact `alias(A)` collision culprit |
|
|
18
|
-
| 8.15 logic and control | negation, once, repeat, `call/2` through `call/8`, `false/0` | `logtalk_once`, `corrigenda_call_closure`, `false_builtin`, plus
|
|
19
|
-
| 8.16 atomic processing | atoms, characters, codes and number conversion with prescribed errors | `atomic_term_processing`, focused forward/reverse cases, parenthesized-number rejection, Logtalk-derived
|
|
20
|
-
| 8.17 flags and
|
|
18
|
+
| 8.15 logic and control | negation, once, repeat, `call/2` through `call/8`, `false/0` | `logtalk_once`, `corrigenda_call_closure`, `false_builtin`, plus the complete 8.15 row-audit in `ISO-BUILTIN-MODE-ERROR-MATRIX.md` |
|
|
19
|
+
| 8.16 atomic processing | atoms, characters, codes and number conversion with prescribed errors | `atomic_term_processing`, focused forward/reverse cases, parenthesized-number rejection, Logtalk-derived cases, and the complete 8.16 mode/error slice in `ISO-BUILTIN-MODE-ERROR-MATRIX.md` |
|
|
20
|
+
| 8.17 flags and halt | complete required Part 1 flag set, selected defaults, standard value domains/changeability, and halt status handling | `exceptions_and_flags`, `remaining_builtins_and_directives`, the complete strict flag audit, halt cases, and explicit 8.17 rows in `ISO-BUILTIN-MODE-ERROR-MATRIX.md` |
|
|
21
21
|
| Clause 9 evaluable functors | integer, float, rounding, transcendental and bitwise operations | `arithmetic`, `corrigenda_arithmetic`, `corrigenda_atan2_zero`, `corrigenda_integer_negative_power`, strict exclusion of the normal-mode `e` evaluable extension, zero-arity unknown-evaluable checks, prescribed operand/type and power-error precedence, float-only rounding modes, I->F overflow before floating functors, explicit `exp/1`/`**/2`/`^/2` underflow, Part 1 mixed integer/float comparison conversion, and resource-error normalization for finite-host exhaustion of unbounded integer operations |
|
|
22
22
|
| Module compatibility profile (related to ISO/IEC 13211-2 and later WG17 amendment work) | module declarations, exports, imports, qualification, meta-predicate context | `modules/qualified_call`, `modules/selective_library_import`, `dcg_module_nonterminal_indicator` |
|
|
23
23
|
| Part 3-oriented DCG compatibility profile | `-->`, terminal and partial sequences, grammar control constructs, semicontexts, nonterminal indicators, modules, `phrase/2-3`, steadfastness and errors | `dcg_terminals_and_remainder`, `dcg_control_constructs`, `dcg_partial_sequences`, `dcg_phrase_steadfastness`, `dcg_dynamic_nonterminal_indicator`, `logtalk_dcg_phrase_identity`, `logtalk_dcg_semicontexts`, DCG error and precedence cases |
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# ISO Part 1 processor-requirements audit
|
|
2
|
+
|
|
3
|
+
This is the clause-level checklist for the processor requirements that sit
|
|
4
|
+
above the individual built-ins. It complements `ISO-COMPLIANCE.md`: the latter
|
|
5
|
+
is release-facing prose, while this file keeps each Clause 5 requirement or
|
|
6
|
+
extension boundary visible as its own auditable row.
|
|
7
|
+
|
|
8
|
+
The normative baseline is ISO/IEC 13211-1:1995 plus Technical Corrigenda 1-3.
|
|
9
|
+
`covered` means the requirement has an implementation/documentation decision
|
|
10
|
+
and executable evidence. `audit` means the implementation has relevant tests
|
|
11
|
+
but the project has not yet reduced every dependent Clause 6-9 requirement to
|
|
12
|
+
an explicit pass/not-applicable decision. No row here is an independent
|
|
13
|
+
certification claim.
|
|
14
|
+
|
|
15
|
+
## 5.1 — conforming processor obligations
|
|
16
|
+
|
|
17
|
+
| Requirement | Status | Current evidence / remaining work |
|
|
18
|
+
| --- | --- | --- |
|
|
19
|
+
| 5.1(a) prepare conforming Prolog text | audit | parser/preparation tests, directives, include behavior, preparation-time operators/flags/character conversion, and the complete vendored WG17 syntax matrix; the remaining Clause 6/7.4 shall-by-shall map is still open |
|
|
20
|
+
| 5.1(b) execute conforming Prolog goals | audit | Clause 7-9 suites plus the row-audited built-in slices in `ISO-BUILTIN-MODE-ERROR-MATRIX.md`; 8.6-8.14 and remaining Clause 7/9 semantic rows are still being enumerated |
|
|
21
|
+
| 5.1(c) reject nonconforming text/read terms | audit | syntax-error corpus, WG17 negative syntax cases, strict extension rejection; exhaustive Clause 6 rejection mapping remains open |
|
|
22
|
+
| 5.1(d) specify permitted variations | covered | `ISO-IMPLEMENTATION-DEFINED.md` records the Part 1 implementation-defined choices and implementation-specific extension families |
|
|
23
|
+
| 5.1(e) offer a strictly conforming mode | covered | CLI `--iso-strict` and API `isoStrict: true`; registry/directive/operator/flag extension filtering plus disabled implementation-specific execution shortcuts |
|
|
24
|
+
|
|
25
|
+
## 5.2-5.4 — text, goals, and documentation
|
|
26
|
+
|
|
27
|
+
| Requirement | Status | Current evidence / remaining work |
|
|
28
|
+
| --- | --- | --- |
|
|
29
|
+
| 5.2 conforming and strictly conforming Prolog text boundary | audit | strict parser accepts Part 1 + Corrigenda syntax plus implementation-defined PCS choices and rejects implementation-specific language facilities; full Clause 6/7.4 dependency audit remains open |
|
|
30
|
+
| 5.3 conforming and strictly conforming Prolog goal boundary | audit | strict registry/control/evaluable filtering and Clause 7-9 regression suites; remaining prescribed mode/error and goal-semantics rows remain open |
|
|
31
|
+
| 5.4 accompanying documentation for implementation-defined and implementation-specific features | covered | `ISO-IMPLEMENTATION-DEFINED.md`, *The Art of EyeProlog*, strict-boundary documentation, and release-facing conformance ledgers |
|
|
32
|
+
|
|
33
|
+
## 5.5 — extension boundaries
|
|
34
|
+
|
|
35
|
+
| Requirement | Status | EyeProlog decision / evidence |
|
|
36
|
+
| --- | --- | --- |
|
|
37
|
+
| 5.5 general extension rule | covered | normal mode may provide documented extensions; strict mode removes their Part 1 interpretation rather than changing implementation-defined choices |
|
|
38
|
+
| 5.5.1 syntax extensions preserve standard token/text meaning | audit | WG17 syntax is a release gate and strict mode removes module/DCG/quad interpretation; a complete one-row preservation map for every Clause 6 production remains open |
|
|
39
|
+
| 5.5.2 additional predefined operators | covered | strict mode starts from the Part 1 predefined operator table; normal-profile extra operators are documented and filtered |
|
|
40
|
+
| 5.5.3 initial character-conversion mapping | covered | identity initial mapping; user changes are exercised through preparation/execution `char_conversion/2` behavior |
|
|
41
|
+
| 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)` |
|
|
42
|
+
| 5.5.5 additional directives | covered | normal module/library directives are documented implementation-specific features and are rejected by strict mode |
|
|
43
|
+
| 5.5.6 additional side effects | audit | host/proof/statistics/library effects are outside the strict registry or documented normal-mode behavior; exhaustive side-effect preservation mapping remains part of the Clause 7.7/7.10 audit |
|
|
44
|
+
| 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 |
|
|
45
|
+
| 5.5.8 additional flags | covered | normal `occurs_check` extension is absent from strict mode; the Part 1 flag family is fully audited |
|
|
46
|
+
| 5.5.9 additional built-in predicates and error forms | audit | strict registry excludes normal-profile library/native additions; `ISO-BUILTIN-MODE-ERROR-MATRIX.md` now closes 8.2-8.5 and 8.15-8.17 row-by-row, while 8.6-8.14 remain open |
|
|
47
|
+
| 5.5.10 additional evaluable functors/types | audit | strict mode excludes normal-profile arithmetic extensions such as evaluable `e`; Clause 9 exceptional-value and error-precedence rows remain under audit |
|
|
48
|
+
| 5.5.11 reserved atoms | not applicable | EyeProlog declares no reserved-atom extension; extension names remain ordinary atoms unless used in a documented syntactic/predicate/directive role |
|
|
49
|
+
|
|
50
|
+
## Exit-use rule
|
|
51
|
+
|
|
52
|
+
A top-level row stays `audit` until all of the normative clauses it depends on
|
|
53
|
+
have explicit pass, not-applicable, or documented implementation-defined
|
|
54
|
+
outcomes. This prevents a large green regression suite from being mistaken for
|
|
55
|
+
a completed processor-requirement audit.
|
|
@@ -9,7 +9,10 @@ The suite is intentionally file-based. Exact standard output, errors, warnings,
|
|
|
9
9
|
and proof output test the behavior of the JavaScript implementation.
|
|
10
10
|
[ISO-MATRIX.md](ISO-MATRIX.md) maps Part 1 normative clause families, all three
|
|
11
11
|
corrigenda, plus EyeProlog's module and DCG compatibility profiles, to representative
|
|
12
|
-
executable cases. [
|
|
12
|
+
executable cases. [ISO-BUILTIN-MODE-ERROR-MATRIX.md](ISO-BUILTIN-MODE-ERROR-MATRIX.md)
|
|
13
|
+
tracks the row-by-row built-in audit, while
|
|
14
|
+
[ISO-PROCESSOR-REQUIREMENTS.md](ISO-PROCESSOR-REQUIREMENTS.md) decomposes the
|
|
15
|
+
Clause 5 processor obligations. [WG17-SYNTAX-STATUS.md](WG17-SYNTAX-STATUS.md) records the
|
|
13
16
|
complete one-to-one trace for the vendored active upstream WG17 syntax cases.
|
|
14
17
|
[STC-DRAFT-STATUS.md](STC-DRAFT-STATUS.md) separately tracks executable
|
|
15
18
|
implementation questions from the post-N289 working draft; those cases are
|
|
@@ -19,12 +22,11 @@ review evidence, not normative ISO claims.
|
|
|
19
22
|
profile and implementation extensions. The default registry covers the exact
|
|
20
23
|
predicate indicators listed in Appendix B of the book across the Part 1 strict-core
|
|
21
24
|
target and the normal-mode module/DCG compatibility families. [ISO-COMPLIANCE.md](ISO-COMPLIANCE.md) is the explicit
|
|
22
|
-
|
|
25
|
+
release-facing ledger for the Part 1 strict-core audit. This suite is
|
|
23
26
|
still not an independent certification of every processor requirement, lexical
|
|
24
|
-
edge, or option combination.
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
tracked in the compliance ledger. Cases under `iso/`
|
|
27
|
+
edge, or option combination. The 8.2-8.5 and 8.15-8.17 built-in slices are now
|
|
28
|
+
tracked one prescribed mode/error row at a time; 8.6-8.14 and the remaining
|
|
29
|
+
processor semantics stay explicitly open in the dedicated audit files. Cases under `iso/`
|
|
28
30
|
identify standards-derived behavior; other directories cover EyeProlog host
|
|
29
31
|
contracts and extensions. EyeProlog-only execution features such as automatic
|
|
30
32
|
tabling and `tnot/1` well-founded negation are outside the Part 1 strict-core
|
package/test/run-iso-strict.mjs
CHANGED
|
@@ -6,10 +6,12 @@ import {
|
|
|
6
6
|
Program,
|
|
7
7
|
Solver,
|
|
8
8
|
Env,
|
|
9
|
+
compound,
|
|
9
10
|
createStrictIsoRegistry,
|
|
10
11
|
parseGoalText,
|
|
11
12
|
parseProgramText,
|
|
12
13
|
run,
|
|
14
|
+
stringTerm,
|
|
13
15
|
} from '../src/index.js';
|
|
14
16
|
import { TestReporter, isMainModule, runStandalone } from './test-style.mjs';
|
|
15
17
|
|
|
@@ -177,6 +179,23 @@ export function runIsoStrict(reporter = new TestReporter()) {
|
|
|
177
179
|
equal(strict.stats.completed_goal_lists, 1, 'strict Unicode char_code/2');
|
|
178
180
|
});
|
|
179
181
|
|
|
182
|
+
reporter.test('rejects the normal-profile string term extension at strict API boundaries', () => {
|
|
183
|
+
const normalSolver = new Solver(Program.parse(''), {});
|
|
184
|
+
const normalGoal = compound('=', [stringTerm('x'), stringTerm('x')]);
|
|
185
|
+
equal([...normalSolver.solve([normalGoal], new Env(), 0)].length, 1,
|
|
186
|
+
'normal API string terms remain usable');
|
|
187
|
+
|
|
188
|
+
const strictSolver = new Solver(Program.parse('', { isoStrict: true }), { isoStrict: true });
|
|
189
|
+
equal(capture(() => [...strictSolver.solve([normalGoal], new Env(), 0)]).formal,
|
|
190
|
+
'representation_error(term)', 'strict execution rejects API string terms');
|
|
191
|
+
|
|
192
|
+
equal(capture(() => new Program([{
|
|
193
|
+
head: compound('p', [stringTerm('x')]),
|
|
194
|
+
body: [],
|
|
195
|
+
}], { isoStrict: true })).formal,
|
|
196
|
+
'representation_error(term)', 'strict program construction rejects API string terms');
|
|
197
|
+
});
|
|
198
|
+
|
|
180
199
|
reporter.test('keeps the strict write-option surface to Part 1 plus Corrigendum 3', () => {
|
|
181
200
|
const strictError = capture(() => run('', {
|
|
182
201
|
isoStrict: true,
|
|
@@ -608,6 +627,157 @@ export function runIsoStrict(reporter = new TestReporter()) {
|
|
|
608
627
|
1, 'resource handling does not reintroduce a finite max_arity');
|
|
609
628
|
});
|
|
610
629
|
|
|
630
|
+
reporter.test('converts asserted control bodies recursively per ISO 7.6.2', () => {
|
|
631
|
+
const source = ':- dynamic(p/0).\n:- dynamic(q/0).\n:- dynamic(r/0).\n';
|
|
632
|
+
const disjunction = run(source, {
|
|
633
|
+
isoStrict: true,
|
|
634
|
+
goal: 'assertz((p :- (X;true))), clause(p,B), arg(1,B,L), nonvar(L), functor(L,call,1)',
|
|
635
|
+
});
|
|
636
|
+
equal(disjunction.stats.completed_goal_lists, 1, 'variable in asserted disjunction becomes call/1');
|
|
637
|
+
|
|
638
|
+
const ifThenElse = run(source, {
|
|
639
|
+
isoStrict: true,
|
|
640
|
+
goal: 'assertz((q :- (X->Y;Z))), clause(q,B), arg(1,B,I), arg(1,I,XG), arg(2,I,YG), arg(2,B,ZG), nonvar(XG), nonvar(YG), nonvar(ZG), functor(XG,call,1), functor(YG,call,1), functor(ZG,call,1)',
|
|
641
|
+
});
|
|
642
|
+
equal(ifThenElse.stats.completed_goal_lists, 1, 'variables in asserted if-then-else become call/1');
|
|
643
|
+
|
|
644
|
+
const disjunctionError = capture(() => run(source, { isoStrict: true, goal: 'assertz((r :- (true;4)))' }));
|
|
645
|
+
equal(disjunctionError.formal, 'type_error(callable)', 'invalid asserted disjunction rejected during conversion');
|
|
646
|
+
includes(disjunctionError.message, "';'(true, 4)", 'asserted disjunction error identifies body');
|
|
647
|
+
|
|
648
|
+
const conjunctionError = capture(() => run(source, { isoStrict: true, goal: 'asserta((r :- (true,4)))' }));
|
|
649
|
+
equal(conjunctionError.formal, 'type_error(callable)', 'invalid asserted conjunction rejected during conversion');
|
|
650
|
+
includes(conjunctionError.message, '(true, 4)', 'asserted conjunction error identifies body');
|
|
651
|
+
});
|
|
652
|
+
|
|
653
|
+
reporter.test('closes the ISO 8.2-8.5 prescribed mode/error rows', () => {
|
|
654
|
+
const cases = [
|
|
655
|
+
['compare(1,3,3.0)', 'type_error(atom)', 'compare/3 order type'],
|
|
656
|
+
['compare(>=,3,3.0)', 'domain_error(order)', 'compare/3 order domain'],
|
|
657
|
+
['sort([1|T],_)', 'instantiation_error', 'sort/2 partial input'],
|
|
658
|
+
['sort(foo,_)', 'type_error(list)', 'sort/2 input list type'],
|
|
659
|
+
['sort([],foo)', 'type_error(list)', 'sort/2 output list type'],
|
|
660
|
+
['keysort([1-a|T],_)', 'instantiation_error', 'keysort/2 partial input'],
|
|
661
|
+
['keysort(foo,_)', 'type_error(list)', 'keysort/2 input list type'],
|
|
662
|
+
['keysort([],foo)', 'type_error(list)', 'keysort/2 output list type'],
|
|
663
|
+
['keysort([X],_)', 'instantiation_error', 'keysort/2 variable pair'],
|
|
664
|
+
['keysort([foo],_)', 'type_error(pair)', 'keysort/2 input pair type'],
|
|
665
|
+
['keysort([],[foo])', 'type_error(pair)', 'keysort/2 output pair type'],
|
|
666
|
+
['functor(X,Y,3)', 'instantiation_error', 'functor/3 Name instantiation'],
|
|
667
|
+
['functor(X,foo,N)', 'instantiation_error', 'functor/3 Arity instantiation'],
|
|
668
|
+
['functor(X,foo(a),a)', 'type_error(atomic)', 'functor/3 Name atomic type before Arity type'],
|
|
669
|
+
['functor(X,foo,a)', 'type_error(integer)', 'functor/3 Arity integer type'],
|
|
670
|
+
['functor(X,1.5,1)', 'type_error(atom)', 'functor/3 positive-arity atom name'],
|
|
671
|
+
['functor(X,foo,-1)', 'domain_error(not_less_than_zero)', 'functor/3 non-negative arity'],
|
|
672
|
+
['arg(X,foo(a),_)', 'instantiation_error', 'arg/3 index instantiation'],
|
|
673
|
+
['arg(1,X,_)', 'instantiation_error', 'arg/3 term instantiation'],
|
|
674
|
+
['arg(a,foo(a),_)', 'type_error(integer)', 'arg/3 index type'],
|
|
675
|
+
['arg(0,atom,_)', 'type_error(compound)', 'arg/3 term type before index domain'],
|
|
676
|
+
['arg(-1,foo(a),_)', 'domain_error(not_less_than_zero)', 'arg/3 index domain'],
|
|
677
|
+
['X=..Y', 'instantiation_error', '=../2 both variables'],
|
|
678
|
+
['X=..[foo|T]', 'instantiation_error', '=../2 partial list'],
|
|
679
|
+
['X=..foo', 'type_error(list)', '=../2 list type'],
|
|
680
|
+
['X=..[F,a]', 'instantiation_error', '=../2 head instantiation'],
|
|
681
|
+
['X=..[3,a]', 'type_error(atom)', '=../2 compound functor atom type'],
|
|
682
|
+
['X=..[foo(a)]', 'type_error(atomic)', '=../2 singleton atomic type'],
|
|
683
|
+
['X=..[]', 'domain_error(non_empty_list)', '=../2 non-empty list'],
|
|
684
|
+
['term_variables(t,[X|foo])', 'type_error(list)', 'term_variables/2 output list type'],
|
|
685
|
+
];
|
|
686
|
+
for (const [goal, formal, label] of cases) {
|
|
687
|
+
equal(capture(() => run('', { isoStrict: true, goal })).formal, formal, label);
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
for (const goal of [
|
|
691
|
+
'unify_with_occurs_check(X,1)',
|
|
692
|
+
'subsumes_term(f(X,Y),f(Z,Z))',
|
|
693
|
+
'compare(<,a,b)',
|
|
694
|
+
'sort([1,1],[1])',
|
|
695
|
+
'keysort([2-b,1-a],[1-a,2-b])',
|
|
696
|
+
'copy_term(f(X,X),f(Y,Y))',
|
|
697
|
+
'term_variables(A+B+B,[A,B])',
|
|
698
|
+
]) {
|
|
699
|
+
equal(run('', { isoStrict: true, goal }).stats.completed_goal_lists, 1, `${goal} mode`);
|
|
700
|
+
}
|
|
701
|
+
});
|
|
702
|
+
|
|
703
|
+
reporter.test('closes the ISO 8.15-8.17 prescribed mode/error rows', () => {
|
|
704
|
+
const cases = [
|
|
705
|
+
['\\+(X)', 'instantiation_error', '\+/1 variable goal'],
|
|
706
|
+
['\\+(3)', 'type_error(callable)', '\+/1 callable type'],
|
|
707
|
+
['once(X)', 'instantiation_error', 'once/1 variable goal'],
|
|
708
|
+
['once(3)', 'type_error(callable)', 'once/1 callable type'],
|
|
709
|
+
['call(X,a)', 'instantiation_error', 'call/2 variable closure'],
|
|
710
|
+
['call(3,a)', 'type_error(callable)', 'call/2 callable closure'],
|
|
711
|
+
['call(foo,a,b,c,d,e,f,g,h)', 'existence_error(procedure)', 'selected call/N ceiling at call/8'],
|
|
712
|
+
['atom_length(X,4)', 'instantiation_error', 'atom_length/2 atom instantiation'],
|
|
713
|
+
['atom_length(1.2,4)', 'type_error(atom)', 'atom_length/2 atom type'],
|
|
714
|
+
["atom_length(atom,'4')", 'type_error(integer)', 'atom_length/2 length type'],
|
|
715
|
+
['atom_length(atom,-1)', 'domain_error(not_less_than_zero)', 'atom_length/2 length domain'],
|
|
716
|
+
['atom_concat(X,small,Y)', 'instantiation_error', 'atom_concat/3 first/whole under-instantiation'],
|
|
717
|
+
['atom_concat(small,X,Y)', 'instantiation_error', 'atom_concat/3 second/whole under-instantiation'],
|
|
718
|
+
['atom_concat(1,a,b)', 'type_error(atom)', 'atom_concat/3 first type'],
|
|
719
|
+
['atom_concat(a,1,b)', 'type_error(atom)', 'atom_concat/3 second type'],
|
|
720
|
+
['atom_concat(a,b,1)', 'type_error(atom)', 'atom_concat/3 whole type'],
|
|
721
|
+
['sub_atom(X,0,1,0,a)', 'instantiation_error', 'sub_atom/5 source instantiation'],
|
|
722
|
+
['sub_atom(1,0,1,0,a)', 'type_error(atom)', 'sub_atom/5 source type'],
|
|
723
|
+
['sub_atom(a,0,1,0,1)', 'type_error(atom)', 'sub_atom/5 result atom type'],
|
|
724
|
+
['sub_atom(a,x,1,0,_)', 'type_error(integer)', 'sub_atom/5 Before type'],
|
|
725
|
+
['sub_atom(a,0,x,0,_)', 'type_error(integer)', 'sub_atom/5 Length type'],
|
|
726
|
+
['sub_atom(a,0,1,x,_)', 'type_error(integer)', 'sub_atom/5 After type'],
|
|
727
|
+
['sub_atom(a,-1,1,0,_)', 'domain_error(not_less_than_zero)', 'sub_atom/5 Before domain'],
|
|
728
|
+
['sub_atom(a,0,-1,0,_)', 'domain_error(not_less_than_zero)', 'sub_atom/5 Length domain'],
|
|
729
|
+
['sub_atom(a,0,1,-1,_)', 'domain_error(not_less_than_zero)', 'sub_atom/5 After domain'],
|
|
730
|
+
['atom_chars(X,Y)', 'instantiation_error', 'atom_chars/2 under-instantiation'],
|
|
731
|
+
['atom_chars(1,[])', 'type_error(atom)', 'atom_chars/2 atom type'],
|
|
732
|
+
['atom_chars(X,[a|foo])', 'type_error(list)', 'atom_chars/2 improper list'],
|
|
733
|
+
['atom_chars(X,[Y,a])', 'instantiation_error', 'atom_chars/2 variable prefix element'],
|
|
734
|
+
['atom_chars(X,[a,1])', 'type_error(character)', 'atom_chars/2 character element type'],
|
|
735
|
+
['atom_codes(X,Y)', 'instantiation_error', 'atom_codes/2 under-instantiation'],
|
|
736
|
+
['atom_codes(1,[])', 'type_error(atom)', 'atom_codes/2 atom type'],
|
|
737
|
+
['atom_codes(X,[97|foo])', 'type_error(list)', 'atom_codes/2 improper list'],
|
|
738
|
+
['atom_codes(X,[Y,97])', 'instantiation_error', 'atom_codes/2 variable prefix element'],
|
|
739
|
+
['atom_codes(X,[97,foo])', 'type_error(integer)', 'atom_codes/2 code integer type'],
|
|
740
|
+
['atom_codes(X,[97,-1])', 'representation_error(character_code)', 'atom_codes/2 code representation'],
|
|
741
|
+
['char_code(X,Y)', 'instantiation_error', 'char_code/2 under-instantiation'],
|
|
742
|
+
['char_code(ab,foo)', 'type_error(character)', 'char_code/2 character type before code type'],
|
|
743
|
+
['char_code(a,foo)', 'type_error(integer)', 'char_code/2 code type'],
|
|
744
|
+
['char_code(a,-1)', 'representation_error(character_code)', 'char_code/2 code representation'],
|
|
745
|
+
['number_chars(X,Y)', 'instantiation_error', 'number_chars/2 under-instantiation'],
|
|
746
|
+
['number_chars(foo,[])', 'type_error(number)', 'number_chars/2 number type'],
|
|
747
|
+
['number_chars(X,[a|foo])', 'type_error(list)', 'number_chars/2 improper list'],
|
|
748
|
+
['number_chars(X,[Y,a])', 'instantiation_error', 'number_chars/2 variable prefix element'],
|
|
749
|
+
['number_chars(X,[a,1])', 'type_error(character)', 'number_chars/2 character element type'],
|
|
750
|
+
['number_chars(X,[a])', 'syntax_error(number)', 'number_chars/2 number syntax'],
|
|
751
|
+
['number_codes(X,Y)', 'instantiation_error', 'number_codes/2 under-instantiation'],
|
|
752
|
+
['number_codes(foo,[])', 'type_error(number)', 'number_codes/2 number type'],
|
|
753
|
+
['number_codes(X,[49|foo])', 'type_error(list)', 'number_codes/2 improper list'],
|
|
754
|
+
['number_codes(X,[Y,49])', 'instantiation_error', 'number_codes/2 variable prefix element'],
|
|
755
|
+
['number_codes(X,[49,foo])', 'type_error(integer)', 'number_codes/2 code integer type'],
|
|
756
|
+
['number_codes(X,[49,-1])', 'representation_error(character_code)', 'number_codes/2 code representation'],
|
|
757
|
+
['number_codes(X,[97])', 'syntax_error(number)', 'number_codes/2 number syntax'],
|
|
758
|
+
['current_prolog_flag(1,_)', 'type_error(atom)', 'current_prolog_flag/2 flag type'],
|
|
759
|
+
['current_prolog_flag(no_such_iso_flag,_)', 'domain_error(prolog_flag)', 'current_prolog_flag/2 flag domain'],
|
|
760
|
+
['halt(X)', 'instantiation_error', 'halt/1 instantiation'],
|
|
761
|
+
['halt(a)', 'type_error(integer)', 'halt/1 integer type'],
|
|
762
|
+
];
|
|
763
|
+
for (const [goal, formal, label] of cases) {
|
|
764
|
+
equal(capture(() => run('', { isoStrict: true, goal })).formal, formal, label);
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
equal(run('', { isoStrict: true, goal: 'false' }).stats.completed_goal_lists, 0, 'false/0 fails');
|
|
768
|
+
const onceSolver = new Solver(Program.parse('', { isoStrict: true }), { isoStrict: true });
|
|
769
|
+
equal([...onceSolver.solve([parseGoalText('once((X=1;X=2))', { isoStrict: true })], new Env(), 0)].length,
|
|
770
|
+
1, 'once/1 first solution');
|
|
771
|
+
const onceCommittedSolver = new Solver(Program.parse('', { isoStrict: true }), { isoStrict: true });
|
|
772
|
+
equal([...onceCommittedSolver.solve([parseGoalText('once((X=1;X=2)), X=2', { isoStrict: true })], new Env(), 0)].length,
|
|
773
|
+
0, 'once/1 commits to its first solution');
|
|
774
|
+
const callSolver = new Solver(Program.parse('', { isoStrict: true }), { isoStrict: true });
|
|
775
|
+
equal([...callSolver.solve([parseGoalText('call(atom_concat,pro,log,prolog)', { isoStrict: true })], new Env(), 0)].length,
|
|
776
|
+
1, 'call/4 closure expansion');
|
|
777
|
+
equal(run('', { isoStrict: true, goal: 'atom_concat(A,B,ab)' }).stats.completed_goal_lists, 3, 'atom_concat/3 re-executable splits');
|
|
778
|
+
equal(run('', { isoStrict: true, goal: 'sub_atom(ab,_,_,_,_)' }).stats.completed_goal_lists, 6, 'sub_atom/5 re-executable slices');
|
|
779
|
+
});
|
|
780
|
+
|
|
611
781
|
reporter.test('covers ISO database predicate errors and empty-procedure lifetime', () => {
|
|
612
782
|
const errors = [
|
|
613
783
|
['current_predicate(4)', '', 'type_error(predicate_indicator)'],
|