eyeprolog 1.3.17 → 1.3.18

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/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.3.17",
6
+ "version": "1.3.18",
7
7
  "description": "EyeProlog turns facts and rules into answers and proofs.",
8
8
  "type": "module",
9
9
  "main": "./index.js",
package/src/iso.js CHANGED
@@ -1370,6 +1370,7 @@ function writeBuiltin(mode) {
1370
1370
  const options = defaultTermWriteOptions(mode);
1371
1371
  solver.io.writeUnit(stream, formatTermForWrite(goal.args[goal.arity - 1], env, {
1372
1372
  ...options,
1373
+ generateVariableNames: true,
1373
1374
  operators: solver.program.operators.values(),
1374
1375
  }));
1375
1376
  yield env;
@@ -1386,6 +1387,7 @@ function* writeTermBuiltin({ solver, goal, env }) {
1386
1387
  }
1387
1388
  solver.io.writeUnit(stream, formatTermForWrite(goal.args[goal.arity - 2], env, {
1388
1389
  ...options,
1390
+ generateVariableNames: true,
1389
1391
  operators: solver.program.operators.values(),
1390
1392
  }));
1391
1393
  yield env;
package/src/write.js CHANGED
@@ -174,6 +174,40 @@ function printableReadVariableNames(term, env, explicit) {
174
174
  return names;
175
175
  }
176
176
 
177
+ function generatedVariableName(index) {
178
+ const letter = String.fromCharCode(65 + (index % 26));
179
+ const suffix = Math.floor(index / 26);
180
+ return suffix === 0 ? `_${letter}` : `_${letter}${suffix}`;
181
+ }
182
+
183
+ function printableGeneratedVariableNames(term, env, explicit) {
184
+ const names = new Map(explicit);
185
+ const used = new Set(names.values());
186
+ const seenVariables = new Set();
187
+ const seenTerms = new Set();
188
+ const stack = [term];
189
+ let generated = 0;
190
+
191
+ while (stack.length) {
192
+ const current = deref(stack.pop(), env);
193
+ if (current.type === VAR) {
194
+ if (seenVariables.has(current.name)) continue;
195
+ seenVariables.add(current.name);
196
+ if (names.has(current.name)) continue;
197
+ let candidate;
198
+ do candidate = generatedVariableName(generated++); while (used.has(candidate));
199
+ names.set(current.name, candidate);
200
+ used.add(candidate);
201
+ continue;
202
+ }
203
+ if (current.type !== COMPOUND || seenTerms.has(current)) continue;
204
+ seenTerms.add(current);
205
+ for (let i = current.arity - 1; i >= 0; i--) stack.push(current.args[i]);
206
+ }
207
+
208
+ return names;
209
+ }
210
+
177
211
  function format(term, env, options, table, maxPriority = 1200, context = 'term') {
178
212
  const resolved = deref(term, env);
179
213
  if (resolved.type === VAR) {
@@ -282,7 +316,9 @@ export function formatTermForWrite(term, env = new Env(), options = {}) {
282
316
  ignoreOps: options.ignoreOps === true,
283
317
  numbervars: options.numbervars !== false,
284
318
  doubleQuotes: options.doubleQuotes,
285
- variableNames: printableReadVariableNames(term, env, explicitVariableNames),
319
+ variableNames: options.generateVariableNames === true
320
+ ? printableGeneratedVariableNames(term, env, explicitVariableNames)
321
+ : printableReadVariableNames(term, env, explicitVariableNames),
286
322
  compact: options.compact === true,
287
323
  operatorAtomsAsArgs: options.operatorAtomsAsArgs === true,
288
324
  dottedGraphicAtoms: options.dottedGraphicAtoms === true,
@@ -4128,7 +4128,7 @@
4128
4128
  "type": "success",
4129
4129
  "stages": [
4130
4130
  {
4131
- "output": "+(__anon0,__anon1)",
4131
+ "output": "+(_A,_B)",
4132
4132
  "variables": "[]"
4133
4133
  }
4134
4134
  ]
@@ -4144,7 +4144,7 @@
4144
4144
  "type": "success",
4145
4145
  "stages": [
4146
4146
  {
4147
- "output": "+(B,B)",
4147
+ "output": "+(_A,_A)",
4148
4148
  "variables": "['B' = B]"
4149
4149
  }
4150
4150
  ]
@@ -5221,7 +5221,7 @@
5221
5221
  "type": "success",
5222
5222
  "stages": [
5223
5223
  {
5224
- "output": "1 is __anon0",
5224
+ "output": "1 is _A",
5225
5225
  "variables": "[]"
5226
5226
  }
5227
5227
  ]
@@ -1860,7 +1860,7 @@ c4 ?- call((!;1)).
1860
1860
  'check :- read(A), read(B), A \\== B, write_canonical(pair(A, B)), nl.\n',
1861
1861
  { goal: 'check', ioOptions: { input: 'V.\nV.\n' } },
1862
1862
  );
1863
- assertEqual(distinctReads.stdout, 'pair(V,V_1)\ncheck.\n', 'separate read variable sets');
1863
+ assertEqual(distinctReads.stdout, 'pair(_A,_B)\ncheck.\n', 'separate read variable sets');
1864
1864
  },
1865
1865
  },
1866
1866
  {
@@ -2975,6 +2975,20 @@ child.stdin.write(\`consult(${consultedAtom}).\\n\`);
2975
2975
  }
2976
2976
  },
2977
2977
  },
2978
+ {
2979
+ name: 'writeq gives unnamed variables underscore-prefixed names (issue #53)',
2980
+ run: () => {
2981
+ const result = runCli([], {
2982
+ input: "writeq(E).\nwriteq(pair(X,X,Y)).\nwrite_term(pair(X,Y), [variable_names(['Left'=X])]).\nhalt.\n",
2983
+ });
2984
+ assertEqual(result.status, 0, 'exit status');
2985
+ assertIncludes(result.stdout, ' _A true.\n', 'single unnamed variable');
2986
+ assertIncludes(result.stdout, ' pair(_A,_A,_B) true.\n', 'stable repeated variable names');
2987
+ assertIncludes(result.stdout, ' pair(Left,_A) true.\n', 'explicit variable name plus generated fallback');
2988
+ const fresh = run('emit :- writeq(E), nl.\n', { goal: 'emit' });
2989
+ assertEqual(fresh.stdout, '_A\nemit.\n', 'fresh clause variable hides its internal suffix');
2990
+ },
2991
+ },
2978
2992
  {
2979
2993
  name: 'write predicates and write_term options select distinct formats',
2980
2994
  run: () => {
package/test/run-wg17.mjs CHANGED
@@ -18,7 +18,7 @@ function runnerStage(index, maximum) {
18
18
  return `read_term(G${index}, [variable_names(V${index})]), ` +
19
19
  `(G${index} == end_of_file -> write('\\n<WG17-COMPLETE>') ; (` +
20
20
  `write('\\n<WG17-BEGIN-${index}>'), call(G${index}), ` +
21
- `write('<WG17-VARS>'), writeq(V${index}), write('<WG17-END>'), ` +
21
+ `write('<WG17-VARS>'), write_term(V${index}, [quoted(true), variable_names(V${index})]), write('<WG17-END>'), ` +
22
22
  `${runnerStage(index + 1, maximum)}))`;
23
23
  }
24
24