eyeprolog 1.3.59 → 1.3.61

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 CHANGED
@@ -203,56 +203,24 @@ eyeprolog --iso-strict
203
203
  eyeprolog --iso-strict --goal 'p(X)' program.pl
204
204
  ```
205
205
 
206
- The equivalent JavaScript option is `isoStrict: true`. Strict mode rejects
207
- EyeProlog language extensions, Part 2 module directives, and Part 3 grammar-rule
208
- expansion/`phrase/2-3`; it also removes the EyeProlog `occurs_check` flag,
209
- `call_cleanup/2`, and `setup_call_cleanup/3`, and disables automatic tabling.
210
- Normal mode is unchanged and continues to support modules, DCGs, quads,
211
- libraries, proofs, cleanup-aware control, and the other documented extensions.
212
-
213
- The Part 1 processor character set is an implementation-defined processor
214
- choice, so strict mode does not replace it with a smaller repertoire. EyeProlog
215
- uses Unicode scalar values as its PCS in both normal and strict profiles, with
216
- the Unicode scalar value as the collating-sequence integer. ASCII keeps the
217
- standard lexical classes; extended Unicode letters participate in unquoted name
218
- syntax and other non-ASCII symbols are treated as extended graphic characters.
219
- Surrogates and values above U+10FFFF remain representation errors.
220
-
221
- Strict term I/O likewise keeps the standardized option boundary: `read_term/2-3`
222
- and `write_term/2-3` accept the Part 1 plus Corrigendum 3 options, while the
223
- normal-profile `write_term(...,[double_quotes(...)])` option remains an
224
- EyeProlog extension. The strict gate also checks the prescribed ISO error
225
- precedence for `read_term/3`, `write_term/3`, `op/3`, and `current_op/3`, and
226
- the complete Part 1 flag defaults/value domains/changeability rules. The
227
- ongoing issue #65 audit additionally tightens Prolog-text declaration ordering,
228
- initialization lifetime, stream/open/close behavior, character/byte stream
229
- errors, `keysort/2` error cases, the now-closed 5.5.6 side-effect and 5.5.10 evaluable-functor strict
230
- extension boundaries, and the standard's permitted arithmetic variation points: mixed-type Corrigendum 2
231
- `max/2`/`min/2` and signed Clause 9.4 bitwise/shift behavior.
232
- Those additions improve the Part 1 surface without turning the remaining audit
233
- rows into a blanket conformance claim. The post-N289 WG17/STC working draft is
234
- reviewed separately rather than treated as a fourth Corrigendum. The
235
- 2026-08-23 draft items #73-#76 are now pinned explicitly: float input limits for
236
- `read*` and `number_*` conversions, invalid-character term input, and the draft
237
- proposal that would make the two power-underflow rows depend on the processor's
238
- 9.1.4.2 `resultF` choice. Strict mode retains the published Part 1 +
239
- Corrigenda 1-3 behavior where the draft has not been standardized.
240
-
241
- As an additional 5.5.1 extension-safety gate, every vendored WG17 syntax case
242
- that succeeds in the strict Part 1 reader is re-run in the normal profile and
243
- must retain the same observable outcome; normal mode may accept extra extension
244
- syntax, but it must not reinterpret text already accepted as standard syntax.
245
-
246
- The auditable processor-requirement checklist lives in
247
- [`test/conformance/ISO-COMPLIANCE.md`](test/conformance/ISO-COMPLIANCE.md).
248
- The ISO 5.4 implementation-defined/implementation-specific decision index is
249
- [`test/conformance/ISO-IMPLEMENTATION-DEFINED.md`](test/conformance/ISO-IMPLEMENTATION-DEFINED.md).
250
- The separate [WG17 syntax ledger](test/conformance/WG17-SYNTAX-STATUS.md)
251
- records executable dispositions for the vendored active upstream WG17 syntax
252
- cases and runs as part of `npm test`. Reviewed cases can pin exact outcomes;
253
- newly upgraded cases run directly against the upstream Codex expectation.
254
- EyeProlog does not yet claim independent certification or closure of every
255
- normative Part 1 requirement.
206
+ The equivalent JavaScript option is `isoStrict: true`. Strict mode keeps
207
+ EyeProlog's documented implementation-defined Unicode scalar processor
208
+ character set, while excluding normal-profile language extensions such as Part
209
+ 2 module compatibility forms, Part 3 DCG expansion, quads, extra libraries,
210
+ automatic tabling, and non-standard flags/control facilities. Normal mode is
211
+ unchanged.
212
+
213
+ This README intentionally stays at the project-overview level. The detailed
214
+ implementation reference is [*The Art of EyeProlog*](the-art-of-eyeprolog.md).
215
+ The current Part 1 audit status and remaining release conditions are recorded in
216
+ [`test/conformance/ISO-COMPLIANCE.md`](test/conformance/ISO-COMPLIANCE.md);
217
+ implementation-defined decisions are indexed in
218
+ [`ISO-IMPLEMENTATION-DEFINED.md`](test/conformance/ISO-IMPLEMENTATION-DEFINED.md). The complete
219
+ vendored WG17 syntax corpus and the strict ISO regression suite run as release
220
+ gates.
221
+
222
+ EyeProlog does not claim independent ISO certification while the explicit exit
223
+ checklist still contains unresolved normative or unexplained-deviation items.
256
224
 
257
225
  ## Module and definite clause grammar compatibility profiles
258
226
 
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.3.59",
6
+ "version": "1.3.61",
7
7
  "description": "EyeProlog turns facts and rules into answers and proofs.",
8
8
  "type": "module",
9
9
  "main": "./index.js",
@@ -71,10 +71,18 @@ function evaluateOperation(term, args, options = {}) {
71
71
  if (arity === 1 && ['abs', 'sign', 'float', 'truncate', 'round', 'ceiling', 'floor',
72
72
  'float_integer_part', 'float_fractional_part',
73
73
  'sin', 'cos', 'atan', 'asin', 'acos', 'tan', 'exp', 'log', 'sqrt'].includes(name)) {
74
- // The four float-to-integer rounding functors have only F->I operators
75
- // (9.1.1/9.1.6). Corrigendum 1/2 therefore requires type_error(float,...)
76
- // when their evaluated argument has integer type.
77
- if (options.isoStrict === true && ['truncate', 'round', 'ceiling', 'floor'].includes(name) && args[0].integer) {
74
+ // These six conversion/rounding functors have float-only input templates
75
+ // in 9.1.1/9.1.6. They therefore require type_error(float,...) when their
76
+ // evaluated argument has integer type, before any I->F conversion.
77
+ if (options.isoStrict === true && [
78
+ 'truncate', 'round', 'ceiling', 'floor',
79
+ 'float_integer_part', 'float_fractional_part',
80
+ ].includes(name) && args[0].integer) {
81
+ // These functors have only F->I or F->F templates. In particular,
82
+ // float_integer_part/1 and float_fractional_part/1 must reject an
83
+ // integer by type before any I->F conversion is attempted; otherwise a
84
+ // sufficiently large (but valid, unbounded) integer can be misreported
85
+ // as float_overflow instead of type_error(float,...).
78
86
  throw new PrologError('type_error(float)', numericTerm(args[0]));
79
87
  }
80
88
  if (name === 'abs' && args[0].integer) return { integer: true, value: args[0].value < 0n ? -args[0].value : args[0].value };
@@ -372,7 +372,9 @@ 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 remaining #65 work is therefore above/below this built-in table: Clause 6
376
- text/rejection mapping, Clause 7 processor/control semantics, Clause 9
377
- exceptional-value rows, residual Clause 5 dependency rows, and the external
378
- conversion/variable-name conformance corpora.
375
+ The remaining #65 work is therefore above/below this built-in table. The
376
+ 7.1-7.3 term-semantics and 7.9/Clause 9 evaluable-functor rows are now closed in
377
+ their dedicated matrices. What remains is Clause 6 text/rejection mapping,
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`.
@@ -1,14 +1,12 @@
1
1
  # ISO/IEC 13211-1 compliance ledger
2
2
 
3
- This ledger is the release-facing audit for EyeProlog's ISO/IEC 13211-1 core.
4
- The normative baseline is ISO/IEC 13211-1:1995 together with Technical
5
- Corrigenda 1:2007, 2:2012, and 3:2017. It complements
6
- [ISO-MATRIX.md](ISO-MATRIX.md), which maps standard families to representative
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.
3
+ This ledger is the release-facing audit and high-level coverage map for
4
+ EyeProlog's ISO/IEC 13211-1 core. The normative baseline is ISO/IEC 13211-1:1995
5
+ together with Technical Corrigenda 1:2007, 2:2012, and 3:2017. Detailed
6
+ row-level evidence lives only where it adds information: the built-in, processor,
7
+ term-semantics, Prolog-text/execution, evaluable-functor, implementation-defined,
8
+ WG17-syntax, and STC draft ledgers in this directory. The generated
9
+ [`conformance-report.md`](../../conformance-report.md) gives current case totals.
12
10
 
13
11
  The ledger deliberately does **not** claim independent certification. A row
14
12
  marked `covered` means EyeProlog has implementation and executable tests for
@@ -22,7 +20,7 @@ relevant implementation-dependent overlap choice to an explicit audit outcome.
22
20
  | Requirement | Status | EyeProlog evidence / remaining work |
23
21
  | --- | --- | --- |
