eyeprolog 1.5.83 → 1.5.85

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.
Files changed (100) hide show
  1. package/README.md +2 -3
  2. package/conformance-report.md +11 -19
  3. package/package.json +1 -2
  4. package/src/quads.js +39 -13
  5. package/test/README.md +3 -3
  6. package/test/conformance/ISO-COMPLIANCE.md +9 -9
  7. package/test/conformance/NEUMERKEL-LATEST.md +3 -7
  8. package/test/conformance/README.md +13 -16
  9. package/test/conformance/THIRD_PARTY.md +1 -0
  10. package/test/conformance/cases/iso/scryer_backslash_atom.pl +8 -0
  11. package/test/conformance/cases/iso/scryer_bare_exponent_lexing.pl +10 -0
  12. package/test/conformance/cases/iso/scryer_bracket_and_curly_term_parsing.pl +12 -0
  13. package/test/conformance/cases/iso/scryer_default_prefix_operator_priorities.pl +8 -0
  14. package/test/conformance/cases/iso/scryer_dollar_sign_atoms.pl +10 -0
  15. package/test/conformance/cases/iso/scryer_empty_list_atom_functor.pl +7 -0
  16. package/test/conformance/cases/iso/scryer_exponent_minus_lexing.pl +12 -0
  17. package/test/conformance/cases/iso/scryer_large_float_exponent.pl +11 -0
  18. package/test/conformance/cases/iso/scryer_line_continuation_in_quoted_atoms.pl +15 -0
  19. package/test/conformance/cases/iso/scryer_lower_priority_prefix_with_infix.pl +11 -0
  20. package/test/conformance/cases/iso/scryer_mixed_prefix_infix_operator_priority.pl +11 -0
  21. package/test/conformance/cases/iso/scryer_op_error_conditions.pl +29 -0
  22. package/test/conformance/cases/iso/scryer_operator_application_vs_functor_notation.pl +10 -0
  23. package/test/conformance/cases/iso/scryer_postfix_operator_negative_number.pl +10 -0
  24. package/test/conformance/cases/iso/scryer_prefix_minus_chain.pl +8 -0
  25. package/test/conformance/cases/iso/scryer_quote_and_char_code_literals.pl +16 -0
  26. package/test/conformance/cases/iso/scryer_special_atom_names.pl +10 -0
  27. package/test/conformance/cases/iso/scryer_subnormal_float_underflow.pl +9 -0
  28. package/test/conformance/cases/iso/scryer_unary_plus_compound.pl +12 -0
  29. package/test/conformance/cases/iso/scryer_user_operator_with_prefix_minus.pl +14 -0
  30. package/test/conformance/cases/iso/trealla_append_modes.pl +11 -0
  31. package/test/conformance/cases/iso/trealla_arithmetic_constants.pl +7 -0
  32. package/test/conformance/cases/iso/trealla_atom_codes_unicode.pl +11 -0
  33. package/test/conformance/cases/iso/trealla_bagof_multi_free_variables.pl +23 -0
  34. package/test/conformance/cases/iso/trealla_bignum_arithmetic.pl +32 -0
  35. package/test/conformance/cases/iso/trealla_call_missing_extended_arity.pl +6 -0
  36. package/test/conformance/cases/iso/trealla_findall_solution_independence.pl +9 -0
  37. package/test/conformance/cases/iso/trealla_float_parts_extremes.pl +25 -0
  38. package/test/conformance/cases/iso/trealla_forall_double_negation.pl +12 -0
  39. package/test/conformance/cases/iso/trealla_if_then_else_backtracking.pl +22 -0
  40. package/test/conformance/cases/iso/trealla_number_codes_char_literal.pl +6 -0
  41. package/test/conformance/cases/iso/trealla_shared_variable_unification.pl +63 -0
  42. package/test/conformance/cases/iso/trealla_sub_atom_modes.pl +32 -0
  43. package/test/conformance/cases/iso/trealla_term_variables_partial_list_error.pl +6 -0
  44. package/test/conformance/cases/iso/trealla_variable_goal_normalization.pl +11 -0
  45. package/test/conformance/cases/iso/trealla_write_canonical_operators.pl +26 -0
  46. package/test/conformance/cases/iso/trealla_write_term_duplicate_variable_names.pl +6 -0
  47. package/test/conformance/expected/iso/scryer_backslash_atom.pl +1 -0
  48. package/test/conformance/expected/iso/scryer_bare_exponent_lexing.pl +1 -0
  49. package/test/conformance/expected/iso/scryer_bracket_and_curly_term_parsing.pl +1 -0
  50. package/test/conformance/expected/iso/scryer_default_prefix_operator_priorities.pl +1 -0
  51. package/test/conformance/expected/iso/scryer_dollar_sign_atoms.pl +1 -0
  52. package/test/conformance/expected/iso/scryer_empty_list_atom_functor.pl +1 -0
  53. package/test/conformance/expected/iso/scryer_exponent_minus_lexing.pl +1 -0
  54. package/test/conformance/expected/iso/scryer_large_float_exponent.pl +1 -0
  55. package/test/conformance/expected/iso/scryer_line_continuation_in_quoted_atoms.pl +1 -0
  56. package/test/conformance/expected/iso/scryer_lower_priority_prefix_with_infix.pl +1 -0
  57. package/test/conformance/expected/iso/scryer_mixed_prefix_infix_operator_priority.pl +1 -0
  58. package/test/conformance/expected/iso/scryer_op_error_conditions.pl +5 -0
  59. package/test/conformance/expected/iso/scryer_operator_application_vs_functor_notation.pl +1 -0
  60. package/test/conformance/expected/iso/scryer_postfix_operator_negative_number.pl +1 -0
  61. package/test/conformance/expected/iso/scryer_prefix_minus_chain.pl +1 -0
  62. package/test/conformance/expected/iso/scryer_quote_and_char_code_literals.pl +1 -0
  63. package/test/conformance/expected/iso/scryer_special_atom_names.pl +1 -0
  64. package/test/conformance/expected/iso/scryer_subnormal_float_underflow.pl +1 -0
  65. package/test/conformance/expected/iso/scryer_unary_plus_compound.pl +1 -0
  66. package/test/conformance/expected/iso/scryer_user_operator_with_prefix_minus.pl +1 -0
  67. package/test/conformance/expected/iso/trealla_append_modes.pl +6 -0
  68. package/test/conformance/expected/iso/trealla_arithmetic_constants.pl +1 -0
  69. package/test/conformance/expected/iso/trealla_atom_codes_unicode.pl +2 -0
  70. package/test/conformance/expected/iso/trealla_bagof_multi_free_variables.pl +5 -0
  71. package/test/conformance/expected/iso/trealla_bignum_arithmetic.pl +4 -0
  72. package/test/conformance/expected/iso/trealla_call_missing_extended_arity.pl +1 -0
  73. package/test/conformance/expected/iso/trealla_findall_solution_independence.pl +1 -0
  74. package/test/conformance/expected/iso/trealla_float_parts_extremes.pl +4 -0
  75. package/test/conformance/expected/iso/trealla_forall_double_negation.pl +1 -0
  76. package/test/conformance/expected/iso/trealla_if_then_else_backtracking.pl +5 -0
  77. package/test/conformance/expected/iso/trealla_number_codes_char_literal.pl +1 -0
  78. package/test/conformance/expected/iso/trealla_shared_variable_unification.pl +10 -0
  79. package/test/conformance/expected/iso/trealla_sub_atom_modes.pl +22 -0
  80. package/test/conformance/expected/iso/trealla_term_variables_partial_list_error.pl +1 -0
  81. package/test/conformance/expected/iso/trealla_variable_goal_normalization.pl +1 -0
  82. package/test/conformance/expected/iso/trealla_write_canonical_operators.pl +5 -0
  83. package/test/conformance/expected/iso/trealla_write_term_duplicate_variable_names.pl +2 -0
  84. package/test/fixtures/README.md +8 -11
  85. package/test/fixtures/prologue_quad.pl +166 -13
  86. package/test/neumerkel.mjs +20 -7
  87. package/test/regression/cases-documentation-sync.mjs +7 -44
  88. package/test/regression/cases-regression.mjs +21 -38
  89. package/test/regression/support.mjs +6 -8
  90. package/test/run-all.mjs +0 -2
  91. package/test/run-conformance-all.mjs +0 -2
  92. package/test/run-conformance-report.mjs +14 -75
  93. package/test/run-wg17.mjs +20 -39
  94. package/the-art-of-eyeprolog.md +13 -10
  95. package/tools/{upgrade-wg17.mjs → wg17-syntax.mjs} +4 -228
  96. package/test/conformance/WG17-SYNTAX-STATUS.md +0 -51
  97. package/test/conformance/wg17-syntax-coverage.json +0 -21
  98. package/test/fixtures/prologue_call_nth_quad.pl +0 -32
  99. package/test/fixtures/prologue_call_nth_quad_runner.pl +0 -2
  100. package/tools/report-wg17-syntax-coverage.mjs +0 -167
