eyeprolog 1.2.14 → 1.2.15
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 +6 -4
- package/package.json +1 -1
- package/src/parser.js +40 -9
- package/test/run-regression.mjs +42 -3
- package/the-art-of-eyeprolog.md +10 -3
package/README.md
CHANGED
|
@@ -79,10 +79,12 @@ member_test ?- member(X, [prolog, logic]).
|
|
|
79
79
|
; X = logic.
|
|
80
80
|
```
|
|
81
81
|
|
|
82
|
-
A label
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
82
|
+
A label is simply the first argument of the ordinary `(?-)/2` term, so it may
|
|
83
|
+
use any normal Prolog term syntax; EyeProlog only requires it to be ground when
|
|
84
|
+
the quad is checked. A non-ground label is a quad failure, not a source syntax
|
|
85
|
+
error, and later quads still run. When a query has multiple indented answer
|
|
86
|
+
descriptions, each description is checked and counted independently, so one
|
|
87
|
+
failed expectation does not prevent the later ones from running.
|
|
86
88
|
|
|
87
89
|
## Strict ISO/IEC 13211-1 core
|
|
88
90
|
|
package/package.json
CHANGED
package/src/parser.js
CHANGED
|
@@ -794,13 +794,47 @@ class Parser {
|
|
|
794
794
|
accept(clause);
|
|
795
795
|
continue;
|
|
796
796
|
}
|
|
797
|
+
// Program clauses historically parse comma separately from the head, so
|
|
798
|
+
// keep that grammar unchanged. A quad id, however, is simply the first
|
|
799
|
+
// argument of the ordinary ?-/2 term. If the initial head parse stops at
|
|
800
|
+
// a comma, tentatively reparse that left operand with the normal term
|
|
801
|
+
// grammar (where comma is the predefined priority-1000 xfy operator).
|
|
802
|
+
// Only when the resulting term is actually followed by ?- do we keep the
|
|
803
|
+
// tentative parse; otherwise restore the parser and retain the existing
|
|
804
|
+
// clause/DCG handling below.
|
|
805
|
+
const headState = {
|
|
806
|
+
pos: this.pos,
|
|
807
|
+
line: this.line,
|
|
808
|
+
anonymous: this.anonymous,
|
|
809
|
+
variables: new Map(this.variables),
|
|
810
|
+
previousToken: this.previousToken,
|
|
811
|
+
token: this.token,
|
|
812
|
+
};
|
|
813
|
+
const restoreHeadState = () => {
|
|
814
|
+
this.pos = headState.pos;
|
|
815
|
+
this.line = headState.line;
|
|
816
|
+
this.anonymous = headState.anonymous;
|
|
817
|
+
this.variables = new Map(headState.variables);
|
|
818
|
+
this.previousToken = headState.previousToken;
|
|
819
|
+
this.token = headState.token;
|
|
820
|
+
};
|
|
821
|
+
|
|
797
822
|
let head = this.parseTerm(3);
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
823
|
+
if (this.token.type === TOK.COMMA && !this.strictIso) {
|
|
824
|
+
restoreHeadState();
|
|
825
|
+
const quadId = this.parseTerm(3, true);
|
|
826
|
+
if (this.operatorTokenName() === '?-') {
|
|
827
|
+
this.advance();
|
|
828
|
+
this.parseQuad(quadId, line, accept);
|
|
829
|
+
continue;
|
|
830
|
+
}
|
|
831
|
+
restoreHeadState();
|
|
832
|
+
head = this.parseTerm(3);
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
// Outside quad syntax, preserve the existing program-level comma rule,
|
|
836
|
+
// including the TS 13211-3 semicontext boundary. This is deliberately
|
|
837
|
+
// not a grammar for quad ids.
|
|
804
838
|
if (this.token.type === TOK.COMMA) {
|
|
805
839
|
const items = [head];
|
|
806
840
|
let extraCommaLine = null;
|
|
@@ -809,9 +843,6 @@ class Parser {
|
|
|
809
843
|
this.advance();
|
|
810
844
|
items.push(this.parseTerm(3));
|
|
811
845
|
}
|
|
812
|
-
// Historically the program grammar admitted exactly one comma in a
|
|
813
|
-
// DCG semicontext. Keep that boundary: the broader comma sequence is
|
|
814
|
-
// specifically the quad-label extension, not a new DCG syntax.
|
|
815
846
|
if (extraCommaLine != null && this.operatorTokenName() !== '?-') {
|
|
816
847
|
throw new Error(`parse line ${extraCommaLine}: expected ., got ,`);
|
|
817
848
|
}
|
package/test/run-regression.mjs
CHANGED
|
@@ -279,8 +279,11 @@ why(
|
|
|
279
279
|
},
|
|
280
280
|
},
|
|
281
281
|
{
|
|
282
|
-
name: 'quad
|
|
282
|
+
name: 'quad ids use ordinary term syntax and each answer description is independent',
|
|
283
283
|
run: () => {
|
|
284
|
+
// Issue #21: the first argument of ?-/2 is an ordinary Prolog term.
|
|
285
|
+
// The commas here are the normal priority-1000 comma operator, not a
|
|
286
|
+
// special metadata grammar owned by the quad parser.
|
|
284
287
|
const source = `9, "✳54·43", passes
|
|
285
288
|
` +
|
|
286
289
|
`?- X is 1+1.
|
|
@@ -298,14 +301,50 @@ why(
|
|
|
298
301
|
const program = Program.parseSources([{ text: source, filename: 'issue-21.pl' }]);
|
|
299
302
|
assertEqual(program.quads.length, 1, 'query group count');
|
|
300
303
|
assertEqual(program.quads[0].answers.length, 4, 'answer-description count');
|
|
301
|
-
assertEqual(program.quads[0].id.name, ',', 'outer
|
|
302
|
-
assertEqual(program.quads[0].id.args[1].name, ',', 'right-associated
|
|
304
|
+
assertEqual(program.quads[0].id.name, ',', 'ordinary outer comma operator');
|
|
305
|
+
assertEqual(program.quads[0].id.args[1].name, ',', 'ordinary right-associated comma operator');
|
|
303
306
|
const result = publicApi.runQuads(program);
|
|
304
307
|
assertEqual(result.total, 4, 'answer-description total');
|
|
305
308
|
assertEqual(result.passed, 4, 'answer-description passed');
|
|
306
309
|
assertEqual(result.failed, 0, 'answer-description failed');
|
|
307
310
|
assertEqual(result.stdout, 'quads: 4 run, 4 passed, 0 failed.\n', 'issue #21 report');
|
|
308
311
|
|
|
312
|
+
// No convention is imposed on the id term. Functional/list/curly and
|
|
313
|
+
// non-comma operator forms all go through the same ordinary term parser.
|
|
314
|
+
const ordinaryIds = Program.parse(
|
|
315
|
+
`meta(9, passes) ?- true.
|
|
316
|
+
true.
|
|
317
|
+
` +
|
|
318
|
+
`[9, passes] ?- true.
|
|
319
|
+
true.
|
|
320
|
+
` +
|
|
321
|
+
`{passes} ?- true.
|
|
322
|
+
true.
|
|
323
|
+
` +
|
|
324
|
+
`(alpha ; beta) ?- true.
|
|
325
|
+
true.
|
|
326
|
+
`,
|
|
327
|
+
);
|
|
328
|
+
assertEqual(ordinaryIds.quads.length, 4, 'ordinary id term count');
|
|
329
|
+
assertEqual(publicApi.runQuads(ordinaryIds).stdout, 'quads: 4 run, 4 passed, 0 failed.\n',
|
|
330
|
+
'ordinary id term report');
|
|
331
|
+
|
|
332
|
+
// Groundness is a quad semantic check, not source syntax. A bad id is
|
|
333
|
+
// reported as a test failure and processing continues to the next quad.
|
|
334
|
+
const nonGround = publicApi.runQuads(
|
|
335
|
+
`Id ?- true.
|
|
336
|
+
true.
|
|
337
|
+
` +
|
|
338
|
+
`ok ?- true.
|
|
339
|
+
true.
|
|
340
|
+
`,
|
|
341
|
+
);
|
|
342
|
+
assertEqual(nonGround.total, 2, 'non-ground id does not abort parsing');
|
|
343
|
+
assertEqual(nonGround.passed, 1, 'following quad still passes');
|
|
344
|
+
assertEqual(nonGround.failed, 1, 'non-ground id is a quad failure');
|
|
345
|
+
assertIncludes(nonGround.stdout, 'quads: BAD_ID Id, <input>:1', 'non-ground id diagnostic');
|
|
346
|
+
assertIncludes(nonGround.stdout, 'quads: 2 run, 1 passed, 1 failed.', 'non-ground continuation summary');
|
|
347
|
+
|
|
309
348
|
const continuing = publicApi.runQuads(
|
|
310
349
|
`case ?- X is 1+1.
|
|
311
350
|
X = 3.
|
package/the-art-of-eyeprolog.md
CHANGED
|
@@ -5170,8 +5170,11 @@ from the parsed `?-/1` or `?-/2` term rather than from one privileged surface
|
|
|
5170
5170
|
spelling. Thus `Label ?- Query.`, `?-(Label, Query).`, mixed forms such as
|
|
5171
5171
|
`?-((Label), Query).`, quoted-functor notation, and a parenthesized whole
|
|
5172
5172
|
`(?-(Label, Query)).` denote the same quad when followed by indented answer
|
|
5173
|
-
descriptions.
|
|
5174
|
-
|
|
5173
|
+
descriptions. `Label` itself is parsed with the ordinary Prolog term grammar:
|
|
5174
|
+
there is no quad-specific comma or metadata syntax. The runner requires the
|
|
5175
|
+
resulting first argument to be ground; if it is not, that quad is reported as
|
|
5176
|
+
`BAD_ID` and later quads are still processed. In `--iso-strict` mode this quad
|
|
5177
|
+
interpretation is disabled, and `?-/2` remains ordinary Prolog term syntax.
|
|
5175
5178
|
|
|
5176
5179
|
Run [`iso-dynamic-database.pl`](https://github.com/eyereasoner/eyeprolog/blob/main/examples/iso-dynamic-database.pl)
|
|
5177
5180
|
for an explicitly stateful queue and
|
|
@@ -6401,7 +6404,11 @@ colors ?- color(X).
|
|
|
6401
6404
|
```
|
|
6402
6405
|
|
|
6403
6406
|
Run all quads in a file with `eyeprolog --quads file.pl` or `eyeprolog -q
|
|
6404
|
-
file.pl`. A label such as `colors` is optional.
|
|
6407
|
+
file.pl`. A label such as `colors` is optional. A label is not a separate
|
|
6408
|
+
mini-language: it is the ordinary first argument of `(?-)/2`, and therefore may
|
|
6409
|
+
be any Prolog term admitted there by the normal term grammar. Quad execution
|
|
6410
|
+
requires that argument to be ground; a non-ground label is reported as a quad
|
|
6411
|
+
failure rather than aborting source parsing. Loading the file normally only
|
|
6405
6412
|
records its quads; it does not execute them or add their queries and answers as
|
|
6406
6413
|
program clauses. A quad run prints a summary and exits with status `1` when any
|
|
6407
6414
|
description fails. Quad mode imports `library(prologue)` as a compatibility
|