eyeprolog 1.3.52 → 1.3.54
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 +7 -7
- package/package.json +1 -1
- package/src/iso-arithmetic.js +52 -39
- package/src/iso-character.js +9 -11
- package/src/iso.js +4 -3
- package/src/parser.js +56 -20
- package/src/term.js +15 -2
- package/test/conformance/ISO-COMPLIANCE.md +27 -13
- package/test/conformance/ISO-IMPLEMENTATION-DEFINED.md +20 -15
- package/test/conformance/ISO-MATRIX.md +4 -3
- package/test/conformance/README.md +4 -4
- package/test/conformance/STC-DRAFT-STATUS.md +8 -1
- package/test/run-iso-strict.mjs +105 -25
- package/the-art-of-eyeprolog.md +18 -18
- package/why-eyeprolog.md +5 -4
package/README.md
CHANGED
|
@@ -210,13 +210,13 @@ expansion/`phrase/2-3`; it also removes the EyeProlog `occurs_check` flag,
|
|
|
210
210
|
Normal mode is unchanged and continues to support modules, DCGs, quads,
|
|
211
211
|
libraries, proofs, cleanup-aware control, and the other documented extensions.
|
|
212
212
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
213
|
+
The Part 1 processor character set is an implementation-defined processor
|
|
214
|
+
choice, so strict mode does not replace it with a smaller repertoire. EyeProlog
|
|
215
|
+
uses Unicode scalar values as its PCS in both normal and strict profiles, with
|
|
216
|
+
the Unicode scalar value as the collating-sequence integer. ASCII keeps the
|
|
217
|
+
standard lexical classes; extended Unicode letters participate in unquoted name
|
|
218
|
+
syntax and other non-ASCII symbols are treated as extended graphic characters.
|
|
219
|
+
Surrogates and values above U+10FFFF remain representation errors.
|
|
220
220
|
|
|
221
221
|
Strict term I/O likewise keeps the standardized option boundary: `read_term/2-3`
|
|
222
222
|
and `write_term/2-3` accept the Part 1 plus Corrigendum 3 options, while the
|
package/package.json
CHANGED
package/src/iso-arithmetic.js
CHANGED
|
@@ -41,7 +41,12 @@ function evaluate(term, env, options = {}) {
|
|
|
41
41
|
// arguments before selecting an implementation-dependent evaluation order.
|
|
42
42
|
const operands = term.args.map((arg) => deref(arg, env));
|
|
43
43
|
if (operands.some((arg) => arg.type === VAR)) throw new PrologError('instantiation_error');
|
|
44
|
-
|
|
44
|
+
// Once the direct-variable precedence is satisfied, each operand is
|
|
45
|
+
// itself an expression. An atom such as foo therefore fails as the
|
|
46
|
+
// non-evaluable functor foo/0 (7.9.2(c)); it is not a numeric value that
|
|
47
|
+
// can subsequently trigger type_error(number,...). STC #69 corrects the
|
|
48
|
+
// misleading 9.1.7 example accordingly.
|
|
49
|
+
args = operands.map((arg) => evaluate(arg, env, options));
|
|
45
50
|
} else {
|
|
46
51
|
// Preserve the normal EyeProlog profile's established left-to-right
|
|
47
52
|
// evaluator and diagnostics; the stricter prescribed errors belong to
|
|
@@ -51,38 +56,6 @@ function evaluate(term, env, options = {}) {
|
|
|
51
56
|
return evaluateOperation(term, args, options);
|
|
52
57
|
}
|
|
53
58
|
|
|
54
|
-
function evaluatesAtomDirectly(term, options) {
|
|
55
|
-
return term.type === ATOM && (term.name === 'pi' || (term.name === 'e' && options.isoStrict !== true));
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function directOperandType(term) {
|
|
59
|
-
const name = term.name;
|
|
60
|
-
const arity = term.arity;
|
|
61
|
-
if ((arity === 1 && name === '\\') ||
|
|
62
|
-
(arity === 2 && ['>>', '<<', '/\\', '\\/', 'xor'].includes(name))) return 'integer';
|
|
63
|
-
|
|
64
|
-
if ((arity === 1 && ['+', '-', 'abs', 'sign', 'float', 'truncate', 'round', 'ceiling', 'floor',
|
|
65
|
-
'float_integer_part', 'float_fractional_part', 'sin', 'cos', 'atan', 'asin', 'acos', 'tan',
|
|
66
|
-
'exp', 'log', 'sqrt'].includes(name)) ||
|
|
67
|
-
(arity === 2 && ['+', '-', '*', '/', '//', 'div', 'mod', 'rem', '**', '^', 'max', 'min', 'atan2'].includes(name))) {
|
|
68
|
-
return 'number';
|
|
69
|
-
}
|
|
70
|
-
return null;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function evaluateOperand(parent, operand, env, options) {
|
|
74
|
-
// The arithmetic-functor error clauses use the offending operand as the
|
|
75
|
-
// culprit when an atomic operand is not numeric (e.g. +(foo,77),
|
|
76
|
-
// truncate(foo), and the bitwise families). A nested compound still goes
|
|
77
|
-
// through ordinary expression evaluation so an unknown nested F/N retains
|
|
78
|
-
// type_error(evaluable,F/N).
|
|
79
|
-
if (operand.type === ATOM && !evaluatesAtomDirectly(operand, options)) {
|
|
80
|
-
const expected = directOperandType(parent);
|
|
81
|
-
if (expected) throw new PrologError(`type_error(${expected})`, operand);
|
|
82
|
-
}
|
|
83
|
-
return evaluate(operand, env, options);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
59
|
function evaluateOperation(term, args, options = {}) {
|
|
87
60
|
const name = term.name;
|
|
88
61
|
const arity = term.arity;
|
|
@@ -104,9 +77,17 @@ function evaluateOperation(term, args, options = {}) {
|
|
|
104
77
|
if (options.isoStrict === true && ['truncate', 'round', 'ceiling', 'floor'].includes(name) && args[0].integer) {
|
|
105
78
|
throw new PrologError('type_error(float)', numericTerm(args[0]));
|
|
106
79
|
}
|
|
107
|
-
const a = Number(args[0].value);
|
|
108
80
|
if (name === 'abs' && args[0].integer) return { integer: true, value: args[0].value < 0n ? -args[0].value : args[0].value };
|
|
109
81
|
if (name === 'sign' && args[0].integer) return { integer: true, value: args[0].value < 0n ? -1n : args[0].value > 0n ? 1n : 0n };
|
|
82
|
+
const a = Number(args[0].value);
|
|
83
|
+
// The int-exp -> float templates first apply the processor's I->F
|
|
84
|
+
// conversion. With unbounded integers that conversion can overflow even
|
|
85
|
+
// though the integer itself is representable. Do not let a host math
|
|
86
|
+
// function observe +/-Infinity and turn the required float-overflow into
|
|
87
|
+
// a different result (for example atan(Huge) = pi/2).
|
|
88
|
+
if (options.isoStrict === true && args[0].integer && !Number.isFinite(a)) {
|
|
89
|
+
throw new PrologError('evaluation_error(float_overflow)');
|
|
90
|
+
}
|
|
110
91
|
if (name === 'truncate' || name === 'round' || name === 'ceiling' || name === 'floor') {
|
|
111
92
|
const fn = name === 'truncate' ? Math.trunc : name === 'round' ? Math.round : name === 'ceiling' ? Math.ceil : Math.floor;
|
|
112
93
|
return { integer: true, value: BigInt(fn(a)) };
|
|
@@ -120,6 +101,13 @@ function evaluateOperation(term, args, options = {}) {
|
|
|
120
101
|
const value = fn(a);
|
|
121
102
|
if (Number.isNaN(value) || (name === 'log' && a === 0)) throw new PrologError('evaluation_error(undefined)');
|
|
122
103
|
if (!Number.isFinite(value)) throw new PrologError('evaluation_error(float_overflow)');
|
|
104
|
+
// Unlike the implementation-defined resultF choice for ordinary floating
|
|
105
|
+
// arithmetic, exp/1 has an explicit exceptional condition when its
|
|
106
|
+
// mathematical non-zero result is too small to represent. Math.exp()
|
|
107
|
+
// signals that boundary by rounding the positive result to zero.
|
|
108
|
+
if (options.isoStrict === true && name === 'exp' && value === 0) {
|
|
109
|
+
throw new PrologError('evaluation_error(underflow)');
|
|
110
|
+
}
|
|
123
111
|
return { integer: false, value };
|
|
124
112
|
}
|
|
125
113
|
if (arity !== 2) throw new PrologError('type_error(evaluable)', compound('/', [atom(name), numberTerm(arity)]));
|
|
@@ -158,6 +146,28 @@ function evaluateOperation(term, args, options = {}) {
|
|
|
158
146
|
if (name === '<<') return { integer: true, value: integerResource(() => a << b) };
|
|
159
147
|
if (name === '>>') return { integer: true, value: integerResource(() => a >> b) };
|
|
160
148
|
}
|
|
149
|
+
// Power has prescribed exceptional conditions that depend on the evaluated
|
|
150
|
+
// operand values/types and therefore precede any I->F conversion needed by
|
|
151
|
+
// the selected floating template. Checking these first matters with
|
|
152
|
+
// unbounded integers: conversion overflow must not hide an already-satisfied
|
|
153
|
+
// undefined-power condition.
|
|
154
|
+
const aNegative = args[0].integer ? a < 0n : a < 0;
|
|
155
|
+
const aZero = args[0].integer ? a === 0n : a === 0;
|
|
156
|
+
const bNegative = args[1].integer ? b < 0n : b < 0;
|
|
157
|
+
if (options.isoStrict === true && name === '**' && aNegative && !args[1].integer) {
|
|
158
|
+
// Corrigendum 3 corrects the operand name in 9.3.1.3(c): **/2 requires
|
|
159
|
+
// an integer-typed exponent for a negative base. A float such as 2.0 is
|
|
160
|
+
// still not an integer value of the required type here.
|
|
161
|
+
throw new PrologError('evaluation_error(undefined)');
|
|
162
|
+
}
|
|
163
|
+
if (options.isoStrict === true && name === '^' && aNegative && !args[1].integer && !Number.isInteger(b)) {
|
|
164
|
+
// Corrigendum 2 ^/2 additionally accepts a float with an integer value.
|
|
165
|
+
throw new PrologError('evaluation_error(undefined)');
|
|
166
|
+
}
|
|
167
|
+
if ((name === '**' || name === '^') && aZero && bNegative) {
|
|
168
|
+
throw new PrologError('evaluation_error(undefined)');
|
|
169
|
+
}
|
|
170
|
+
|
|
161
171
|
const x = Number(a), y = Number(b);
|
|
162
172
|
if ((!Number.isFinite(x) || !Number.isFinite(y)) && name !== 'max' && name !== 'min') {
|
|
163
173
|
throw new PrologError('evaluation_error(float_overflow)');
|
|
@@ -173,11 +183,6 @@ function evaluateOperation(term, args, options = {}) {
|
|
|
173
183
|
if (x === 0 && y === 0) throw new PrologError('evaluation_error(undefined)');
|
|
174
184
|
value = Math.atan2(x, y);
|
|
175
185
|
}
|
|
176
|
-
else if ((name === '**' || name === '^') && x === 0 && y < 0) {
|
|
177
|
-
// 9.3.1.3(d) and Cor.2 9.3.10.3(d): zero to a negative power is
|
|
178
|
-
// undefined, not floating-point overflow.
|
|
179
|
-
throw new PrologError('evaluation_error(undefined)');
|
|
180
|
-
}
|
|
181
186
|
else if (name === '+') value = x + y;
|
|
182
187
|
else if (name === '-') value = x - y;
|
|
183
188
|
else if (name === '*') value = x * y;
|
|
@@ -186,6 +191,14 @@ function evaluateOperation(term, args, options = {}) {
|
|
|
186
191
|
else throw new PrologError('type_error(evaluable)', compound('/', [atom(name), numberTerm(arity)]));
|
|
187
192
|
if (Number.isNaN(value)) throw new PrologError('evaluation_error(undefined)');
|
|
188
193
|
if (!Number.isFinite(value)) throw new PrologError('evaluation_error(float_overflow)');
|
|
194
|
+
// Part 1 **/2 and Corrigendum 2 ^/2 prescribe underflow when a
|
|
195
|
+
// mathematically non-zero floating power is too small. A non-zero finite
|
|
196
|
+
// base cannot have an exact zero power result, so a host result of +/-0 is
|
|
197
|
+
// the observable underflow boundary. Zero raised to a positive power remains
|
|
198
|
+
// the ordinary exact zero case.
|
|
199
|
+
if (options.isoStrict === true && (name === '**' || name === '^') && value === 0 && x !== 0) {
|
|
200
|
+
throw new PrologError('evaluation_error(underflow)');
|
|
201
|
+
}
|
|
189
202
|
return { integer: false, value };
|
|
190
203
|
}
|
|
191
204
|
export function arithmeticValueTerm(value) {
|
package/src/iso-character.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
// ISO/IEC 13211-1 processor-character-set choices used by
|
|
1
|
+
// ISO/IEC 13211-1 processor-character-set choices used by EyeProlog.
|
|
2
2
|
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
3
|
+
// The PCS is implementation defined (6.5), so --iso-strict must not replace
|
|
4
|
+
// the processor's ordinary character repertoire with a smaller one. EyeProlog
|
|
5
|
+
// uses Unicode scalar values in both normal and strict profiles. Strict mode
|
|
6
|
+
// still rejects implementation-specific language features; it does not alter
|
|
7
|
+
// implementation-defined character-set choices.
|
|
7
8
|
|
|
8
9
|
export class CharacterRepresentationError extends Error {
|
|
9
10
|
constructor(formal = 'representation_error(character)') {
|
|
@@ -13,13 +14,9 @@ export class CharacterRepresentationError extends Error {
|
|
|
13
14
|
}
|
|
14
15
|
}
|
|
15
16
|
|
|
16
|
-
// Strict PCS: the 128 ASCII characters U+0000..U+007F. Printable ASCII
|
|
17
|
-
// carries the Part 1 lexical classes; the remaining C0 controls plus DEL are
|
|
18
|
-
// implementation-defined extended layout characters. This lets every ISO
|
|
19
|
-
// octal/hexadecimal character escape in the ASCII range denote a PCS member.
|
|
20
|
-
// The collating-sequence integer is the Unicode/ASCII code point.
|
|
21
17
|
export function isStrictIsoPcsCodePoint(code) {
|
|
22
|
-
return Number.isInteger(code) && code >= 0 && code <=
|
|
18
|
+
return Number.isInteger(code) && code >= 0 && code <= 0x10ffff &&
|
|
19
|
+
!(code >= 0xd800 && code <= 0xdfff);
|
|
23
20
|
}
|
|
24
21
|
|
|
25
22
|
export function isStrictIsoPcsCharacter(character) {
|
|
@@ -27,6 +24,7 @@ export function isStrictIsoPcsCharacter(character) {
|
|
|
27
24
|
return isStrictIsoPcsCodePoint(character.codePointAt(0));
|
|
28
25
|
}
|
|
29
26
|
|
|
27
|
+
// EyeProlog chooses the Unicode scalar value as the collating-sequence integer.
|
|
30
28
|
export function strictIsoCollatingInteger(character) {
|
|
31
29
|
return isStrictIsoPcsCharacter(character) ? character.codePointAt(0) : null;
|
|
32
30
|
}
|
package/src/iso.js
CHANGED
|
@@ -1352,9 +1352,10 @@ function* termTextCandidates(stream, solver) {
|
|
|
1352
1352
|
let quote = null, lineComment = false, blockComment = false;
|
|
1353
1353
|
for (let i = stream.position; i < source.length; i++) {
|
|
1354
1354
|
const ch = source[i], next = source[i + 1];
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1355
|
+
// The PCS is shared by normal and strict modes (issue #67). UTF-16
|
|
1356
|
+
// source indexing here must not reject one half of a supplementary scalar.
|
|
1357
|
+
// Character/code predicates validate scalar boundaries where a character
|
|
1358
|
+
// value is actually required.
|
|
1358
1359
|
// Text streams preserve invalid UTF-8 bytes as an impossible Unicode
|
|
1359
1360
|
// sentinel. read/1-2 and read_term/2-3 must surface the same character
|
|
1360
1361
|
// representation error as get_char/1-2 instead of misclassifying the
|
package/src/parser.js
CHANGED
|
@@ -35,12 +35,27 @@ const TOK = {
|
|
|
35
35
|
};
|
|
36
36
|
|
|
37
37
|
function isWhitespaceCode(code) {
|
|
38
|
-
// EyeProlog classifies ASCII C0 controls and DEL as layout characters. In
|
|
39
|
-
// strict mode these are the implementation-defined extended-layout members
|
|
40
|
-
// of the ASCII processor character set.
|
|
41
38
|
return (code >= 0 && code <= 32) || code === 127;
|
|
42
39
|
}
|
|
43
40
|
|
|
41
|
+
function isWhitespaceCharacter(character) {
|
|
42
|
+
if (!character) return false;
|
|
43
|
+
const code = character.charCodeAt(0);
|
|
44
|
+
return isWhitespaceCode(code) || /\p{White_Space}/u.test(character);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function isUnicodeUpperCharacter(character) {
|
|
48
|
+
return Boolean(character) && /[\p{Lu}\p{Lt}]/u.test(character);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function isUnicodeLetterCharacter(character) {
|
|
52
|
+
return Boolean(character) && /\p{L}/u.test(character);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function isUnicodeNameContinueCharacter(character) {
|
|
56
|
+
return Boolean(character) && /[\p{L}\p{M}\p{Nd}]/u.test(character);
|
|
57
|
+
}
|
|
58
|
+
|
|
44
59
|
function isDigitCode(code) {
|
|
45
60
|
return code >= 48 && code <= 57;
|
|
46
61
|
}
|
|
@@ -53,13 +68,22 @@ function isNameContinueCode(code) {
|
|
|
53
68
|
return code === 95 || isAsciiLetterCode(code) || isDigitCode(code);
|
|
54
69
|
}
|
|
55
70
|
|
|
71
|
+
function isNameContinueCharacter(character) {
|
|
72
|
+
return Boolean(character) && (isNameContinueCode(character.charCodeAt(0)) ||
|
|
73
|
+
isUnicodeNameContinueCharacter(character));
|
|
74
|
+
}
|
|
56
75
|
|
|
57
|
-
function
|
|
58
|
-
|
|
76
|
+
function isVariableStartCharacter(character) {
|
|
77
|
+
if (!character) return false;
|
|
78
|
+
const code = character.charCodeAt(0);
|
|
79
|
+
return code === 95 || (code >= 65 && code <= 90) || isUnicodeUpperCharacter(character);
|
|
59
80
|
}
|
|
60
81
|
|
|
61
|
-
function
|
|
62
|
-
|
|
82
|
+
function isPlainAtomStartCharacter(character) {
|
|
83
|
+
if (!character) return false;
|
|
84
|
+
const code = character.charCodeAt(0);
|
|
85
|
+
return (code >= 97 && code <= 122) ||
|
|
86
|
+
(isUnicodeLetterCharacter(character) && !isUnicodeUpperCharacter(character));
|
|
63
87
|
}
|
|
64
88
|
|
|
65
89
|
const graphicAtomChars = '#$&*+-./<=>?@^~\\:';
|
|
@@ -161,6 +185,19 @@ function isGraphicAtomCode(code) {
|
|
|
161
185
|
return graphicAtomChars.includes(String.fromCharCode(code));
|
|
162
186
|
}
|
|
163
187
|
|
|
188
|
+
function isGraphicAtomCharacter(character) {
|
|
189
|
+
if (!character) return false;
|
|
190
|
+
const code = character.charCodeAt(0);
|
|
191
|
+
if (isGraphicAtomCode(code)) return true;
|
|
192
|
+
if (code <= 0x7f || isWhitespaceCharacter(character) ||
|
|
193
|
+
isUnicodeNameContinueCharacter(character)) return false;
|
|
194
|
+
// Non-ASCII symbols/punctuation are EyeProlog extended graphic characters.
|
|
195
|
+
// Surrogate code units are kept together by the maximal-token scan, so a
|
|
196
|
+
// supplementary scalar remains one atom spelling even though source offsets
|
|
197
|
+
// are UTF-16 based.
|
|
198
|
+
return true;
|
|
199
|
+
}
|
|
200
|
+
|
|
164
201
|
function defineParserOperator(state, priority, specifier, name) {
|
|
165
202
|
const strength = operatorStrength(priority);
|
|
166
203
|
if (['xfx', 'xfy', 'yfx'].includes(specifier)) {
|
|
@@ -237,11 +274,10 @@ class Parser {
|
|
|
237
274
|
return this.parserFlagState.charConversions.get(character) ?? character;
|
|
238
275
|
}
|
|
239
276
|
rawPeek(offset = 0) {
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
return ch;
|
|
277
|
+
// The processor character set is an implementation-defined processor
|
|
278
|
+
// choice, shared by normal and strict profiles. Do not narrow it merely
|
|
279
|
+
// because ISO conformance checking is enabled (issue #67).
|
|
280
|
+
return this.source[this.pos + offset] ?? '';
|
|
245
281
|
}
|
|
246
282
|
rawTake() {
|
|
247
283
|
const ch = this.rawPeek();
|
|
@@ -367,7 +403,7 @@ class Parser {
|
|
|
367
403
|
while (true) {
|
|
368
404
|
while (this.rawPeek()) {
|
|
369
405
|
const ch = this.peek();
|
|
370
|
-
if (!
|
|
406
|
+
if (!isWhitespaceCharacter(ch)) break;
|
|
371
407
|
this.take();
|
|
372
408
|
}
|
|
373
409
|
if (this.peek() === '%') {
|
|
@@ -461,7 +497,7 @@ class Parser {
|
|
|
461
497
|
if (ch === '.' && !this.terminatingFullStop()) {
|
|
462
498
|
const start = this.pos;
|
|
463
499
|
this.take();
|
|
464
|
-
while (
|
|
500
|
+
while (isGraphicAtomCharacter(this.peek()) &&
|
|
465
501
|
!this.terminatingFullStop()) this.take();
|
|
466
502
|
return { type: TOK.ATOM, text: this.convertedSlice(start, this.pos), line };
|
|
467
503
|
}
|
|
@@ -627,25 +663,25 @@ class Parser {
|
|
|
627
663
|
return { type: TOK.NUMBER, text, line };
|
|
628
664
|
}
|
|
629
665
|
|
|
630
|
-
if (
|
|
666
|
+
if (isVariableStartCharacter(ch)) {
|
|
631
667
|
const start = this.pos;
|
|
632
668
|
this.take();
|
|
633
|
-
while (
|
|
669
|
+
while (isNameContinueCharacter(this.peek())) this.take();
|
|
634
670
|
const text = this.convertedSlice(start, this.pos);
|
|
635
671
|
return { type: TOK.VAR, text, line };
|
|
636
672
|
}
|
|
637
673
|
|
|
638
|
-
if (
|
|
674
|
+
if (isPlainAtomStartCharacter(ch)) {
|
|
639
675
|
const start = this.pos;
|
|
640
676
|
this.take();
|
|
641
|
-
while (
|
|
677
|
+
while (isNameContinueCharacter(this.peek())) this.take();
|
|
642
678
|
return { type: TOK.ATOM, text: this.convertedSlice(start, this.pos), line };
|
|
643
679
|
}
|
|
644
680
|
|
|
645
|
-
if (
|
|
681
|
+
if (isGraphicAtomCharacter(ch)) {
|
|
646
682
|
const start = this.pos;
|
|
647
683
|
this.take();
|
|
648
|
-
while (
|
|
684
|
+
while (isGraphicAtomCharacter(this.peek()) &&
|
|
649
685
|
!this.terminatingFullStop()) this.take();
|
|
650
686
|
return { type: TOK.ATOM, text: this.convertedSlice(start, this.pos), line };
|
|
651
687
|
}
|
package/src/term.js
CHANGED
|
@@ -664,6 +664,19 @@ export function variantTerms(left, leftEnv, right, rightEnv, pairs = new Map(),
|
|
|
664
664
|
return true;
|
|
665
665
|
}
|
|
666
666
|
|
|
667
|
+
|
|
668
|
+
function compareCharacterText(left, right) {
|
|
669
|
+
const a = Array.from(left);
|
|
670
|
+
const b = Array.from(right);
|
|
671
|
+
const length = Math.min(a.length, b.length);
|
|
672
|
+
for (let i = 0; i < length; i++) {
|
|
673
|
+
const ac = a[i].codePointAt(0);
|
|
674
|
+
const bc = b[i].codePointAt(0);
|
|
675
|
+
if (ac !== bc) return ac < bc ? -1 : 1;
|
|
676
|
+
}
|
|
677
|
+
return a.length < b.length ? -1 : a.length > b.length ? 1 : 0;
|
|
678
|
+
}
|
|
679
|
+
|
|
667
680
|
export function compareTerms(left, right, variableRanks = null) {
|
|
668
681
|
// ISO 7.2.1 deliberately leaves the order of distinct variables
|
|
669
682
|
// implementation dependent. Do not attach a permanent ordinal to a
|
|
@@ -703,9 +716,9 @@ function compareTermsWithRanks(left, right, variableRanks) {
|
|
|
703
716
|
const rightOrder = variableRank(right.name, variableRanks);
|
|
704
717
|
return leftOrder < rightOrder ? -1 : 1;
|
|
705
718
|
}
|
|
706
|
-
if (left.type === ATOM || left.type === STRING) return left.name
|
|
719
|
+
if (left.type === ATOM || left.type === STRING) return compareCharacterText(left.name, right.name);
|
|
707
720
|
if (left.arity !== right.arity) return left.arity < right.arity ? -1 : 1;
|
|
708
|
-
if (left.name !== right.name) return left.name
|
|
721
|
+
if (left.name !== right.name) return compareCharacterText(left.name, right.name);
|
|
709
722
|
for (let i = 0; i < left.arity; i++) {
|
|
710
723
|
const cmp = compareTermsWithRanks(left.args[i], right.args[i], variableRanks);
|
|
711
724
|
if (cmp) return cmp;
|
|
@@ -30,18 +30,18 @@ error-ordering alternative to an individual executable assertion.
|
|
|
30
30
|
|
|
31
31
|
| Standard area | Status | Current evidence |
|
|
32
32
|
| --- | --- | --- |
|
|
33
|
-
| Clause 6 — tokens, terms, lists, operators, quoted text | audit | Complete vendored WG17 syntax matrix, `lexical_and_curly_terms`, `scryer_lexical_terms`, operator suites, syntax-error cases, quoted-layout/escape error cases, writer/read-back regressions, and
|
|
33
|
+
| Clause 6 — tokens, terms, lists, operators, quoted text | audit | Complete vendored WG17 syntax matrix, `lexical_and_curly_terms`, `scryer_lexical_terms`, operator suites, syntax-error cases, quoted-layout/escape error cases, writer/read-back regressions, and Unicode-scalar PCS/collation boundary tests. The implementation-defined 6.5/6.6 character-model decisions are now closed; wider shall-by-shall lexical mapping remains open. |
|
|
34
34
|
| 7.1-7.3 — term types, term order, unification | audit | Standard-order, identity, finite-tree and occurs-check suites, Corrigendum 2 term predicates, plus strict checks for the required `variable < float < integer < atom < compound` type order, PCS-based atom collation, and the `max_arity=unbounded` compound-term model. |
|
|
35
35
|
| 7.4 — Prolog text and directives | audit | All Part 1 directive indicators are parsed; include/ensure-loaded/operator/flag/character-conversion behavior has executable coverage. Preparation-time `char_conversion/2` affects later unquoted source text and respects `char_conversion=off`. Strict preparation now enforces declaration-before-clause ordering for `dynamic/1`, `multifile/1`, and `discontiguous/1`, cross-text `multifile/1`, discontiguous clause grouping, empty declared procedures, include textual-replacement behavior, and one-time initialization per prepared program. The remaining shall-by-shall mapping is still open. |
|
|
36
36
|
| 7.5-7.6 — database and term/clause conversion | audit | Dynamic database and logical-update-view suites. Strict mode restores Part 1 private-static/public-dynamic `clause/2` access; focused strict checks now cover `current_predicate/1`, `clause/2`, `asserta/1`, `assertz/1`, `retract/1`, Corrigendum 2 `retractall/1`, and `abolish/1` errors plus empty-procedure lifetime. Runtime protection includes the solver-native conjunction control construct `','/2` and, following STC #56's accepted-direction action item, the source syntax functors `(:-)/1-2` for database modification/private access while leaving their call behavior distinct. The remaining clause-conversion shall-by-shall mapping is still open. |
|
|
37
37
|
| 7.7 — execution and backtracking | audit | Control/search suites. Strict mode disables EyeProlog automatic tabling, cycle guards, and recursive numeric shortcuts so core execution uses ordinary clause selection/backtracking. |
|
|
38
38
|
| 7.8 — control constructs and exceptions | audit | call, cut, conjunction, disjunction (including failed branches after callee-local cuts), if-then, catch/throw, renamed-copy tests. |
|
|
39
|
-
| 7.9 — expression evaluation | audit | Arithmetic/evaluation/error suites, including Corrigenda. Strict mode now
|
|
39
|
+
| 7.9 — expression evaluation | audit | Arithmetic/evaluation/error suites, including Corrigenda. Strict mode now pins direct-variable precedence, 7.9.2 non-evaluable `F/N` errors (including STC #69), arithmetic numeric/integer type errors, float-only rounding conversions, the Part 1 mixed integer/float comparison conversion rule, I->F overflow before floating evaluable functors (STC #42), explicit `exp/1`/power underflow, and prescribed negative/zero power errors before later conversion overflow. Unbounded integer powers/shifts no longer leak host `RangeError`; finite-host exhaustion is normalized to `resource_error(memory)` in line with the Part 1 resource-error note and STC #21. The remaining exceptional-value/error-precedence rows are still being exhaustively enumerated. |
|
|
40
40
|
| 7.10 — input/output concepts | audit | Stream, character/byte I/O, read/write options, operator-sensitive write-back, and Corrigendum 3 writer cases. The audit now also covers write-mode creation/truncation, append creation, repositioned overwrite, flushing, EOF actions, close/current-stream handling, strict stream-position terms, stream-property validation, stream-term requirements, text-vs-binary permission errors, and the prescribed `alias(A)` culprit for `open/4` alias collisions. The full option/mode cross-product is still being mapped. |
|
|
41
|
-
| 7.11 — flags | covered | The complete Part 1 flag set, selected defaults, standard value domains, changeability, `current_prolog_flag/2`, and `set_prolog_flag/2` error behavior have dedicated strict tests. EyeProlog selects `bounded=false` and `integer_rounding_function=toward_zero`; valid alternative values of those fixed flags reach `permission_error(modify,flag,...)`, while `max_integer` and `min_integer` have no current value. Strict mode excludes the EyeProlog `occurs_check` extension. |
|
|
41
|
+
| 7.11 — flags | covered | The complete Part 1 flag set, selected defaults, standard value domains, changeability, `current_prolog_flag/2`, and `set_prolog_flag/2` error behavior have dedicated strict tests. EyeProlog selects `bounded=false` and `integer_rounding_function=toward_zero`; valid alternative values of those fixed flags reach `permission_error(modify,flag,...)`, while `max_integer` and `min_integer` have no current value. STC #70 is recorded explicitly: EyeProlog has no separate finite procedure-arity ceiling, so the optional `max_procedure_arity` flag is absent while `max_arity` remains `unbounded`. Strict mode excludes the EyeProlog `occurs_check` extension. |
|
|
42
42
|
| 7.12 — errors | audit | ISO `error(Error, Context)` envelope, type/domain/permission/representation/evaluation/syntax/resource families and focused error cases. Exact ISO 8.14.1-8.14.4 error precedence is covered for `read_term/3`, `write_term/3`, `op/3`, and `current_op/3`; the continuing audit has corrected additional 8.11-8.13 stream/character/byte errors (including the complete `alias(A)` culprit for `open/4` alias collisions), Corrigendum 2 `keysort/2` errors, atomic-conversion list-shape precedence, `arg/3`, `atom_concat/3`, `sub_atom/5`, `char_conversion/2`, runtime control-construct/database protection, arithmetic culprit/precedence reporting, and host-resource normalization for unbounded term/integer operations. A complete one-row-per-prescribed-error ordering map remains open. |
|
|
43
43
|
| 8.2-8.17 — built-in predicates | audit | Predicate-family coverage is mapped in ISO-MATRIX.md; Corrigendum 2 additions (`subsumes_term/2`, `term_variables/2`, `call/2..8`, `false/0`) are in the strict registry. The audit now includes corrected `keysort/2` variable/non-pair errors, stricter 8.11-8.13 stream and character/byte modes/errors, the 8.14 option/error-order subfamily, closed 8.17 flags, additional prescribed precedence for `arg/3`, `atom_concat/3`, `sub_atom/5`, number/atom list conversions, and `char_conversion/2`, plus finite-host resource handling for unbounded `functor/3` construction. The remaining mode/error matrix is not yet one-row-per-standard-row. |
|
|
44
|
-
| Clause 9 — evaluable functors | audit | Integer/float/rounding/transcendental/bitwise suites and corrigendum cases. Strict mode excludes the EyeProlog-only evaluable atom `e`, retains Corrigendum 2 arithmetic additions, reports unknown zero-arity evaluables with the required `F/0` culprit shape,
|
|
44
|
+
| Clause 9 — evaluable functors | audit | Integer/float/rounding/transcendental/bitwise suites and corrigendum cases. Strict mode excludes the EyeProlog-only evaluable atom `e`, retains Corrigendum 2 arithmetic additions, reports unknown zero-arity evaluables with the required `F/0` culprit shape, distinguishes non-evaluable `F/N` errors from numeric/integer operand errors per 7.9.2 and STC #69, and enforces float-only rounding modes, performs I->F conversion before floating functors (including overflow), reports the explicit `exp/1`, `**/2`, and Corrigendum 2 `^/2` underflow conditions, preserves the power-specific undefined conditions ahead of conversion overflow, and uses the Part 1 integer-to-float rule for mixed arithmetic comparisons. Normal mode retains EyeProlog's exact mixed-type comparison and round-to-zero arithmetic behavior as extensions. Unbounded BigInt resource exhaustion is translated into the Prolog error model rather than leaking host exceptions. Host floating-point representation choices remain documented implementation-defined behavior; the remaining exceptional-value rows are still under audit. |
|
|
45
45
|
| Corrigendum 1 | covered | Double-quoted atom/operator-priority corrections have dedicated cases. |
|
|
46
46
|
| Corrigendum 2 | covered | Added predicates/functors, catch corrections, bar/operator and uninstantiation corrections have dedicated cases. |
|
|
47
47
|
| Corrigendum 3 | covered | Writer options, `variable_names/1`, canonical list output and negative-power corrections have dedicated cases. |
|
|
@@ -59,15 +59,16 @@ conformance claims:
|
|
|
59
59
|
when the `char_conversion` flag is `on`, leaves quoted characters unchanged,
|
|
60
60
|
and feeds the same mapping into execution-time term input.
|
|
61
61
|
|
|
62
|
-
A follow-on audit
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
62
|
+
A follow-on audit made the processor-character-set/collation choices explicit.
|
|
63
|
+
Issue #67 then corrected an over-strict interpretation: because PCS membership
|
|
64
|
+
and extended-character classification are implementation defined by Part 1,
|
|
65
|
+
`--iso-strict` must not replace EyeProlog's ordinary processor choice. Both
|
|
66
|
+
profiles now use Unicode scalar values as PCS members and collating integers;
|
|
67
|
+
Unicode letters/white-space/graphics receive documented extended lexical
|
|
68
|
+
classes, while surrogates and values above U+10FFFF remain representation
|
|
69
|
+
errors. Strict mode continues to reject implementation-specific facilities
|
|
70
|
+
without changing these implementation-defined character choices. The complete
|
|
71
|
+
WG17 syntax matrix remains a release gate.
|
|
71
72
|
|
|
72
73
|
|
|
73
74
|
The subsequent arity audit originally selected a finite `max_arity=65535`, but
|
|
@@ -137,6 +138,19 @@ its exact cross-type comparison as an extension. Dedicated strict regressions
|
|
|
137
138
|
cover these distinctions without changing the normal-profile arithmetic error
|
|
138
139
|
contract.
|
|
139
140
|
|
|
141
|
+
A further Clause 9 pass closes the floating conversion and exceptional-value
|
|
142
|
+
boundary exposed by unbounded integers. Strict floating evaluable functors now
|
|
143
|
+
perform the required integer-to-float conversion before invoking the host math
|
|
144
|
+
operation, so an integer outside the selected finite binary64 range reports
|
|
145
|
+
`evaluation_error(float_overflow)` rather than producing a secondary host-math
|
|
146
|
+
result. The explicit underflow clauses for `exp/1`, Part 1 `**/2`, and
|
|
147
|
+
Corrigendum 2 `^/2` are enforced even though EyeProlog retains the
|
|
148
|
+
implementation-defined `round(x)` choice for generic `resultF` arithmetic. The
|
|
149
|
+
power audit also preserves the specified negative-base and zero/negative
|
|
150
|
+
exception conditions before any later I->F overflow, including Corrigendum 3's
|
|
151
|
+
correction to the `**/2` operand wording and Corrigendum 2's distinct rule that
|
|
152
|
+
`^/2` may accept an integer-valued float exponent.
|
|
153
|
+
|
|
140
154
|
## Post-Corrigendum STC cross-check
|
|
141
155
|
|
|
142
156
|
The public WG17 STC draft is tracked as useful defect-discovery material, but it
|
|
@@ -28,12 +28,12 @@ Status values are:
|
|
|
28
28
|
| Clause | Decision completed by ISO 5.4 documentation | EyeProlog choice | Status / implementation evidence |
|
|
29
29
|
| --- | --- | --- | --- |
|
|
30
30
|
| 5.5.11 | Reserved atoms and the effect of instantiating a variable to one | EyeProlog reserves no Prolog atom under 5.5.11. Atoms with implementation-looking names remain ordinary terms unless a particular predicate interprets them. | **defined** — term representation and built-ins in `src/term.js`, `src/iso.js`. |
|
|
31
|
-
| 6.5 | Processor character set (PCS) |
|
|
32
|
-
| 6.5 | Classification of additional/extended PCS characters | Printable ASCII uses the lexical classes specified by Part 1.
|
|
33
|
-
| 6.6 | Collating-sequence integers |
|
|
34
|
-
| 6.6 | Collating values of control escapes and extended characters |
|
|
31
|
+
| 6.5 | Processor character set (PCS) | EyeProlog's PCS is the Unicode scalar repertoire U+0000..U+10FFFF excluding surrogates. This implementation-defined processor choice is shared by normal and `--iso-strict` modes; strict conformance does not narrow it. | **defined** — `src/iso-character.js`, parser/character-I/O validation, and strict-core/WG17 coverage. |
|
|
32
|
+
| 6.5 | Classification of additional/extended PCS characters | Printable ASCII uses the lexical classes specified by Part 1. C0 controls and DEL are extended layout characters. Non-ASCII Unicode letters extend alphanumeric name syntax; Unicode white-space is layout; remaining non-ASCII symbols/punctuation are extended graphic characters. | **defined** — `src/parser.js`, `src/syntax-scan.js`, `src/iso-character.js`. |
|
|
33
|
+
| 6.6 | Collating-sequence integers | Each PCS character's collating-sequence integer is its Unicode scalar value. Atom/functor comparison is lexicographic by those scalar integers, satisfying the required monotonic ASCII capital-letter, small-letter, and contiguous decimal-digit constraints while remaining well-defined for supplementary characters. | **defined** — `src/iso-character.js`, `src/term.js` (`compareTerms`), `src/iso.js` character-code predicates. |
|
|
34
|
+
| 6.6 | Collating values of control escapes and extended characters | Control escapes, octal/hexadecimal escapes, character-code constants, and extended Unicode characters all use the denoted Unicode scalar value as collating integer. | **defined** — `src/iso-character.js`, parser escape handling, `char_code/2`, `atom_codes/2`, and WG17 escape cases. |
|
|
35
35
|
| 7.1.2.2 | Mapping between a character code and bytes | Text file streams decode and encode UTF-8. Binary streams expose bytes 0..255 directly. | **defined** — `src/io.js`. |
|
|
36
|
-
| 7.1.4.1 | Set `C` of characters represented by one-char atoms | In
|
|
36
|
+
| 7.1.4.1 | Set `C` of characters represented by one-char atoms | In both profiles `C` is the Unicode scalar repertoire U+0000..U+10FFFF excluding surrogates. | **defined** — `src/iso-character.js`, `src/iso.js` character-code validation. |
|
|
37
37
|
| 7.4.2.4 | Whether `op/3` directives affect other Prolog texts or execution | An `op/3` directive changes parsing of subsequent text loaded into the same `Program`; the resulting operator table is also used by execution-time term I/O. Separately created `Program` objects are independent. | **defined** — `src/parser.js`, `src/program.js`, `src/iso.js`. |
|
|
38
38
|
| 7.4.2.5 | Whether directive-created `Convc` affects other text/execution | Yes. A `char_conversion/2` directive updates preparation-time conversion for later unquoted source characters and the recorded mapping initializes execution-time term input. Quoted characters are not converted; `char_conversion=off` disables following preparation-time conversion. | **defined** — `src/parser.js`, `src/program.js`, `src/solver.js`; strict-core regression coverage. |
|
|
39
39
|
| 7.4.2.6 | Order of `initialization/1` goals | Initialization goals run once per prepared `Program`, in source/inclusion order, before requested goals; each must obtain a first solution. Reusing the same prepared program in another solver does not execute its initialization goals again. | **defined** — `Program.initializations`, preparation state, `Solver.runInitializations()`. |
|
|
@@ -68,12 +68,12 @@ Status values are:
|
|
|
68
68
|
| 7.11.2.3 | Default `max_arity` | `unbounded`: EyeProlog imposes no fixed semantic ceiling on compound-term arity. Practical host allocation exhaustion is a resource condition. This flag is distinct from any potential implementation-specific procedure-arity limit; EyeProlog currently declares no separate finite procedure limit. | **defined** — `src/iso-limits.js`, `src/solver.js`, `src/parser.js`, `src/iso.js`; issue #66 regression coverage. |
|
|
69
69
|
| 7.11.2.5 | Default `double_quotes` | `chars`. | **defined** — `src/solver.js`, parser flag state. |
|
|
70
70
|
| 7.12.1 | Second argument of `error/2` | The default context term is the atom `eyeprolog`. A few implementation-specific diagnostics may deliberately supply a more specific context term. | **defined** — `formalErrorTerm()` in `src/iso.js`. |
|
|
71
|
-
| 7.12.2(f) | Implementation-defined representation limits |
|
|
71
|
+
| 7.12.2(f) | Implementation-defined representation limits | Character and character-code operations are limited to Unicode scalar values; surrogates and values above U+10FFFF are representation errors. Arity/integer values are modeled as unbounded but may hit host/resource limits. Float input overflow uses the implementation-specific `max_float`/`min_float` representation names documented by the STC-oriented tests. | **defined** — parser/ISO numeric and character guards. |
|
|
72
72
|
| 8.17.1 | Implementation-defined flag value ranges | Strict mode exposes only Part 1 core flags and their standard value sets. Normal mode additionally exposes EyeProlog's `occurs_check` flag. With `bounded=false`, `max_integer` and `min_integer` have no current or selectable value and their `current_prolog_flag/2` queries fail. Valid alternative values of fixed standard flags are distinguished from invalid values so `set_prolog_flag/2` reports permission versus domain errors as prescribed. | **defined** — strict registry/flag filtering in `src/solver.js`; strict flag tests. |
|
|
73
73
|
| 8.17.3 | Other effects of `halt/0` | Terminates EyeProlog execution and returns host/process status `0`; it produces no Prolog solution. | **defined** — `HaltSignal`, `haltBuiltin()`, CLI/runner handling. |
|
|
74
74
|
| 8.17.4 | Meaning/effects of `halt(Status)` | Integer `Status` is converted to the host process/runner halt code; it produces no Prolog solution. | **defined** — `haltBuiltin()`, `src/execute.js`, `src/cli.js`. |
|
|
75
75
|
| 9.1.4.1 | Floating-point rounding function `rndF` | Floating values and operations use ECMAScript `Number` (IEEE-754 binary64) and the host's specified binary64 arithmetic/conversions. | **defined** — `src/iso-arithmetic.js`, `src/number-value.js`. |
|
|
76
|
-
| 9.1.4.2 | Floating-point result function
|
|
76
|
+
| 9.1.4.2 | Floating-point result function for operations whose result is governed only by `resultF` | EyeProlog chooses `round(x)` rather than the optional exceptional value `underflow`. ECMAScript binary64 arithmetic therefore preserves a representable subnormal result and rounds a still-smaller generic arithmetic result to `0.0`, consistently with float-token and `number_chars/2` input. This implementation-defined choice does not suppress the explicit mandatory underflow conditions stated separately for Part 1 `**/2`, `exp/1`, and Corrigendum 2 `^/2`. | **defined** — arithmetic evaluation in `src/iso-arithmetic.js` and parser/number conversion; strict exceptional-value regressions. |
|
|
77
77
|
| 9.1.4.3 | Approximate-addition function | ECMAScript binary64 addition is used; subtraction is implemented through the corresponding host operation and all finite results remain binary64 values. | **defined** — arithmetic evaluation in `src/iso-arithmetic.js`. |
|
|
78
78
|
| 9.4 | Representation of negative integers for bitwise operations | BigInt's unbounded signed binary semantics are used, equivalent to an infinite two's-complement sign extension for bitwise operations. | **defined** — `src/iso-arithmetic.js` BigInt bitwise operators. |
|
|
79
79
|
| 9.4.1 | Right shift of negative integers and unusual shift counts | `>>` is arithmetic/sign-propagating. A negative count reverses direction according to JavaScript BigInt shift semantics; there is no finite integer bit-size ceiling in the Prolog model. | **defined** — `a >> b` in `src/iso-arithmetic.js`. |
|
|
@@ -86,15 +86,20 @@ Status values are:
|
|
|
86
86
|
### Issue #56: one underflow policy
|
|
87
87
|
|
|
88
88
|
Clause 9.1.4.2 permits the processor to choose `round(x)` or the exceptional
|
|
89
|
-
value `underflow` for a tiny non-zero
|
|
90
|
-
`round(x)`. Because its
|
|
91
|
-
|
|
89
|
+
value `underflow` for a tiny non-zero result when an operation is governed by
|
|
90
|
+
the generic floating result function. EyeProlog chooses `round(x)`. Because its
|
|
91
|
+
floating-point profile is ECMAScript IEEE-754 binary64, representable
|
|
92
|
+
subnormal values remain non-zero and still-smaller generic results round to
|
|
92
93
|
`0.0`. Float-token and `number_chars/2` input use the same finite-double
|
|
93
|
-
rounding policy
|
|
94
|
-
`0.0` on input while rejected as an arithmetic result.
|
|
94
|
+
rounding policy.
|
|
95
95
|
|
|
96
|
-
|
|
97
|
-
|
|
96
|
+
That generic implementation-defined choice is distinct from evaluable functors
|
|
97
|
+
whose own error clauses prescribe underflow. In strict mode, `exp/1`, Part 1
|
|
98
|
+
`**/2`, and Corrigendum 2 `^/2` therefore raise
|
|
99
|
+
`evaluation_error(underflow)` when their mathematical non-zero result falls
|
|
100
|
+
below the representable range and the host would otherwise round it to zero.
|
|
101
|
+
The regression suite pins both sides of this boundary, while
|
|
102
|
+
`stc/float_underflow_input` covers the related input conversion policy.
|
|
98
103
|
|
|
99
104
|
## Implementation-specific features required to be documented by 5.4
|
|
100
105
|
|
|
@@ -105,7 +110,7 @@ families; `--iso-strict` is intended to remove their Part 1 interpretation.
|
|
|
105
110
|
|
|
106
111
|
| Part 1 extension hook | EyeProlog normal-profile feature | Strict-core disposition |
|
|
107
112
|
| --- | --- | --- |
|
|
108
|
-
| 5.5.1 Syntax | Part 2 modules, Part 3 grammar-rule expansion, embedded quad syntax
|
|
113
|
+
| 5.5.1 Syntax | Part 2 modules, Part 3 grammar-rule expansion, and embedded quad syntax | Module directives are rejected; grammar rules remain ordinary `-->/2` terms rather than being expanded; quad syntax is rejected. Unicode PCS membership/classification is implementation defined and therefore shared with normal mode rather than treated as an extension. |
|
|
109
114
|
| 5.5.2 Predefined operators | Part 3 `|` and EyeProlog's labelable infix `(?-)/2`; CLP(Z) operators when that library is imported | Only the Part 1 operator table is predefined; a conforming `op/3` may still add permitted operators. |
|
|
110
115
|
| 5.5.3 Character-conversion mapping | No non-identity initial `Convc` extension | Identity initial mapping. |
|
|
111
116
|
| 5.5.4 Types | No additional runtime Prolog term type is exposed by the core solver | Only variable, integer, float, atom, and compound term ordering participates in strict mode. |
|
|
@@ -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,
|
|
11
|
+
| Clause 6 lexical and term syntax | tokenizer, operator parser, lists, curly terms, quotes, numeric syntax, comments, Unicode-scalar PCS/collation | `scryer_lexical_terms`, `lexical_and_curly_terms`, `double_quoted_lists`, `corrigendum1_double_quote_operator`, `wg17_syntax_high_risk`, `wg17_invalid_octal_escape`, `wg17_unterminated_quoted_token`, `wg17_literal_newline_in_quote`, `wg17_non_iso_escape`, strict PCS/collation tests in `run-iso-strict.mjs`, 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, Corrigendum 2 `keysort/2` variable/non-pair errors, and strict `arg/3`, `functor/3` / `=../2` error-order plus unbounded-arity/resource checks |
|
|
@@ -18,7 +18,7 @@ compliance audit and the remaining work before a full conformance claim.
|
|
|
18
18
|
| 8.15 logic and control | negation, once, repeat, `call/2` through `call/8`, `false/0` | `logtalk_once`, `corrigenda_call_closure`, `false_builtin`, plus strict Corrigendum 2 resulting-goal `max_arity` error coverage |
|
|
19
19
|
| 8.16 atomic processing | atoms, characters, codes and number conversion with prescribed errors | `atomic_term_processing`, focused forward/reverse cases, parenthesized-number rejection, Logtalk-derived error cases, strict Corrigendum 2 partial/improper-list precedence for atom/number conversions, and prescribed `atom_concat/3` / `sub_atom/5` ordering checks |
|
|
20
20
|
| 8.17 flags and hooks | complete required Part 1 flag set, selected defaults, standard value domains/changeability, halt and character conversion | `exceptions_and_flags`, `remaining_builtins_and_directives`, flag error cases, strict `char_conversion/2` precedence, and the complete strict flag audit in `run-iso-strict.mjs` |
|
|
21
|
-
| Clause 9 evaluable functors | integer, float, rounding, transcendental and bitwise operations | `arithmetic`, `corrigenda_arithmetic`, `corrigenda_atan2_zero`, `corrigenda_integer_negative_power`, strict exclusion of the normal-mode `e` evaluable extension, zero-arity unknown-evaluable checks, prescribed operand/type and
|
|
21
|
+
| Clause 9 evaluable functors | integer, float, rounding, transcendental and bitwise operations | `arithmetic`, `corrigenda_arithmetic`, `corrigenda_atan2_zero`, `corrigenda_integer_negative_power`, strict exclusion of the normal-mode `e` evaluable extension, zero-arity unknown-evaluable checks, prescribed operand/type and power-error precedence, float-only rounding modes, I->F overflow before floating functors, explicit `exp/1`/`**/2`/`^/2` underflow, Part 1 mixed integer/float comparison conversion, and resource-error normalization for finite-host exhaustion of unbounded integer operations |
|
|
22
22
|
| Module compatibility profile (related to ISO/IEC 13211-2 and later WG17 amendment work) | module declarations, exports, imports, qualification, meta-predicate context | `modules/qualified_call`, `modules/selective_library_import`, `dcg_module_nonterminal_indicator` |
|
|
23
23
|
| Part 3-oriented DCG compatibility profile | `-->`, terminal and partial sequences, grammar control constructs, semicontexts, nonterminal indicators, modules, `phrase/2-3`, steadfastness and errors | `dcg_terminals_and_remainder`, `dcg_control_constructs`, `dcg_partial_sequences`, `dcg_phrase_steadfastness`, `dcg_dynamic_nonterminal_indicator`, `logtalk_dcg_phrase_identity`, `logtalk_dcg_semicontexts`, DCG error and precedence cases |
|
|
24
24
|
|
|
@@ -33,7 +33,8 @@ clause-by-clause in [ISO-IMPLEMENTATION-DEFINED.md](ISO-IMPLEMENTATION-DEFINED.m
|
|
|
33
33
|
with *The Art of EyeProlog* remaining the implementation reference. In
|
|
34
34
|
particular, the index records the unbounded integer model, `double_quotes=chars`,
|
|
35
35
|
`//` rounding toward zero, the ECMAScript binary64 float policy (including the
|
|
36
|
-
9.1.4.2 choice to round tiny
|
|
36
|
+
9.1.4.2 choice to round generic tiny results while retaining explicit
|
|
37
|
+
functor-specific underflow errors),
|
|
37
38
|
stream/character decisions, and the normal-profile extension boundary.
|
|
38
39
|
|
|
39
40
|
This is an executable conformance/compatibility matrix, not a certification issued by an
|
|
@@ -29,10 +29,10 @@ identify standards-derived behavior; other directories cover EyeProlog host
|
|
|
29
29
|
contracts and extensions. EyeProlog-only execution features such as automatic
|
|
30
30
|
tabling and `tnot/1` well-founded negation are outside the Part 1 strict-core
|
|
31
31
|
claim. Their focused semantic coverage lives primarily in regression tests;
|
|
32
|
-
`tnot/1` is absent from the strict ISO registry. The
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
`tnot/1` is absent from the strict ISO registry. The processor character set is documented as the Unicode scalar repertoire with
|
|
33
|
+
scalar-value collation in both normal and strict profiles; `--iso-strict`
|
|
34
|
+
therefore changes only implementation-specific language facilities, not this
|
|
35
|
+
implementation-defined processor choice.
|
|
36
36
|
|
|
37
37
|
All conformance files live under topic directories such as `arithmetic/`, `lists/`, `syntax/`, or `variables/`; new top-level numbered files should not be added. The report uses those directories as coverage categories.
|
|
38
38
|
|
|
@@ -17,20 +17,27 @@ regressions.
|
|
|
17
17
|
|
|
18
18
|
| STC item | Topic | EyeProlog evidence / finding |
|
|
19
19
|
| --- | --- | --- |
|
|
20
|
+
| [#17](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#17) | expression-error overlap | The strict suite pins both `X is 1/0+_` and `X is _+1/0` to `instantiation_error`, so the direct-variable rule is not masked by implementation evaluation order or a zero-divisor on the other operand. |
|
|
20
21
|
| [#18](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#18) | `eof_action(error)` | Stream regressions verify the first EOF observation yields the EOF value and a subsequent read with `eof_action(error)` raises `permission_error(input,past_end_of_stream,...)`; `eof_code` and `reset` remain distinct. |
|
|
21
22
|
| [#21](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#21) | unbounded-integer resource exhaustion | The strict suite now prevents host `RangeError` leakage from oversized integer shifts/powers and reports `resource_error(memory)`, consistent with the Part 1 resource-error note and the STC correction proposal. The same principle is used when unbounded `functor/3` construction exhausts a finite host resource. |
|
|
22
23
|
| [#27](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#27)-[#29](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#29) | overlapping character/code/byte stream errors | Existing stream tests plus strict probes preserve argument validation before later stream-state errors where the published error clauses require it; the STC examples with an open alias produce the stated instantiation/type errors. |
|
|
24
|
+
| [#32](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#32) | `number_chars/2` declarative/procedural wording | The strict suite follows the published procedural number-syntax path: `number_chars(N,['0','1'])` succeeds with `N = 1`. This records the executable behavior without treating the draft wording proposal as a new normative clause. |
|
|
23
25
|
| [#37](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#37) | `clause/2` variable identity | `stc/clause_variable_identity` verifies sharing between head and body is preserved. |
|
|
24
26
|
| [#39](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#39) | negative-number syntax | Covered extensively by the upstream-first WG17 syntax matrix; unary-minus read-back discrepancies found by that matrix were fixed in v1.3.27. |
|
|
25
27
|
| [#40](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#40) | inexact float representation | EyeProlog uses the host IEEE-754 binary64 value and requires written floats to read back to that same value. Input underflow is covered by `stc/float_underflow_input`. |
|
|
26
|
-
| [#
|
|
28
|
+
| [#41](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#41) | preparation-time `op/3` ordering | A strict parser regression verifies an `op/3` directive affects following text and cannot retroactively make preceding text parse with the new operator. The same preparation machinery is used for `set_prolog_flag/2`. |
|
|
29
|
+
| [#42](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#42) | integer-to-float conversion for float functions | `stc/integer_to_float_evaluable` verifies an integer expression is accepted by `sin/1` and produces a float. The strict suite additionally verifies that an unbounded integer outside the finite binary64 range raises `evaluation_error(float_overflow)` during I->F conversion before `sin/1`, `cos/1`, `atan/1`, the Corrigendum 2 inverse/trigonometric additions, `exp/1`, `log/1`, `sqrt/1`, or `float/1` can observe a host infinity. |
|
|
27
30
|
| [#44](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#44) | `char_code/2` error classification | Strict coverage distinguishes `type_error(integer,Code)` for a non-integer code from `representation_error(character_code)` for an integer outside the character-code set. |
|
|
31
|
+
| [#48](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#48) | `read_term/3` option wording with `variables([])` | The strict suite verifies `read_term(T,[variables([])])` on input `T.` has no solution because the actual variable list cannot unify with `[]`; this keeps the operational option semantics clear despite the draft's wording concern. |
|
|
28
32
|
| [#49](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#49) | `read_term/3` and EOF | Covered by strict reader/conformance tests and the interactive-read regressions. |
|
|
29
33
|
| [#50](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#50) | mixed integer/float arithmetic comparison | The STC-facing normal-profile case requires exact cross-type ordering and `max/2`/`min/2` use the same comparison. `--iso-strict` deliberately retains the published Part 1 integer-to-float comparison rule; the draft case is not silently substituted for that normative baseline. |
|
|
30
34
|
| [#55](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#55) | integer rounding function | Existing flag conformance verifies `integer_rounding_function = toward_zero`. |
|
|
31
35
|
| [#56](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#56) | protect `(:-)/1` and `(:-)/2` from database modification | **Found a gap during the #65 audit.** Strict database operations now treat both functors as static/private for `assert*`, `retract*`, `abolish/1`, declarations, and `clause/2`, while ordinary calls still follow the separate procedure-existence behavior described by the STC item. |
|
|
32
36
|
| [#58](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#58) | `set_prolog_flag/2` instantiation error | Existing strict/error coverage requires an instantiation error when a required flag value is a variable. |
|
|
33
37
|
| [#67](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#67) | `bagof/3` answer-order example | `stc/bagof_answer_order` verifies the proposed clarifying example produces `[2,1]`. |
|
|
38
|
+
| [#68](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#68) | division examples | Existing arithmetic coverage evaluates signed integer `/` through the floating operation; no implementation-defined signed-division result is used. |
|
|
39
|
+
| [#69](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#69) | arithmetic example culprit | **Found a #65 gap.** Strict expression evaluation now applies 7.9.2(c) to an atomic subexpression such as `foo`: it reports `type_error(evaluable,foo/0)` rather than the misleading `type_error(number,foo)` shown by the old 9.1.7 example. |
|
|
40
|
+
| [#70](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#70) | optional `max_procedure_arity` | Reviewed after issue #66 corrected the earlier #71 pointer. EyeProlog has no declared procedure-arity limit smaller than its `max_arity=unbounded` term model, so the implementation-defined optional flag is intentionally absent. |
|
|
34
41
|
| [#73](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/stc#73) | float-reading limits discussed from issue #54 | Positive/negative literal and `number_chars/2` overflow are kept as explicit draft cases; underflow is tested separately. See the note below. |
|
|
35
42
|
|
|
36
43
|
## Float-reading note for #73
|
package/test/run-iso-strict.mjs
CHANGED
|
@@ -99,6 +99,14 @@ export function runIsoStrict(reporter = new TestReporter()) {
|
|
|
99
99
|
1, 'large nonexistent predicate indicator');
|
|
100
100
|
});
|
|
101
101
|
|
|
102
|
+
reporter.test('does not invent max_procedure_arity without a separate procedure ceiling', () => {
|
|
103
|
+
// STC #70 makes max_procedure_arity implementation defined and needed
|
|
104
|
+
// only when a processor has a smaller procedure-arity ceiling. EyeProlog
|
|
105
|
+
// has no such separate declared ceiling, so the optional flag is absent.
|
|
106
|
+
equal(capture(() => run('', { isoStrict: true, goal: 'current_prolog_flag(max_procedure_arity,_)' })).formal,
|
|
107
|
+
'domain_error(prolog_flag)', 'STC #70 optional flag absent');
|
|
108
|
+
});
|
|
109
|
+
|
|
102
110
|
reporter.test('preparation-time char_conversion affects later unquoted source only', () => {
|
|
103
111
|
const program = Program.parse(
|
|
104
112
|
":- char_conversion(x,y).\np(x).\nquoted('x').\n:- set_prolog_flag(char_conversion,off).\nraw(x).\n",
|
|
@@ -110,18 +118,19 @@ export function runIsoStrict(reporter = new TestReporter()) {
|
|
|
110
118
|
});
|
|
111
119
|
|
|
112
120
|
|
|
113
|
-
reporter.test('uses
|
|
121
|
+
reporter.test('uses the implementation-defined Unicode scalar PCS and collation', () => {
|
|
114
122
|
const program = Program.parse('', { isoStrict: true });
|
|
115
123
|
const solver = new Solver(program, { isoStrict: true });
|
|
116
124
|
const answers = (text) => [...solver.solve([parseGoalText(text, { isoStrict: true })], new Env(), 0)].length;
|
|
117
125
|
equal(answers("char_code('\\0\\',0)"), 1, 'NUL collating integer');
|
|
118
126
|
equal(answers("char_code('A',65)"), 1, 'A collating integer');
|
|
119
|
-
equal(answers("char_code('
|
|
127
|
+
equal(answers("char_code('ä',228)"), 1, 'extended Latin character');
|
|
128
|
+
equal(answers("char_code('😀',128512)"), 1, 'supplementary Unicode scalar');
|
|
120
129
|
equal(answers("'\\0\\' @< 'A'"), 1, 'control before capital');
|
|
121
130
|
equal(answers("'A' @< 'a'"), 1, 'capital before small letter');
|
|
131
|
+
equal(answers("'\\xe000\\' @< '\\x10000\\'"), 1, 'atom order follows scalar collating integers');
|
|
122
132
|
});
|
|
123
133
|
|
|
124
|
-
|
|
125
134
|
reporter.test('follows the Part 1 standard term-type and atom ordering', () => {
|
|
126
135
|
const program = Program.parse('', { isoStrict: true });
|
|
127
136
|
const solver = new Solver(program, { isoStrict: true });
|
|
@@ -134,30 +143,38 @@ export function runIsoStrict(reporter = new TestReporter()) {
|
|
|
134
143
|
equal(answers("'A' @< 'B'"), 1, 'atom collation');
|
|
135
144
|
});
|
|
136
145
|
|
|
137
|
-
reporter.test('
|
|
138
|
-
const
|
|
139
|
-
equal(
|
|
146
|
+
reporter.test('does not narrow implementation-defined character choices in strict mode', () => {
|
|
147
|
+
const program = Program.parse("p('é').\nä.\n", { isoStrict: true });
|
|
148
|
+
equal(Boolean(program.findGroup('p', 1)), true, 'quoted extended character in source');
|
|
149
|
+
equal(Boolean(program.findGroup('ä', 0)), true, 'extended small-letter atom in source');
|
|
140
150
|
|
|
141
|
-
const
|
|
151
|
+
const readResult = run('', {
|
|
142
152
|
isoStrict: true,
|
|
143
|
-
goal:
|
|
153
|
+
goal: "read('é')",
|
|
144
154
|
ioOptions: { input: "'é'." },
|
|
145
|
-
})
|
|
146
|
-
equal(
|
|
155
|
+
});
|
|
156
|
+
equal(readResult.stats.completed_goal_lists, 1, 'extended character through strict text input');
|
|
157
|
+
|
|
158
|
+
const written = run('', { isoStrict: true, goal: 'writeq("ä")' });
|
|
159
|
+
includes(written.stdout, 'ä', 'issue #67 writeq example');
|
|
147
160
|
});
|
|
148
161
|
|
|
149
|
-
reporter.test('restricts
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
162
|
+
reporter.test('restricts character codes only to the Unicode scalar PCS boundary', () => {
|
|
163
|
+
equal(run('', { isoStrict: true, goal: 'char_code(_,128)' }).stats.completed_goal_lists, 1,
|
|
164
|
+
'code 128 is a PCS member');
|
|
165
|
+
equal(capture(() => run('', { isoStrict: true, goal: 'char_code(_,55296)' })).formal,
|
|
166
|
+
'representation_error(character_code)', 'surrogate is not a scalar');
|
|
167
|
+
equal(capture(() => run('', { isoStrict: true, goal: 'atom_codes(_, [1114112])' })).formal,
|
|
168
|
+
'representation_error(character_code)', 'above Unicode scalar range');
|
|
169
|
+
equal(capture(() => run('', { isoStrict: true, goal: 'put_code(1114112)' })).formal,
|
|
170
|
+
'representation_error(character_code)', 'put_code/1 above scalar range');
|
|
156
171
|
});
|
|
157
172
|
|
|
158
|
-
reporter.test('
|
|
159
|
-
const
|
|
160
|
-
|
|
173
|
+
reporter.test('uses the same processor character repertoire in normal and strict profiles', () => {
|
|
174
|
+
const normal = run('', { goal: "char_code('é',233)" });
|
|
175
|
+
const strict = run('', { isoStrict: true, goal: "char_code('é',233)" });
|
|
176
|
+
equal(normal.stats.completed_goal_lists, 1, 'normal Unicode char_code/2');
|
|
177
|
+
equal(strict.stats.completed_goal_lists, 1, 'strict Unicode char_code/2');
|
|
161
178
|
});
|
|
162
179
|
|
|
163
180
|
reporter.test('keeps the strict write-option surface to Part 1 plus Corrigendum 3', () => {
|
|
@@ -282,11 +299,11 @@ export function runIsoStrict(reporter = new TestReporter()) {
|
|
|
282
299
|
|
|
283
300
|
reporter.test('follows Part 1 arithmetic type and exceptional errors', () => {
|
|
284
301
|
const cases = [
|
|
285
|
-
["X is '+'(foo,77)", 'type_error(
|
|
286
|
-
['X is mod(foo,77)', 'type_error(
|
|
302
|
+
["X is '+'(foo,77)", 'type_error(evaluable)', 'STC #69 simple arithmetic atom is foo/0'],
|
|
303
|
+
['X is mod(foo,77)', 'type_error(evaluable)', 'integer arithmetic atom is non-evaluable'],
|
|
287
304
|
['X is mod(7.5,2)', 'type_error(integer)', 'integer arithmetic numeric type'],
|
|
288
|
-
['X is truncate(foo)', 'type_error(
|
|
289
|
-
['X is sin(foo)', 'type_error(
|
|
305
|
+
['X is truncate(foo)', 'type_error(evaluable)', 'rounding atom is non-evaluable'],
|
|
306
|
+
['X is sin(foo)', 'type_error(evaluable)', 'transcendental atom is non-evaluable'],
|
|
290
307
|
['X is foo+Y', 'instantiation_error', 'direct variable before another operand error'],
|
|
291
308
|
['X is floor(7)', 'type_error(float)', 'floor integer operand'],
|
|
292
309
|
['X is truncate(7)', 'type_error(float)', 'truncate integer operand'],
|
|
@@ -300,6 +317,56 @@ export function runIsoStrict(reporter = new TestReporter()) {
|
|
|
300
317
|
}
|
|
301
318
|
});
|
|
302
319
|
|
|
320
|
+
reporter.test('uses the STC #69 evaluable culprit for atomic arithmetic expressions', () => {
|
|
321
|
+
const error = capture(() => run('', { isoStrict: true, goal: "X is '+'(foo,77)" }));
|
|
322
|
+
equal(error.formal, 'type_error(evaluable)', 'formal error');
|
|
323
|
+
includes(error.message, '/(foo, 0)', 'foo/0 culprit');
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
reporter.test('applies integer-to-float conversion before floating evaluable functors', () => {
|
|
327
|
+
const huge = `1${'0'.repeat(400)}`;
|
|
328
|
+
for (const functor of ['float', 'sin', 'cos', 'atan', 'asin', 'acos', 'tan', 'exp', 'log', 'sqrt']) {
|
|
329
|
+
equal(capture(() => run('', { isoStrict: true, goal: `X is ${functor}(${huge})` })).formal,
|
|
330
|
+
'evaluation_error(float_overflow)', `${functor}/1 integer-to-float overflow`);
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
reporter.test('reports explicit transcendental and power underflow in strict mode', () => {
|
|
335
|
+
for (const [goal, label] of [
|
|
336
|
+
['X is exp(-1000.0)', 'exp/1 underflow'],
|
|
337
|
+
['X is 2.0 ** -1075.0', '**/2 underflow'],
|
|
338
|
+
['X is 2.0 ^ -1075.0', 'Corrigendum 2 ^/2 underflow'],
|
|
339
|
+
]) {
|
|
340
|
+
equal(capture(() => run('', { isoStrict: true, goal })).formal,
|
|
341
|
+
'evaluation_error(underflow)', label);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
equal(run('', { isoStrict: true, goal: 'X is 0.0 ** 2.0' }).stats.completed_goal_lists,
|
|
345
|
+
1, 'exact zero power remains zero');
|
|
346
|
+
equal(run('', { isoStrict: true, goal: 'X is 4.9406564584124654e-324 * 0.5' }).stats.completed_goal_lists,
|
|
347
|
+
1, 'generic resultF retains the selected round-to-zero policy');
|
|
348
|
+
|
|
349
|
+
// Keep these stricter exceptional conditions confined to --iso-strict.
|
|
350
|
+
equal(run('', { goal: 'X is exp(-1000.0)' }).stats.completed_goal_lists, 1, 'normal exp behavior');
|
|
351
|
+
equal(run('', { goal: 'X is 2.0 ** -1075.0' }).stats.completed_goal_lists, 1, 'normal power behavior');
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
reporter.test('preserves prescribed power errors before integer-to-float conversion', () => {
|
|
355
|
+
const hugeNegative = `-1${'0'.repeat(400)}`;
|
|
356
|
+
equal(capture(() => run('', { isoStrict: true, goal: 'X is (-2) ** 2.0' })).formal,
|
|
357
|
+
'evaluation_error(undefined)', '**/2 negative base requires integer-typed exponent');
|
|
358
|
+
equal(run('', { isoStrict: true, goal: 'X is (-2.0) ** 2' }).stats.completed_goal_lists,
|
|
359
|
+
1, '**/2 negative base with integer exponent');
|
|
360
|
+
equal(run('', { isoStrict: true, goal: 'X is (-2) ^ 2.0' }).stats.completed_goal_lists,
|
|
361
|
+
1, 'Corrigendum 2 ^/2 accepts integer-valued float exponent');
|
|
362
|
+
equal(capture(() => run('', { isoStrict: true, goal: 'X is (-2) ^ 0.5' })).formal,
|
|
363
|
+
'evaluation_error(undefined)', 'Corrigendum 2 ^/2 fractional exponent');
|
|
364
|
+
equal(capture(() => run('', { isoStrict: true, goal: `X is ${hugeNegative} ** 0.5` })).formal,
|
|
365
|
+
'evaluation_error(undefined)', 'undefined power precedes base conversion overflow');
|
|
366
|
+
equal(capture(() => run('', { isoStrict: true, goal: `X is 0.0 ** (${hugeNegative})` })).formal,
|
|
367
|
+
'evaluation_error(undefined)', 'zero-negative power precedes exponent conversion overflow');
|
|
368
|
+
});
|
|
369
|
+
|
|
303
370
|
reporter.test('uses the Part 1 mixed arithmetic comparison operations', () => {
|
|
304
371
|
// 8.7 converts the integer operand to float in mixed comparisons.
|
|
305
372
|
equal(run('', { isoStrict: true, goal: '18014398509481985 =:= 18014398509481984.0' }).stats.completed_goal_lists,
|
|
@@ -362,8 +429,15 @@ export function runIsoStrict(reporter = new TestReporter()) {
|
|
|
362
429
|
});
|
|
363
430
|
|
|
364
431
|
reporter.test('pins applicable post-Corrigendum STC clarifications', () => {
|
|
432
|
+
equal(capture(() => run('', { isoStrict: true, goal: 'X is 1/0+_' })).formal,
|
|
433
|
+
'instantiation_error', 'STC 17 direct variable precedes zero divisor on the other branch');
|
|
434
|
+
equal(capture(() => run('', { isoStrict: true, goal: 'X is _+1/0' })).formal,
|
|
435
|
+
'instantiation_error', 'STC 17 is independent of operand order');
|
|
436
|
+
|
|
365
437
|
equal(run('', { isoStrict: true, goal: 'integer(- /**/ 1)' }).stats.completed_goal_lists,
|
|
366
438
|
1, 'layout between minus and integer token');
|
|
439
|
+
equal(run('', { isoStrict: true, goal: "number_chars(N,['0','1']),N=1" }).stats.completed_goal_lists,
|
|
440
|
+
1, 'STC 32 number_chars/2 follows the procedural number syntax for leading zero');
|
|
367
441
|
|
|
368
442
|
const shared = run(
|
|
369
443
|
':- dynamic(a/1).\na(X) :- b(X).\n',
|
|
@@ -387,7 +461,13 @@ export function runIsoStrict(reporter = new TestReporter()) {
|
|
|
387
461
|
|
|
388
462
|
Program.parse(':- op(500,xfx,foo).\na foo b.\n', { isoStrict: true });
|
|
389
463
|
const beforeDefinition = capture(() => Program.parse('a foo b.\n:- op(500,xfx,foo).\n', { isoStrict: true }));
|
|
390
|
-
includes(beforeDefinition.message, 'expected .', 'op/3 directive applies only to following text');
|
|
464
|
+
includes(beforeDefinition.message, 'expected .', 'STC 41 op/3 directive applies only to following text');
|
|
465
|
+
|
|
466
|
+
equal(run('', {
|
|
467
|
+
isoStrict: true,
|
|
468
|
+
goal: 'read_term(T,[variables([])])',
|
|
469
|
+
ioOptions: { input: 'T.' },
|
|
470
|
+
}).stats.completed_goal_lists, 0, 'STC 48 variables([]) does not match an input variable');
|
|
391
471
|
});
|
|
392
472
|
|
|
393
473
|
reporter.test('rejects EyeProlog module directives', () => {
|
package/the-art-of-eyeprolog.md
CHANGED
|
@@ -5119,12 +5119,11 @@ this part makes control, reflection, state, operators, and streams explicit.
|
|
|
5119
5119
|
For Part 1 portability work, EyeProlog also provides a strict core mode:
|
|
5120
5120
|
`--iso-strict` on the CLI or `isoStrict: true` in the JavaScript API restricts
|
|
5121
5121
|
the language/runtime surface to ISO/IEC 13211-1:1995 plus Technical Corrigenda
|
|
5122
|
-
1–3.
|
|
5123
|
-
|
|
5124
|
-
|
|
5125
|
-
|
|
5126
|
-
|
|
5127
|
-
extension. Isolated mode and error cases live in `test/conformance/cases/iso/`.
|
|
5122
|
+
1–3. The processor character set is an implementation-defined choice shared by
|
|
5123
|
+
normal and strict profiles: EyeProlog uses Unicode scalar values U+0000..U+10FFFF
|
|
5124
|
+
excluding surrogates, with the scalar value as the collating-sequence integer.
|
|
5125
|
+
Strict mode restricts implementation-specific language facilities, but it does
|
|
5126
|
+
not narrow this processor-defined character repertoire. Isolated mode and error cases live in `test/conformance/cases/iso/`.
|
|
5128
5127
|
The examples here compose those operations into programs worth changing and
|
|
5129
5128
|
rerunning.
|
|
5130
5129
|
|
|
@@ -5510,13 +5509,14 @@ lowercase ASCII letter. Variables begin with uppercase or underscore. The bare
|
|
|
5510
5509
|
ISO double-quoted-list notation. Integers, decimals, scientific notation,
|
|
5511
5510
|
binary/octal/hexadecimal integers, and character-code constants are accepted.
|
|
5512
5511
|
|
|
5513
|
-
|
|
5514
|
-
|
|
5515
|
-
|
|
5516
|
-
|
|
5517
|
-
|
|
5518
|
-
|
|
5519
|
-
|
|
5512
|
+
The processor character set is shared by normal and `--iso-strict` modes because
|
|
5513
|
+
Part 1 makes it implementation defined rather than an extension boundary.
|
|
5514
|
+
EyeProlog's PCS is the Unicode scalar repertoire. Printable ASCII keeps the Part
|
|
5515
|
+
1 lexical classes; Unicode letters extend alphanumeric name syntax, Unicode
|
|
5516
|
+
white-space characters are layout, and remaining non-ASCII symbols/punctuation
|
|
5517
|
+
are extended graphic characters. Character-code and collation values are the
|
|
5518
|
+
corresponding Unicode scalar integers. Quoting remains available for any atom
|
|
5519
|
+
spelling that should not depend on an extended lexical class:
|
|
5520
5520
|
|
|
5521
5521
|
```eyeprolog
|
|
5522
5522
|
|
|
@@ -6049,8 +6049,8 @@ quoted_atom("ab"). % quoted_atom(ab)
|
|
|
6049
6049
|
| `atom_length(+Atom,?Length)` | Counts Unicode code points, not UTF-16 code units. A supplied length must be a nonnegative integer. |
|
|
6050
6050
|
| `atom_concat(?Prefix,?Suffix,?Whole)` | Concatenates two atoms, removes a supplied prefix or suffix, or enumerates every split when only `Whole` is bound. At least `Whole`, or both parts, must determine the operation. |
|
|
6051
6051
|
| `sub_atom(+Atom,?Before,?Length,?After,?SubAtom)` | Enumerates substrings and their Unicode-code-point offsets. Supplied counts must be nonnegative integers. |
|
|
6052
|
-
| `atom_chars(?Atom,?Chars)`, `atom_codes(?Atom,?Codes)` | Convert between an atom and a proper list of one-character atoms or character codes.
|
|
6053
|
-
| `char_code(?Character,?Code)` | Converts one character atom and its collating/code value.
|
|
6052
|
+
| `atom_chars(?Atom,?Chars)`, `atom_codes(?Atom,?Codes)` | Convert between an atom and a proper list of one-character atoms or character codes. Both profiles use EyeProlog's Unicode scalar PCS/codes; surrogates and values above U+10FFFF are rejected. At least one side must be instantiated. |
|
|
6053
|
+
| `char_code(?Character,?Code)` | Converts one character atom and its collating/code value. Both profiles accept Unicode scalar codes and reject surrogates/out-of-range values. |
|
|
6054
6054
|
| `number_chars(?Number,?Chars)`, `number_codes(?Number,?Codes)` | Convert finite numbers to canonical text or parse a proper character/code list using ISO number and negative-number syntax, including radix integers, character-code constants, and leading layout. The input is not parsed as a general term: grouping such as `(0)` is a syntax error. At least one side must be instantiated; malformed numeric input raises *syntax_error(number)*. |
|
|
6055
6055
|
|
|
6056
6056
|
Conversions accept partial output lists when the atomic input is known, but
|
|
@@ -6091,12 +6091,12 @@ input or output.
|
|
|
6091
6091
|
| `at_end_of_stream`, `at_end_of_stream(+Stream)` | Succeeds when the current or selected input position is at or beyond its content. |
|
|
6092
6092
|
| `get_char(?Character)`, `get_char(+Stream,?Character)` | Reads one text character; end of input is `end_of_file`. |
|
|
6093
6093
|
| `peek_char(?Character)`, `peek_char(+Stream,?Character)` | Observes the next text character without advancing. |
|
|
6094
|
-
| `get_code(?Code)`, `get_code(+Stream,?Code)` | Reads a character code; end of input is `-1`.
|
|
6095
|
-
| `peek_code(?Code)`, `peek_code(+Stream,?Code)` | Observes the next character code without advancing
|
|
6094
|
+
| `get_code(?Code)`, `get_code(+Stream,?Code)` | Reads a character code; end of input is `-1`. Both profiles return codes from EyeProlog's Unicode scalar PCS. |
|
|
6095
|
+
| `peek_code(?Code)`, `peek_code(+Stream,?Code)` | Observes the next Unicode scalar character code without advancing. |
|
|
6096
6096
|
| `get_byte(?Byte)`, `get_byte(+Stream,?Byte)` | Reads one unit from a binary stream; end of input is `-1`. |
|
|
6097
6097
|
| `peek_byte(?Byte)`, `peek_byte(+Stream,?Byte)` | Observes the next binary unit without advancing. |
|
|
6098
6098
|
| `put_char(+Character)`, `put_char(+Stream,+Character)` | Writes one character atom to a text stream. |
|
|
6099
|
-
| `put_code(+Code)`, `put_code(+Stream,+Code)` | Writes one character code to a text stream.
|
|
6099
|
+
| `put_code(+Code)`, `put_code(+Stream,+Code)` | Writes one character code to a text stream. Both profiles accept Unicode scalar codes. |
|
|
6100
6100
|
| `put_byte(+Byte)`, `put_byte(+Stream,+Byte)` | Writes an integer in `0..255` to a binary stream. |
|
|
6101
6101
|
| `nl`, `nl(+Stream)` | Writes a newline to a text stream. |
|
|
6102
6102
|
|
package/why-eyeprolog.md
CHANGED
|
@@ -19,10 +19,11 @@ syntax.
|
|
|
19
19
|
|
|
20
20
|
EyeProlog targets the Part 1 core together with Technical Corrigenda 1, 2,
|
|
21
21
|
and 3, and provides documented module and definite-clause-grammar compatibility
|
|
22
|
-
profiles for normal-mode programs.
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
profiles for normal-mode programs. The processor character model is explicitly
|
|
23
|
+
implementation defined: EyeProlog uses Unicode scalar values as the PCS and as
|
|
24
|
+
collating-sequence integers in both normal and strict profiles. Strict mode
|
|
25
|
+
therefore rejects implementation-specific language extensions without changing
|
|
26
|
+
that processor choice. Its executable conformance matrix and tests
|
|
26
27
|
document the supported behavior, including an executable trace of the vendored
|
|
27
28
|
active WG17 syntax cases. This is extensive implementation evidence, not a
|
|
28
29
|
claim that every Part 1, Part 2, or Part 3 normative requirement has already
|