package/README.md CHANGED
@@ -95,11 +95,10 @@ npm test
95
95
  ```
96
96
  The npm command list is deliberately small:
97
97
 
98
- - `npm test` (or `npm run test`): run the release gate, including live upstream conformity checks.
99
- - `npm run conformance:update:wg17`: update the vendored WG17 syntax cases and their inventory documentation.
98
+ - `npm test` (or `npm run test`): run the release gate, including live upstream conformity checks (WG17 syntax among them).
100
99
  - `npm run generate`: rebuild generated library and book files.
101
100
  - `npm run benchmark`: run the wall-clock benchmarks.
102
101
 
103
- Use `npm test -- --offline` for a network-free local pass. Focused checks remain available directly, for example `node test/run-regression.mjs docs` or `node test/run-wg17.mjs`; see [test runners](test/README.md). The automatic version hooks still run the release gate, refresh and stage conformance reports, and push the release. Detailed upstream report maintenance is documented in the [conformance guide](test/conformance/README.md).
102
+ Use `npm test -- --offline` for a network-free local pass (this also skips the live-discovered WG17 syntax check, since it has no offline snapshot). Focused checks remain available directly, for example `node test/run-regression.mjs docs`; see [test runners](test/README.md). The automatic version hooks still run the release gate, refresh and stage conformance reports, and push the release. Detailed upstream report maintenance is documented in the [conformance guide](test/conformance/README.md).
104
103
 
105
104
  EyeProlog is released under the [MIT License](LICENSE.md).
@@ -1,25 +1,17 @@
1
1
  # EyeProlog conformance report
2
2
 
3
- This report combines an executable external conformance gate with the file-based
4
- conformance corpus under `test/conformance/`. The executable result is measured
5
- when this report is generated; it is not inferred from fixture counts.
3
+ This report combines a live external conformance gate with the file-based
4
+ conformance corpus under `test/conformance/`. The file-based corpus is
5
+ measured when this report is generated; it is not inferred from fixture counts.
6
6
 
7
7
  ## Latest Neumerkel evidence
8
8
 
9
- See the tracked [latest Neumerkel conformity report](test/conformance/NEUMERKEL-LATEST.md).
10
- `npm test` fetches all eight TU Wien sources once and executes the discovered inventory.
11
- The release workflow then synchronizes this tracked report from those exact successful
12
- cached source bytes, avoiding a second live fetch and its race window.
13
-
14
- ## Executable conformance status
15
-
16
- | Gate | Passed | Total | Status |
17
- |---|---:|---:|---|
18
- | WG17 syntax | 379 | 379 | pass |
19
-
20
- The WG17 syntax row executes the vendored 379-case conformity-testing matrix
21
- against EyeProlog's strict ISO reader/writer. A behavior fix such as operator-token
22
- spelling therefore changes this report even when no corpus file is added or removed.
9
+ See the tracked [latest Neumerkel conformity report](test/conformance/NEUMERKEL-LATEST.md)
10
+ for the executable external gate, including WG17 syntax conformance: `npm test`
11
+ fetches all eight TU Wien sources (syntax discovered and executed live, not a
12
+ vendored fixture) and executes the discovered inventory. The release workflow
13
+ then synchronizes this tracked report from those exact successful cached source
14
+ bytes, avoiding a second live fetch and its race window.
23
15
 
24
16
  ## File-based corpus inventory
25
17
 
@@ -32,7 +24,7 @@ spelling therefore changes this report even when no corpus file is added or remo
32
24
  | context | 11 | 0 | 0 | 0 | 11 |
33
25
  | control | 15 | 0 | 0 | 0 | 15 |
34
26
  | explicit-tabling | 6 | 0 | 0 | 0 | 6 |
35
- | iso | 174 | 219 | 0 | 0 | 393 |
27
+ | iso | 211 | 219 | 0 | 0 | 430 |
36
28
  | lists | 52 | 3 | 0 | 0 | 55 |
37
29
  | modules | 2 | 0 | 0 | 0 | 2 |
38
30
  | negation | 8 | 0 | 19 | 0 | 27 |
@@ -45,7 +37,7 @@ spelling therefore changes this report even when no corpus file is added or remo
45
37
  | terms | 26 | 3 | 0 | 0 | 29 |
46
38
  | unification | 18 | 0 | 0 | 0 | 18 |
47
39
  | variables | 16 | 7 | 0 | 0 | 23 |
48
- | **Total** | **496** | **274** | **19** | **21** | **810** |
40
+ | **Total** | **533** | **274** | **19** | **21** | **847** |
49
41
 
50
42
  ## DCG conformance clarification
51
43
 
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.5.83",
6
+ "version": "1.5.85",
7
7
  "description": "EyeProlog turns facts and rules into answers and proofs.",
8
8
  "type": "module",
9
9
  "main": "./index.js",
@@ -46,7 +46,6 @@
46
46
  },
47
47
  "scripts": {
48
48
  "test": "node test/run-all.mjs",
49
- "conformance:update:wg17": "node tools/upgrade-wg17.mjs",
50
49
  "benchmark": "node test/benchmark.mjs",
51
50
  "generate": "node tools/generate-library-autoload-index.mjs && node tools/generate-predicate-reference.mjs && node tools/extract-book-examples.mjs",
52
51
  "preversion": "npm test && node test/run-neumerkel.mjs --cached --update-report && node test/run-conformance-report.mjs conformance-report.md && git add test/conformance/NEUMERKEL-LATEST.md conformance-report.md",
package/src/quads.js CHANGED
@@ -252,14 +252,29 @@ function checkAnswerPermutation(program, query, leaves, actual, alternative) {
252
252
 
253
253
  function malformedAlternative(query, alternative) {
254
254
  const queryNames = new Set(namedVariables(query).map((variable) => variable.name));
255
- for (const leaf of splitOperator(alternative, ';').map(describeLeaf)) {
255
+ const altLeaves = splitOperator(alternative, ';').map(describeLeaf);
256
+ // `sto` is written once, on the branch's first outcome, to declare the
257
+ // whole `;`-separated branch occurs-check/rational-tree dependent (see the
258
+ // matching `leaves.some((leaf) => leaf.sto)` in checkAlternative); a later
259
+ // leaf in the same branch carries that declaration too even though only
260
+ // the first leaf's text says so.
261
+ const branchSto = altLeaves.some((leaf) => leaf.sto);
262
+ for (const leaf of altLeaves) {
256
263
  if (leaf.malformed != null) return leaf.malformed;
257
264
  const names = new Set();
258
265
  const substitutions = [...leaf.bindings, ...leaf.approximations];
266
+ // A binding's left-hand variable may be a query variable, or an auxiliary
267
+ // variable this same answer description already introduced on an earlier
268
+ // binding's right-hand side. `Xs = [_A|_B], _B = [E|_B]` names the "rest
269
+ // of the same infinite structure" as _B before binding it -- the usual
270
+ // idiom for describing a rational-tree or repeating-pattern answer
271
+ // (see also substitutionMatches, which resolves these the same way).
272
+ const introduced = new Set(queryNames);
259
273
  for (const binding of substitutions) {
260
274
  const name = binding.args[0].name;
261
- if (!queryNames.has(name) || names.has(name)) return binding;
275
+ if (!introduced.has(name) || names.has(name)) return binding;
262
276
  names.add(name);
277
+ for (const variable of namedVariables(binding.args[1])) introduced.add(variable.name);
263
278
  }
264
279
  for (const binding of substitutions) {
265
280
  const name = binding.args[0].name;
@@ -276,7 +291,7 @@ function malformedAlternative(query, alternative) {
276
291
  // outside `sto`: an answer description should give each variable's
277
292
  // value in fully resolved form rather than in terms of a sibling
278
293
  // binding.
279
- if (!leaf.sto && referenced.some((variable) => names.has(variable.name))) return binding;
294
+ if (!branchSto && referenced.some((variable) => names.has(variable.name))) return binding;
280
295
  }
281
296
  }
282
297
  return null;
@@ -522,22 +537,33 @@ function substitutionMatches(query, bindings, approximations, actualEnv) {
522
537
  const queryVariablesByName = new Map(queryVariables.map((variable) => [variable.name, variable]));
523
538
  const expectedEnv = new Env();
524
539
  const rebound = new Set();
540
+ // A binding's left-hand variable may be a query variable, or an auxiliary
541
+ // variable this same answer description already introduced on an earlier
542
+ // binding's right-hand side (see malformedAlternative's matching
543
+ // `introduced` set): `Xs = [_A|_B], _B = [E|_B]` names the "rest of the
544
+ // same infinite structure" as _B before binding it, the usual idiom for
545
+ // describing a rational-tree or repeating-pattern answer.
546
+ const introduced = new Set(queryNames);
525
547
  for (const binding of [...bindings, ...approximations]) {
526
548
  const variable = binding.args[0];
527
- if (!queryNames.has(variable.name) || rebound.has(variable.name)) return false;
549
+ if (!introduced.has(variable.name) || rebound.has(variable.name)) return false;
528
550
  rebound.add(variable.name);
529
551
  if (binding.name === '=') {
530
552
  if (!unify(variable, binding.args[1], expectedEnv)) return false;
531
- continue;
553
+ } else {
554
+ // Approximate (~~) bindings compare against an actually observed value,
555
+ // which only exists for the query's own variables.
556
+ const actualVariable = queryVariablesByName.get(variable.name);
557
+ if (actualVariable == null) return false;
558
+ const actualValue = deref(actualVariable, actualEnv);
559
+ if (!approximatelyMatches(actualValue, binding.args[1])) return false;
560
+ // Once the approximate predicate has accepted the actual float, bind the
561
+ // expected-side variable to that exact observed term. This lets the
562
+ // ordinary variant matcher continue to check the rest of the answer,
563
+ // including variable sharing, without turning `~~` into a fuzzy unifier.
564
+ if (!unify(variable, copyResolved(actualValue, actualEnv), expectedEnv)) return false;
532
565
  }
533
- const actualVariable = queryVariablesByName.get(variable.name);
534
- const actualValue = deref(actualVariable, actualEnv);
535
- if (!approximatelyMatches(actualValue, binding.args[1])) return false;
536
- // Once the approximate predicate has accepted the actual float, bind the
537
- // expected-side variable to that exact observed term. This lets the
538
- // ordinary variant matcher continue to check the rest of the answer,
539
- // including variable sharing, without turning `~~` into a fuzzy unifier.
540
- if (!unify(variable, copyResolved(actualValue, actualEnv), expectedEnv)) return false;
566
+ for (const referenced of namedVariables(binding.args[1])) introduced.add(referenced.name);
541
567
  }
542
568
  const expected = compound('$quad_answer', queryVariables.map((variable) => copyResolved(variable, expectedEnv)));
543
569
  const actual = compound('$quad_answer', queryVariables.map((variable) => copyResolved(variable, actualEnv)));
package/test/README.md CHANGED
@@ -1,7 +1,8 @@
1
1
  # Test runners
2
2
 
3
- Normally, run `npm test`. Use `npm test -- --offline` to skip live upstream fetching.
4
- `npm run conformance:update:wg17` refreshes the vendored WG17 snapshot.
3
+ Normally, run `npm test`. Use `npm test -- --offline` to skip live upstream fetching
4
+ (this also skips the WG17 syntax check, which is discovered live and has no
5
+ offline snapshot).
5
6
 
6
7
  For development, run a focused check directly from the repository root:
7
8
 
@@ -9,7 +10,6 @@ For development, run a focused check directly from the repository root:
9
10
  node test/run-regression.mjs # all regression sections
10
11
  node test/run-regression.mjs docs # documentation checks only
11
12
  node test/run-conformance-all.mjs # conformance layers; accepts --offline
12
- node test/run-wg17.mjs # vendored WG17 syntax
13
13
  node test/run-iso-strict.mjs # strict ISO core
14
14
  node test/run-iso-part2-amendment.mjs
15
15
  node test/run-neumerkel.mjs # live upstream; --cached reproduces last fetch
@@ -23,7 +23,7 @@ relevant implementation-dependent overlap choice to an explicit review outcome.
23
23
 
24
24
  | Requirement | Status | EyeProlog evidence / remaining work |
25
25
  | --- | --- | --- |
26
- | 5.1(a) prepare conforming Prolog text | covered | Clause 6 token/term production and rejection families are mapped by the strict production gate and the complete 379-case vendored WG17 syntax matrix; 7.4 preparation/directive behavior is separately closed. |
26
+ | 5.1(a) prepare conforming Prolog text | covered | Clause 6 token/term production and rejection families are mapped by the strict production gate and the complete WG17 syntax matrix, discovered dynamically and executed live as part of the Neumerkel conformity gate; 7.4 preparation/directive behavior is separately closed. |
27
27
  | 5.1(b) execute conforming Prolog goals | covered | Clause 7 term/control/execution semantics, the higher-level 7.10 stream model, 7.11 flags, the 7.12 error envelope, all 8.2-8.17 built-in rows, and Clause 9 arithmetic have explicit executable dispositions. |
28
28
  | 5.1(c) reject nonconforming text/read-terms | covered | WG17 negative syntax cases, focused malformed-production/escape/comment/operator cases, read-term syntax errors, and strict rejection of implementation-specific syntax provide explicit rejection evidence across the Clause 6 families. |
29
29
  | 5.1(d) document permitted variations | covered | The clause-by-clause [ISO 5.4 decision index](ISO-IMPLEMENTATION-DEFINED.md) records every explicit implementation-defined decision found in the Part 1 + Corrigenda baseline and separately inventories implementation-specific extension families. The index retains an `gap` category for future discoveries; no current release-facing row depends on one. |
@@ -35,7 +35,7 @@ relevant implementation-dependent overlap choice to an explicit review outcome.
35
35
 
36
36
  | Standard area | Status | Current evidence |
37
37
  | --- | --- | --- |
38
- | Clause 6 — tokens, terms, lists, operators, quoted text | covered | The strict Clause 6 gate maps atomic/variable/compound/operator/list/curly/double-quoted term forms, layout/comments, quoted escapes, integer bases/character codes, floating tokens, and solo/meta token boundaries, with malformed counterparts rejected. The complete 379-case WG17 syntax matrix provides externally sourced production-level expectations, and a cross-profile gate verifies that normal syntax extensions preserve every strict-accepted standard observation. The implementation-defined 6.5/6.6 PCS/collation choices are documented separately. |
38
+ | Clause 6 — tokens, terms, lists, operators, quoted text | covered | The strict Clause 6 gate maps atomic/variable/compound/operator/list/curly/double-quoted term forms, layout/comments, quoted escapes, integer bases/character codes, floating tokens, and solo/meta token boundaries, with malformed counterparts rejected. The complete WG17 syntax matrix, discovered dynamically at run time, provides externally sourced production-level expectations, and a cross-profile gate verifies that normal syntax extensions preserve every strict-accepted standard observation. The implementation-defined 6.5/6.6 PCS/collation choices are documented separately. |
39
39
  | 7.1-7.3 — term types, term order, unification | covered | [ISO-TERM-SEMANTICS-MATRIX.md](ISO-TERM-SEMANTICS-MATRIX.md) records the five mutually exclusive strict term types, derived variable/compound/list notions, the complete standard-order classes and implementation-dependent variable-order choice, NSTO MGU/failure behavior, and EyeProlog's permitted consistent occurs-check failure for Part 1's undefined STO ordinary-unification cases. The normal JavaScript API string term is documented as a 5.5.4 extension and rejected at strict program/goal entry. |
40
40
  | 7.4 — Prolog text and directives | covered | [ISO-PROLOG-TEXT-EXECUTION-MATRIX.md](ISO-PROLOG-TEXT-EXECUTION-MATRIX.md) closes the preparation/directive rows: declaration semantics, source clauses, cross-text operators/character conversion/flags, initialization order/lifetime, `include/1`, and one-time `ensure_loaded/1`, with implementation-defined cross-text choices indexed under 5.4. |
41
41
  | 7.5-7.6 — database and term/clause conversion | covered | [ISO-PROLOG-TEXT-EXECUTION-MATRIX.md](ISO-PROLOG-TEXT-EXECUTION-MATRIX.md) closes static/dynamic and private/public procedure semantics, clause order, logical-update visibility, empty/unknown lifetime, and term/body/clause conversion. Source and runtime assertion conversion recurse through `,/2`, `;/2`, and `->/2`, preserve variable identity, and protect standardized static/control procedures. |
@@ -278,10 +278,11 @@ A release intended to advance ISO conformance uses one canonical command:
278
278
  npm test
279
279
  ```
