eyeprolog 1.3.43 → 1.3.45
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 +12 -0
- package/package.json +1 -1
- package/src/io.js +33 -10
- package/src/iso-arithmetic.js +12 -10
- package/src/iso.js +339 -116
- package/src/program.js +130 -19
- package/src/solver.js +8 -4
- package/test/conformance/ISO-COMPLIANCE.md +32 -6
- package/test/conformance/ISO-IMPLEMENTATION-DEFINED.md +5 -5
- package/test/conformance/ISO-MATRIX.md +4 -4
- package/test/conformance/README.md +3 -1
- package/test/conformance/expected-errors/iso/get_byte_text_stream.txt +1 -1
- package/test/conformance/expected-errors/iso/swipl_current_op_float_priority.txt +1 -1
- package/test/conformance/expected-errors/iso/swipl_current_op_priority_type.txt +1 -1
- package/test/conformance/expected-errors/iso/swipl_current_op_specifier_type.txt +1 -1
- package/test/run-iso-strict.mjs +106 -0
- package/the-art-of-eyeprolog.md +19 -4
package/README.md
CHANGED
|
@@ -218,6 +218,18 @@ raise representation errors in strict parsing and character operations. Normal
|
|
|
218
218
|
mode retains Unicode scalar character data as an implementation-specific
|
|
219
219
|
extension.
|
|
220
220
|
|
|
221
|
+
Strict term I/O likewise keeps the standardized option boundary: `read_term/2-3`
|
|
222
|
+
and `write_term/2-3` accept the Part 1 plus Corrigendum 3 options, while the
|
|
223
|
+
normal-profile `write_term(...,[double_quotes(...)])` option remains an
|
|
224
|
+
EyeProlog extension. The strict gate also checks the prescribed ISO error
|
|
225
|
+
precedence for `read_term/3`, `write_term/3`, `op/3`, and `current_op/3`, and
|
|
226
|
+
the complete Part 1 flag defaults/value domains/changeability rules. The
|
|
227
|
+
ongoing issue #65 audit additionally tightens Prolog-text declaration ordering,
|
|
228
|
+
initialization lifetime, stream/open/close behavior, character/byte stream
|
|
229
|
+
errors, `keysort/2` error cases, and strict arithmetic-extension boundaries.
|
|
230
|
+
Those additions improve the Part 1 surface without turning the remaining audit
|
|
231
|
+
rows into a blanket conformance claim.
|
|
232
|
+
|
|
221
233
|
The auditable processor-requirement checklist lives in
|
|
222
234
|
[`test/conformance/ISO-COMPLIANCE.md`](test/conformance/ISO-COMPLIANCE.md).
|
|
223
235
|
The ISO 5.4 implementation-defined/implementation-specific decision index is
|
package/package.json
CHANGED
package/src/io.js
CHANGED
|
@@ -88,8 +88,13 @@ export class StreamManager {
|
|
|
88
88
|
const raw = fs.readFileSync(path);
|
|
89
89
|
if (type === 'binary') content = raw;
|
|
90
90
|
else { content = decodeUtf8ForTextStream(raw); strictUtf8 = true; }
|
|
91
|
-
} else if (mode === '
|
|
92
|
-
|
|
91
|
+
} else if (mode === 'write') {
|
|
92
|
+
// ISO 7.10.1.1: opening an existing sink in write mode empties it,
|
|
93
|
+
// while a missing sink is created at open time (not deferred to close).
|
|
94
|
+
fs.writeFileSync(path, type === 'binary' ? BufferCtor.from([]) : '');
|
|
95
|
+
} else if (mode === 'append') {
|
|
96
|
+
if (fs.existsSync(path)) content = fs.readFileSync(path, type === 'binary' ? null : 'utf8');
|
|
97
|
+
else fs.writeFileSync(path, type === 'binary' ? BufferCtor.from([]) : '');
|
|
93
98
|
}
|
|
94
99
|
if (BufferCtor?.isBuffer(content)) content = [...content];
|
|
95
100
|
return this.add({
|
|
@@ -100,13 +105,18 @@ export class StreamManager {
|
|
|
100
105
|
pastEnd: false,
|
|
101
106
|
});
|
|
102
107
|
}
|
|
103
|
-
|
|
104
|
-
if (!stream.standard
|
|
105
|
-
|
|
106
|
-
|
|
108
|
+
flush(stream) {
|
|
109
|
+
if (!stream || stream.standard || stream.mode === 'read') return;
|
|
110
|
+
fs.writeFileSync(stream.path, stream.type === 'binary' ? BufferCtor.from(stream.content) : stream.content);
|
|
111
|
+
}
|
|
112
|
+
discard(stream) {
|
|
107
113
|
if (stream.alias) this.aliases.delete(stream.alias);
|
|
108
114
|
this.streams.delete(stream.id);
|
|
109
115
|
}
|
|
116
|
+
close(stream) {
|
|
117
|
+
this.flush(stream);
|
|
118
|
+
this.discard(stream);
|
|
119
|
+
}
|
|
110
120
|
readUnit(stream, peek = false) {
|
|
111
121
|
if (stream.position >= stream.content.length) return null;
|
|
112
122
|
if (stream.type === 'binary') {
|
|
@@ -126,9 +136,22 @@ export class StreamManager {
|
|
|
126
136
|
return value;
|
|
127
137
|
}
|
|
128
138
|
writeUnit(stream, value) {
|
|
129
|
-
if (stream.standard && stream.write)
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
139
|
+
if (stream.standard && stream.write) {
|
|
140
|
+
stream.write(String(value));
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
// 7.10.2.8: output after repositioning overwrites the existing sink
|
|
144
|
+
// contents at the selected stream position rather than always appending.
|
|
145
|
+
if (stream.type === 'binary') {
|
|
146
|
+
if (stream.position < stream.content.length) stream.content[stream.position] = value;
|
|
147
|
+
else stream.content.push(value);
|
|
148
|
+
stream.position++;
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
const text = String(value);
|
|
152
|
+
const content = String(stream.content);
|
|
153
|
+
const end = Math.min(content.length, stream.position + text.length);
|
|
154
|
+
stream.content = `${content.slice(0, stream.position)}${text}${content.slice(end)}`;
|
|
155
|
+
stream.position += text.length;
|
|
133
156
|
}
|
|
134
157
|
}
|
package/src/iso-arithmetic.js
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
} from './term.js';
|
|
6
6
|
import { PrologError } from './errors.js';
|
|
7
7
|
|
|
8
|
-
function evaluate(term, env) {
|
|
8
|
+
function evaluate(term, env, options = {}) {
|
|
9
9
|
term = deref(term, env);
|
|
10
10
|
if (term.type === VAR) throw new PrologError('instantiation_error');
|
|
11
11
|
if (term.type === NUMBER) {
|
|
@@ -16,10 +16,11 @@ function evaluate(term, env) {
|
|
|
16
16
|
}
|
|
17
17
|
if (term.type === ATOM) {
|
|
18
18
|
if (term.name === 'pi') return { integer: false, value: Math.PI };
|
|
19
|
-
if (term.name === 'e') return { integer: false, value: Math.E };
|
|
19
|
+
if (term.name === 'e' && options.isoStrict !== true) return { integer: false, value: Math.E };
|
|
20
|
+
throw new PrologError('type_error(evaluable)', compound('/', [atom(term.name), numberTerm(0)]));
|
|
20
21
|
}
|
|
21
22
|
if (term.type !== COMPOUND) throw new PrologError('type_error(evaluable)', term);
|
|
22
|
-
const args = term.args.map((arg) => evaluate(arg, env));
|
|
23
|
+
const args = term.args.map((arg) => evaluate(arg, env, options));
|
|
23
24
|
return evaluateOperation(term, args);
|
|
24
25
|
}
|
|
25
26
|
function evaluateOperation(term, args) {
|
|
@@ -120,8 +121,8 @@ export function arithmeticValueTerm(value) {
|
|
|
120
121
|
function numericTerm(value) {
|
|
121
122
|
return arithmeticValueTerm(value);
|
|
122
123
|
}
|
|
123
|
-
export function evaluateArithmetic(term, env) {
|
|
124
|
-
return evaluate(term, env);
|
|
124
|
+
export function evaluateArithmetic(term, env, options = {}) {
|
|
125
|
+
return evaluate(term, env, options);
|
|
125
126
|
}
|
|
126
127
|
function compareIntegerToFloat(integerValue, floatValue) {
|
|
127
128
|
if (!Number.isFinite(floatValue)) throw new PrologError('evaluation_error(float_overflow)');
|
|
@@ -151,15 +152,16 @@ export function compareArithmeticValues(left, right) {
|
|
|
151
152
|
if (right.integer) return -compareIntegerToFloat(b, a);
|
|
152
153
|
return a < b ? -1 : a > b ? 1 : 0;
|
|
153
154
|
}
|
|
154
|
-
export function* isBuiltin({ goal, env }) {
|
|
155
|
-
const result = arithmeticValueTerm(evaluateArithmetic(goal.args[1], env));
|
|
155
|
+
export function* isBuiltin({ solver, goal, env }) {
|
|
156
|
+
const result = arithmeticValueTerm(evaluateArithmetic(goal.args[1], env, { isoStrict: solver?.isoStrict === true }));
|
|
156
157
|
const next = env.clone();
|
|
157
158
|
if (unify(goal.args[0], result, next)) yield next;
|
|
158
159
|
}
|
|
159
160
|
export function arithmeticComparison(test) {
|
|
160
|
-
return function* ({ goal, env }) {
|
|
161
|
-
const
|
|
162
|
-
const
|
|
161
|
+
return function* ({ solver, goal, env }) {
|
|
162
|
+
const options = { isoStrict: solver?.isoStrict === true };
|
|
163
|
+
const left = evaluateArithmetic(goal.args[0], env, options);
|
|
164
|
+
const right = evaluateArithmetic(goal.args[1], env, options);
|
|
163
165
|
const cmp = compareArithmeticValues(left, right);
|
|
164
166
|
if (test(cmp)) yield env;
|
|
165
167
|
};
|