eyeprolog 1.2.4 → 1.2.5
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/conformance-report.md +2 -2
- package/package.json +1 -1
- package/src/iso.js +5 -2
- package/src/parser.js +4 -0
- package/src/repl.js +5 -2
- package/src/write.js +2 -0
- package/test/conformance/ISO-MATRIX.md +1 -1
- package/test/conformance/README.md +1 -1
- package/test/conformance/cases/iso/wg17_syntax_high_risk.pl +5 -1
- package/test/conformance/errors/iso/wg17_invalid_octal_escape.pl +1 -0
- package/test/conformance/expected/iso/wg17_syntax_high_risk.pl +2 -0
- package/test/conformance/expected-errors/iso/wg17_invalid_octal_escape.txt +1 -0
- package/test/run-regression.mjs +35 -0
- package/the-art-of-eyeprolog.md +5 -2
package/conformance-report.md
CHANGED
|
@@ -11,7 +11,7 @@ This report summarizes the file-based conformance corpus under `test/conformance
|
|
|
11
11
|
| builtins | 11 | 0 | 0 | 0 | 11 |
|
|
12
12
|
| context | 11 | 0 | 0 | 0 | 11 |
|
|
13
13
|
| control | 15 | 0 | 0 | 0 | 15 |
|
|
14
|
-
| iso | 167 |
|
|
14
|
+
| iso | 167 | 210 | 0 | 0 | 377 |
|
|
15
15
|
| lists | 52 | 3 | 0 | 0 | 55 |
|
|
16
16
|
| modules | 2 | 0 | 0 | 0 | 2 |
|
|
17
17
|
| negation | 8 | 0 | 19 | 0 | 27 |
|
|
@@ -23,4 +23,4 @@ This report summarizes the file-based conformance corpus under `test/conformance
|
|
|
23
23
|
| terms | 26 | 3 | 0 | 0 | 29 |
|
|
24
24
|
| unification | 18 | 0 | 0 | 0 | 18 |
|
|
25
25
|
| variables | 16 | 9 | 0 | 0 | 25 |
|
|
26
|
-
| **Total** | **482** | **
|
|
26
|
+
| **Total** | **482** | **261** | **19** | **21** | **783** |
|
package/package.json
CHANGED
package/src/iso.js
CHANGED
|
@@ -1075,9 +1075,12 @@ function quotedEscapeEnd(source, index) {
|
|
|
1075
1075
|
while (/^[0-9A-Fa-f]$/.test(source[cursor] ?? '')) cursor++;
|
|
1076
1076
|
return source[cursor] === '\\' ? cursor : Math.max(index + 1, cursor - 1);
|
|
1077
1077
|
}
|
|
1078
|
-
if (/^[0-
|
|
1078
|
+
if (/^[0-9]$/.test(escaped)) {
|
|
1079
1079
|
let cursor = index + 1;
|
|
1080
|
-
|
|
1080
|
+
// Scan all decimal digits here, including 8 and 9. This scanner only
|
|
1081
|
+
// locates the end of a candidate quoted escape; the parser remains
|
|
1082
|
+
// authoritative and rejects non-octal digits.
|
|
1083
|
+
while (/^[0-9]$/.test(source[cursor] ?? '')) cursor++;
|
|
1081
1084
|
return source[cursor] === '\\' ? cursor : Math.max(index + 1, cursor - 1);
|
|
1082
1085
|
}
|
|
1083
1086
|
|
package/src/parser.js
CHANGED
|
@@ -303,6 +303,10 @@ class Parser {
|
|
|
303
303
|
if (this.take() !== '\\') throw new Error(`parse line ${line}: bad octal escape`);
|
|
304
304
|
return String.fromCodePoint(Number.parseInt(digits, 8));
|
|
305
305
|
}
|
|
306
|
+
// A backslash followed by a decimal digit is numeric-escape syntax, but
|
|
307
|
+
// ISO octal digits are limited to 0..7. Do not reinterpret \8 or \9 as
|
|
308
|
+
// implementation-specific one-character escapes.
|
|
309
|
+
if (/^[0-9]$/.test(escaped)) throw new Error(`parse line ${line}: bad octal escape`);
|
|
306
310
|
return escaped;
|
|
307
311
|
}
|
|
308
312
|
nextToken() {
|
package/src/repl.js
CHANGED
|
@@ -253,9 +253,12 @@ function quotedEscapeEnd(source, index) {
|
|
|
253
253
|
while (/^[0-9A-Fa-f]$/.test(source[cursor] ?? '')) cursor++;
|
|
254
254
|
return source[cursor] === '\\' ? cursor : Math.max(index + 1, cursor - 1);
|
|
255
255
|
}
|
|
256
|
-
if (/^[0-
|
|
256
|
+
if (/^[0-9]$/.test(escaped)) {
|
|
257
257
|
let cursor = index + 1;
|
|
258
|
-
|
|
258
|
+
// Scan all decimal digits here, including 8 and 9. This scanner only
|
|
259
|
+
// locates the end of a candidate quoted escape; the parser remains
|
|
260
|
+
// authoritative and rejects non-octal digits.
|
|
261
|
+
while (/^[0-9]$/.test(source[cursor] ?? '')) cursor++;
|
|
259
262
|
return source[cursor] === '\\' ? cursor : Math.max(index + 1, cursor - 1);
|
|
260
263
|
}
|
|
261
264
|
|
package/src/write.js
CHANGED
|
@@ -22,6 +22,7 @@ function quoteAtom(name) {
|
|
|
22
22
|
for (const ch of name) {
|
|
23
23
|
if (ch === "'") out += "''";
|
|
24
24
|
else if (ch === '\\') out += '\\\\';
|
|
25
|
+
else if (ch === '\x00') out += '\\0\\';
|
|
25
26
|
else if (ch === '\x07') out += '\\a';
|
|
26
27
|
else if (ch === '\b') out += '\\b';
|
|
27
28
|
else if (ch === '\r') out += '\\r';
|
|
@@ -59,6 +60,7 @@ function writeString(value) {
|
|
|
59
60
|
let out = '"';
|
|
60
61
|
for (const ch of value) {
|
|
61
62
|
if (ch === '"' || ch === '\\') out += `\\${ch}`;
|
|
63
|
+
else if (ch === '\x00') out += '\\0\\';
|
|
62
64
|
else if (ch === '\x07') out += '\\a';
|
|
63
65
|
else if (ch === '\b') out += '\\b';
|
|
64
66
|
else if (ch === '\r') out += '\\r';
|
|
@@ -8,7 +8,7 @@ compliance audit and the remaining work before a full conformance claim.
|
|
|
8
8
|
|
|
9
9
|
| Standard area | Implementation | Representative executable coverage |
|
|
10
10
|
| --- | --- | --- |
|
|
11
|
-
| Clause 6 lexical and term syntax | tokenizer, operator parser, lists, curly terms, quotes, numeric syntax, comments | `scryer_lexical_terms`, `lexical_and_curly_terms`, `double_quoted_lists`, `corrigendum1_double_quote_operator`, `wg17_syntax_high_risk`, syntax error cases |
|
|
11
|
+
| Clause 6 lexical and term syntax | tokenizer, operator parser, lists, curly terms, quotes, numeric syntax, comments | `scryer_lexical_terms`, `lexical_and_curly_terms`, `double_quoted_lists`, `corrigendum1_double_quote_operator`, `wg17_syntax_high_risk`, `wg17_invalid_octal_escape`, syntax error cases |
|
|
12
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
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
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 |
|
|
@@ -102,7 +102,7 @@ Selected cases are adapted from the ISO and standard-core suites of Logtalk,
|
|
|
102
102
|
Scryer Prolog, Trealla Prolog, and SWI-Prolog. Their upstream identifiers and licenses
|
|
103
103
|
are recorded in [THIRD_PARTY.md](THIRD_PARTY.md).
|
|
104
104
|
|
|
105
|
-
The corpus has
|
|
105
|
+
The corpus has 377 cases in `iso/` and 783 file-based conformance cases in
|
|
106
106
|
total. The generated `conformance-report.md` is the authoritative source for
|
|
107
107
|
current category totals. Together with regression, documentation-sync, API,
|
|
108
108
|
example, and book-example checks, `npm test` is the release gate.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
% High-risk ISO syntax/write regressions, independently derived from
|
|
2
2
|
% ISO/IEC 13211-1 clauses 6.3, 6.4 and 7.10 and cross-checked against the
|
|
3
|
-
% public WG17 conformity-testing syntax cases (#1, #14-15, #28-31, #33-34).
|
|
3
|
+
% public WG17 conformity-testing syntax cases (#1, #14-15, #28-31, #33-34, #301).
|
|
4
4
|
|
|
5
5
|
%% goal: wg17_numeric_escape
|
|
6
6
|
wg17_numeric_escape :-
|
|
@@ -24,3 +24,7 @@ wg17_operator_precedence :-
|
|
|
24
24
|
%% goal: wg17_canonical_list
|
|
25
25
|
wg17_canonical_list :-
|
|
26
26
|
write_canonical([a]), nl.
|
|
27
|
+
|
|
28
|
+
%% goal: wg17_zero_character_escape
|
|
29
|
+
wg17_zero_character_escape :-
|
|
30
|
+
writeq('\0\'), nl.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
'\8\'.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
parse line 1: bad octal escape
|
package/test/run-regression.mjs
CHANGED
|
@@ -671,6 +671,31 @@ c4 ?- call((!;1)).
|
|
|
671
671
|
assertEqual(result.stderr, '', 'stderr');
|
|
672
672
|
},
|
|
673
673
|
},
|
|
674
|
+
{
|
|
675
|
+
name: 'writeq preserves the NUL character with an ISO octal escape',
|
|
676
|
+
run: () => {
|
|
677
|
+
const result = runCli([], {
|
|
678
|
+
input: "writeq('\\0\\').\nhalt.\n",
|
|
679
|
+
});
|
|
680
|
+
assertEqual(result.status, 0, 'exit status');
|
|
681
|
+
assertEqual(result.stdout, "?- '\\0\\' true.\n?- ", 'stdout');
|
|
682
|
+
assertEqual(result.stderr, '', 'stderr');
|
|
683
|
+
},
|
|
684
|
+
},
|
|
685
|
+
{
|
|
686
|
+
name: 'REPL rejects non-octal numeric escapes without waiting for continuation',
|
|
687
|
+
run: () => {
|
|
688
|
+
const result = runCli([], {
|
|
689
|
+
input: "'\\8\\'.\nhalt.\n",
|
|
690
|
+
});
|
|
691
|
+
assertEqual(result.status, 0, 'exit status');
|
|
692
|
+
assertEqual(result.stdout,
|
|
693
|
+
'?- parse line 1: bad octal escape.\n' +
|
|
694
|
+
'?- ',
|
|
695
|
+
'stdout');
|
|
696
|
+
assertEqual(result.stderr, '', 'stderr');
|
|
697
|
+
},
|
|
698
|
+
},
|
|
674
699
|
{
|
|
675
700
|
name: 'REPL read predicates consume following interactive term input',
|
|
676
701
|
run: () => {
|
|
@@ -1312,6 +1337,16 @@ c4 ?- call((!;1)).
|
|
|
1312
1337
|
"answer('\\a').\n",
|
|
1313
1338
|
'read/1 user_input numeric escape',
|
|
1314
1339
|
);
|
|
1340
|
+
|
|
1341
|
+
const invalidOctal = String.fromCharCode(39, 92, 56, 92, 39, 46);
|
|
1342
|
+
assertEqual(
|
|
1343
|
+
run('answer(T) :- catch(read(T), E, T=E).\n', {
|
|
1344
|
+
goal: 'answer(T)',
|
|
1345
|
+
ioOptions: { input: invalidOctal },
|
|
1346
|
+
}).stdout,
|
|
1347
|
+
'answer(error(syntax_error(read_term), eyeprolog)).\n',
|
|
1348
|
+
'read/1 rejects non-octal numeric escape',
|
|
1349
|
+
);
|
|
1315
1350
|
},
|
|
1316
1351
|
},
|
|
1317
1352
|
{
|
package/the-art-of-eyeprolog.md
CHANGED
|
@@ -5279,7 +5279,10 @@ message("café").
|
|
|
5279
5279
|
Inside a quoted atom, a single quote is doubled: `'don''t'`. Quoted characters
|
|
5280
5280
|
support the ISO symbolic control escapes such as `\a`, `\n`, and `\t`, and numeric
|
|
5281
5281
|
octal or hexadecimal escapes are terminated by a backslash; for example, `'\7\'`
|
|
5282
|
-
and `'\x7\'` both denote the alert character.
|
|
5282
|
+
and `'\x7\'` both denote the alert character. The NUL character, when present in
|
|
5283
|
+
the processor character set, is written readably as `'\0\'`; digits `8` and `9`
|
|
5284
|
+
are not octal digits, so forms such as `'\8\'` are syntax errors rather than
|
|
5285
|
+
continuation input. Double-quoted lists use the same
|
|
5283
5286
|
quoted-character escapes. Whitespace is insignificant
|
|
5284
5287
|
between tokens, and a `%` comment continues to the end of its line. Doubling
|
|
5285
5288
|
the active delimiter is also accepted inside either quoted form, so `""`
|
|
@@ -6946,7 +6949,7 @@ precedence still need one-by-one closure. `test/conformance/ISO-MATRIX.md`
|
|
|
6946
6949
|
maps language families to representative executable cases.
|
|
6947
6950
|
|
|
6948
6951
|
The complete suite must pass before release. The file-based conformance corpus
|
|
6949
|
-
contains
|
|
6952
|
+
contains 783 cases, including 377 focused ISO
|
|
6950
6953
|
cases derived from the success, failure, mode, and error behavior in
|
|
6951
6954
|
ISO/IEC 13211-1 clauses 7 and 8, Part 2 modules, and Part 3 grammar rules.
|
|
6952
6955
|
Separate exact-output suites check 189 normal
|