eyeprolog 1.3.61 → 1.3.63
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -4
- package/package.json +1 -1
- package/test/conformance/ISO-BUILTIN-MODE-ERROR-MATRIX.md +5 -8
- package/test/conformance/ISO-COMPLIANCE.md +31 -37
- package/test/conformance/ISO-EVALUABLE-FUNCTOR-MATRIX.md +3 -4
- package/test/conformance/ISO-IMPLEMENTATION-DEFINED.md +2 -2
- package/test/conformance/ISO-PROCESSOR-REQUIREMENTS.md +31 -16
- package/test/conformance/README.md +4 -7
- package/test/conformance/STC-DRAFT-STATUS.md +5 -7
- package/test/run-iso-strict.mjs +170 -1
- package/test/run-regression.mjs +149 -41
- package/the-art-of-eyeprolog.md +17 -33
- package/why-eyeprolog.md +8 -7
package/README.md
CHANGED
|
@@ -212,15 +212,14 @@ unchanged.
|
|
|
212
212
|
|
|
213
213
|
This README intentionally stays at the project-overview level. The detailed
|
|
214
214
|
implementation reference is [*The Art of EyeProlog*](the-art-of-eyeprolog.md).
|
|
215
|
-
The current Part 1 audit status and
|
|
215
|
+
The current Part 1 audit status and closure criteria are recorded in
|
|
216
216
|
[`test/conformance/ISO-COMPLIANCE.md`](test/conformance/ISO-COMPLIANCE.md);
|
|
217
217
|
implementation-defined decisions are indexed in
|
|
218
218
|
[`ISO-IMPLEMENTATION-DEFINED.md`](test/conformance/ISO-IMPLEMENTATION-DEFINED.md). The complete
|
|
219
219
|
vendored WG17 syntax corpus and the strict ISO regression suite run as release
|
|
220
220
|
gates.
|
|
221
221
|
|
|
222
|
-
|
|
223
|
-
checklist still contains unresolved normative or unexplained-deviation items.
|
|
222
|
+
The release-facing Part 1 audit ledger has explicit dispositions for its tracked requirements. This implementation evidence is not an independent ISO certification.
|
|
224
223
|
|
|
225
224
|
## Module and definite clause grammar compatibility profiles
|
|
226
225
|
|
|
@@ -285,7 +284,7 @@ headroom, so an exhausted finite heap is reported as a catchable
|
|
|
285
284
|
`library(iso_ext)` is also accepted as a common interop module name.
|
|
286
285
|
EyeProlog exports `call_nth/2`, `time/1`, and the DCG helper `... //0` there.
|
|
287
286
|
The latter describes an arbitrary number of input elements and supports the
|
|
288
|
-
nonterminal hand-off benchmark
|
|
287
|
+
nonterminal hand-off benchmark used by the interoperability tests. These common predicates
|
|
289
288
|
may be imported explicitly, while source/CLI/API dependency loading can resolve
|
|
290
289
|
their unqualified forms conservatively. For Trealla-style interactive timing,
|
|
291
290
|
`time/1` is also available directly in the normal EyeProlog runtime; strict ISO
|
package/package.json
CHANGED
|
@@ -209,7 +209,7 @@ The Corrigendum 2 additions have the same shape.
|
|
|
209
209
|
| 8.11.5 errors: argument shapes | non-atom mode; non-list options; non-variable stream output (Cor.2 uninstantiation) | covered | strict `open/4` assertions |
|
|
210
210
|
| 8.11.5 errors: domains | invalid source/sink, I/O mode, or stream option | covered | strict `open/4` assertions |
|
|
211
211
|
| 8.11.5 source/sink errors | missing read source or source/sink that cannot be opened | covered | strict host-I/O probes for existence/permission conditions |
|
|
212
|
-
| 8.11.5 alias collision | `alias(A)` already names an open stream -> open permission error with complete `alias(A)` culprit | covered | focused
|
|
212
|
+
| 8.11.5 alias collision | `alias(A)` already names an open stream -> open permission error with complete `alias(A)` culprit | covered | focused alias-collision regression |
|
|
213
213
|
| 8.11.5 `reposition(true)` impossible | permission error when the requested stream cannot be repositioned | covered | stream option corpus and implementation-defined stream capability checks |
|
|
214
214
|
| 8.11.6 `close/2`, `close/1` | close an open non-standard stream and maintain current-stream fallbacks | covered | stream lifecycle corpus |
|
|
215
215
|
| 8.11.6 errors | variable stream/option element; non-list options; invalid stream-or-alias; invalid close option; missing stream | covered | strict close assertions |
|
|
@@ -364,7 +364,7 @@ built-in matrix does not have a gap at 8.17.
|
|
|
364
364
|
| 8.17.4 variable status | instantiation error | covered | strict `halt(X)` |
|
|
365
365
|
| 8.17.4 non-integer status | integer type error | covered | strict `halt(a)` |
|
|
366
366
|
|
|
367
|
-
##
|
|
367
|
+
## Closure note
|
|
368
368
|
|
|
369
369
|
The built-in **8.2-8.17 row audit is complete** at the level tracked by this
|
|
370
370
|
file: prescribed modes, success/failure behavior, individual error conditions,
|
|
@@ -372,9 +372,6 @@ and conditional/not-applicable processor branches all have explicit outcomes.
|
|
|
372
372
|
ISO 7.12 simultaneous-error selection remains an implementation-dependent
|
|
373
373
|
processor choice unless more specific normative text constrains it.
|
|
374
374
|
|
|
375
|
-
The
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
Clause 7.4-7.8 plus higher-level 7.10/7.12 processor/control semantics, residual
|
|
379
|
-
Clause 5 dependency rows and the unexplained-deviation exit criterion
|
|
380
|
-
recorded in `ISO-COMPLIANCE.md`.
|
|
375
|
+
The surrounding Clause 5-7 processor requirements are closed in
|
|
376
|
+
`ISO-PROCESSOR-REQUIREMENTS.md` and `ISO-COMPLIANCE.md`; this matrix remains the
|
|
377
|
+
detailed evidence for the 8.2-8.17 built-in layer.
|
|
@@ -19,39 +19,38 @@ relevant implementation-dependent overlap choice to an explicit audit outcome.
|
|
|
19
19
|
|
|
20
20
|
| Requirement | Status | EyeProlog evidence / remaining work |
|
|
21
21
|
| --- | --- | --- |
|
|
22
|
-
| 5.1(a) prepare conforming Prolog text |
|
|
23
|
-
| 5.1(b) execute conforming Prolog goals |
|
|
24
|
-
| 5.1(c) reject nonconforming text/read-terms |
|
|
25
|
-
| 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.
|
|
22
|
+
| 5.1(a) prepare conforming Prolog text | covered | Clause 6 token/term production and rejection families are mapped by the strict production gate and the complete 366-case vendored WG17 syntax matrix; 7.4 preparation/directive behavior is separately closed. |
|
|
23
|
+
| 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
|
+
| 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
|
+
| 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
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, disable automatic tabling/recursion guards, and reject the normal-profile host `stringTerm/1` term type at strict program/goal entry. |
|
|
27
|
-
| 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
|
-
| 5.5 extension boundaries |
|
|
27
|
+
| 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
|
+
| 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
29
|
|
|
30
30
|
## Normative language families
|
|
31
31
|
|
|
32
32
|
| Standard area | Status | Current evidence |
|
|
33
33
|
| --- | --- | --- |
|
|
34
|
-
| Clause 6 — tokens, terms, lists, operators, quoted text |
|
|
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 independent production-level coverage, 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
35
|
| 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
36
|
| 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
37
|
| 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. |
|
|
38
38
|
| 7.7 — execution and backtracking | covered | [ISO-PROLOG-TEXT-EXECUTION-MATRIX.md](ISO-PROLOG-TEXT-EXECUTION-MATRIX.md) closes ordinary clause selection/backtracking, source/database order, empty-versus-unknown procedures, logical-update visibility, and strict dispatch. EyeProlog automatic tabling, cycle guards, and recursive numeric shortcuts remain disabled in the strict profile. |
|
|
39
39
|
| 7.8 — control constructs and exceptions | covered | [ISO-PROLOG-TEXT-EXECUTION-MATRIX.md](ISO-PROLOG-TEXT-EXECUTION-MATRIX.md) closes `true/0`, `fail/0`, `call/1`, cut, conjunction, disjunction, if-then(-else), and `catch/3`/`throw/1`, including Corrigendum 2 catchability of errors arising from the protected goal and Corrigendum 3 term-to-body conversion. The 8.15 built-in additions remain independently row-audited. |
|
|
40
40
|
| 7.9 — expression evaluation | covered | [ISO-EVALUABLE-FUNCTOR-MATRIX.md](ISO-EVALUABLE-FUNCTOR-MATRIX.md) closes recursive evaluation, direct-variable precedence, corrected non-evaluable `F/N` errors (including STC #69), operand template/type rules, mixed arithmetic-comparison conversion, exceptional values, and finite-host resource normalization. The audit also fixes float-only `float_integer_part/1` and `float_fractional_part/1` so even huge valid integers reach `type_error(float,...)` before any I->F overflow. |
|
|
41
|
-
| 7.10 — input/output concepts |
|
|
41
|
+
| 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. 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
42
|
| 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
|
-
| 7.12 — errors |
|
|
43
|
+
| 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
44
|
| 8.2-8.17 — built-in predicates | covered | [ISO-BUILTIN-MODE-ERROR-MATRIX.md](ISO-BUILTIN-MODE-ERROR-MATRIX.md) now records the complete Part 1 + Corrigenda built-in family at one row per prescribed mode, success/failure behavior, individual error condition, and conditional/not-applicable branch. The row 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
45
|
| 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
46
|
| Corrigendum 1 | covered | Double-quoted atom/operator-priority corrections have dedicated cases. |
|
|
47
47
|
| Corrigendum 2 | covered | Added predicates/functors, catch corrections, bar/operator and uninstantiation corrections have dedicated cases. |
|
|
48
48
|
| Corrigendum 3 | covered | Writer options, `variable_names/1`, canonical list output and negative-power corrections have dedicated cases. |
|
|
49
49
|
|
|
50
|
-
##
|
|
50
|
+
## Conformance corrections and audit closure
|
|
51
51
|
|
|
52
|
-
The
|
|
53
|
-
concrete mismatches
|
|
54
|
-
conformance claims:
|
|
52
|
+
The audit against the licensed Part 1 text and Corrigenda closed two
|
|
53
|
+
concrete mismatches that are now part of the closed Part 1 audit:
|
|
55
54
|
|
|
56
55
|
- `bounded=false` no longer exposes implementation-specific `unbounded` values
|
|
57
56
|
for `max_integer` or `min_integer`; the corresponding
|
|
@@ -61,7 +60,7 @@ conformance claims:
|
|
|
61
60
|
and feeds the same mapping into execution-time term input.
|
|
62
61
|
|
|
63
62
|
A follow-on audit made the processor-character-set/collation choices explicit.
|
|
64
|
-
|
|
63
|
+
A follow-up processor-character-set review corrected an over-strict interpretation: because PCS membership
|
|
65
64
|
and extended-character classification are implementation defined by Part 1,
|
|
66
65
|
`--iso-strict` must not replace EyeProlog's ordinary processor choice. Both
|
|
67
66
|
profiles now use Unicode scalar values as PCS members and collating integers;
|
|
@@ -73,7 +72,7 @@ WG17 syntax matrix remains a release gate.
|
|
|
73
72
|
|
|
74
73
|
|
|
75
74
|
The subsequent arity audit originally selected a finite `max_arity=65535`, but
|
|
76
|
-
|
|
75
|
+
the post-Corrigendum STC arity review exposed that as the wrong
|
|
77
76
|
abstraction: Part 1 `max_arity` is the maximum arity of **compound terms**, not
|
|
78
77
|
a procedure-arity limit. EyeProlog now again selects `max_arity=unbounded` and
|
|
79
78
|
removes the artificial 65535 checks from source parsing, `functor/3`, `=../2`,
|
|
@@ -88,7 +87,7 @@ The public WG17 `number_chars/2` comparison used in preparation of Corrigendum
|
|
|
88
87
|
2 has additionally been checked during the audit. It remains supporting review
|
|
89
88
|
evidence rather than a duplicated vendored corpus or release criterion.
|
|
90
89
|
|
|
91
|
-
|
|
90
|
+
The flag and term-I/O audit closes the Part 1 flag family and tightens the 8.14
|
|
92
91
|
term-I/O/operator error rules. The strict flag registry now distinguishes a
|
|
93
92
|
standard value that is valid but not selectable from a value outside the
|
|
94
93
|
standard domain: attempts to change fixed `bounded` or
|
|
@@ -102,7 +101,7 @@ the Part 1 plus Corrigendum 3 option surface; the normal-profile
|
|
|
102
101
|
extension.
|
|
103
102
|
|
|
104
103
|
|
|
105
|
-
The
|
|
104
|
+
The preparation, stream, conversion, sorting, and arithmetic audit expands the coverage into Prolog-text,
|
|
106
105
|
stream, atomic-conversion, sorting, and arithmetic edge cases. Strict
|
|
107
106
|
preparation now enforces the Part 1 declaration constraints for `dynamic/1`,
|
|
108
107
|
`multifile/1`, and `discontiguous/1`, including cross-text multifile use and
|
|
@@ -112,13 +111,11 @@ requirements, and tightens creation, truncation/append, repositioning, flush,
|
|
|
112
111
|
EOF, close, and current-stream behavior. Corrigendum 2 `keysort/2` variable and
|
|
113
112
|
non-pair errors are corrected. Strict arithmetic no longer exposes the
|
|
114
113
|
EyeProlog-only evaluable atom `e`, while the Corrigendum arithmetic additions
|
|
115
|
-
remain available. These corrections
|
|
116
|
-
not by themselves close the full shall-by-shall/error-condition exit criteria.
|
|
114
|
+
remain available. These corrections are retained as regression evidence inside the closed shall-by-shall/error-condition audit.
|
|
117
115
|
|
|
118
116
|
The next Corrigendum 2 pass closed the prescribed `call/2..8` max-arity
|
|
119
117
|
branch for processors with a finite `max_arity`, and corrected reverse
|
|
120
|
-
`atom_chars/2` / `atom_codes/2` improper-list culprits.
|
|
121
|
-
EyeProlog's selected `max_arity=unbounded`, the conditional `call/N`
|
|
118
|
+
`atom_chars/2` / `atom_codes/2` improper-list culprits. With EyeProlog's selected `max_arity=unbounded`, the conditional `call/N`
|
|
122
119
|
`representation_error(max_arity)` branch is intentionally unreachable unless a
|
|
123
120
|
future processor profile selects a finite compound-term limit; closure
|
|
124
121
|
expansion itself remains covered by strict regressions.
|
|
@@ -165,8 +162,7 @@ describes: a later `force(false)` does not cancel an earlier `force(true)` when
|
|
|
165
162
|
a Resource Error or System Error occurs during closure. Focused strict tests
|
|
166
163
|
cover both overlap families.
|
|
167
164
|
|
|
168
|
-
The
|
|
169
|
-
than leaving it as a broad test-count claim.
|
|
165
|
+
The row-level matrices make the exit criteria concrete rather than leaving conformance as a broad test-count claim.
|
|
170
166
|
[ISO-BUILTIN-MODE-ERROR-MATRIX.md](ISO-BUILTIN-MODE-ERROR-MATRIX.md) now records
|
|
171
167
|
each prescribed mode/error row for the 8.2-8.5 and 8.15-8.17 slices, and
|
|
172
168
|
[ISO-PROCESSOR-REQUIREMENTS.md](ISO-PROCESSOR-REQUIREMENTS.md) decomposes the
|
|
@@ -206,9 +202,7 @@ individual-error outcomes in `ISO-BUILTIN-MODE-ERROR-MATRIX.md`. During this
|
|
|
206
202
|
pass `stream_property/2` exposed a lifecycle distinction: a syntactically valid
|
|
207
203
|
stream-term for a stream that has been closed denotes no currently open stream
|
|
208
204
|
property pair and therefore fails, whereas a term that is not a stream-term is
|
|
209
|
-
still a `domain_error(stream, ...)`.
|
|
210
|
-
higher-level 7.10 stream semantics, residual 7.12 processor errors, and final
|
|
211
|
-
unexplained-deviation closure rather than unmapped built-in tables.
|
|
205
|
+
still a `domain_error(stream, ...)`. The higher-level Clause 6, 7.10, and 7.12 gates now close those surrounding processor requirements as well, so the built-in table participates in a fully dispositioned release-facing ledger.
|
|
212
206
|
|
|
213
207
|
## Post-Corrigendum STC cross-check
|
|
214
208
|
|
|
@@ -224,7 +218,7 @@ type precedence, `read_term/3` EOF handling, mixed arithmetic comparison,
|
|
|
224
218
|
and `bagof/3` answer order. STC #21 is also used to keep finite-host exhaustion
|
|
225
219
|
of unbounded integer operations inside the Prolog resource-error model.
|
|
226
220
|
|
|
227
|
-
|
|
221
|
+
The newer STC arity discussion clarifies that `max_arity` describes
|
|
228
222
|
compound terms. EyeProlog therefore selects `unbounded` and does not invent a
|
|
229
223
|
finite predicate/procedure ceiling merely to preserve the former 65535 value.
|
|
230
224
|
STC #56, which became a WG17 action item, is implemented narrowly for database
|
|
@@ -284,25 +278,25 @@ outputs are never auto-accepted.
|
|
|
284
278
|
|
|
285
279
|
## Exit criteria for a full conformance claim
|
|
286
280
|
|
|
287
|
-
|
|
288
|
-
The
|
|
289
|
-
|
|
290
|
-
|
|
281
|
+
The Part 1 audit is closed by explicit dispositions, not by a test-count threshold.
|
|
282
|
+
The table below records the closure criteria used by the project. A `covered`
|
|
283
|
+
status is an implementation/audit result, not an independent certification. Public
|
|
284
|
+
post-N289 STC drafts remain review input until standardized.
|
|
291
285
|
|
|
292
|
-
| Criterion | Status | Evidence
|
|
286
|
+
| Criterion | Status | Evidence |
|
|
293
287
|
| --- | --- | --- |
|
|
294
|
-
| Clause 5 processor obligations have explicit dispositions |
|
|
295
|
-
| Clause 6 lexical/syntactic requirements have explicit dispositions |
|
|
296
|
-
| Clause 7 semantic requirements have explicit dispositions |
|
|
288
|
+
| 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
|
+
| 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
|
+
| 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. |
|
|
297
291
|
| Clause 8 built-in modes/errors have explicit dispositions | covered | `ISO-BUILTIN-MODE-ERROR-MATRIX.md` closes 8.2-8.17 row by row |
|
|
298
292
|
| 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 |
|
|
299
293
|
| Implementation-defined choices are documented | covered | `ISO-IMPLEMENTATION-DEFINED.md` is the Clause 5.4 decision index and strict tests pin execution-visible choices |
|
|
300
|
-
| Implementation-specific strict/normal boundary is documented and tested |
|
|
294
|
+
| 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. |
|
|
301
295
|
| Published Corrigenda 1-3 are incorporated | covered | dedicated conformance/strict tests and this ledger track all three published Corrigenda |
|
|
302
296
|
| 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 |
|
|
303
297
|
| Independent external syntax corpus is an offline release gate | covered | the vendored WG17 syntax matrix has 366 executable dispositions checked against its upstream expectations |
|
|
304
298
|
| 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` |
|
|
305
|
-
| No unexplained deviation remains in the release-facing ledger |
|
|
299
|
+
| 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. |
|
|
306
300
|
|
|
307
301
|
The specialized row matrices are evidence for this ledger, not separate public
|
|
308
302
|
status documents. *The Art of EyeProlog* remains the implementation reference.
|
|
@@ -85,7 +85,6 @@ unbounded integer model and translate finite-host exhaustion to
|
|
|
85
85
|
## Closure note
|
|
86
86
|
|
|
87
87
|
With this matrix and the strict arithmetic regression, the release-facing
|
|
88
|
-
Clause 7.9 and Clause 9 rows are `covered`. The
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
and the remaining processor-level exit criteria.
|
|
88
|
+
Clause 7.9 and Clause 9 rows are `covered`. The surrounding processor and syntax
|
|
89
|
+
requirements are dispositioned in `ISO-PROCESSOR-REQUIREMENTS.md` and
|
|
90
|
+
`ISO-COMPLIANCE.md`.
|
|
@@ -65,7 +65,7 @@ Status values are:
|
|
|
65
65
|
| 9.1.3.1 | Integer division rounding function `rndI` | Truncation toward zero, matching the `integer_rounding_function=toward_zero` flag. | **defined** — BigInt division for `//` in `src/iso-arithmetic.js`. |
|
|
66
66
|
| 7.11.2.1 | Whether preparation-time `Convc` affects execution-time `Convc` | Yes: mappings created while Prolog text is prepared are retained and initialize the solver's execution-time conversion map. | **defined** — `src/parser.js`, `src/program.js`, `src/solver.js`. |
|
|
67
67
|
| 7.11.2.2 | Effect when `debug=on` | The flag is accepted and stored; it does not change goal semantics or enable a debugger. | **defined** — `src/solver.js`; no semantic branch depends on `debug`. |
|
|
68
|
-
| 7.11.2.3 | Default `max_arity` | `unbounded`: EyeProlog imposes no fixed semantic ceiling on compound-term arity. Practical host allocation exhaustion is a resource condition. This flag is distinct from any potential implementation-specific procedure-arity limit; EyeProlog currently declares no separate finite procedure limit. | **defined** — `src/iso-limits.js`, `src/solver.js`, `src/parser.js`, `src/iso.js`;
|
|
68
|
+
| 7.11.2.3 | Default `max_arity` | `unbounded`: EyeProlog imposes no fixed semantic ceiling on compound-term arity. Practical host allocation exhaustion is a resource condition. This flag is distinct from any potential implementation-specific procedure-arity limit; EyeProlog currently declares no separate finite procedure limit. | **defined** — `src/iso-limits.js`, `src/solver.js`, `src/parser.js`, `src/iso.js`; strict regression coverage. |
|
|
69
69
|
| 7.11.2.5 | Default `double_quotes` | `chars`. | **defined** — `src/solver.js`, parser flag state. |
|
|
70
70
|
| 7.12.1 | Second argument of `error/2` | The default context term is the atom `eyeprolog`. A few implementation-specific diagnostics may deliberately supply a more specific context term. | **defined** — `formalErrorTerm()` in `src/iso.js`. |
|
|
71
71
|
| 7.12.2(f) | Implementation-defined representation limits | Character and character-code operations are limited to Unicode scalar values; surrogates and values above U+10FFFF are representation errors. Arity/integer values are modeled as unbounded but may hit host/resource limits. Float input overflow uses the implementation-specific `max_float`/`min_float` representation names documented by the STC-oriented tests. | **defined** — parser/ISO numeric and character guards. |
|
|
@@ -83,7 +83,7 @@ Status values are:
|
|
|
83
83
|
| 9.4.5 | Bitwise complement | BigInt complement, i.e. `~N = -N-1`. | **defined** — `~a`. |
|
|
84
84
|
| Cor.2 9.4.6 | `xor/2` with negative operands | BigInt infinite-two's-complement semantics. | **defined** — `a ^ b`. |
|
|
85
85
|
|
|
86
|
-
###
|
|
86
|
+
### Floating underflow policy
|
|
87
87
|
|
|
88
88
|
Clause 9.1.4.2 permits the processor to choose `round(x)` or the exceptional
|
|
89
89
|
value `underflow` for a tiny non-zero result when an operation is governed by
|
|
@@ -7,27 +7,26 @@ extension boundary visible as its own auditable row.
|
|
|
7
7
|
|
|
8
8
|
The normative baseline is ISO/IEC 13211-1:1995 plus Technical Corrigenda 1-3.
|
|
9
9
|
`covered` means the requirement has an implementation/documentation decision
|
|
10
|
-
and executable evidence. `
|
|
11
|
-
|
|
12
|
-
an explicit pass/not-applicable decision. No row here is an independent
|
|
10
|
+
and executable evidence. `not applicable` records a standard variation that does
|
|
11
|
+
not apply to EyeProlog's selected processor profile. No row here is an independent
|
|
13
12
|
certification claim.
|
|
14
13
|
|
|
15
14
|
## 5.1 — conforming processor obligations
|
|
16
15
|
|
|
17
|
-
| Requirement | Status | Current evidence
|
|
16
|
+
| Requirement | Status | Current evidence |
|
|
18
17
|
| --- | --- | --- |
|
|
19
|
-
| 5.1(a) prepare conforming Prolog text |
|
|
20
|
-
| 5.1(b) execute conforming Prolog goals |
|
|
21
|
-
| 5.1(c) reject nonconforming text/read terms |
|
|
18
|
+
| 5.1(a) prepare conforming Prolog text | covered | the strict Clause 6 production/rejection gate, complete vendored WG17 syntax matrix, and closed 7.4 preparation/directive matrix cover text recognition and preparation |
|
|
19
|
+
| 5.1(b) execute conforming Prolog goals | covered | 7.1-7.12 semantics, all 8.2-8.17 built-in rows, and Clause 9 evaluable functors have explicit executable dispositions |
|
|
20
|
+
| 5.1(c) reject nonconforming text/read terms | covered | WG17 negative cases plus focused malformed token, list, operator, argument, escape, comment, and extension-syntax cases exercise rejection across the Clause 6 families |
|
|
22
21
|
| 5.1(d) specify permitted variations | covered | `ISO-IMPLEMENTATION-DEFINED.md` records the Part 1 implementation-defined choices and implementation-specific extension families |
|
|
23
22
|
| 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
23
|
|
|
25
24
|
## 5.2-5.4 — text, goals, and documentation
|
|
26
25
|
|
|
27
|
-
| Requirement | Status | Current evidence
|
|
26
|
+
| Requirement | Status | Current evidence |
|
|
28
27
|
| --- | --- | --- |
|
|
29
|
-
| 5.2 conforming and strictly conforming Prolog text boundary |
|
|
30
|
-
| 5.3 conforming and strictly conforming Prolog goal boundary |
|
|
28
|
+
| 5.2 conforming and strictly conforming Prolog text boundary | covered | strict parsing/preparation accepts the Part 1 + Corrigenda language under the documented PCS choices and rejects implementation-specific language facilities; normal-profile preservation is checked against every strict-accepted WG17 case |
|
|
29
|
+
| 5.3 conforming and strictly conforming Prolog goal boundary | covered | strict registry/control/evaluable filtering plus closed 7.1-7.12, 8.2-8.17, and Clause 9 audits define the goal boundary |
|
|
31
30
|
| 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
31
|
|
|
33
32
|
## 5.5 — extension boundaries
|
|
@@ -35,7 +34,7 @@ certification claim.
|
|
|
35
34
|
| Requirement | Status | EyeProlog decision / evidence |
|
|
36
35
|
| --- | --- | --- |
|
|
37
36
|
| 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 |
|
|
37
|
+
| 5.5.1 syntax extensions preserve standard token/text meaning | covered | WG17 syntax is a release gate and strict mode removes module/DCG/quad interpretation. Every vendored WG17 case that succeeds in the strict reader has the same observable outcome in normal mode; the focused Clause 6 gate separately covers each standard token/term family and malformed counterparts. |
|
|
39
38
|
| 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
39
|
| 5.5.3 initial character-conversion mapping | covered | identity initial mapping; user changes are exercised through preparation/execution `char_conversion/2` behavior |
|
|
41
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)` |
|
|
@@ -47,10 +46,26 @@ certification claim.
|
|
|
47
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 |
|
|
48
47
|
| 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
48
|
|
|
49
|
+
## Clause 6 syntax-preservation closure
|
|
50
|
+
|
|
51
|
+
The production audit is kept here rather than in another status file. The strict
|
|
52
|
+
regression gate covers the following families directly, while the complete WG17
|
|
53
|
+
matrix supplies the detailed independent syntax cases.
|
|
54
|
+
|
|
55
|
+
| Clause family | Disposition | Executable evidence |
|
|
56
|
+
| --- | --- | --- |
|
|
57
|
+
| 6.2 Prolog text/data boundary | covered | complete-term parsing, end-token/boundary rejection, preparation tests |
|
|
58
|
+
| 6.3.1-6.3.3 atomic, variable, functional compound terms | covered | atoms, integers/floats, negative numbers, variables, functional arguments |
|
|
59
|
+
| 6.3.4 operator notation | covered | precedence/associativity/operator-table tests plus invalid `xfx` chaining |
|
|
60
|
+
| 6.3.5-6.3.7 list, curly and double-quoted notation | covered | list tails, curly terms, `double_quotes` behavior and read/write round trips |
|
|
61
|
+
| 6.4.1-6.4.8 tokens | covered | layout/comments, quoted escapes, names, integer bases/character codes, floats, double-quoted tokens, solo/meta tokens, malformed counterparts |
|
|
62
|
+
| 6.5 processor characters | covered | documented Unicode-scalar PCS and lexical classes, invalid-scalar representation errors |
|
|
63
|
+
| 6.6 collating sequence | covered | Unicode scalar value collation, atom-order regressions |
|
|
64
|
+
| 5.5.1 preservation under extensions | covered | every WG17 case accepted in strict mode has the same observable result in normal mode |
|
|
65
|
+
|
|
50
66
|
## Exit-use rule
|
|
51
67
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
being mistaken for a completed processor-requirement audit.
|
|
68
|
+
All top-level rows now have covered, not-applicable, or documented
|
|
69
|
+
implementation-defined outcomes. `ISO-COMPLIANCE.md` records the same closure in
|
|
70
|
+
its embedded release-exit checklist. The green suite is evidence for those
|
|
71
|
+
dispositions; it is not presented as independent certification.
|
|
@@ -24,13 +24,10 @@ review evidence, not normative ISO claims.
|
|
|
24
24
|
profile and implementation extensions. The default registry covers the exact
|
|
25
25
|
predicate indicators listed in Appendix B of the book across the Part 1 strict-core
|
|
26
26
|
target and the normal-mode module/DCG compatibility families. [ISO-COMPLIANCE.md](ISO-COMPLIANCE.md) is the explicit
|
|
27
|
-
release-facing ledger for the Part 1 strict-core audit. This suite is
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
tracked and closed at row level. The remaining Clause 6, higher-level
|
|
32
|
-
7.10/7.12, processor-dependency, and unexplained-deviation criteria stay
|
|
33
|
-
explicitly open in the dedicated audit files. Public comparison material used during the audit remains supporting review
|
|
27
|
+
release-facing ledger for the Part 1 strict-core audit. This suite is not an independent certification. The release-facing Part 1
|
|
28
|
+
ledger now has explicit dispositions for Clause 5 processor obligations, Clause 6
|
|
29
|
+
syntax/rejection, Clause 7 semantics, the complete 8.2-8.17 built-in family, and
|
|
30
|
+
Clause 9 evaluable functors. Public comparison material remains supporting review
|
|
34
31
|
evidence rather than a duplicated vendored corpus. Cases under `iso/`
|
|
35
32
|
identify standards-derived behavior; other directories cover EyeProlog host
|
|
36
33
|
contracts and extensions. EyeProlog-only execution features such as automatic
|
|
@@ -32,23 +32,22 @@ regressions.
|
|
|
32
32
|
| [#49](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#49) | `read_term/3` and EOF | Covered by strict reader/conformance tests and the interactive-read regressions. |
|
|
33
33
|
| [#50](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#50) | mixed integer/float arithmetic comparison | The STC-facing normal-profile case requires exact cross-type ordering and `max/2`/`min/2` use the same comparison. `--iso-strict` deliberately retains the published Part 1 integer-to-float comparison rule; the draft case is not silently substituted for that normative baseline. |
|
|
34
34
|
| [#55](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#55) | integer rounding function | Existing flag conformance verifies `integer_rounding_function = toward_zero`. |
|
|
35
|
-
| [#56](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#56) | protect `(:-)/1` and `(:-)/2` from database modification | **
|
|
35
|
+
| [#56](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#56) | protect `(:-)/1` and `(:-)/2` from database modification | **The audit found a gap.** Strict database operations now treat both functors as static/private for `assert*`, `retract*`, `abolish/1`, declarations, and `clause/2`, while ordinary calls still follow the separate procedure-existence behavior described by the STC item. |
|
|
36
36
|
| [#58](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#58) | `set_prolog_flag/2` instantiation error | Existing strict/error coverage requires an instantiation error when a required flag value is a variable. |
|
|
37
37
|
| [#67](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#67) | `bagof/3` answer-order example | `stc/bagof_answer_order` verifies the proposed clarifying example produces `[2,1]`. |
|
|
38
38
|
| [#68](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#68) | division examples | Existing arithmetic coverage evaluates signed integer `/` through the floating operation; no implementation-defined signed-division result is used. |
|
|
39
|
-
| [#69](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#69) | arithmetic example culprit | **
|
|
40
|
-
| [#70](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#70) | optional `max_procedure_arity` | Reviewed after
|
|
39
|
+
| [#69](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#69) | arithmetic example culprit | **The audit found a gap.** Strict expression evaluation now applies 7.9.2(c) to an atomic subexpression such as `foo`: it reports `type_error(evaluable,foo/0)` rather than the misleading `type_error(number,foo)` shown by the old 9.1.7 example. |
|
|
40
|
+
| [#70](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#70) | optional `max_procedure_arity` | Reviewed after the STC arity discussion corrected the earlier #71 pointer. EyeProlog has no declared procedure-arity limit smaller than its `max_arity=unbounded` term model, so the implementation-defined optional flag is intentionally absent. |
|
|
41
41
|
| [#72](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#72) | tentative non-ground stream-term instances | Reviewed as a tentative post-2026 proposal. EyeProlog does not make this draft wording normative in `--iso-strict`; the published Part 1 stream-term/domain rules remain the baseline until WG17 settles the proposal. |
|
|
42
42
|
| [#73](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#73) | `read/1-2` and `read_term/2-3` representation limits | The 2026-08-23 post-N289 draft now explicitly proposes `max_float` / `min_float` alongside the existing representation-limit flags. EyeProlog already reports those errors while reading overflowing positive/negative float tokens; strict regression coverage now exercises both `read/1` and `read_term/2`, and the literal STC cases pin parser preparation. |
|
|
43
43
|
| [#74](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#74) | `number_chars/2` and `number_codes/2` representation limits | Positive and negative overflow now have explicit draft-facing cases for both conversion predicates, reporting `representation_error(max_float)` / `representation_error(min_float)` rather than a syntax error. |
|
|
44
44
|
| [#75](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#75) | power underflow versus the 9.1.4.2 `resultF` choice | The draft proposes making the Part 1 `**/2` and Corrigendum 2 `^/2` underflow rows conditional on the implementation-defined `resultF` underflow choice. EyeProlog's published-baseline strict mode intentionally retains the currently published unconditional power-underflow clauses; its separate 9.1.4.2 choice remains `round(x)`. This proposal is tracked, not silently adopted. |
|
|
45
45
|
| [#76](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#76) | `read/1-2` and `read_term/2-3` invalid input entity | Existing file-stream regressions already require `representation_error(character)` for invalid UTF-8 through all four read/read_term arities. The regression is now cross-referenced to the new draft item. |
|
|
46
|
-
| [issue #54](https://github.com/eyereasoner/eyeprolog/issues/54) | float input range and underflow background | The earlier EyeProlog issue remains useful background for finite-double input overflow/underflow. Its overflow cases are now tracked by STC #73/#74; input underflow remains a separate implementation-profile check and must not be conflated with STC #75's power-underflow proposal. |
|
|
47
46
|
|
|
48
|
-
## Float-reading note
|
|
47
|
+
## Float-reading implementation note
|
|
49
48
|
|
|
50
49
|
EyeProlog currently has a finite-double numeric profile. The draft-facing cases
|
|
51
|
-
record
|
|
50
|
+
record EyeProlog's finite-double behavior:
|
|
52
51
|
|
|
53
52
|
- a positive finite numeric token beyond the representable range raises
|
|
54
53
|
`representation_error(max_float)`;
|
|
@@ -69,7 +68,6 @@ how power underflow relates to the implementation-defined `resultF` choice.
|
|
|
69
68
|
Relevant background:
|
|
70
69
|
|
|
71
70
|
- [WG17 float update](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/core_update_float-2014-07-21)
|
|
72
|
-
- [Issue #54](https://github.com/eyereasoner/eyeprolog/issues/54)
|
|
73
71
|
|
|
74
72
|
## Maintenance rule
|
|
75
73
|
|
package/test/run-iso-strict.mjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Release gate for the ISO/IEC 13211-1 strict-core execution profile.
|
|
3
3
|
// This is intentionally separate from the broader `iso/` corpus because that
|
|
4
4
|
// corpus also exercises Part 2 modules and Part 3 grammar rules.
|
|
5
|
-
import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
|
|
5
|
+
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
6
6
|
import { tmpdir } from 'node:os';
|
|
7
7
|
import { join } from 'node:path';
|
|
8
8
|
|
|
@@ -184,6 +184,56 @@ export function runIsoStrict(reporter = new TestReporter()) {
|
|
|
184
184
|
equal(strict.stats.completed_goal_lists, 1, 'strict Unicode char_code/2');
|
|
185
185
|
});
|
|
186
186
|
|
|
187
|
+
reporter.test('closes the Clause 6 syntax production and rejection rows', () => {
|
|
188
|
+
const accepted = [
|
|
189
|
+
['p(a).', '6.3.1 atom'],
|
|
190
|
+
['p(123).', '6.3.1 integer'],
|
|
191
|
+
['p(1.5).', '6.3.1 float'],
|
|
192
|
+
['p(-1).', '6.3.1 negative integer'],
|
|
193
|
+
['p(-1.5).', '6.3.1 negative float'],
|
|
194
|
+
['p(X,_,_).', '6.3.2 variables'],
|
|
195
|
+
['p(f(a,b)).', '6.3.3 functional compound'],
|
|
196
|
+
['p((a+b*c)).', '6.3.4 operator notation'],
|
|
197
|
+
['p([a,b|T]).', '6.3.5 list notation'],
|
|
198
|
+
['p({a}).', '6.3.6 curly term'],
|
|
199
|
+
['p("ab").', '6.3.7/6.4.6 double quoted list'],
|
|
200
|
+
['% line comment\np(a).', '6.4.1 layout and line comment'],
|
|
201
|
+
['/* block comment */ p(a).', '6.4.1 bracketed comment'],
|
|
202
|
+
["p('a\\n').", '6.4.2 quoted character escape'],
|
|
203
|
+
['p(0b101).', '6.4.4 binary integer'],
|
|
204
|
+
['p(0o17).', '6.4.4 octal integer'],
|
|
205
|
+
['p(0x1f).', '6.4.4 hexadecimal integer'],
|
|
206
|
+
["p(0'a).", '6.4.4 character-code integer'],
|
|
207
|
+
['p(1.2e3).', '6.4.5 exponent float'],
|
|
208
|
+
['p(!).', '6.4.8 solo token'],
|
|
209
|
+
];
|
|
210
|
+
for (const [source, label] of accepted) {
|
|
211
|
+
equal(parseProgramText(source, { isoStrict: true }).length, 1, label);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const rejected = [
|
|
215
|
+
['p(`x`).', '6.4.7 back quoted string has no Part 1 token'],
|
|
216
|
+
["p('x).", 'unterminated quoted token'],
|
|
217
|
+
['p([a|b,c]).', 'invalid list production'],
|
|
218
|
+
['p((1 = 2 = 3)).', 'invalid xfx associativity'],
|
|
219
|
+
['p(a).x', 'end character requires a token boundary'],
|
|
220
|
+
['p(1.0e).', 'malformed floating point token'],
|
|
221
|
+
['p(a b).', 'adjacent alphanumeric tokens need separation/grammar'],
|
|
222
|
+
['p(a,,b).', 'invalid argument production'],
|
|
223
|
+
['/* unterminated', 'unterminated bracketed comment'],
|
|
224
|
+
["p('\\x').", 'invalid hexadecimal escape'],
|
|
225
|
+
];
|
|
226
|
+
for (const [source, label] of rejected) {
|
|
227
|
+
let threw = false;
|
|
228
|
+
try {
|
|
229
|
+
parseProgramText(source, { isoStrict: true });
|
|
230
|
+
} catch (_) {
|
|
231
|
+
threw = true;
|
|
232
|
+
}
|
|
233
|
+
equal(threw, true, label);
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
|
|
187
237
|
reporter.test('rejects the normal-profile string term extension at strict API boundaries', () => {
|
|
188
238
|
const normalSolver = new Solver(Program.parse(''), {});
|
|
189
239
|
const normalGoal = compound('=', [stringTerm('x'), stringTerm('x')]);
|
|
@@ -472,6 +522,92 @@ export function runIsoStrict(reporter = new TestReporter()) {
|
|
|
472
522
|
], new Env(), 0)].length, 1, 'set_stream_position/2 successful mode');
|
|
473
523
|
});
|
|
474
524
|
|
|
525
|
+
reporter.test('closes the higher-level ISO 7.10 stream model rows', () => {
|
|
526
|
+
const directory = mkdtempSync(join(tmpdir(), 'eyeprolog-iso-710-'));
|
|
527
|
+
const atomPath = (value) => `'${String(value).replaceAll("'", "''")}'`;
|
|
528
|
+
try {
|
|
529
|
+
const inputPath = join(directory, 'input.txt');
|
|
530
|
+
writeFileSync(inputPath, 'ab');
|
|
531
|
+
equal(run('', {
|
|
532
|
+
isoStrict: true,
|
|
533
|
+
goal: [
|
|
534
|
+
`open(${atomPath(inputPath)},read,S,[alias(tmp_in),reposition(true),eof_action(eof_code)])`,
|
|
535
|
+
'\\+ atom(S)',
|
|
536
|
+
'stream_property(S,input)',
|
|
537
|
+
'stream_property(S,alias(tmp_in))',
|
|
538
|
+
'stream_property(S,reposition(true))',
|
|
539
|
+
'stream_property(S,eof_action(eof_code))',
|
|
540
|
+
'set_input(tmp_in)',
|
|
541
|
+
"get_char('a')",
|
|
542
|
+
'close(tmp_in)',
|
|
543
|
+
'current_input(C)',
|
|
544
|
+
'stream_property(C,alias(user_input))',
|
|
545
|
+
'catch(set_input(tmp_in),error(existence_error(stream,tmp_in),eyeprolog),true)',
|
|
546
|
+
].join(','),
|
|
547
|
+
}).stats.completed_goal_lists, 1, 'stream-term, alias lifetime, target/current input, and close fallback');
|
|
548
|
+
|
|
549
|
+
const truncatePath = join(directory, 'truncate.txt');
|
|
550
|
+
writeFileSync(truncatePath, 'old');
|
|
551
|
+
equal(run('', {
|
|
552
|
+
isoStrict: true,
|
|
553
|
+
goal: `open(${atomPath(truncatePath)},write,S,[]),close(S)`,
|
|
554
|
+
}).stats.completed_goal_lists, 1, 'write open/close succeeds');
|
|
555
|
+
equal(readFileSync(truncatePath, 'utf8'), '', 'write mode empties an existing sink');
|
|
556
|
+
|
|
557
|
+
const appendPath = join(directory, 'append.txt');
|
|
558
|
+
writeFileSync(appendPath, 'ab');
|
|
559
|
+
equal(run('', {
|
|
560
|
+
isoStrict: true,
|
|
561
|
+
goal: `open(${atomPath(appendPath)},append,S,[reposition(true)]),put_char(S,c),set_stream_position(S,1),put_char(S,'Z'),close(S)`,
|
|
562
|
+
}).stats.completed_goal_lists, 1, 'append and repositioned output succeed');
|
|
563
|
+
equal(readFileSync(appendPath, 'utf8'), 'aZc', 'append starts at end and repositioned output overwrites');
|
|
564
|
+
|
|
565
|
+
const optionsPath = join(directory, 'options.txt');
|
|
566
|
+
writeFileSync(optionsPath, 'x');
|
|
567
|
+
equal(run('', {
|
|
568
|
+
isoStrict: true,
|
|
569
|
+
goal: [
|
|
570
|
+
`open(${atomPath(optionsPath)},read,S,[type(binary),type(text),reposition(false),reposition(true),eof_action(error),eof_action(eof_code)])`,
|
|
571
|
+
'stream_property(S,type(text))',
|
|
572
|
+
'stream_property(S,reposition(true))',
|
|
573
|
+
'stream_property(S,eof_action(eof_code))',
|
|
574
|
+
'close(S)',
|
|
575
|
+
].join(','),
|
|
576
|
+
}).stats.completed_goal_lists, 1, 'rightmost contradictory stream option applies');
|
|
577
|
+
|
|
578
|
+
const binaryPath = join(directory, 'roundtrip.bin');
|
|
579
|
+
equal(run('', {
|
|
580
|
+
isoStrict: true,
|
|
581
|
+
goal: [
|
|
582
|
+
`open(${atomPath(binaryPath)},write,W,[type(binary)])`,
|
|
583
|
+
'put_byte(W,0)',
|
|
584
|
+
'put_byte(W,255)',
|
|
585
|
+
'close(W)',
|
|
586
|
+
`open(${atomPath(binaryPath)},read,R,[type(binary)])`,
|
|
587
|
+
'get_byte(R,0)',
|
|
588
|
+
'get_byte(R,255)',
|
|
589
|
+
'get_byte(R,-1)',
|
|
590
|
+
'close(R)',
|
|
591
|
+
].join(','),
|
|
592
|
+
}).stats.completed_goal_lists, 1, 'binary stream round-trip is byte exact');
|
|
593
|
+
equal([...readFileSync(binaryPath)].join(','), '0,255', 'binary sink contains exactly the output bytes');
|
|
594
|
+
|
|
595
|
+
const textPath = join(directory, 'text.txt');
|
|
596
|
+
equal(run('', {
|
|
597
|
+
isoStrict: true,
|
|
598
|
+
goal: `open(${atomPath(textPath)},write,S,[]),put_char(S,a),flush_output(S),close(S)`,
|
|
599
|
+
}).stats.completed_goal_lists, 1, 'text flush/close succeeds');
|
|
600
|
+
equal(readFileSync(textPath, 'utf8'), 'a', 'flush/close does not synthesize a final newline');
|
|
601
|
+
|
|
602
|
+
equal(run('', {
|
|
603
|
+
isoStrict: true,
|
|
604
|
+
goal: 'current_input(I),close(I),current_input(I),current_output(O),close(O),current_output(O)',
|
|
605
|
+
}).stats.completed_goal_lists, 1, 'standard streams remain open when close/1 is called');
|
|
606
|
+
} finally {
|
|
607
|
+
rmSync(directory, { recursive: true, force: true });
|
|
608
|
+
}
|
|
609
|
+
});
|
|
610
|
+
|
|
475
611
|
reporter.test('closes the ISO 8.12-8.14 character, byte, and term-I/O rows', () => {
|
|
476
612
|
const errors = [
|
|
477
613
|
['get_char(S,C)', 'instantiation_error', 'get_char/2 stream instantiation'],
|
|
@@ -611,6 +747,39 @@ export function runIsoStrict(reporter = new TestReporter()) {
|
|
|
611
747
|
closeWith('[force(false),force(true)]');
|
|
612
748
|
});
|
|
613
749
|
|
|
750
|
+
reporter.test('closes the ISO 7.12 processor error envelope and classification rows', () => {
|
|
751
|
+
const caught = [
|
|
752
|
+
"catch(atom_length(X,N),error(instantiation_error,eyeprolog),true)",
|
|
753
|
+
"catch(atom_length(1,N),error(type_error(atom,1),eyeprolog),true)",
|
|
754
|
+
"catch(op(1300,xfx,foo),error(domain_error(operator_priority,1300),eyeprolog),true)",
|
|
755
|
+
"catch(call(no_such_predicate),error(existence_error(procedure,no_such_predicate/0),eyeprolog),true)",
|
|
756
|
+
"catch(abolish(atom/1),error(permission_error(modify,static_procedure,atom/1),eyeprolog),true)",
|
|
757
|
+
"catch(char_code(C,1114112),error(representation_error(character_code),eyeprolog),true)",
|
|
758
|
+
"catch(X is 1/0,error(evaluation_error(zero_divisor),eyeprolog),true)",
|
|
759
|
+
"catch(X is 1<<4294967296,error(resource_error(memory),eyeprolog),true)",
|
|
760
|
+
];
|
|
761
|
+
for (const goal of caught) {
|
|
762
|
+
equal(run('', { isoStrict: true, goal }).stats.completed_goal_lists, 1, goal);
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
equal(run('', {
|
|
766
|
+
isoStrict: true,
|
|
767
|
+
goal: "catch(read_term(T,[]),error(syntax_error(read_term),eyeprolog),true)",
|
|
768
|
+
ioOptions: { input: "'unterminated." },
|
|
769
|
+
}).stats.completed_goal_lists, 1, 'syntax error uses error/2 envelope and implementation-defined context');
|
|
770
|
+
|
|
771
|
+
const systemSolver = new Solver(Program.parse('', { isoStrict: true }), { isoStrict: true });
|
|
772
|
+
systemSolver.io.flush = () => { throw new Error('simulated host I/O failure'); };
|
|
773
|
+
equal([...systemSolver.solve([
|
|
774
|
+
parseGoalText('catch(flush_output(user_output),error(system_error,eyeprolog),true)', { isoStrict: true }),
|
|
775
|
+
], new Env(), 0)].length, 1, 'system error uses error/2 envelope and implementation-defined context');
|
|
776
|
+
|
|
777
|
+
// ISO 7.12 deliberately leaves the choice implementation-dependent when
|
|
778
|
+
// several error conditions hold simultaneously. Existing overlap tests
|
|
779
|
+
// above pin EyeProlog's deterministic choices without treating table order
|
|
780
|
+
// as an additional normative requirement.
|
|
781
|
+
});
|
|
782
|
+
|
|
614
783
|
reporter.test('follows Part 1 arithmetic type and exceptional errors', () => {
|
|
615
784
|
const cases = [
|
|
616
785
|
["X is '+'(foo,77)", 'type_error(evaluable)', 'STC #69 simple arithmetic atom is foo/0'],
|
package/test/run-regression.mjs
CHANGED
|
@@ -2221,22 +2221,16 @@ c4 ?- call((!;1)).
|
|
|
2221
2221
|
{
|
|
2222
2222
|
name: 'REPL term input is on demand in conjunctions and Ctrl-D does not exit the top level',
|
|
2223
2223
|
run: () => {
|
|
2224
|
-
if (
|
|
2225
|
-
const
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
`script -qefc ${shellQuote(command)} /dev/null`;
|
|
2235
|
-
const result = spawnSync('sh', ['-c', scriptCommand], {
|
|
2236
|
-
cwd: packageRoot,
|
|
2237
|
-
encoding: 'utf8',
|
|
2238
|
-
timeout: 5000,
|
|
2239
|
-
});
|
|
2224
|
+
if (!hasUtilLinuxScript()) return;
|
|
2225
|
+
const result = runScriptedRepl([
|
|
2226
|
+
{ waitFor: '?- ', send: 'read(X), read(Y).\n' },
|
|
2227
|
+
{ waitFor: ' |: ', send: 'foo.\n' },
|
|
2228
|
+
{ waitFor: '|: ', send: 'bar.\n' },
|
|
2229
|
+
{ waitFor: 'X = foo, Y = bar.', send: 'read(Z).\n' },
|
|
2230
|
+
{ waitFor: ' |: ', send: '\u0004' },
|
|
2231
|
+
{ waitFor: 'Z = end_of_file.', send: 'true.\n' },
|
|
2232
|
+
{ waitFor: ' true.', send: 'halt.\n' },
|
|
2233
|
+
]);
|
|
2240
2234
|
assertEqual(result.error?.code, undefined, 'interactive read timeout');
|
|
2241
2235
|
assertEqual(result.status, 0, 'exit status');
|
|
2242
2236
|
assertIncludes(result.stdout, 'X = foo, Y = bar.', 'conjunction reads');
|
|
@@ -2248,23 +2242,18 @@ c4 ?- call((!;1)).
|
|
|
2248
2242
|
{
|
|
2249
2243
|
name: 'REPL character input is on demand and Ctrl-D stays local (issue #55)',
|
|
2250
2244
|
run: () => {
|
|
2251
|
-
if (
|
|
2252
|
-
const
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
const result = spawnSync('sh', ['-c', scriptCommand], {
|
|
2264
|
-
cwd: packageRoot,
|
|
2265
|
-
encoding: 'utf8',
|
|
2266
|
-
timeout: 5000,
|
|
2267
|
-
});
|
|
2245
|
+
if (!hasUtilLinuxScript()) return;
|
|
2246
|
+
const result = runScriptedRepl([
|
|
2247
|
+
{ waitFor: '?- ', send: 'peek_char(P), get_char(C), get_code(K).\n' },
|
|
2248
|
+
{ waitFor: ' |: ', send: 'ab\n' },
|
|
2249
|
+
{ waitFor: 'P = a, C = a, K = 98.', send: 'get_char(N).\n' },
|
|
2250
|
+
{ waitFor: ' |: ', send: 'z\n' },
|
|
2251
|
+
{ waitFor: 'N = z.', send: 'get_char(E).\n' },
|
|
2252
|
+
{ waitFor: ' |: ', send: '\u0004' },
|
|
2253
|
+
{ waitFor: 'E = end_of_file.', send: 'get_char(D).\n' },
|
|
2254
|
+
{ waitFor: ' |: ', send: 'q\n' },
|
|
2255
|
+
{ waitFor: 'D = q.', send: 'halt.\n' },
|
|
2256
|
+
]);
|
|
2268
2257
|
assertEqual(result.error?.code, undefined, 'interactive character input timeout');
|
|
2269
2258
|
assertEqual(result.status, 0, 'exit status');
|
|
2270
2259
|
assertIncludes(result.stdout, 'P = a, C = a, K = 98.', 'peek/get char and code input');
|
|
@@ -3665,7 +3654,7 @@ function documentationSyncCases() {
|
|
|
3665
3654
|
run: () => assertArrayEqual(documentationSourceStyleIssues(), [], 'documentation source style'),
|
|
3666
3655
|
},
|
|
3667
3656
|
{
|
|
3668
|
-
name: 'DCG nonterminal indicator prose uses valid ... //0 spacing
|
|
3657
|
+
name: 'DCG nonterminal indicator prose uses valid ... //0 spacing',
|
|
3669
3658
|
run: () => {
|
|
3670
3659
|
for (const filename of ['README.md', 'the-art-of-eyeprolog.md', 'src/standard-library.js', 'src/solver.js']) {
|
|
3671
3660
|
const text = fs.readFileSync(path.join(packageRoot, filename), 'utf8');
|
|
@@ -3674,7 +3663,7 @@ function documentationSyncCases() {
|
|
|
3674
3663
|
},
|
|
3675
3664
|
},
|
|
3676
3665
|
{
|
|
3677
|
-
name: 'ISO 5.4 decision index inventories implementation-defined choices
|
|
3666
|
+
name: 'ISO 5.4 decision index inventories implementation-defined choices',
|
|
3678
3667
|
run: () => {
|
|
3679
3668
|
const filename = path.join(testRoot, 'conformance', 'ISO-IMPLEMENTATION-DEFINED.md');
|
|
3680
3669
|
const text = fs.readFileSync(filename, 'utf8');
|
|
@@ -3687,7 +3676,7 @@ function documentationSyncCases() {
|
|
|
3687
3676
|
'8.17.3', '8.17.4', '9.1.3.1', '9.1.4.1', '9.1.4.2', '9.1.4.3', '9.4',
|
|
3688
3677
|
'9.4.1', '9.4.2', '9.4.3', '9.4.4', '9.4.5', 'Cor.2 9.4.6',
|
|
3689
3678
|
]) assertIncludes(text, `| ${clause} |`, `ISO 5.4 clause ${clause}`);
|
|
3690
|
-
assertIncludes(text, '
|
|
3679
|
+
assertIncludes(text, 'Floating underflow policy', 'floating underflow policy explanation');
|
|
3691
3680
|
assertIncludes(text, 'Implementation-specific features required to be documented by 5.4', '5.5 extension inventory');
|
|
3692
3681
|
},
|
|
3693
3682
|
},
|
|
@@ -3722,17 +3711,33 @@ function documentationSyncCases() {
|
|
|
3722
3711
|
},
|
|
3723
3712
|
},
|
|
3724
3713
|
{
|
|
3725
|
-
name: 'ISO
|
|
3714
|
+
name: 'ISO Clause 6, 7.10, and 7.12 closure is documented',
|
|
3715
|
+
run: () => {
|
|
3716
|
+
const compliance = fs.readFileSync(path.join(testRoot, 'conformance', 'ISO-COMPLIANCE.md'), 'utf8');
|
|
3717
|
+
const processor = fs.readFileSync(path.join(testRoot, 'conformance', 'ISO-PROCESSOR-REQUIREMENTS.md'), 'utf8');
|
|
3718
|
+
for (const row of [
|
|
3719
|
+
'| Clause 6 — tokens, terms, lists, operators, quoted text | covered |',
|
|
3720
|
+
'| 7.10 — input/output concepts | covered |',
|
|
3721
|
+
'| 7.12 — errors | covered |',
|
|
3722
|
+
]) assertIncludes(compliance, row, row);
|
|
3723
|
+
assertIncludes(processor, '## Clause 6 syntax-preservation closure', 'Clause 6 closure map');
|
|
3724
|
+
assertIncludes(processor, '| 5.5.1 syntax extensions preserve standard token/text meaning | covered |', '5.5.1 covered');
|
|
3725
|
+
},
|
|
3726
|
+
},
|
|
3727
|
+
{
|
|
3728
|
+
name: 'ISO release-facing exit criteria are explicitly closed',
|
|
3726
3729
|
run: () => {
|
|
3727
3730
|
const exit = fs.readFileSync(path.join(testRoot, 'conformance', 'ISO-COMPLIANCE.md'), 'utf8');
|
|
3728
3731
|
for (const item of [
|
|
3729
|
-
'| Clause
|
|
3730
|
-
'| Clause
|
|
3732
|
+
'| Clause 5 processor obligations have explicit dispositions | covered |',
|
|
3733
|
+
'| Clause 6 lexical/syntactic requirements have explicit dispositions | covered |',
|
|
3734
|
+
'| Clause 7 semantic requirements have explicit dispositions | covered |',
|
|
3731
3735
|
'| Clause 8 built-in modes/errors have explicit dispositions | covered |',
|
|
3732
3736
|
'| Clause 9 evaluable-functor requirements have explicit dispositions | covered |',
|
|
3733
3737
|
'| Independent external syntax corpus is an offline release gate | covered |',
|
|
3734
|
-
'| No unexplained deviation remains in the release-facing ledger |
|
|
3738
|
+
'| No unexplained deviation remains in the release-facing ledger | covered |',
|
|
3735
3739
|
]) assertIncludes(exit, item, item);
|
|
3740
|
+
assertNotIncludes(exit, '| audit |', 'no release-facing audit rows remain');
|
|
3736
3741
|
},
|
|
3737
3742
|
},
|
|
3738
3743
|
{
|
|
@@ -3749,7 +3754,17 @@ function documentationSyncCases() {
|
|
|
3749
3754
|
assertIncludes(readme, 'implementation reference is [*The Art of EyeProlog*]', 'README book hand-off');
|
|
3750
3755
|
assertIncludes(readme, 'test/conformance/ISO-COMPLIANCE.md', 'README concise audit link');
|
|
3751
3756
|
assertEqual(readme.includes('2026-08-23 draft items #73-#76'), false, 'README omits audit-history detail');
|
|
3752
|
-
assertIncludes(profile, '
|
|
3757
|
+
assertIncludes(profile, 'Part 1 processor, syntax, semantic, built-in, and arithmetic', 'Why EyeProlog audit state');
|
|
3758
|
+
},
|
|
3759
|
+
},
|
|
3760
|
+
{
|
|
3761
|
+
name: 'documentation avoids repository issue references',
|
|
3762
|
+
run: () => {
|
|
3763
|
+
for (const file of listMarkdownFiles(packageRoot)) {
|
|
3764
|
+
const text = fs.readFileSync(file, 'utf8');
|
|
3765
|
+
assertEqual(/github\.com\/eyereasoner\/eyeprolog\/issues\//.test(text), false, `${path.relative(packageRoot, file)} repository issue URL`);
|
|
3766
|
+
assertEqual(/\bissue\s+#\d+\b/i.test(text), false, `${path.relative(packageRoot, file)} repository issue number`);
|
|
3767
|
+
}
|
|
3753
3768
|
},
|
|
3754
3769
|
},
|
|
3755
3770
|
{
|
|
@@ -6086,6 +6101,99 @@ function shellQuote(value) {
|
|
|
6086
6101
|
return `'${String(value).replaceAll("'", "'\"'\"'")}'`;
|
|
6087
6102
|
}
|
|
6088
6103
|
|
|
6104
|
+
let utilLinuxScriptAvailable = null;
|
|
6105
|
+
|
|
6106
|
+
function hasUtilLinuxScript() {
|
|
6107
|
+
if (process.platform === 'win32') return false;
|
|
6108
|
+
if (utilLinuxScriptAvailable == null) {
|
|
6109
|
+
const available = spawnSync('sh', ['-c',
|
|
6110
|
+
'command -v script >/dev/null 2>&1 && script --version 2>/dev/null | grep -qi util-linux']);
|
|
6111
|
+
utilLinuxScriptAvailable = available.status === 0;
|
|
6112
|
+
}
|
|
6113
|
+
return utilLinuxScriptAvailable;
|
|
6114
|
+
}
|
|
6115
|
+
|
|
6116
|
+
function runScriptedRepl(steps, { timeout = 5000 } = {}) {
|
|
6117
|
+
const command = `${shellQuote(process.execPath)} ${shellQuote(bin)}`;
|
|
6118
|
+
const payload = Buffer.from(JSON.stringify({
|
|
6119
|
+
command,
|
|
6120
|
+
cwd: packageRoot,
|
|
6121
|
+
steps,
|
|
6122
|
+
timeout,
|
|
6123
|
+
})).toString('base64');
|
|
6124
|
+
const helper = String.raw`
|
|
6125
|
+
const { spawn } = require('node:child_process');
|
|
6126
|
+
const config = JSON.parse(Buffer.from(process.env.EYEPROLOG_REPL_SCRIPT, 'base64').toString('utf8'));
|
|
6127
|
+
const child = spawn('script', ['-qefc', config.command, '/dev/null'], {
|
|
6128
|
+
cwd: config.cwd,
|
|
6129
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
6130
|
+
});
|
|
6131
|
+
let stdout = '';
|
|
6132
|
+
let stderr = '';
|
|
6133
|
+
let cursor = 0;
|
|
6134
|
+
let step = 0;
|
|
6135
|
+
let finished = false;
|
|
6136
|
+
|
|
6137
|
+
function advance() {
|
|
6138
|
+
while (step < config.steps.length) {
|
|
6139
|
+
const current = config.steps[step];
|
|
6140
|
+
const index = stdout.indexOf(current.waitFor, cursor);
|
|
6141
|
+
if (index === -1) return;
|
|
6142
|
+
cursor = index + current.waitFor.length;
|
|
6143
|
+
child.stdin.write(current.send);
|
|
6144
|
+
step++;
|
|
6145
|
+
}
|
|
6146
|
+
}
|
|
6147
|
+
|
|
6148
|
+
child.stdout.on('data', (chunk) => {
|
|
6149
|
+
stdout += chunk;
|
|
6150
|
+
advance();
|
|
6151
|
+
});
|
|
6152
|
+
child.stderr.on('data', (chunk) => {
|
|
6153
|
+
stderr += chunk;
|
|
6154
|
+
});
|
|
6155
|
+
|
|
6156
|
+
const timer = setTimeout(() => {
|
|
6157
|
+
if (finished) return;
|
|
6158
|
+
finished = true;
|
|
6159
|
+
child.kill('SIGKILL');
|
|
6160
|
+
process.stdout.write(JSON.stringify({ status: null, stdout, stderr, timedOut: true, step }));
|
|
6161
|
+
}, config.timeout);
|
|
6162
|
+
|
|
6163
|
+
child.on('close', (status, signal) => {
|
|
6164
|
+
if (finished) return;
|
|
6165
|
+
finished = true;
|
|
6166
|
+
clearTimeout(timer);
|
|
6167
|
+
process.stdout.write(JSON.stringify({ status, signal, stdout, stderr, timedOut: false, step }));
|
|
6168
|
+
});
|
|
6169
|
+
`;
|
|
6170
|
+
const helperResult = spawnSync(process.execPath, ['-e', helper], {
|
|
6171
|
+
cwd: packageRoot,
|
|
6172
|
+
encoding: 'utf8',
|
|
6173
|
+
env: { ...process.env, EYEPROLOG_REPL_SCRIPT: payload },
|
|
6174
|
+
timeout: timeout + 1000,
|
|
6175
|
+
});
|
|
6176
|
+
if (helperResult.error) return helperResult;
|
|
6177
|
+
if (helperResult.status !== 0) return helperResult;
|
|
6178
|
+
let result;
|
|
6179
|
+
try {
|
|
6180
|
+
result = JSON.parse(helperResult.stdout);
|
|
6181
|
+
} catch (error) {
|
|
6182
|
+
return {
|
|
6183
|
+
...helperResult,
|
|
6184
|
+
error: new Error(`interactive REPL helper returned invalid JSON: ${error.message}`),
|
|
6185
|
+
};
|
|
6186
|
+
}
|
|
6187
|
+
return {
|
|
6188
|
+
status: result.status,
|
|
6189
|
+
stdout: result.stdout,
|
|
6190
|
+
stderr: `${result.stderr ?? ''}${helperResult.stderr ?? ''}`,
|
|
6191
|
+
error: result.timedOut
|
|
6192
|
+
? Object.assign(new Error(`interactive REPL timed out after step ${result.step}`), { code: 'ETIMEDOUT' })
|
|
6193
|
+
: undefined,
|
|
6194
|
+
};
|
|
6195
|
+
}
|
|
6196
|
+
|
|
6089
6197
|
function runCli(args, options = {}) {
|
|
6090
6198
|
return spawnSync(process.execPath, [bin, ...args], {
|
|
6091
6199
|
cwd: packageRoot,
|
package/the-art-of-eyeprolog.md
CHANGED
|
@@ -7584,9 +7584,7 @@ node test/run-conformance-report.mjs
|
|
|
7584
7584
|
```
|
|
7585
7585
|
|
|
7586
7586
|
`test/conformance/ISO-COMPLIANCE.md` is the processor-requirement ledger for the
|
|
7587
|
-
Part 1 conformance audit. It
|
|
7588
|
-
requirements whose normative `shall` clauses, option combinations, or error
|
|
7589
|
-
precedence still need one-by-one closure. `test/conformance/ISO-COMPLIANCE.md`
|
|
7587
|
+
Part 1 conformance audit. It records explicit dispositions for the tracked processor, syntax, semantic, built-in, and arithmetic requirements. `test/conformance/ISO-COMPLIANCE.md`
|
|
7590
7588
|
maps language families to representative executable cases.
|
|
7591
7589
|
`test/conformance/ISO-IMPLEMENTATION-DEFINED.md` is the ISO 5.4 decision
|
|
7592
7590
|
index: it enumerates the Part 1 implementation-defined decisions and the
|
|
@@ -7595,8 +7593,7 @@ proposals into the licensed baseline. `ISO-TERM-SEMANTICS-MATRIX.md` closes the
|
|
|
7595
7593
|
rows, `ISO-PROLOG-TEXT-EXECUTION-MATRIX.md` closes 7.4-7.8 preparation,
|
|
7596
7594
|
database, conversion, execution, and control, and
|
|
7597
7595
|
`ISO-EVALUABLE-FUNCTOR-MATRIX.md` closes 7.9/Clause 9 expression and arithmetic
|
|
7598
|
-
rows. The exit checklist in `ISO-COMPLIANCE.md`
|
|
7599
|
-
unexplained-deviation conditions explicit. `test/conformance/WG17-SYNTAX-STATUS.md` separately traces the vendored active
|
|
7596
|
+
rows. The exit checklist in `ISO-COMPLIANCE.md` records the closure criteria and their evidence. `test/conformance/WG17-SYNTAX-STATUS.md` separately traces the vendored active
|
|
7600
7597
|
upstream syntax cases. Reviewed cases can pin exact strict-reader outcomes, while
|
|
7601
7598
|
newly upgraded cases execute directly against the upstream Codex expectation.
|
|
7602
7599
|
|
|
@@ -7660,29 +7657,18 @@ expansion/`phrase/2-3`, quads, EyeProlog libraries, the `occurs_check` flag,
|
|
|
7660
7657
|
automatic tabling, `call_cleanup/2`, and `setup_call_cleanup/3` are outside
|
|
7661
7658
|
that Part 1 strict surface.
|
|
7662
7659
|
|
|
7663
|
-
|
|
7664
|
-
|
|
7665
|
-
|
|
7666
|
-
|
|
7667
|
-
|
|
7668
|
-
|
|
7669
|
-
|
|
7670
|
-
|
|
7671
|
-
|
|
7672
|
-
|
|
7673
|
-
|
|
7674
|
-
|
|
7675
|
-
creation/position/EOF behavior and text-vs-binary permission errors, corrects
|
|
7676
|
-
Corrigendum 2 `keysort/2` error cases, closes the 5.5.6 Prolog-visible
|
|
7677
|
-
side-effect boundary by excluding statistics/cleanup extensions from strict
|
|
7678
|
-
mode, closes 5.5.10 by keeping the non-standard evaluable atom `e` outside
|
|
7679
|
-
strict mode, closes the row-level 7.1-7.3 term-semantics, 7.4-7.8 preparation/database/control, and 7.9/Clause 9
|
|
7680
|
-
arithmetic audits, and pins the permitted arithmetic variation points for
|
|
7681
|
-
mixed-type Corrigendum 2 `max/2`/`min/2` plus signed Clause 9.4 bitwise and
|
|
7682
|
-
negative-shift behavior. The Clause 9 audit also corrected float-only
|
|
7683
|
-
`float_integer_part/1` and `float_fractional_part/1` so integer operands are
|
|
7684
|
-
rejected by type before a potentially overflowing integer-to-float conversion.
|
|
7685
|
-
The 7.4-7.8 closure also pins cross-text directive state, include/ensure-loaded lifetime, initialization order and one-shot execution, logical-update visibility, empty-versus-unknown procedures, term-to-body conversion, and the general Part 1 control/exception constructs. These are conformance improvements, while the remaining qualifications are:
|
|
7660
|
+
The strict-core audit has explicit dispositions for the Clause 5 processor
|
|
7661
|
+
obligations, Clause 6 syntax and rejection families, Clause 7 term/execution/I/O
|
|
7662
|
+
and error semantics, the 8.2-8.17 built-in families, and Clause 9 evaluable
|
|
7663
|
+
functors. The complete vendored WG17 syntax matrix is a release gate, and each
|
|
7664
|
+
strict-success WG17 observation is also checked through normal mode so syntax
|
|
7665
|
+
extensions cannot reinterpret accepted standard text. Implementation-defined
|
|
7666
|
+
choices—including the Unicode-scalar processor character set, stream details,
|
|
7667
|
+
flag defaults, floating behavior, and signed bitwise/shift semantics—are indexed
|
|
7668
|
+
in `test/conformance/ISO-IMPLEMENTATION-DEFINED.md`. The release-facing closure
|
|
7669
|
+
ledger is `test/conformance/ISO-COMPLIANCE.md`.
|
|
7670
|
+
|
|
7671
|
+
Notable implementation boundaries are:
|
|
7686
7672
|
|
|
7687
7673
|
- zero-arity compound syntax such as `ready()` is represented by the atom
|
|
7688
7674
|
`ready`;
|
|
@@ -7700,11 +7686,9 @@ The 7.4-7.8 closure also pins cross-text directive state, include/ensure-loaded
|
|
|
7700
7686
|
|
|
7701
7687
|
Write terms explicitly, keep variables uppercase or underscore-prefixed, and
|
|
7702
7688
|
quote atom names that are neither lowercase plain names nor graphic tokens.
|
|
7703
|
-
|
|
7704
|
-
|
|
7705
|
-
|
|
7706
|
-
exit checklist in `test/conformance/ISO-COMPLIANCE.md` has no unresolved normative
|
|
7707
|
-
audits or unexplained deviations.
|
|
7689
|
+
The conformance ledger and release gates verify this documented strict-core
|
|
7690
|
+
boundary. Their closure is implementation evidence, not independent ISO
|
|
7691
|
+
certification.
|
|
7708
7692
|
|
|
7709
7693
|
### Security and resource use
|
|
7710
7694
|
|
package/why-eyeprolog.md
CHANGED
|
@@ -26,13 +26,14 @@ the published strict baseline. The processor character model is explicitly
|
|
|
26
26
|
implementation defined: EyeProlog uses Unicode scalar values as the PCS and as
|
|
27
27
|
collating-sequence integers in both normal and strict profiles. Strict mode
|
|
28
28
|
therefore rejects implementation-specific language extensions without changing
|
|
29
|
-
that processor choice. Its executable conformance matrix
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
Part
|
|
29
|
+
that processor choice. Its executable conformance matrix records explicit
|
|
30
|
+
dispositions for the Part 1 processor, syntax, semantic, built-in, and arithmetic
|
|
31
|
+
requirements, including the complete vendored WG17 syntax cases and cross-profile
|
|
32
|
+
preservation of strict-success syntax outcomes. Implementation-defined choices
|
|
33
|
+
such as mixed-type `max/2`/`min/2` and signed bitwise/shift operations are pinned
|
|
34
|
+
by regression tests. This is extensive implementation evidence, not an independent
|
|
35
|
+
ISO certification; the Part 2 and Part 3 compatibility profiles also remain
|
|
36
|
+
separate from the Part 1 strict-core claim.
|
|
36
37
|
|
|
37
38
|
## Why a small implementation?
|
|
38
39
|
|