280
280
 
281
- That command first fetches and runs the **latest seven Neumerkel conformity
282
- sources**, then executes the deterministic local conformance, strict ISO,
283
- vendored WG17 regression, regression/API, examples, documentation and
284
- architecture gates. The upstream case counts are discovered dynamically.
281
+ That command first fetches and runs the **latest eight Neumerkel conformity
282
+ sources** (WG17 syntax among them, discovered live, not vendored), then
283
+ executes the deterministic local conformance, strict ISO,
284
+ regression/API, examples, documentation and architecture gates. The upstream
285
+ case counts are discovered dynamically.
285
286
 
286
287
  Useful focused commands are:
287
288
 
@@ -289,7 +290,6 @@ Useful focused commands are:
289
290
  node test/run-conformance-all.mjs
290
291
  node test/run-neumerkel.mjs
291
292
  node test/run-iso-strict.mjs
292
- node test/run-wg17.mjs
293
293
  npm test -- --offline
294
294
  ```
295
295
 
@@ -307,7 +307,7 @@ post-N289 STC drafts remain review input until standardized.
307
307
  | Criterion | Status | Evidence |
308
308
  | --- | --- | --- |
309
309
  | Clause 5 processor obligations have explicit dispositions | covered | `ISO-PROCESSOR-REQUIREMENTS.md` gives explicit outcomes for 5.1-5.5, including the strict/normal extension boundary. |
310
- | Clause 6 lexical/syntactic requirements have explicit dispositions | covered | the strict Clause 6 production/rejection gate and the 379-case vendored WG17 matrix cover the standard families; cross-profile preservation verifies that normal extensions do not reinterpret strict-accepted text. |
310
+ | Clause 6 lexical/syntactic requirements have explicit dispositions | covered | the strict Clause 6 production/rejection gate and the live-discovered WG17 matrix cover the standard families; cross-profile preservation verifies that normal extensions do not reinterpret strict-accepted text. |
311
311
  | Clause 7 semantic requirements have explicit dispositions | covered | 7.1-7.12 now have explicit semantic, implementation-defined, or error-envelope dispositions backed by strict tests and the specialized matrices. |
312
312
  | Clause 8 built-in modes/errors have explicit dispositions | covered | `ISO-BUILTIN-MODE-ERROR-MATRIX.md` accounts for 8.2-8.17 condition by condition, using grouped rows only where every grouped condition and its evidence are named |
313
313
  | 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 |
@@ -315,7 +315,7 @@ post-N289 STC drafts remain review input until standardized.
315
315
  | Implementation-specific strict/normal boundary is documented and tested | covered | all 5.5 hooks have explicit dispositions; the WG17 cross-profile gate verifies syntax-preservation for standard text accepted by the strict reader. |
316
316
  | Published Corrigenda 1-3 are incorporated | covered | `ISO-CORRIGENDA-MATRIX.md` inventories every published amendment cluster with executable, editorial, or superseded disposition |
317
317
  | 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 |
318
- | Latest Neumerkel conformity is a live release gate | covered | `npm test` fetches and executes the eight current TU Wien conformity sources with dynamic inventories; the vendored WG17 matrix remains an offline reviewed-outcome regression layer |
318
+ | Latest Neumerkel conformity is a live release gate | covered | `npm test` fetches and executes the eight current TU Wien conformity sources with dynamic inventories, including WG17 syntax; a small offline corpus of reviewed cases (`test/conformance/wg17-syntax-cases.json`) supplies an additional exact-outcome regression lock, cross-referenced by id against the live-discovered cases |
319
319
  | 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` |