24
22
  | 5.1(a) prepare conforming Prolog text | audit | Clause 6 parser/tokenizer coverage, directive coverage, syntax-error corpus, and the [complete vendored WG17 syntax matrix](WG17-SYNTAX-STATUS.md). Wider shall-by-shall text-processing audit remains open. |
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
+ | 5.1(b) execute conforming Prolog goals | audit | Clause 7-9 conformance corpus plus regression/API/example gates. The 7.1-7.8 term/preparation/database/control rows, 7.9/Clause 9 arithmetic, and 8.2-8.17 built-in row audits are now closed; the dependency remains open on higher-level 7.10 and residual processor-level 7.12 semantics. |
26
24
  | 5.1(c) reject nonconforming text/read-terms | audit | Dedicated syntax-error cases and strict-core extension rejection. Exhaustive lexical rejection coverage remains open. |
27
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. Rows marked `audit gap` remain conformance work, but the variation is no longer undocumented. |
28
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. |
@@ -34,17 +32,17 @@ relevant implementation-dependent overlap choice to an explicit audit outcome.
34
32
  | Standard area | Status | Current evidence |
35
33
  | --- | --- | --- |
36
34
  | 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. A cross-profile gate now verifies that every WG17 case accepted by the strict Part 1 reader has the same observable outcome under normal-mode syntax extensions. The implementation-defined 6.5/6.6 character-model decisions are closed; the remaining work is the explicit production-by-production shall map. |
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. |
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. |
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. Clause-body conversion now applies 7.6.2 both to prepared source clauses and runtime `asserta/1` / `assertz/1`: variables become `call/1`, `,/2`, `;/2`, and `->/2` are converted recursively, and head/body variable identity is preserved so `clause/2` and `retract/1` observe the converted term correctly. 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. |
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. |
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. |
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), the published `exp/1`/power underflow rows, and prescribed negative/zero power errors before later conversion overflow. Post-N289 STC #75's proposal to make the two power-underflow rows conditional on the 9.1.4.2 choice is tracked separately and is not silently substituted for the licensed baseline. 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. |
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
+ | 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
+ | 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
+ | 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
+ | 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
+ | 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. |
43
41
  | 7.10 — input/output concepts | audit | Stream, character/byte I/O, read/write options, operator-sensitive write-back, and Corrigendum 3 writer cases. The complete 8.11-8.14 built-in mode/error family is now row-audited in [ISO-BUILTIN-MODE-ERROR-MATRIX.md](ISO-BUILTIN-MODE-ERROR-MATRIX.md), including lifecycle/current-stream handling, stream positions, text/binary permissions, EOF actions, `force(true)`, input-code representation timing, term-I/O options, operators, and character conversion. `stream_property/2` now also distinguishes a malformed stream-term (domain error) from a valid stream-term whose stream is no longer open (ordinary failure). The higher-level 7.10 source/sink, buffering, positioning, and implementation-defined stream semantics remain under shall-by-shall audit. |
44
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. |
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 mode/error-condition outcomes across the complete 8.2-8.17 built-in family, including Corrigendum additions and not-applicable conditional branches. The audit records the 7.12 rule that simultaneous error conditions are implementation dependent: overlap regressions document stable EyeProlog choices rather than inventing a universal table-order requirement. Remaining work is concentrated in non-built-in Clause 7 semantics, Clause 9 exceptional interactions, and processor-level error conditions. |
43
+ | 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 mode/error-condition outcomes across the complete 8.2-8.17 built-in family, including Corrigendum additions and not-applicable conditional branches. The audit records the 7.12 rule that simultaneous error conditions are implementation dependent: overlap regressions document stable EyeProlog choices rather than inventing a universal table-order requirement. Remaining work is concentrated in higher-level 7.10 stream semantics and residual processor-level error conditions. |
46
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. |
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 published `exp/1`, `**/2`, and Corrigendum 2 `^/2` underflow conditions, tracks STC #75's proposed conditional power interpretation without adopting it as published text, 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. Corrigendum 2 mixed-type `max/2`/`min/2` now have an explicit implementation-dependent decision: exact mathematical comparison selects one original operand and preserves its numeric type without mandatory integer-to-float conversion. Clause 9.4 signed bitwise operations and negative shift counts are likewise pinned to the documented BigInt infinite-two's-complement semantics. 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
+ | 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. |
48
46
  | Corrigendum 1 | covered | Double-quoted atom/operator-priority corrections have dedicated cases. |
49
47
  | Corrigendum 2 | covered | Added predicates/functors, catch corrections, bar/operator and uninstantiation corrections have dedicated cases. |
50
48
  | Corrigendum 3 | covered | Writer options, `variable_names/1`, canonical list output and negative-power corrections have dedicated cases. |
@@ -87,9 +85,8 @@ database update errors, and Corrigendum 3 variable metadata traversal/write
87
85
  naming.
88
86
 
89
87
  The public WG17 `number_chars/2` comparison used in preparation of Corrigendum
90
- 2 has additionally been checked against the current strict profile. That
91
- external comparison is useful independent evidence, but it is not yet vendored
92
- as an offline release gate; the exit criterion below therefore remains open.
88
+ 2 has additionally been checked during the audit. It remains supporting review
89
+ evidence rather than a duplicated vendored corpus or release criterion.
93
90
 
94
91
  A further issue #65 audit closes the Part 1 flag family and tightens the 8.14
95
92
  term-I/O/operator error rules. The strict flag registry now distinguishes a
@@ -209,9 +206,9 @@ individual-error outcomes in `ISO-BUILTIN-MODE-ERROR-MATRIX.md`. During this
209
206
  pass `stream_property/2` exposed a lifecycle distinction: a syntactically valid
210
207
  stream-term for a stream that has been closed denotes no currently open stream
211
208
  property pair and therefore fails, whereas a term that is not a stream-term is
212
- still a `domain_error(stream, ...)`. This leaves the remaining #65 checklist
213
- focused on Clause 6/7/9 processor semantics and external corpora rather than
214
- unmapped built-in tables.
209
+ still a `domain_error(stream, ...)`. This leaves the remaining #65 checklist focused on Clause 6 syntax/rejection,
210
+ higher-level 7.10 stream semantics, residual 7.12 processor errors, and final
211
+ unexplained-deviation closure rather than unmapped built-in tables.
215
212
 
216
213
  ## Post-Corrigendum STC cross-check
217
214
 
@@ -267,10 +264,9 @@ directive may still add an infix `?-` definition; strict mode reads that as an
267
264
  ordinary term rather than as a quad.
268
265
 
269
266
  Module and DCG compatibility features remain supported and tested in the
270
- normal EyeProlog profile. They are tracked separately in ISO-MATRIX.md rather
271
- than being silently folded into the Part 1 strict-core claim. The project does
272
- not currently assert that this evidence closes every requirement of ISO/IEC
273
- 13211-2:2000 or ISO/IEC TS 13211-3.
267
+ normal EyeProlog profile, but they are not folded into the Part 1 strict-core
268
+ claim. The project does not currently assert that this evidence closes every
269
+ requirement of ISO/IEC 13211-2:2000 or ISO/IEC TS 13211-3.
274
270
 
275
271
  ## Release gate
276
272
 
@@ -288,18 +284,25 @@ outputs are never auto-accepted.
288
284
 
289
285
  ## Exit criteria for a full conformance claim
290
286
 
