eyeprolog 1.2.12 → 1.2.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.2.12",
6
+ "version": "1.2.13",
7
7
  "description": "EyeProlog turns facts and rules into answers and proofs.",
8
8
  "type": "module",
9
9
  "main": "./index.js",
package/src/parser.js CHANGED
@@ -746,11 +746,11 @@ class Parser {
746
746
  const accept = emit ?? ((clause) => clauses.push(clause));
747
747
  while (this.token.type !== TOK.EOF) {
748
748
  const line = this.token.line;
749
- // In the normal EyeProlog profile, canonical functional ?-/1 and
750
- // ?-/2 notation denotes the same quad marker as the corresponding
751
- // operator notation. Keep the existing operator-form query parsing so
752
- // a query containing comma remains wholly to the right of `?-`, while
753
- // functional notation is parsed as a term and then decomposed by arity.
749
+ // Prefix operator notation needs one program-level distinction so
750
+ // a comma in `?- A, B.` remains inside the query rather than outside the
751
+ // prefix term. Ordinary functional notation is parsed as a term and then
752
+ // recognized structurally by parseQuadTerm; further equivalent spellings
753
+ // are recognized after the general head parser below.
754
754
  if (this.operatorTokenName() === '?-' && !this.strictIso) {
755
755
  if (this.peek() === '(') {
756
756
  const quadTerm = this.parseTerm(0, true);
@@ -818,6 +818,14 @@ class Parser {
818
818
  head = items.pop();
819
819
  while (items.length > 0) head = compound(',', [items.pop(), head]);
820
820
  }
821
+ // Parentheses and other ordinary term syntax may hide the surface ?-
822
+ // token from the program-level dispatch above. Once the complete head
823
+ // term has been parsed, recognize the same ?-/1 or ?-/2 structure here.
824
+ // Requiring the following dot prevents an ordinary rule whose head just
825
+ // happens to be ?-/1 or ?-/2 from being consumed as a quad mid-clause.
826
+ if (!this.strictIso && this.token.type === TOK.DOT && this.parseQuadTerm(head, line, accept)) {
827
+ continue;
828
+ }
821
829
  if (this.operatorTokenName() === '?-') {
822
830
  if (this.strictIso) {
823
831
  // There is no predefined infix ?-/2 in strict core mode. If a
@@ -222,7 +222,7 @@ why(
222
222
  },
223
223
  },
224
224
  {
225
- name: 'quad parser treats operator and functional ?- notation equivalently',
225
+ name: 'quad parser treats regular term spellings of ?- equivalently',
226
226
  run: () => {
227
227
  const labelled = Program.parse(
228
228
  `0,passes
@@ -253,9 +253,28 @@ why(
253
253
  const functionalReport = publicApi.runQuads(functional);
254
254
  assertEqual(functionalReport.stdout, 'quads: 1 run, 1 passed, 0 failed.\n', 'functional quad report');
255
255
 
256
- const strict = Program.parse(`?-(','(0,passes),=(X,1)).\n`, { isoStrict: true });
256
+ // Issue #11 is about ordinary term syntax, not one privileged
257
+ // canonical spelling. Parentheses, quoted functor syntax, and mixed
258
+ // operator/functional notation must all denote the same ?-/2 term and
259
+ // therefore the same quad in the normal EyeProlog profile.
260
+ for (const [name, source] of [
261
+ ['mixed', `?-((0,passes), X = 1).\n X = 1.\n`],
262
+ ['parenthesized', `(?-(','(0,passes),=(X,1))).\n X = 1.\n`],
263
+ ['parenthesized mixed', `(?-((0,passes), X = 1)).\n X = 1.\n`],
264
+ ['quoted functor', `'?-'(','(0,passes),=(X,1)).\n X = 1.\n`],
265
+ ['quoted parenthesized', `('?-'(','(0,passes),=(X,1))).\n X = 1.\n`],
266
+ ]) {
267
+ const regular = Program.parse(source);
268
+ assertEqual(regular.quads.length, 1, `${name} quad count`);
269
+ assertEqual(regular.clauses.length, 0, `${name} quad clause count`);
270
+ assertEqual(termToString(regular.quads[0].id), termToString(labelled.quads[0].id), `${name} label`);
271
+ assertEqual(termToString(regular.quads[0].query), termToString(labelled.quads[0].query), `${name} query`);
272
+ assertEqual(publicApi.runQuads(regular).stdout, 'quads: 1 run, 1 passed, 0 failed.\n', `${name} report`);
273
+ }
274
+
275
+ const strict = Program.parse(`(?-(','(0,passes),=(X,1))).\n`, { isoStrict: true });
257
276
  assertEqual(strict.quads.length, 0, 'strict mode has no quads');
258
- assertEqual(strict.clauses.length, 1, 'strict functional ?-/2 remains an ordinary term');
277
+ assertEqual(strict.clauses.length, 1, 'strict ?-/2 remains an ordinary term');
259
278
  },
260
279
  },
261
280
  {
@@ -5156,10 +5156,12 @@ an optional label before the query marker (`Label ?- Query.`), so while quad
5156
5156
  syntax is supported it additionally exposes `?-` at priority 1200 with
5157
5157
  specifier `xfx` as an implementation-specific operator. Consequently
5158
5158
  `current_op(Priority, Specifier, ?-)` enumerates both definitions. At top level in the normal EyeProlog profile, the quad marker is recognized
5159
- after term parsing, so equivalent syntax stays equivalent: `Label ?- Query.`
5160
- and canonical `?-(Label, Query).` denote the same labelled quad when followed
5161
- by its indented answer descriptions. In `--iso-strict` mode this quad
5162
- interpretation is disabled, and `?-/2` remains ordinary Prolog term syntax.
5159
+ from the parsed `?-/1` or `?-/2` term rather than from one privileged surface
5160
+ spelling. Thus `Label ?- Query.`, `?-(Label, Query).`, mixed forms such as
5161
+ `?-((Label), Query).`, quoted-functor notation, and a parenthesized whole
5162
+ `(?-(Label, Query)).` denote the same quad when followed by indented answer
5163
+ descriptions. In `--iso-strict` mode this quad interpretation is disabled, and
5164
+ `?-/2` remains ordinary Prolog term syntax.
5163
5165
 
5164
5166
  Run [`iso-dynamic-database.pl`](https://github.com/eyereasoner/eyeprolog/blob/main/examples/iso-dynamic-database.pl)
5165
5167
  for an explicitly stateful queue and
@@ -6432,9 +6434,11 @@ Trealla and the ISO Prolog working examples. Because answer descriptions are
6432
6434
  layout-sensitive, indent every description while keeping ordinary clause heads
6433
6435
  and the next quad query at the left margin. A quad label may contain any number
6434
6436
  of comma-separated metadata fields, including across layout before `?-`; for
6435
- example `9, "case", passes ?- Goal.` is one labelled query. Canonical
6436
- functional notation is semantically equivalent: `?-(Label, Query).` followed by
6437
- the same indented answer descriptions creates the same labelled quad as
6437
+ example `9, "case", passes ?- Goal.` is one labelled query. Quad recognition
6438
+ is structural after ordinary term parsing: functional, mixed, quoted-functor,
6439
+ and parenthesized spellings of the same `?-/1` or `?-/2` term are semantically
6440
+ equivalent. For example `?-(Label, Query).` and `(?-(Label, Query)).`, followed
6441
+ by the same indented answer descriptions, create the same labelled quad as
6438
6442
  `Label ?- Query.`.
6439
6443
 
6440
6444
  Statistics are comparative evidence, not a score in isolation. Preserve the