320
320
  | No unexplained deviation remains in the release-facing ledger | covered | the release-facing ledger contains no remaining `review` rows; documented variation points are implementation-defined/specific or draft-only rather than unexplained deviations. |
321
321
 
@@ -1,6 +1,6 @@
1
1
  # EyeProlog — latest Neumerkel conformity
2
2
 
3
- Status: **PASS — 1 divergence to be addressed** — **718/719** discovered upstream cases passed.
3
+ Status: **PASS** — **758/758** discovered upstream cases passed.
4
4
 
5
5
  This tracked report records the latest upstream inventory successfully checked by EyeProlog.
6
6
  `npm test` fetches the eight TU Wien sources again and executes the discovered cases.
@@ -15,13 +15,9 @@ Counts are output from upstream, not hard-coded test constants.
15
15
  | dif/2 | 26 | 26 |
16
16
  | length/2 | 37 | 37 |
17
17
  | phrase/2,3 | 58 | 58 |
18
- | Prologue draft | 32 | 33 |
18
+ | Prologue draft | 72 | 72 |
19
19
  | setup_call_cleanup/3 | 25 | 25 |
20
- | **Total** | **718** | **719** |
21
-
22
- ## Known divergences
23
-
24
- - **Prologue draft** (line 118): bounded=false: EyeProlog reports no max_integer value at all (ISO 7.11.1.1), so this quad's evaluation_error(int_overflow) | Max = unbounded pair never applies
20
+ | **Total** | **758** | **758** |
25
21
 