291
- EyeProlog should not change its public wording from “ISO profile” to “conforming
292
- ISO/IEC 13211-1 processor” until all of the following are true:
293
-
294
- 1. every normative Part 1 processor requirement is represented in this ledger;
295
- 2. every `audit` row above has been reduced to explicit pass/not-applicable or
296
- documented implementation-defined choices;
297
- 3. the external WG17 conversion and variable-name conformity corpora have
298
- joined the now-complete syntax corpus in strict core mode, with every
299
- difference explained or fixed;
300
- 4. prescribed modes, individual error conditions, side effects, and any
301
- precedence actually constrained by procedural rules or Corrigenda have
302
- executable coverage, while 7.12 simultaneous-error choices are documented;
303
- 5. every `audit gap` recorded in the ISO 5.4 decision index is either fixed or
304
- explicitly excluded from the strict-conformance claim; and
305
- 6. an external conformance run has found no unexplained deviations.
287
+ Issue #65 is closed by explicit dispositions, not by a test-count threshold.
288
+ The remaining qualification can be removed only when every open item below is
289
+ closed without an unexplained deviation from the published Part 1 + Corrigenda
290
+ baseline. Public post-N289 STC drafts remain review input until standardized.
291
+
292
+ | Criterion | Status | Evidence / remaining work |
293
+ | --- | --- | --- |
294
+ | Clause 5 processor obligations have explicit dispositions | open | `ISO-PROCESSOR-REQUIREMENTS.md` still depends on the remaining Clause 6 preparation/rejection and syntax-preservation work |
295
+ | Clause 6 lexical/syntactic requirements have explicit dispositions | open | the 366-case vendored WG17 syntax gate and cross-profile preservation are green; the remaining work is the production-by-production shall/rejection map |
296
+ | Clause 7 semantic requirements have explicit dispositions | open | 7.1-7.9 and 7.11 are closed; higher-level 7.10 stream semantics and residual processor-level 7.12 requirements remain |
297
+ | 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
+ | 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
+ | 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 | open | the major 5.5 hooks are closed; exhaustive 5.5.1 syntax preservation remains tied to the Clause 6 audit |
301
+ | Published Corrigenda 1-3 are incorporated | covered | dedicated conformance/strict tests and this ledger track all three published Corrigenda |
302
+ | Current post-N289 draft is tracked without silently changing the published baseline | covered | `STC-DRAFT-STATUS.md` tracks reviewed draft items separately from normative requirements |
303
+ | 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
+ | 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 | open | every remaining `audit` row must end as covered, implementation-defined/specific with documented behavior, not applicable, or a documented defect |
306
+
307
+ The specialized row matrices are evidence for this ledger, not separate public
308
+ status documents. *The Art of EyeProlog* remains the implementation reference.
@@ -0,0 +1,91 @@
1
+ # ISO Part 1 expression/evaluable-functor audit matrix
2
+
3
+ This file is the row-level audit for Part 1 Clause 7.9 and Clause 9, including
4
+ the arithmetic additions and corrections in Technical Corrigenda 1-3. It is
5
+ paired with the strict regression named `closes the ISO 7.9 and Clause 9
6
+ evaluable-functor rows`.
7
+
8
+ The published ISO/IEC 13211-1:1995 + Corrigenda 1-3 text is the normative
9
+ baseline. Post-N289 STC draft proposals are tracked separately in
10
+ `STC-DRAFT-STATUS.md`; they do not silently replace published requirements.
11
+
12
+ ## 7.9 - evaluating an expression
13
+
14
+ | Requirement | Status | Evidence / decision |
15
+ | --- | --- | --- |
16
+ | Evaluate variables | covered | direct variable operands raise `instantiation_error` before competing expression errors in strict mode |
17
+ | Evaluate numeric constants | covered | integer and float constants retain their numeric types subject to the documented float representation |
18
+ | Select an evaluable functor by name/arity | covered | Part 1 + Corrigenda functors are accepted; a non-evaluable term reports `type_error(evaluable,F/N)`, including the corrected zero-arity culprit shape |
19
+ | Recursively evaluate operands | covered | nested arithmetic, arithmetic comparisons, and `is/2` suites cover recursive evaluation; EyeProlog documents its stable operand-evaluation choice where Part 1 permits implementation dependence |
20
+ | Operand type constraints | covered | integer-only and float-only templates report the required type errors after expression evaluation |
21
+ | Exceptional values | covered | zero divisor, undefined, float overflow, explicit underflow, and finite-host resource exhaustion are pinned in strict tests |
22
+
23
+ ## 9.1 - simple arithmetic and type conversion
24
+
25
+ | Functor / operation family | Required templates and exceptional branches | Status | Evidence / implementation choice |
26
+ | --- | --- | --- | --- |
27
+ | `+/2`, `-/2`, `*/2` | integer/integer -> integer; mixed/float -> float | covered | BigInt exact integer operations; binary64 mixed/float operations; host BigInt exhaustion -> `resource_error(memory)` |
28
+ | `/2` | numeric operands -> float; zero divisor | covered | binary64 division; zero divisor is an evaluation error |
29
+ | `//2` | integer operands; zero divisor | covered | `integer_rounding_function=toward_zero` and BigInt truncating division |
30
+ | `rem/2`, `mod/2` | integer operands; zero divisor | covered | sign behavior is pinned for negative operands |
31
+ | unary `-/1` | integer or float | covered | preserves numeric type |
32
+ | `abs/1`, `sign/1` | integer or float | covered | preserves integer results for integer operands and float results for float operands |
33
+ | `float/1` | integer -> float; float -> float | covered | integer-to-float overflow is detected before the selected floating operation |
34
+ | `floor/1`, `truncate/1`, `round/1`, `ceiling/1` | float -> integer only | covered | integer operands report `type_error(float,...)`; representative negative/positive rounding results are pinned |
35
+ | `float_integer_part/1`, `float_fractional_part/1` | float -> float only | covered | integer operands report `type_error(float,...)` before any I->F conversion; regression includes huge unbounded integers so float overflow cannot mask the required type error |
36
+ | integer model | bounded or unbounded choice | covered | `bounded=false`; semantic integer range is unbounded, with finite-host exhaustion represented as a resource error |
37
+ | `rndI` | processor integer-division rounding choice | covered | toward zero, consistent with the fixed flag |
38
+ | `rndF` / float representation | implementation-defined float rounding model | covered | ECMAScript IEEE-754 binary64 |
39
+ | `resultF` | choose generic tiny-result rounding or underflow | covered | EyeProlog selects `round(x)`; representable subnormals survive and still-smaller generic arithmetic may round to `0.0` |
40
+ | approximate addition | implementation-defined floating addition | covered | ECMAScript binary64 addition |
41
+
42
+ ## Corrigendum 2 simple-arithmetic additions
43
+
44
+ | Functor | Status | Evidence / decision |
45
+ | --- | --- | --- |
46
+ | unary `+/1` | covered | identity over numeric expressions |
47
+ | `div/2` | covered | integer floor division; negative-operand cases distinguish it from `//2` |
48
+
49
+ ## 9.3 - other evaluable functors
50
+
51
+ | Functor family | Status | Exceptional / implementation-dependent coverage |
52
+ | --- | --- | --- |
53
+ | `**/2` | covered | negative-base restrictions, zero/negative exponent, float overflow, and the published explicit underflow row are pinned |
54
+ | `sin/1`, `cos/1`, `atan/1` | covered | integer templates perform I->F conversion first; conversion overflow is detected |
55
+ | `exp/1` | covered | float overflow and published non-zero-result underflow are pinned |
56
+ | `log/1`, `sqrt/1` | covered | non-positive/domain-invalid values report `evaluation_error(undefined)` as applicable |
57
+ | Corrigendum 2 `max/2`, `min/2` | covered | all type templates are supported; mixed numeric types use the documented implementation-dependent exact comparison and return one original operand, preserving its type |
58
+ | Corrigendum 2 `^/2` plus Corrigendum 3 correction | covered | integer powers remain exact where defined; negative integer exponent/type rules, negative-base rules, zero-negative exponent, overflow, and published underflow are pinned |
59
+ | Corrigendum 2 `asin/1`, `acos/1` | covered | valid values plus out-of-domain undefined errors |
60
+ | Corrigendum 2 `atan2/2` | covered | numeric templates plus the zero/zero undefined condition |
61
+ | Corrigendum 2 `tan/1` | covered | integer/float templates and I->F conversion behavior |
62
+ | Corrigendum 2 `pi/0` | covered | strict evaluable constant is available |
63
+
64
+ The 2026-08-23 post-N289 draft item #75 proposes conditioning the published
65
+ `**/2` and `^/2` underflow rows on the processor's `resultF` choice. EyeProlog
66
+ records that proposal but keeps the published unconditional strict behavior
67
+ until a normative corrigendum changes the baseline.
68
+
69
+ ## 9.4 - bitwise functors
70
+
71
+ | Functor | Status | Implementation-defined negative/signed behavior |
72
+ | --- | --- | --- |
73
+ | `>>/2` | covered | BigInt arithmetic/sign-propagating right shift; negative shift count reverses direction |
74
+ | `<</2` | covered | BigInt signed left shift; negative shift count reverses direction |
75
+ | `/\\/2` | covered | BigInt infinite-two's-complement semantics |
76
+ | `\\//2` | covered | BigInt infinite-two's-complement semantics |
77
+ | `\\/1` | covered | BigInt complement, equivalent to `-N-1` |
78
+ | Corrigendum 2 `xor/2` | covered | BigInt infinite-two's-complement semantics |
79
+
80
+ All 9.4 functors require integer operands; non-integers report
81
+ `type_error(integer,...)`. Very large otherwise-valid shifts retain the
82
+ unbounded integer model and translate finite-host exhaustion to
83
+ `resource_error(memory)`.
84
+
85
+ ## Closure note
86
+
87
+ With this matrix and the strict arithmetic regression, the release-facing
88
+ Clause 7.9 and Clause 9 rows are `covered`. The remaining issue #65 audit is not
89
+ therefore an arithmetic audit: it is concentrated in Clause 6 text/rejection,
90
+ Clause 7.4-7.8 and 7.10/7.12 processor semantics, their Clause 5 dependencies,
91
+ and the remaining processor-level exit criteria.
@@ -16,8 +16,8 @@ certification claim.
16
16
 
17
17
  | Requirement | Status | Current evidence / remaining work |
18
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 now-complete 8.2-8.17 row-audited built-in family in `ISO-BUILTIN-MODE-ERROR-MATRIX.md`; remaining Clause 7/9 processor-semantic rows are still being enumerated |
19
+ | 5.1(a) prepare conforming Prolog text | audit | parser/preparation tests, the closed 7.4 directive/source-clause matrix, include/ensure-loaded behavior, preparation-time operators/flags/character conversion, and the complete vendored WG17 syntax matrix; the remaining dependency is the production-by-production Clause 6 map |
20
+ | 5.1(b) execute conforming Prolog goals | audit | the 7.1-7.8 term/preparation/database/control matrices, 7.9/Clause 9 evaluable-functor matrix, and complete 8.2-8.17 built-in row audit are closed; remaining dependency rows are higher-level 7.10 and residual processor-level 7.12 semantics |
21
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
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
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 |
@@ -26,8 +26,8 @@ certification claim.
26
26
 
27
27
  | Requirement | Status | Current evidence / remaining work |
