eyeprolog 1.5.48 → 1.5.49

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.
@@ -53,6 +53,11 @@ EyeProlog checks the input and remainder of `phrase/2-3` and reports
53
53
  `type_error(list, S)` when an argument is neither a list nor a partial list.
54
54
  These implementation-defined checks follow ISO/IEC TS 13211-3:2025,
55
55
  8.18.1.3 g and h; this behavior is not a known deviation.
56
+ The checks are optional. EyeProlog elects to perform both consistently.
57
+ Dedicated regressions require the exact error for atomic non-lists and
58
+ improper lists across both arities and both sequence positions, while
59
+ accepting variables, proper lists, and partial lists. The upstream quads
60
+ allow checking and non-checking outcomes and do not prove this policy.
56
61
 
57
62
  The Part 3 implementation target is
58
63
  [ISO/IEC TS 13211-3:2025](https://www.iso.org/standard/83635.html).
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.5.48",
6
+ "version": "1.5.49",
7
7
  "description": "EyeProlog turns facts and rules into answers and proofs.",
8
8
  "type": "module",
9
9
  "main": "./index.js",
package/src/iso.js CHANGED
@@ -3024,7 +3024,9 @@ function* phraseSolutions({ solver, goal, env }, state) {
3024
3024
  validateDcgEmbeddedGoals(grammarBody, input, requestedOutput);
3025
3025
  // ISO/IEC TS 13211-3:2025, 8.18.1.3 g and h permit these checks
3026
3026
  // and specify type_error(list, S) for invalid terminal-sequence arguments.
3027
- // Keep both diagnostics and the unmodified upstream phrase quad gate.
3027
+ // EyeProlog elects to perform both optional checks consistently, including
3028
+ // improper lists. The upstream quads allow non-checking outcomes too; the
3029
+ // dedicated regression matrix requires our exact diagnostics.
3028
3030
  // See conformance-report.md and issue #94.
3029
3031
  if (!isListOrPartialList(input, env)) {
3030
3032
  throw new PrologError('type_error(list)', deref(input, env));
@@ -37,12 +37,23 @@ implementation-dependent negation/if-then choices documented in the reference.
37
37
  `--iso-strict` leaves `-->/2` as ordinary Part 1 operator syntax and excludes
38
38
  Part 3 grammar expansion and `phrase/2-3` from the strict registry.
39
39
 
40
- One compatibility difference is explicit: EyeProlog currently reports
41
- `type_error(list)` when its `phrase/2-3` terminal-sequence validation rejects a
42
- non-list. The Part 3 terminal-sequence specification uses its own terminal
43
- sequence error category. EyeProlog retains the list-shaped error for its normal
44
- interoperability profile, so this behavior must not be presented as evidence of
45
- complete Part 3 conformance.
40
+ EyeProlog elects to perform both implementation-defined terminal-sequence
41
+ checks in ISO/IEC TS 13211-3:2025, 8.18.1.3 g and h. The checks are optional;
42
+ when performed, their specified error type is `list`. EyeProlog consistently
43
+ raises `type_error(list, Culprit)` for a non-list input to `phrase/2` or
44
+ `phrase/3`, and for a non-list remainder to `phrase/3`. The culprit is the
45
+ whole invalid argument, including an improper list, not just its tail.
46
+ Variables, proper lists, and partial lists are accepted by these checks.
47
+ For otherwise valid grammar bodies, validation precedes execution, even when
48
+ the grammar would fail or produce a side effect.
49
+
50
+ The upstream phrase quads permit both checking and non-checking outcomes and
51
+ therefore do not establish this consistency. A dedicated regression matrix in
52
+ `test/run-regression.mjs` requires the exact diagnostic across both arities,
53
+ both sequence positions, atomic and compound non-lists, improper lists at
54
+ several depths, and several grammar bodies. Positive cases protect variables,
55
+ proper lists, and partial lists. These are policy checks, not a relaxation of
56
+ the unmodified upstream corpus.
46
57
 
47
58
  The Part 3 implementation otherwise keeps sequence validation, grammar-body
48
59
  callability, variable-body instantiation errors, `phrase/3` steadfastness, and
@@ -143,6 +143,11 @@ function dcgConformanceSection() {
143
143
  '`type_error(list, S)` when an argument is neither a list nor a partial list.',
144
144
  'These implementation-defined checks follow ISO/IEC TS 13211-3:2025,',
145
145
  '8.18.1.3 g and h; this behavior is not a known deviation.',
146
+ 'The checks are optional. EyeProlog elects to perform both consistently.',
147
+ 'Dedicated regressions require the exact error for atomic non-lists and',
148
+ 'improper lists across both arities and both sequence positions, while',
149
+ 'accepting variables, proper lists, and partial lists. The upstream quads',
150
+ 'allow checking and non-checking outcomes and do not prove this policy.',
146
151
  '',
147
152
  'The Part 3 implementation target is',
148
153
  '[ISO/IEC TS 13211-3:2025](https://www.iso.org/standard/83635.html).',
@@ -1230,6 +1230,44 @@ why(
1230
1230
  assertEqual(forbiddenFresh.failed, 1, 'fresh thrown variable is detected');
1231
1231
  },
1232
1232
  },
1233
+ {
1234
+ name: 'phrase terminal-sequence checks are consistent across arities and list shapes (issue #94)',
1235
+ run: () => {
1236
+ // The upstream quads allow both checking and non-checking processors.
1237
+ // Require EyeProlog's chosen diagnostic, not either portable outcome.
1238
+ const bodies = ['[]', '[a]', '{true}', '{fail}', '{write(reached)}', '!', 'p'];
1239
+ const invalid = ['non_list', '0', 'f(a)', '[a|non_list]', '[a,b|0]', '[a,b,c|f(t)]'];
1240
+ for (const body of bodies) {
1241
+ for (const bad of invalid) {
1242
+ for (const call of [`phrase(${body}, Bad)`, `phrase(${body}, Bad, [])`,
1243
+ `phrase(${body}, [], Bad)`]) {
1244
+ let output = '';
1245
+ runEyeProlog('p --> [a].', {
1246
+ ioOptions: { write: (text) => { output += text; } },
1247
+ goal: `Bad=${bad}, catch((${call}, write(missed)), error(type_error(list, Bad), _), write(ok))`,
1248
+ });
1249
+ assertEqual(output, 'ok', `${call} with ${bad}`);
1250
+ }
1251
+ }
1252
+ }
1253
+ for (const goal of [
1254
+ 'phrase([], [])',
1255
+ 'phrase([a], [a])',
1256
+ 'phrase([a], L), L == [a]',
1257
+ 'phrase([a], [a|T]), T == []',
1258
+ 'phrase([], S, S), var(S)',
1259
+ 'phrase([], [a|T], [a|T]), var(T)',
1260
+ 'phrase([], L, [a|T]), L == [a|T], var(T)',
1261
+ 'phrase([a], [a|T], T), var(T)',
1262
+ 'phrase([f(a),1], [f(a),1])',
1263
+ ]) {
1264
+ let output = '';
1265
+ runEyeProlog('', { goal: `(${goal}), write(ok)`,
1266
+ ioOptions: { write: (text) => { output += text; } } });
1267
+ assertEqual(output, 'ok', goal);
1268
+ }
1269
+ },
1270
+ },
1233
1271
  {
1234
1272
  name: 'runQuads matches the corrected ISO phrase quad boundaries',
1235
1273
  run: () => {
@@ -5870,10 +5870,14 @@ look_ahead(X), [X] --> [X].
5870
5870
  `phrase(+Body,?Sequence)` accepts or generates a complete sequence.
5871
5871
  `phrase(+Body,?Sequence,?Rest)` leaves `Rest` unconsumed and is steadfast in
5872
5872
  that argument. A variable body raises `instantiation_error`; a non-callable
5873
- body raises `type_error(callable)`. EyeProlog performs terminal-sequence checks and currently reports
5874
- `type_error(list)` for a rejected non-list. This is a normal-profile
5875
- interoperability choice, not a Part 3 conformance claim; Part 3 defines a
5876
- dedicated terminal-sequence error category. See
5873
+ body raises `type_error(callable)`. EyeProlog elects to perform the optional
5874
+ terminal-sequence checks of ISO/IEC TS 13211-3:2025, 8.18.1.3 g and h.
5875
+ It consistently reports `type_error(list, Culprit)` for invalid input in both
5876
+ arities and invalid remainder in `phrase/3`, including improper lists.
5877
+ Variables, proper lists, and partial lists pass these checks. Validation
5878
+ precedes grammar execution; an otherwise valid failing grammar does not
5879
+ suppress the diagnostic. Dedicated regressions enforce this policy separately
5880
+ from the portable quads, which accept both checking and non-checking outcomes. See
5877
5881
  [`ISO-PART2-PART3-SCOPE.md`](test/conformance/ISO-PART2-PART3-SCOPE.md).
5878
5882
 
5879
5883
  #### A bidirectional expression grammar