26
22
  ## Upstream sources
27
23
 
@@ -22,8 +22,10 @@ implements of Part 2 (modules) and Part 3 (definite clause grammar rules),
22
22
  including the 2013 module-amendment evidence and the known gaps and deviations.
23
23
  Neither part carries a conformance claim. Built-in rows may group closely related conditions only when the
24
24
  row names every grouped condition and its executable evidence.
25
- The exit checklist is embedded in [ISO-COMPLIANCE.md](ISO-COMPLIANCE.md). [WG17-SYNTAX-STATUS.md](WG17-SYNTAX-STATUS.md) records the
26
- complete one-to-one trace for the vendored active upstream WG17 syntax cases.
25
+ The exit checklist is embedded in [ISO-COMPLIANCE.md](ISO-COMPLIANCE.md). WG17
26
+ syntax cases are discovered live and executed as part of the Neumerkel
27
+ conformity gate (see [NEUMERKEL-LIVE.md](NEUMERKEL-LIVE.md)); there is no
28
+ separate offline coverage ledger to keep in sync.
27
29
  [STC-DRAFT-STATUS.md](STC-DRAFT-STATUS.md) separately tracks executable
28
30
  implementation questions from the post-N289 working draft (reviewed through the 2026-08-23 items #73-#76); those cases are
29
31
  review evidence, not normative ISO claims.
@@ -96,24 +98,19 @@ node test/run-neumerkel.mjs --cached # exact last fetched bytes; reproductio
96
98
  node test/run-neumerkel.mjs --cached --verify-report # verify tracked report against last successful live snapshot
97
99
  node test/run-iso-strict.mjs # Part 1 + Corrigenda strict-core processor gate
98
100
  node test/run-iso-part2-amendment.mjs # 2013 Part 2 amendment module requirements
99
- node test/run-wg17.mjs # vendored reviewed WG17 syntax regression
100
101
  ```
101
102
 
102
103
  `node test/run-neumerkel.mjs` always fetches the current TU Wien sources. It does not skip a
103
104
  fetch because a cache exists. The runner discovers the number of active tests from those sources and fails on any newly introduced case EyeProlog does not pass. If the stable, tracked [NEUMERKEL-LATEST.md](NEUMERKEL-LATEST.md) is stale, normal tests warn rather than turning a passing engine run into a failure. `node test/run-neumerkel.mjs --update-report` performs a fresh live run and refreshes the report; after `npm test`, `node test/run-neumerkel.mjs --cached --update-report` refreshes it from the exact successful cached snapshot; and `node test/run-neumerkel.mjs --cached --verify-report` verifies that snapshot without a second network fetch. Exact bytes, SHA-256 hashes, timestamps, and HTTP validators stay under Git-ignored `.cache/neumerkel/` for inspection/reproduction only. See [NEUMERKEL-LIVE.md](NEUMERKEL-LIVE.md).
104
105
 
105
- The vendored WG17 syntax snapshot is intentionally secondary. Update it with `npm run conformance:update:wg17`. For focused upstream report maintenance and verification:
106
-
107
- ```sh
108
- npm run conformance:update:wg17
109
- node test/run-neumerkel.mjs --update-report
110
- node test/run-neumerkel.mjs --cached --update-report
111
- node test/run-wg17.mjs
112
- ```
113
-
114
- Every vendored syntax case is still checked against its upstream Codex
115
- expectation; reviewed exact outcomes are an additional regression lock rather
116
- than an alternative acceptance rule.
106
+ WG17 syntax cases are discovered live, the same way the other seven TU Wien
107
+ sources are: there is no separate vendored snapshot or update step. A small
108
+ offline corpus, `test/conformance/wg17-syntax-cases.json`, additionally pins
109
+ the exact reviewed EyeProlog outcome for most cases, cross-referenced by id
110
+ against the live-discovered cases in `test/neumerkel.mjs`. Every case, live or
111
+ reviewed, is still checked against its upstream Codex expectation
112
+ (`matchesUpstreamExpectation` in `test/run-wg17.mjs`); a reviewed exact outcome
113
+ is an additional regression lock, never an alternative acceptance rule.
117
114
 
118
115
  Regenerate the top-level local-corpus report with `node test/run-conformance-report.mjs conformance-report.md`. It links to [NEUMERKEL-LATEST.md](NEUMERKEL-LATEST.md) rather than duplicating live evidence. Counts in the tracked Neumerkel report are generated evidence, not permanent constants in project policy.
119
116
 
@@ -141,7 +138,7 @@ Selected cases are adapted from the ISO and standard-core suites of Logtalk,
141
138
  Scryer Prolog, Trealla Prolog, and SWI-Prolog. Their upstream identifiers and licenses
142
139
  are recorded in [THIRD_PARTY.md](THIRD_PARTY.md).
143
140
 
144
- The corpus has 393 cases in `iso/` and 810 file-based conformance cases in total. Of those, 11 cases in `stc/` are explicitly labelled working-draft review evidence rather than normative ISO claims. The separate vendored strict-reader WG17 matrix is a deterministic regression snapshot; the live Neumerkel gate discovers the current upstream inventory at run time; release/report checks separately verify the tracked `NEUMERKEL-LATEST.md`. The generated `conformance-report.md` records local corpus totals and links to that live evidence. Together with regression, documentation-sync, API, example, and book-example checks, `npm test` is the release gate.
141
+ The corpus has 430 cases in `iso/` and 847 file-based conformance cases in total. Of those, 11 cases in `stc/` are explicitly labelled working-draft review evidence rather than normative ISO claims. The strict-reader WG17 syntax matrix is discovered dynamically and executed live by the Neumerkel gate, the same as its other seven TU Wien sources; release/report checks separately verify the tracked `NEUMERKEL-LATEST.md`. The generated `conformance-report.md` records local corpus totals and links to that live evidence. Together with regression, documentation-sync, API, example, and book-example checks, `npm test` is the release gate.
145
142
 
146
143
  ## Updating expected output
147
144
 
@@ -70,6 +70,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
70
70
 
71
71
  Selected standard-core cases under `iso/` are adapted from the numbered tests
72
72
  in [`tests/tests`](https://github.com/trealla-prolog/trealla/tree/main/tests/tests)
73
+ and [`tests/issues`](https://github.com/trealla-prolog/trealla/tree/main/tests/issues)
73
74
  in Trealla Prolog. Each adapted file identifies its upstream test file. The
74
75
  cases were rewritten for EyeProlog's query and exact-output harness.
75
76
 
@@ -0,0 +1,8 @@
1
+ % Adapted from Scryer Prolog tests-pl/iso-conformity-tests.pl, test
2
+ % 41. See test/conformance/THIRD_PARTY.md.
3
+
4
+ %% goal: backslash_atom(A)
5
+
6
+ backslash_atom(A) :-
7
+ A = ('\\'),
8
+ A = (\).
@@ -0,0 +1,10 @@
1
+ % Adapted from Scryer Prolog tests-pl/iso-conformity-tests.pl, test
2
+ % 49. See test/conformance/THIRD_PARTY.md.
3
+
4
+ :- op(9, xf, e9).
5
+
6
+ %% goal: bare_exponent_lexing(X)
7
+
8
+ bare_exponent_lexing(X) :-
9
+ X = (1e9),
10
+ X = e9(1).
@@ -0,0 +1,12 @@
1
+ % Adapted from Scryer Prolog tests-pl/iso-conformity-tests.pl, tests
2
+ % 291, 307, and 309. See test/conformance/THIRD_PARTY.md.
3
+
4
+ %% goal: bracket_and_curly_term_parsing(A, B, C)
5
+
6
+ bracket_and_curly_term_parsing(A, B, C) :-
7
+ A = [(a,b)],
8
+ A = [','(a,b)],
9
+ B = [/**/],
10
+ B == [],
11
+ C = {a,b},
12
+ C = '{}'(','(a,b)).
@@ -0,0 +1,8 @@
1
+ % Adapted from Scryer Prolog tests-pl/iso-conformity-tests.pl, tests
2
+ % 79-80. See test/conformance/THIRD_PARTY.md.
3
+
4
+ %% goal: default_prefix_operator_priorities(A, B)
5
+
6
+ default_prefix_operator_priorities(A, B) :-
7
+ current_op(A, fy, -),
8
+ current_op(B, fy, +).
@@ -0,0 +1,10 @@
1
+ % Adapted from Scryer Prolog tests-pl/iso-conformity-tests.pl, tests
2
+ % 198-199. See test/conformance/THIRD_PARTY.md.
3
+
4
+ %% goal: dollar_sign_atoms(A, B)
5
+
6
+ dollar_sign_atoms(A, B) :-
7
+ atom($-),
8
+ atom(-$),
9
+ A = ($-),
10
+ B = (-$).
@@ -0,0 +1,7 @@
1
+ % Adapted from Scryer Prolog tests-pl/iso-conformity-tests.pl, test
2
+ % 97. See test/conformance/THIRD_PARTY.md.
3
+
4
+ %% goal: empty_list_atom_functor(X)
5
+
6
+ empty_list_atom_functor(X) :-
7
+ '[]'(1) = [ ](X).
@@ -0,0 +1,12 @@
1
+ % Adapted from Scryer Prolog tests-pl/iso-conformity-tests.pl, tests
2
+ % 50-51, 204, and 220. See test/conformance/THIRD_PARTY.md.
3
+
4
+ :- op(9, xf, e).
5
+
6
+ %% goal: exponent_minus_lexing(X, Y)
7
+
8
+ exponent_minus_lexing(X, Y) :-
9
+ X = (1e-9),
10
+ X = -(e(1), 9),
11
+ Y = (1.0e- 9),
12
+ Y = -(e(1.0), 9).
@@ -0,0 +1,11 @@
1
+ % Adapted from Scryer Prolog tests-pl/iso-conformity-tests.pl, test
2
+ % 53. See test/conformance/THIRD_PARTY.md.
3
+
4
+ %% goal: large_float_exponent(X)
5
+
6
+ large_float_exponent(X) :-
7
+ X = 1.0e100,
8
+ float(X),
9
+ X > 1.0e99,
10
+ Y is X / 10.0,
11
+ Y =:= 1.0e99.
@@ -0,0 +1,15 @@
1
+ % Adapted from Scryer Prolog tests-pl/iso-conformity-tests.pl, tests
2
+ % 7-10. See test/conformance/THIRD_PARTY.md.
3
+
4
+ %% goal: line_continuation_in_quoted_atoms(A, B, C)
5
+
6
+ line_continuation_in_quoted_atoms(A, B, C) :-
7
+ A = '\
8
+ ',
9
+ A == '',
10
+ B = '\
11
+ a',
12
+ B == a,
13
+ C = 'a\
14
+ b',
15
+ C == 'a b'.
@@ -0,0 +1,11 @@
1
+ % Adapted from Scryer Prolog tests-pl/iso-conformity-tests.pl, test
2
+ % 164. See test/conformance/THIRD_PARTY.md.
3
+
4
+ :- op(7, fy, p).
5
+ :- op(9, yfx, p).
6
+
7
+ %% goal: lower_priority_prefix_with_infix(T)
8
+
9
+ lower_priority_prefix_with_infix(T) :-
10
+ T = (1 p p p 2),
11
+ T = p(1, p(p(2))).
@@ -0,0 +1,11 @@
1
+ % Adapted from Scryer Prolog tests-pl/iso-conformity-tests.pl, test
2
+ % 163. See test/conformance/THIRD_PARTY.md.
3
+
4
+ :- op(9, fy, p).
5
+ :- op(9, xfy, p).
6
+
7
+ %% goal: mixed_prefix_infix_priority(T)
8
+
9
+ mixed_prefix_infix_priority(T) :-
10
+ T = (1 p p p 2),
11
+ T = p(1, p(p(2))).
@@ -0,0 +1,29 @@
1
+ % Adapted from Scryer Prolog tests-pl/iso-conformity-tests.pl, tests
2
+ % 70-72, 99, 158, 237, and 268. See test/conformance/THIRD_PARTY.md.
3
+
4
+ %% goal: comma_operator_immutable(E1, E2, E3)
5
+
6
+ comma_operator_immutable(E1, E2, E3) :-
7
+ catch((op(1000,xfy,','), fail), error(E1, _), true),
8
+ catch((op(1001,xfy,','), fail), error(E2, _), true),
9
+ catch((op(0,xfy,','), fail), error(E3, _), true).
10
+
11
+ %% goal: bar_low_priority_rejected(E)
12
+
13
+ bar_low_priority_rejected(E) :-
14
+ catch((op(999,xfy,'|'), fail), error(E, _), true).
15
+
16
+ %% goal: invalid_operator_specifier(E)
17
+
18
+ invalid_operator_specifier(E) :-
19
+ catch((op(100,yfy,foo), fail), error(E, _), true).
20
+
21
+ %% goal: curly_braces_operator_rejected(E)
22
+
23
+ curly_braces_operator_rejected(E) :-
24
+ catch((op(500,xfy,'{}'), fail), error(E, _), true).
25
+
26
+ %% goal: infix_postfix_clash_rejected(E)
27
+
28
+ infix_postfix_clash_rejected(E) :-
29
+ catch((op(699,xf,>), fail), error(E, _), true).
@@ -0,0 +1,10 @@
1
+ % Adapted from Scryer Prolog tests-pl/iso-conformity-tests.pl, tests
2
+ % 234-235. See test/conformance/THIRD_PARTY.md.
3
+
4
+ :- op(400, fx, f).
5
+
6
+ %% goal: space_before_paren_is_operator_application(T)
7
+
8
+ space_before_paren_is_operator_application(T) :-
9
+ T = (f (1,2)),
10
+ T = f(','(1,2)).
@@ -0,0 +1,10 @@
1
+ % Adapted from Scryer Prolog tests-pl/iso-conformity-tests.pl, test
2
+ % 55. See test/conformance/THIRD_PARTY.md.
3
+
4
+ :- op(1, yf, yf1).
5
+
6
+ %% goal: postfix_operator_negative_number(T)
7
+
8
+ postfix_operator_negative_number(T) :-
9
+ T = {-1 yf1},
10
+ T = {yf1(-1)}.
@@ -0,0 +1,8 @@
1
+ % Adapted from Scryer Prolog tests-pl/iso-conformity-tests.pl, test
2
+ % 236. See test/conformance/THIRD_PARTY.md.
3
+
4
+ %% goal: prefix_minus_chain(X)
5
+
6
+ prefix_minus_chain(X) :-
7
+ X = (a- - -b),
8
+ X = -(a, -(-(b))).
@@ -0,0 +1,16 @@
1
+ % Adapted from Scryer Prolog tests-pl/iso-conformity-tests.pl, tests
2
+ % 100, 103, 114-116, and 165. See test/conformance/THIRD_PARTY.md.
3
+
4
+ %% goal: quote_and_char_code_literals(A, B, C, D)
5
+
6
+ quote_and_char_code_literals(A, B, C, D) :-
7
+ '''' = '\'',
8
+ A = '\141\141',
9
+ A == a141,
10
+ B = 0'\',
11
+ integer(B),
12
+ C = 0''',
13
+ integer(C),
14
+ C == B,
15
+ D = '.''-''.',
16
+ atom(D).
@@ -0,0 +1,10 @@
1
+ % Adapted from Scryer Prolog tests-pl/iso-conformity-tests.pl, tests
2
+ % 308 and 324. See test/conformance/THIRD_PARTY.md.
3
+
4
+ %% goal: special_atom_names(A, B)
5
+
6
+ special_atom_names(A, B) :-
7
+ A = '.+',
8
+ atom(A),
9
+ B = '%',
10
+ atom(B).
@@ -0,0 +1,9 @@
1
+ % Adapted from Scryer Prolog tests-pl/iso-conformity-tests.pl, tests
2
+ % 172-173. See test/conformance/THIRD_PARTY.md.
3
+
4
+ %% goal: subnormal_float_underflow(X)
5
+
6
+ subnormal_float_underflow(X) :-
7
+ X is 10.0** -323,
8
+ X > 0.0,
9
+ X =:= 1.0e-323.
@@ -0,0 +1,12 @@
1
+ % Adapted from Scryer Prolog tests-pl/iso-conformity-tests.pl, tests
2
+ % 65-66 and 318. See test/conformance/THIRD_PARTY.md.
3
+
4
+ %% goal: unary_plus_compound(A, B)
5
+
6
+ unary_plus_compound(A, B) :-
7
+ compound(+1),
8
+ compound(+ 1),
9
+ A = (+1),
10
+ A = +(1),
11
+ B = (+ (1*2)^3),
12
+ B = +((1*2)^3).
@@ -0,0 +1,14 @@
1
+ % Adapted from Scryer Prolog tests-pl/iso-conformity-tests.pl, tests
2
+ % 215, 248, and 249. See test/conformance/THIRD_PARTY.md.
3
+
4
+ :- op(100, yfx, ~).
5
+
6
+ %% goal: user_operator_with_prefix_minus(A, B, C)
7
+
8
+ user_operator_with_prefix_minus(A, B, C) :-
9
+ A = (- (1~2~3)),
10
+ A = -(~(~(1,2),3)),
11
+ B = (- (1~2)),
12
+ B = -(~(1,2)),
13
+ C = (1~2),
14
+ C = ~(1,2).
@@ -0,0 +1,11 @@
1
+ % Adapted from Trealla Prolog tests/tests/test0046.pl.
2
+ % See test/conformance/THIRD_PARTY.md.
3
+ %% goal: append_concat(X0)
4
+
5
+ append_concat(L) :-
6
+ append([a,b],[c,d],L).
7
+
8
+ %% goal: append_split(X0, X1)
9
+
10
+ append_split(L1, L2) :-
11
+ append(L1, L2, [a,b,c,d]).