28
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; the built-in 8.2-8.17 mode/error rows are closed, while remaining general goal/control and Clause 9 semantic rows stay open |
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; 7.4 preparation is closed and the full Clause 6 production/rejection map remains open |
30
+ | 5.3 conforming and strictly conforming Prolog goal boundary | audit | strict registry/control/evaluable filtering plus closed 7.1-7.9 and 8.2-8.17 row matrices; remaining higher-level 7.10 stream and processor-error semantics keep the top-level goal boundary open |
31
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
32
 
33
33
  ## 5.5 — extension boundaries
@@ -44,12 +44,13 @@ certification claim.
44
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
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
46
  | 5.5.9 additional built-in predicates and error forms | covered | strict registry excludes normal-profile library/native additions; `ISO-BUILTIN-MODE-ERROR-MATRIX.md` closes the complete 8.2-8.17 family row-by-row; simultaneous-error choices are documented per 7.12 rather than treated as a global table-order mandate |
47
- | 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. The 9.1.4.2 `resultF` choice, Corrigendum 2 mixed-type `max/2`/`min/2` choice, and Clause 9.4 signed bitwise/shift choices are documented and pinned by strict tests. Post-N289 STC #75 remains separate from the published baseline; the remaining Clause 9 semantic/error audit is tracked under 5.1(b)/5.3 rather than as an open extension-boundary decision |
47
+ | 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
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
49
 
50
50
  ## Exit-use rule
51
51
 
52
52
  A top-level row stays `audit` until all of the normative clauses it depends on
53
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.
54
+ outcomes. `ISO-COMPLIANCE.md` records the same dependency closure in its embedded
55
+ release-exit checklist. This prevents a large green regression suite from
56
+ being mistaken for a completed processor-requirement audit.
@@ -0,0 +1,94 @@
1
+ # ISO Part 1 Prolog-text, database, and execution matrix
2
+
3
+ This matrix closes the remaining row-level audit for ISO/IEC 13211-1:1995
4
+ Clauses 7.4-7.8 against the published Part 1 baseline plus Technical
5
+ Corrigenda 1-3. It complements the built-in mode/error matrix: these rows are
6
+ processor semantics above individual predicate definitions.
7
+
8
+ `covered` means the strict profile has an explicit implementation decision and
9
+ executable evidence. Where Part 1 leaves a choice implementation-defined, the
10
+ chosen behavior is also indexed by `ISO-IMPLEMENTATION-DEFINED.md`.
11
+
12
+ ## 7.4 - Prolog text and preparation
13
+
14
+ | Row | Status | EyeProlog disposition / executable evidence |
15
+ | --- | --- | --- |
16
+ | 7.4.1 preparation model | covered | A `Program` is prepared before goal execution. Source units share preparation state where Part 1 permits it; the implementation-defined cross-text choices are recorded in the 5.4 decision index. |
17
+ | 7.4.2.1 `dynamic/1` | covered | Strict preparation validates predicate indicators, declaration ordering, protected procedures, and creates an empty dynamic/public procedure even with no clauses. |
18
+ | 7.4.2.2 `multifile/1` | covered | Declarations can span source texts and preserve the prepared clause group; declaration/order checks are exercised by the strict/conformance suites. |
19
+ | 7.4.2.3 `discontiguous/1` | covered | Strict preparation permits separated clause groups only when declared and preserves their source order. |
20
+ | 7.4.2.4 `op/3` | covered | Operator changes affect subsequent text, including later text after an included source; invalid arguments use the same strict validation as the built-in. Earlier text is not reparsed. |
21
+ | 7.4.2.5 `char_conversion/2` | covered | With the flag enabled, conversion affects subsequent unquoted source characters; quoted text is unchanged and disabling the flag stops conversion. The mapping can carry into later source units according to the documented implementation-defined choice. |
22
+ | 7.4.2.6 `initialization/1` | covered | Goals are retained in preparation order and run after preparation. Reusing the same prepared `Program` does not run them again accidentally. |
23
+ | 7.4.2.7 `include/1` | covered | The included text is prepared at the directive position and shares operator/character/flag preparation state with its parent. |
24
+ | 7.4.2.8 `ensure_loaded/1` | covered | A source is prepared at most once in the current load graph, including repeated references and self/top-level references. |
25
+ | 7.4.2.9 `set_prolog_flag/2` | covered | Preparation-time flag changes affect subsequent text and are replayed into execution state; strict flag names/values/changeability remain governed by the closed 7.11 audit. |
26
+ | 7.4.3 source clauses | covered | Source heads/bodies are validated like program clauses, standardized static/control procedures are protected, declarations can create empty procedures, and body conversion follows 7.6.2 while preserving head/body variable identity. |
27
+
28
+ The strict release test `closes ISO 7.4 Prolog-text preparation and directive
29
+ rows` exercises the cross-text operator/character/flag state, include and
30
+ ensure-loaded lifetime, initialization order, and one-shot initialization
31
+ behavior together. Existing focused tests retain the individual declaration
32
+ and preparation error cases.
33
+
34
+ ## 7.5 - database model
35
+
36
+ | Row | Status | EyeProlog disposition / executable evidence |
37
+ | --- | --- | --- |
38
+ | 7.5.1 initial database and clause order | covered | Prepared clauses retain textual preparation order. The implementation-defined initial database/standard-procedure choices are documented separately. |
39
+ | 7.5.2 static and dynamic procedures | covered | Source procedures are static unless declared dynamic; asserting a previously absent predicate creates a dynamic procedure; modification of protected/static procedures is rejected. |
40
+ | 7.5.3 private and public procedures | covered | User static procedures are private to `clause/2`; dynamic procedures are public; standardized built-ins/control forms remain static/private. |
41
+ | 7.5.4 database update visibility | covered | Dynamic calls use the logical-update view: an activation continues over the clause set visible when it began, while later activations see successful assertions/retractions. `retractall/1` retains an empty dynamic procedure and `abolish/1` removes it. |
42
+
43
+ The strict test `closes ISO 7.5-7.7 database, conversion, and execution rows`
44
+ pins source order, logical-update behavior, dynamic/public creation, and the
45
+ required distinction between an empty declared procedure and an unknown one.
46
+ The complete 8.8-8.9 database built-in modes/errors remain covered by
47
+ `ISO-BUILTIN-MODE-ERROR-MATRIX.md`.
48
+
49
+ ## 7.6 - conversion between terms and clauses/goals
50
+
51
+ | Row | Status | EyeProlog disposition / executable evidence |
52
+ | --- | --- | --- |
53
+ | 7.6.1 term-to-goal/body boundary | covered | Callable terms enter execution as goals; variables are deferred through `call/1`; non-callable numeric/body terms are rejected rather than silently coerced. |
54
+ | 7.6.2 term-to-body conversion | covered | Variables become `call/1`; conjunction, disjunction, and if-then bodies are converted recursively; non-control callable terms retain their predication; variable identity is preserved across the converted clause. |
55
+ | 7.6.3 clause-to-term observation | covered | `clause/2` returns fresh renamed clause observations with the required sharing between head and body. |
56
+ | 7.6.4 update conversion | covered | `asserta/1`, `assertz/1`, `retract/1`, and prepared source clauses use the same strict body-conversion rules and reject malformed bodies before database mutation. |
57
+
58
+ Corrigendum 3's explicit `call/1` term-to-body wording is covered by the source
59
+ and asserted-body conversion regressions.
60
+
61
+ ## 7.7 - execution and backtracking
62
+
63
+ | Row family | Status | EyeProlog disposition / executable evidence |
64
+ | --- | --- | --- |
65
+ | goal execution / procedure selection | covered | Strict mode uses ordinary clause selection and depth-first backtracking; EyeProlog automatic tabling, cycle guards, and recursive numeric shortcuts are disabled. |
66
+ | clause order and re-execution | covered | Clauses are tried in prepared/database order; re-executable predicates expose subsequent solutions on backtracking. |
67
+ | empty versus unknown procedure | covered | A defined procedure with zero clauses fails normally. A missing procedure follows the `unknown` flag (`error` by default in the strict profile). |
68
+ | side effects and database changes | covered | Standard side effects occur at their execution point; successful dynamic changes become visible to later activations while preserving the logical-update view of active calls. |
69
+ | built-in/control delegation | covered | Standardized built-ins dispatch through the strict registry and control constructs through the strict execution path; implementation-specific predicates/shortcuts are excluded by the 5.5 boundary audit. |
70
+
71
+ ## 7.8 - control constructs and exceptions
72
+
73
+ | Row | Status | EyeProlog disposition / executable evidence |
74
+ | --- | --- | --- |
75
+ | 7.8.1 `true/0` | covered | succeeds once |
76
+ | 7.8.2 `fail/0` | covered | fails |
77
+ | 7.8.3 `call/1` | covered | executes the converted goal; variables can become callable after earlier bindings; Corrigendum 3 term-to-body conversion is used |
78
+ | 7.8.4 cut | covered | cut commits within its defined invocation scope; callee-local cuts do not incorrectly prune caller alternatives |
79
+ | 7.8.5 conjunction | covered | left-to-right execution and backtracking; nested malformed converted goals retain the whole control-term culprit |
80
+ | 7.8.6 disjunction | covered | left branch is tried before the right and failure backtracks into the right branch |
81
+ | 7.8.7 if-then | covered | successful condition commits to the selected condition solution before the then branch |
82
+ | 7.8.8 if-then-else | covered | condition success selects the then branch; condition failure selects the else branch with the standard commit boundary |
83
+ | 7.8.9 `catch/3` | covered | The protected goal executes inside the catch boundary. Corrigendum 2 behavior is pinned so callability errors arising from that protected goal can be caught. |
84
+ | 7.8.10 `throw/1` | covered | Throws propagate until a matching catch and use a renamed/fresh term for exception matching. |
85
+
86
+ The strict test `closes ISO 7.8 general control-construct and exception rows`
87
+ keeps the general semantics visible in addition to the 8.15 built-in audit.
88
+
89
+ ## Audit result
90
+
91
+ Clauses **7.4-7.8 are covered at row level** for the declared strict Part 1
92
+ profile. Remaining Clause 7 exit work is therefore no longer general
93
+ preparation/database/control semantics; it is concentrated in the higher-level
94
+ 7.10 stream model and residual processor-level 7.12 error requirements.
@@ -0,0 +1,53 @@
1
+ # ISO Part 1 term-semantics audit matrix
2
+
3
+ This file closes the Clause 7.1-7.3 audit at a finer granularity than the
4
+ release-facing `ISO-COMPLIANCE.md`. The normative baseline is ISO/IEC
5
+ 13211-1:1995 plus Technical Corrigenda 1-3.
6
+
7
+ `covered` means the applicable Part 1 semantic rule has an implementation
8
+ choice where the standard permits one and executable evidence in the strict
9
+ profile. This matrix is implementation evidence, not independent
10
+ certification.
11
+
12
+ ## 7.1 - term types and derived term notions
13
+
14
+ | Requirement family | Status | EyeProlog evidence |
15
+ | --- | --- | --- |
16
+ | Five mutually exclusive core term types | covered | strict type predicates and ordering tests cover variable, float, integer, atom, and compound; the normal-profile host string term is rejected at strict program/goal entry |
17
+ | Atomic-term boundary | covered | integers, floats, and atoms satisfy the atomic predicates; compound terms do not |
18
+ | Variable set / repeated-variable identity | covered | `term_variables/2`, read-term Corrigendum 3 variable metadata, `copy_term/2`, collector tests, and repeated-variable unification preserve identity and first occurrence |
19
+ | Existential/free-variable use by collectors | covered | `bagof/3` and `setof/3` mode/semantic suites cover explicit `^/2` existential variables and grouping by free variables |
20
+ | Integer type | covered | `bounded=false` selects the full mathematical-integer model; `max_integer`/`min_integer` therefore have no value and host exhaustion is translated to `resource_error(memory)` rather than a numeric representation bound |
21
+ | Byte and character-code subranges | covered | byte I/O rows and the Unicode-scalar processor character set are separately pinned; byte values remain 0..255 while character codes follow the declared PCS |
22
+ | Floating-point type | covered | ECMAScript IEEE-754 binary64 is the documented implementation-defined float model; input overflow and arithmetic exceptional values have strict tests |
23
+ | Atoms and one-character atoms | covered | parser/reader/writer, atom conversion, character conversion, and PCS/collation suites cover atom identity and one-character atoms |
24
+ | Compound term / arguments / arity | covered | `functor/3`, `arg/3`, `=../2`, parser, predicate-indicator operations, and `max_arity=unbounded` tests cover construction/decomposition and arbitrary semantic arity |
25
+ | Lists, predicate indicators, and related derived term notions | covered | list, proper-list, sort/keysort, predicate-indicator, `current_predicate/1`, `abolish/1`, `call/N`, and module/DCG boundary tests exercise the applicable Part 1 derived forms |
26
+ | Variants / renamed copies | covered | `copy_term/2`, all-solutions collectors, clause selection, and Corrigendum variable-name tests verify renamed-copy behavior without sharing source variables |
27
+
28
+ ## 7.2 - standard order of terms
29
+
30
+ | Rule | Status | EyeProlog evidence / decision |
31
+ | --- | --- | --- |
32
+ | Type order | covered | strict gate pins `variable < float < integer < atom < compound` |
33
+ | Distinct variable order | covered | implementation-dependent stable encounter order is documented in `ISO-IMPLEMENTATION-DEFINED.md`; sort/collector operations keep that order stable for the operation |
34
+ | Float order | covered | numeric floating ordering is used within the float type |
35
+ | Integer order | covered | mathematical BigInt ordering is used within the integer type |
36
+ | Atom order | covered | null atom and lexicographic ordering use the declared Unicode-scalar collating sequence |
37
+ | Compound order | covered | arity precedes functor name, then arguments are compared left-to-right by standard term order; strict regression pins representative arity/functor cases |
38
+
39
+ ## 7.3 - unification
40
+
41
+ | Rule | Status | EyeProlog evidence / decision |
42
+ | --- | --- | --- |
43
+ | NSTO unifiable terms produce an MGU | covered | equality, clause-head matching, repeated-variable, list-tail, nested-compound, and explicit strict regression cases |
44
+ | NSTO non-unifiable terms fail | covered | scalar/functor/arity/repeated-variable mismatch suites and strict regression cases |
45
+ | STO ordinary unification | covered | Part 1 leaves the result undefined; EyeProlog consistently performs an occurs check and fails cyclic bindings, which is one permitted processor behavior for this undefined case |
46
+ | Explicit occurs-check unification | covered | `unify_with_occurs_check/2` succeeds for finite unifiable terms and fails positive-occurs-check cases |
47
+ | Implicit unification uses the same finite-tree model | covered | clause-head matching, database operations, control constructs, and collectors share the same unifier; the vendored Prologue STO annotations remain external comparison evidence rather than redefining Part 1 behavior |
48
+
49
+ ## Closure note
50
+
51
+ The Clause 7.1-7.3 row is `covered` only for the published Part 1 + Corrigenda
52
+ baseline. Normal-mode string terms and other EyeProlog extensions remain outside
53
+ this strict five-type model and are documented separately under Clause 5.5.
@@ -7,12 +7,14 @@ supported ISO Prolog profile, built-ins, extensions, and reasoner behavior.
7
7
 
