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 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
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.3.43",
6
+ "version": "1.3.45",
7
7
  "description": "EyeProlog turns facts and rules into answers and proofs.",
8
8
  "type": "module",
9
9
  "main": "./index.js",
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 === 'append' && fs.existsSync(path)) {
92
- content = fs.readFileSync(path, type === 'binary' ? null : 'utf8');
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
- close(stream) {
104
- if (!stream.standard && stream.mode !== 'read') {
105
- fs.writeFileSync(stream.path, stream.type === 'binary' ? BufferCtor.from(stream.content) : stream.content);
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) stream.write(String(value));
130
- else if (stream.type === 'binary') stream.content.push(value);
131
- else stream.content += value;
132
- stream.position = stream.content.length;
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
  }
@@ -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 left = evaluateArithmetic(goal.args[0], env);
162
- const right = evaluateArithmetic(goal.args[1], env);
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
  };