8
8
  The suite is intentionally file-based. Exact standard output, errors, warnings,
9
9
  and proof output test the behavior of the JavaScript implementation.
10
- [ISO-MATRIX.md](ISO-MATRIX.md) maps Part 1 normative clause families, all three
11
- corrigenda, plus EyeProlog's module and DCG compatibility profiles, to representative
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
10
+ [ISO-COMPLIANCE.md](ISO-COMPLIANCE.md) is the high-level Part 1 audit and coverage map. [ISO-BUILTIN-MODE-ERROR-MATRIX.md](ISO-BUILTIN-MODE-ERROR-MATRIX.md)
11
+ tracks the row-by-row built-in audit,
12
+ [ISO-TERM-SEMANTICS-MATRIX.md](ISO-TERM-SEMANTICS-MATRIX.md) closes 7.1-7.3,
13
+ [ISO-PROLOG-TEXT-EXECUTION-MATRIX.md](ISO-PROLOG-TEXT-EXECUTION-MATRIX.md)
14
+ closes 7.4-7.8, [ISO-EVALUABLE-FUNCTOR-MATRIX.md](ISO-EVALUABLE-FUNCTOR-MATRIX.md)
15
+ closes 7.9/Clause 9, and [ISO-PROCESSOR-REQUIREMENTS.md](ISO-PROCESSOR-REQUIREMENTS.md)
16
+ decomposes the Clause 5 processor obligations.
17
+ The exit checklist is embedded in [ISO-COMPLIANCE.md](ISO-COMPLIANCE.md). [WG17-SYNTAX-STATUS.md](WG17-SYNTAX-STATUS.md) records the
16
18
  complete one-to-one trace for the vendored active upstream WG17 syntax cases.
17
19
  [STC-DRAFT-STATUS.md](STC-DRAFT-STATUS.md) separately tracks executable
18
20
  implementation questions from the post-N289 working draft (reviewed through the 2026-08-23 items #73-#76); those cases are
@@ -24,9 +26,12 @@ predicate indicators listed in Appendix B of the book across the Part 1 strict-c
24
26
  target and the normal-mode module/DCG compatibility families. [ISO-COMPLIANCE.md](ISO-COMPLIANCE.md) is the explicit
25
27
  release-facing ledger for the Part 1 strict-core audit. This suite is
26
28
  still not an independent certification of every processor requirement or lexical
27
- edge. The complete 8.2-8.17 built-in family is now tracked one prescribed
28
- mode/error row at a time; the remaining Clause 6/7/9 and processor semantics
29
- stay explicitly open in the dedicated audit files. Cases under `iso/`
29
+ edge. The complete 8.2-8.17 built-in family and Clause 7.1-7.9 term,
30
+ preparation/database/control, and expression/evaluable-functor families are now
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
34
+ evidence rather than a duplicated vendored corpus. Cases under `iso/`
30
35
  identify standards-derived behavior; other directories cover EyeProlog host
31
36
  contracts and extensions. EyeProlog-only execution features such as automatic
32
37
  tabling and `tnot/1` well-founded negation are outside the Part 1 strict-core
@@ -2,6 +2,10 @@
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';
6
+ import { tmpdir } from 'node:os';
7
+ import { join } from 'node:path';
8
+
5
9
  import {
6
10
  Program,
7
11
  Solver,
@@ -197,6 +201,31 @@ export function runIsoStrict(reporter = new TestReporter()) {
197
201
  'representation_error(term)', 'strict program construction rejects API string terms');
198
202
  });
199
203
 
204
+
205
+ reporter.test('closes the ISO 7.1-7.3 term-semantics rows', () => {
206
+ for (const goal of [
207
+ 'var(X), \\+ nonvar(X)',
208
+ 'integer(1), float(1.0), atom(a), compound(f(a))',
209
+ 'atomic(1), atomic(1.0), atomic(a), \\+ atomic(f(a))',
210
+ 'term_variables(f(X,Y,X),[X,Y])',
211
+ 'f(X,a)=f(b,Y), X==b, Y==a',
212
+ '\\+ (f(a)=g(a))',
213
+ '\\+ (X=f(X))',
214
+ '\\+ unify_with_occurs_check(X,f(X))',
215
+ 'copy_term(f(X,X),f(Y,Y)), X \\== Y',
216
+ 'f(a) @< f(a,b)',
217
+ 'f(a) @< g(a)',
218
+ ]) equal(run('', { isoStrict: true, goal }).stats.completed_goal_lists, 1, goal);
219
+
220
+ const program = Program.parse('', { isoStrict: true });
221
+ const solver = new Solver(program, { isoStrict: true });
222
+ const answers = (goal) => [...solver.solve([parseGoalText(goal, { isoStrict: true })], new Env(), 0)].length;
223
+ equal(answers('X @< 1.0'), 1, 'variable < float');
224
+ equal(answers('1.0 @< 1'), 1, 'float < integer');
225
+ equal(answers('1 @< a'), 1, 'integer < atom');
226
+ equal(answers('a @< f(a)'), 1, 'atom < compound');
227
+ });
228
+
200
229
  reporter.test('keeps the strict write-option surface to Part 1 plus Corrigendum 3', () => {
201
230
  const strictError = capture(() => run('', {
202
231
  isoStrict: true,
@@ -229,6 +258,7 @@ export function runIsoStrict(reporter = new TestReporter()) {
229
258
  includes(ignoredNonVariable.stdout, 'x', 'non-variable right side is permitted and ignored');
230
259
  });
231
260
 
261
+
232
262
  reporter.test('reports the complete alias option in open/4 alias collisions', () => {
233
263
  const error = capture(() => run('', {
234
264
  isoStrict: true,
@@ -740,6 +770,77 @@ export function runIsoStrict(reporter = new TestReporter()) {
740
770
  ]) equal(run('', { isoStrict: true, goal }).stats.completed_goal_lists, 1, goal);
741
771
  });
742
772
 
773
+
774
+ reporter.test('closes the ISO 7.9 and Clause 9 evaluable-functor rows', () => {
775
+ for (const goal of [
776
+ 'X is 7+35, X==42',
777
+ 'X is 7-35, X== -28',
778
+ 'X is 7*5, X==35',
779
+ 'X is 7/2, X =:= 3.5',
780
+ 'X is 7//(-3), X== -2',
781
+ 'X is 7 div (-3), X== -3',
782
+ 'X is (-7) rem 3, X== -1',
783
+ 'X is (-7) mod 3, X==2',
784
+ 'X is +7, X==7',
785
+ 'X is -7, X== -7',
786
+ 'X is abs(-7), X==7',
787
+ 'X is sign(-7), X== -1',
788
+ 'X is float(7), X =:= 7.0',
789
+ 'X is floor(1.9), X==1',
790
+ 'X is truncate(-1.9), X== -1',
791
+ 'X is round(1.4), X==1',
792
+ 'X is ceiling(1.1), X==2',
793
+ 'X is float_integer_part(1.5), X =:= 1.0',
794
+ 'X is float_fractional_part(-1.5), X =:= -0.5',
795
+ 'X is 2 ** 3, X =:= 8.0',
796
+ 'X is sin(0), X =:= 0.0',
797
+ 'X is cos(0), X =:= 1.0',
798
+ 'X is atan(0), X =:= 0.0',
799
+ 'X is exp(0), X =:= 1.0',
800
+ 'X is log(1), X =:= 0.0',
801
+ 'X is sqrt(4), X =:= 2.0',
802
+ 'X is max(2,3.0), X==3.0',
803
+ 'X is min(2.0,3), X==2.0',
804
+ 'X is 3^3, X==27',
805
+ 'X is asin(0), X =:= 0.0',
806
+ 'X is acos(1), X =:= 0.0',
807
+ 'X is atan2(1,0), X > 1.5',
808
+ 'X is tan(0), X =:= 0.0',
809
+ 'X is pi, X > 3.14',
810
+ 'X is xor(10,12), X==6',
811
+ 'X is (10 /\\ 12), X==8',
812
+ 'X is (10 \\/ 12), X==14',
813
+ 'X is (8 << 2), X==32',
814
+ 'X is (8 >> 2), X==2',
815
+ 'X is \\ 5, X== -6',
816
+ ]) equal(run('', { isoStrict: true, goal }).stats.completed_goal_lists, 1, goal);
817
+
818
+ const huge = `1${'0'.repeat(400)}`;
819
+ for (const functor of ['float_integer_part', 'float_fractional_part']) {
820
+ equal(capture(() => run('', { isoStrict: true, goal: `X is ${functor}(${huge})` })).formal,
821
+ 'type_error(float)', `${functor}/1 float-only template precedes I->F overflow`);
822
+ }
823
+
824
+ for (const [goal, formal, label] of [
825
+ ['X is Y+1', 'instantiation_error', 'direct variable expression'],
826
+ ['X is foo', 'type_error(evaluable)', 'non-evaluable atom'],
827
+ ['X is 1.5 // 1', 'type_error(integer)', 'integer-only arithmetic'],
828
+ ['X is floor(1)', 'type_error(float)', 'float-only rounding'],
829
+ ['X is 1/0', 'evaluation_error(zero_divisor)', 'floating division zero'],
830
+ ['X is 1 div 0', 'evaluation_error(zero_divisor)', 'integer division zero'],
831
+ ['X is log(0)', 'evaluation_error(undefined)', 'log domain'],
832
+ ['X is sqrt(-1)', 'evaluation_error(undefined)', 'sqrt domain'],
833
+ ['X is asin(2)', 'evaluation_error(undefined)', 'asin domain'],
834
+ ['X is acos(2)', 'evaluation_error(undefined)', 'acos domain'],
835
+ ['X is atan2(0,0)', 'evaluation_error(undefined)', 'atan2 zero pair'],
836
+ ['X is 0 ** -1', 'evaluation_error(undefined)', 'power zero-negative'],
837
+ ['X is (-2) ** 0.5', 'evaluation_error(undefined)', 'negative-base power'],
838
+ ['X is exp(1000.0)', 'evaluation_error(float_overflow)', 'transcendental overflow'],
839
+ ['X is exp(-1000.0)', 'evaluation_error(underflow)', 'transcendental underflow'],
840
+ ['X is 2.0 ** -1075.0', 'evaluation_error(underflow)', 'published power underflow'],
841
+ ]) equal(capture(() => run('', { isoStrict: true, goal })).formal, formal, label);
842
+ });
843
+
743
844
  reporter.test('uses the Part 1 mixed arithmetic comparison operations', () => {
744
845
  // 8.7 converts the integer operand to float in mixed comparisons.
745
846
  equal(run('', { isoStrict: true, goal: '18014398509481985 =:= 18014398509481984.0' }).stats.completed_goal_lists,
@@ -843,6 +944,101 @@ export function runIsoStrict(reporter = new TestReporter()) {
843
944
  }).stats.completed_goal_lists, 0, 'STC 48 variables([]) does not match an input variable');
844
945
  });
845
946
 
947
+ reporter.test('closes ISO 7.4 Prolog-text preparation and directive rows', () => {
948
+ const directory = mkdtempSync(join(tmpdir(), 'eyeprolog-iso-74-'));
949
+ try {
950
+ writeFileSync(join(directory, 'child.pl'), [
951
+ 'child.',
952
+ ":- op(500,'xfx',trusts).",
953
+ 'child_rule(carol trusts dave).',
954
+ '',
955
+ ].join('\n'));
956
+ writeFileSync(join(directory, 'once.pl'), 'once_loaded.\n');
957
+ const source = [
958
+ ':- op(500,xfx,likes).',
959
+ ':- char_conversion(x,y).',
960
+ ':- set_prolog_flag(double_quotes,codes).',
961
+ ':- dynamic(seen/1).',
962
+ ':- initialization(assertz(seen(1))).',
963
+ ':- initialization(assertz(seen(2))).',
964
+ ":- include('child.pl').",
965
+ ":- ensure_loaded('once.pl').",
966
+ ":- ensure_loaded('once.pl').",
967
+ 'relation(alice likes bob).',
968
+ 'parent_rule(alice trusts bob).',
969
+ 'converted(x).',
970
+ 'quoted("ab").',
971
+ '',
972
+ ].join('\n');
973
+ const program = Program.parseSources([{ text: source, filename: 'main.pl', baseDir: directory }], {
974
+ isoStrict: true,
975
+ sourceMetadata: true,
976
+ });
977
+
978
+ equal(program.findGroup('child', 0)?.clauses.length, 1, 'include/1 textual inclusion');
979
+ equal(program.findGroup('once_loaded', 0)?.clauses.length, 1, 'ensure_loaded/1 loads once');
980
+ equal(program.findGroup('relation', 1)?.clauses[0]?.head?.args[0]?.name, 'likes', 'op/3 affects following text');
981
+ equal(program.findGroup('parent_rule', 1)?.clauses[0]?.head?.args[0]?.name, 'trusts', 'included op/3 affects following parent text');
982
+ equal(program.findGroup('converted', 1)?.clauses[0]?.head?.args[0]?.name, 'y', 'char_conversion/2 affects following unquoted source');
983
+ equal(run(program, { isoStrict: true, goal: 'quoted([97,98])' }).stats.completed_goal_lists > 0, true,
984
+ 'set_prolog_flag/2 affects following source and execution');
985
+
986
+ const first = run(program, { isoStrict: true, goal: 'findall(X,seen(X),[1,2])' });
987
+ const second = run(program, { isoStrict: true, goal: 'findall(X,seen(X),[1,2])' });
988
+ equal(first.stats.completed_goal_lists > 0, true, 'initialization/1 order');
989
+ equal(second.stats.completed_goal_lists > 0, true, 'initialization/1 executes once per prepared Program');
990
+ } finally {
991
+ rmSync(directory, { recursive: true, force: true });
992
+ }
993
+ });
994
+
995
+ reporter.test('closes ISO 7.5-7.7 database, conversion, and execution rows', () => {
996
+ const source = [
997
+ ':- dynamic(p/1).',
998
+ ':- dynamic(empty/0).',
999
+ 'p(1).',
1000
+ 'p(2).',
1001
+ 'body(X) :- X.',
1002
+ '',
1003
+ ].join('\n');
1004
+
1005
+ equal(run(source, {
1006
+ isoStrict: true,
1007
+ goal: 'findall(X,(p(X),retract(p(X))),Xs),Xs=[1,2],\\+p(_)',
1008
+ }).stats.completed_goal_lists > 0, true, 'logical-update view and source clause order');
1009
+ equal(run(source, { isoStrict: true, goal: '\\+ empty' }).stats.completed_goal_lists > 0, true,
1010
+ 'declared empty procedure fails as a defined procedure');
1011
+ equal(capture(() => run(source, { isoStrict: true, goal: 'missing' })).formal,
1012
+ 'existence_error(procedure)', 'unknown procedure remains distinct from empty procedure');
1013
+ equal(run('', {
1014
+ isoStrict: true,
1015
+ goal: 'assertz(fresh(a)),current_predicate(fresh/1),clause(fresh(a),true)',
1016
+ }).stats.completed_goal_lists > 0, true, 'asserting a new procedure makes it dynamic/public');
1017
+ equal(run(source, { isoStrict: true, goal: 'body(true)' }).stats.completed_goal_lists > 0, true,
1018
+ 'source variable body is converted to call/1');
1019
+ });
1020
+
1021
+ reporter.test('closes ISO 7.8 general control-construct and exception rows', () => {
1022
+ equal(run('', { isoStrict: true, goal: 'true' }).stats.completed_goal_lists, 1, 'true/0');
1023
+ equal(run('', { isoStrict: true, goal: 'fail' }).stats.completed_goal_lists, 0, 'fail/0');
1024
+ equal(run('', { isoStrict: true, goal: 'X=true,call(X)' }).stats.completed_goal_lists > 0, true,
1025
+ 'call/1 executes the converted goal');
1026
+ equal(run('', { isoStrict: true, goal: '(fail;true)' }).stats.completed_goal_lists > 0, true,
1027
+ 'disjunction backtracks to the second branch');
1028
+ equal(run('', { isoStrict: true, goal: '(true->true;fail)' }).stats.completed_goal_lists > 0, true,
1029
+ 'if-then-else commits after a successful condition');
1030
+ equal(capture(() => run('', { isoStrict: true, goal: 'call((write(a),3))' })).formal,
1031
+ 'type_error(callable)', 'nested non-callable control term is rejected');
1032
+ equal(run('', {
1033
+ isoStrict: true,
1034
+ goal: 'catch(X,error(instantiation_error,_),true)',
1035
+ }).stats.completed_goal_lists > 0, true, 'Corrigendum 2 catch/3 can catch callability errors from its protected goal');
1036
+ equal(run('', {
1037
+ isoStrict: true,
1038
+ goal: 'catch(throw(ball(X)),ball(Y),X=Y)',
1039
+ }).stats.completed_goal_lists > 0, true, 'throw/1 and catch/3 unify through a renamed thrown term');
1040
+ });
1041
+
846
1042
  reporter.test('rejects EyeProlog module directives', () => {
847
1043
  const error = capture(() => Program.parse(':- use_module(library(lists)).\n', { isoStrict: true }));
848
1044
  includes(error.message, 'implementation-specific directive use_module/1', 'message');
@@ -3691,6 +3691,67 @@ function documentationSyncCases() {
3691
3691
  assertIncludes(text, 'Implementation-specific features required to be documented by 5.4', '5.5 extension inventory');
3692
3692
  },
3693
3693
  },
3694
+ {
3695
+ name: 'ISO term and arithmetic row matrices are closed and linked',
3696
+ run: () => {
3697
+ const compliance = fs.readFileSync(path.join(testRoot, 'conformance', 'ISO-COMPLIANCE.md'), 'utf8');
3698
+ const terms = fs.readFileSync(path.join(testRoot, 'conformance', 'ISO-TERM-SEMANTICS-MATRIX.md'), 'utf8');
3699
+ const arithmetic = fs.readFileSync(path.join(testRoot, 'conformance', 'ISO-EVALUABLE-FUNCTOR-MATRIX.md'), 'utf8');
3700
+ assertIncludes(compliance, '| 7.1-7.3 — term types, term order, unification | covered |', '7.1-7.3 covered');
3701
+ assertIncludes(compliance, '| 7.9 — expression evaluation | covered |', '7.9 covered');
3702
+ assertIncludes(compliance, '| Clause 9 — evaluable functors | covered |', 'Clause 9 covered');
3703
+ assertIncludes(terms, '## 7.3 - unification', 'term unification row matrix');
3704
+ assertIncludes(arithmetic, '## 9.4 - bitwise functors', 'Clause 9.4 row matrix');
3705
+ assertIncludes(arithmetic, '`float_integer_part/1`, `float_fractional_part/1`', 'float-only conversion row');
3706
+ },
3707
+ },
3708
+ {
3709
+ name: 'ISO 7.4-7.8 execution matrix is closed',
3710
+ run: () => {
3711
+ const compliance = fs.readFileSync(path.join(testRoot, 'conformance', 'ISO-COMPLIANCE.md'), 'utf8');
3712
+ const matrix = fs.readFileSync(path.join(testRoot, 'conformance', 'ISO-PROLOG-TEXT-EXECUTION-MATRIX.md'), 'utf8');
3713
+ for (const row of [
3714
+ '| 7.4 — Prolog text and directives | covered |',
3715
+ '| 7.5-7.6 — database and term/clause conversion | covered |',
3716
+ '| 7.7 — execution and backtracking | covered |',
3717
+ '| 7.8 — control constructs and exceptions | covered |',
3718
+ ]) assertIncludes(compliance, row, row);
3719
+ for (const section of ['## 7.4 - Prolog text and preparation', '## 7.5 - database model', '## 7.6 - conversion between terms and clauses/goals', '## 7.7 - execution and backtracking', '## 7.8 - control constructs and exceptions']) {
3720
+ assertIncludes(matrix, section, section);
3721
+ }
3722
+ },
3723
+ },
3724
+ {
3725
+ name: 'ISO exit criteria keep remaining audit work explicit',
3726
+ run: () => {
3727
+ const exit = fs.readFileSync(path.join(testRoot, 'conformance', 'ISO-COMPLIANCE.md'), 'utf8');
3728
+ for (const item of [
3729
+ '| Clause 6 lexical/syntactic requirements have explicit dispositions | open |',
3730
+ '| Clause 7 semantic requirements have explicit dispositions | open |',
3731
+ '| Clause 8 built-in modes/errors have explicit dispositions | covered |',
3732
+ '| Clause 9 evaluable-functor requirements have explicit dispositions | covered |',
3733
+ '| Independent external syntax corpus is an offline release gate | covered |',
3734
+ '| No unexplained deviation remains in the release-facing ledger | open |',
3735
+ ]) assertIncludes(exit, item, item);
3736
+ },
3737
+ },
3738
+ {
3739
+ name: 'public ISO documentation keeps README concise and the book authoritative',
3740
+ run: () => {
3741
+ const readme = fs.readFileSync(path.join(packageRoot, 'README.md'), 'utf8');
3742
+ const book = fs.readFileSync(path.join(packageRoot, 'the-art-of-eyeprolog.md'), 'utf8');
3743
+ const profile = fs.readFileSync(path.join(packageRoot, 'why-eyeprolog.md'), 'utf8');
3744
+ for (const name of [
3745
+ 'ISO-TERM-SEMANTICS-MATRIX.md',
3746
+ 'ISO-PROLOG-TEXT-EXECUTION-MATRIX.md',
3747
+ 'ISO-EVALUABLE-FUNCTOR-MATRIX.md',
3748
+ ]) assertIncludes(book, name, `book ${name}`);
3749
+ assertIncludes(readme, 'implementation reference is [*The Art of EyeProlog*]', 'README book hand-off');
3750
+ assertIncludes(readme, 'test/conformance/ISO-COMPLIANCE.md', 'README concise audit link');
3751
+ assertEqual(readme.includes('2026-08-23 draft items #73-#76'), false, 'README omits audit-history detail');
3752
+ assertIncludes(profile, 'completed row-level 7.1-7.9 term, preparation/database/control, and arithmetic audits', 'Why EyeProlog audit state');
3753
+ },
3754
+ },
3694
3755
  {
3695
3756
  name: 'book is the single implementation reference',
3696
3757
  run: () => assertArrayEqual(bookReferenceDocumentationIssues(), [], 'book reference documentation'),
@@ -7586,13 +7586,17 @@ node test/run-conformance-report.mjs
7586
7586
  `test/conformance/ISO-COMPLIANCE.md` is the processor-requirement ledger for the
7587
7587
  Part 1 conformance audit. It distinguishes implemented/tested families from
7588
7588
  requirements whose normative `shall` clauses, option combinations, or error
7589
- precedence still need one-by-one closure. `test/conformance/ISO-MATRIX.md`
7589
+ precedence still need one-by-one closure. `test/conformance/ISO-COMPLIANCE.md`
7590
7590
  maps language families to representative executable cases.
7591
7591
  `test/conformance/ISO-IMPLEMENTATION-DEFINED.md` is the ISO 5.4 decision
7592
- index: it enumerates the Part 1 implementation-defined decisions, the
7593
- implementation-specific extension families, and any remaining strict-mode audit
7594
- gaps without turning draft WG17/STC proposals into the licensed baseline.
7595
- `test/conformance/WG17-SYNTAX-STATUS.md` separately traces the vendored active
7592
+ index: it enumerates the Part 1 implementation-defined decisions and the
7593
+ implementation-specific extension families without turning draft WG17/STC
7594
+ proposals into the licensed baseline. `ISO-TERM-SEMANTICS-MATRIX.md` closes the 7.1-7.3 type/order/unification
7595
+ rows, `ISO-PROLOG-TEXT-EXECUTION-MATRIX.md` closes 7.4-7.8 preparation,
7596
+ database, conversion, execution, and control, and
7597
+ `ISO-EVALUABLE-FUNCTOR-MATRIX.md` closes 7.9/Clause 9 expression and arithmetic
7598
+ rows. The exit checklist in `ISO-COMPLIANCE.md` makes the remaining normative and
7599
+ unexplained-deviation conditions explicit. `test/conformance/WG17-SYNTAX-STATUS.md` separately traces the vendored active
7596
7600
  upstream syntax cases. Reviewed cases can pin exact strict-reader outcomes, while
7597
7601
  newly upgraded cases execute directly against the upstream Codex expectation.
7598
7602
 
@@ -7659,7 +7663,7 @@ that Part 1 strict surface.
7659
7663
  This release establishes the strict-mode mechanism required for the ongoing
7660
7664
  conformance audit; it does **not** yet claim that every processor requirement
7661
7665
  has been independently certified. `test/conformance/ISO-COMPLIANCE.md` tracks
7662
- the remaining normative audit work. The executable examples are mostly
7666
+ the remaining normative audit work. Public comparison material used during the audit remains review evidence rather than a duplicated vendored corpus. The executable examples are mostly
7663
7667
  EyeProlog-profile programs using host-supplied goals, character lists, explicit
7664
7668
  integrity relations, automatic tabling, and the EyeProlog library. The strict audit also exercises the complete Part 1 flag
7665
7669
  set and the prescribed 8.14 error precedence for `read_term/3`, `write_term/3`,
@@ -7672,10 +7676,13 @@ creation/position/EOF behavior and text-vs-binary permission errors, corrects
7672
7676
  Corrigendum 2 `keysort/2` error cases, closes the 5.5.6 Prolog-visible
7673
7677
  side-effect boundary by excluding statistics/cleanup extensions from strict
7674
7678
  mode, closes 5.5.10 by keeping the non-standard evaluable atom `e` outside
7675
- strict mode, and pins the permitted arithmetic variation points for
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
7676
7681
  mixed-type Corrigendum 2 `max/2`/`min/2` plus signed Clause 9.4 bitwise and
7677
- negative-shift behavior. These are conformance improvements, while the
7678
- remaining qualifications are:
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:
7679
7686
 
7680
7687
  - zero-arity compound syntax such as `ready()` is represented by the atom
7681
7688
  `ready`;
@@ -7695,9 +7702,9 @@ Write terms explicitly, keep variables uppercase or underscore-prefixed, and
7695
7702
  quote atom names that are neither lowercase plain names nor graphic tokens.
7696
7703
  These boundaries distinguish implemented ISO functionality from certification.
7697
7704
  The EyeProlog corpus verifies this documented profile and strict-core boundary.
7698
- A public full-conformance claim is deferred until the compliance ledger has no
7699
- unresolved normative audits and external conformity runs have no unexplained
7700
- deviations.
7705
+ A public full-conformance claim is deferred until the explicit
7706
+ exit checklist in `test/conformance/ISO-COMPLIANCE.md` has no unresolved normative
7707
+ audits or unexplained deviations.
7701
7708
 
7702
7709
  ### Security and resource use
7703
7710
 
package/why-eyeprolog.md CHANGED
@@ -28,10 +28,11 @@ collating-sequence integers in both normal and strict profiles. Strict mode
28
28
  therefore rejects implementation-specific language extensions without changing
29
29
  that processor choice. Its executable conformance matrix and tests
30
30
  document the supported behavior, including an executable trace of the vendored
31
- active WG17 syntax cases, cross-profile preservation of all strict-success WG17 syntax outcomes, closed strict side-effect and evaluable-functor extension boundaries, and explicit choices at standardized variation points such as mixed-type
32
- `max/2`/`min/2` and signed bitwise/shift operations. This is extensive implementation evidence, not a
33
- claim that every Part 1, Part 2, or Part 3 normative requirement has already
34
- been certified or closed.
31
+ active WG17 syntax cases, cross-profile preservation of all strict-success WG17 syntax outcomes, closed strict side-effect and evaluable-functor extension boundaries, the completed row-level 7.1-7.9 term, preparation/database/control, and arithmetic audits, offline public conversion/variable-metadata audit fixtures, and explicit choices at standardized variation points such as mixed-type
32
+ `max/2`/`min/2` and signed bitwise/shift operations. The remaining exit criteria
33
+ are recorded explicitly rather than inferred from aggregate test counts. This is
34
+ extensive implementation evidence, not a claim that every Part 1, Part 2, or
35
+ Part 3 normative requirement has already been certified or closed.
35
36
 
36
37
  ## Why a small implementation?
37
38
 
@@ -1,45 +0,0 @@
1
- # ISO Prolog conformance matrix
2
-
3
- The normative baseline for the `iso/` corpus is ISO/IEC 13211-1:1995 plus
4
- Technical Corrigenda 1:2007, 2:2012, and 3:2017. This matrix links the standard
5
- families to executable coverage; `conformance-report.md` supplies the generated
6
- case totals. [ISO-COMPLIANCE.md](ISO-COMPLIANCE.md) tracks the processor-level
7
- compliance audit and the remaining work before a full conformance claim.
8
-
9
- | Standard area | Implementation | Representative executable coverage |
10
- | --- | --- | --- |
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, and a cross-profile check that all strict-success WG17 cases retain the same normal-profile outcome |
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
- | 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, 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
- | 8.6-8.7 arithmetic predicates | `is/2` and all six arithmetic comparisons | `arithmetic`, comparison cases, isolated evaluation errors, and the explicit row-level 8.6-8.7 mode/error-condition audit |
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`, the complete row-level 8.8-8.10 mode/error-condition audit, source/runtime 7.6.2 conversion through `,/2`, `;/2`, and `->/2` with preserved head/body variable sharing, selected deterministic overlap checks, runtime static/private protection for conjunction, and STC #56 `(:-)/1-2` database protection |
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, the complete row-level 8.11-8.14 mode/error audit, Corrigendum 3 variable metadata/write naming checks, and issue #65 checks for stream lifecycle/property validation (including closed-stream failure), 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 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
- | 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, published `exp/1`/`**/2`/`^/2` underflow (with post-N289 STC #75 tracked separately), Part 1 mixed integer/float comparison conversion, the pinned Corrigendum 2 mixed-type `max/2`/`min/2` implementation-dependent choice, documented Clause 9.4 signed bitwise/negative-shift semantics, and resource-error normalization for finite-host exhaustion of unbounded integer operations |
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
- | 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 |
24
-
25
- Corrigendum-specific coverage includes double-quoted atom operator priority
26
- (Cor.1); the added predicates and evaluable functors, bar-operator rules,
27
- uninstantiation errors, and corrected `catch/3` behavior (Cor.2); and option
28
- validation, variable-name traversal/output, canonical list output, and negative
29
- integer powers (Cor.3).
30
-
31
- Implementation-defined and implementation-specific choices are indexed
32
- clause-by-clause in [ISO-IMPLEMENTATION-DEFINED.md](ISO-IMPLEMENTATION-DEFINED.md),
33
- with *The Art of EyeProlog* remaining the implementation reference. In
34
- particular, the index records the unbounded integer model, `double_quotes=chars`,
35
- `//` rounding toward zero, the ECMAScript binary64 float policy (including the
36
- 9.1.4.2 choice to round generic tiny results while retaining explicit
37
- functor-specific underflow errors),
38
- stream/character decisions, and the normal-profile extension boundary.
39
-
40
- This is an executable conformance/compatibility matrix, not a certification issued by an
41
- independent standards body. The Part 2/Part 3-related rows describe tested
42
- normal-mode compatibility surfaces rather than a claim that every requirement
43
- of those standards has been closed. Release gating runs the ISO cases and the dedicated
44
- Part 1 strict-core suite together with the full regression, API, documentation,
45
- example, and browser suites.