eyeprolog 1.3.16 → 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 +1 -1
- package/src/iso.js +2 -0
- package/src/repl.js +6 -5
- package/src/write.js +37 -1
- package/test/conformance/wg17-syntax-cases.json +3 -3
- package/test/run-regression.mjs +49 -1
- package/test/run-wg17.mjs +1 -1
package/package.json
CHANGED
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/repl.js
CHANGED
|
@@ -366,7 +366,6 @@ function terminalFullStop(source, solver = null) {
|
|
|
366
366
|
let quote = null;
|
|
367
367
|
let lineComment = false;
|
|
368
368
|
let blockComment = false;
|
|
369
|
-
let depth = 0;
|
|
370
369
|
|
|
371
370
|
for (let i = 0; i < source.length; i++) {
|
|
372
371
|
const ch = source[i];
|
|
@@ -415,10 +414,12 @@ function terminalFullStop(source, solver = null) {
|
|
|
415
414
|
quote = ch;
|
|
416
415
|
continue;
|
|
417
416
|
}
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
417
|
+
// ISO 8.14.1.1 locates the end token lexically before read-term parsing.
|
|
418
|
+
// An unmatched opening bracket therefore must not make the top level wait
|
|
419
|
+
// for more input after a terminating full stop; parsing the collected text
|
|
420
|
+
// is what reports the syntax error (for example `[l.` or `{.`).
|
|
421
|
+
if (isTerminatingFullStop(source, i, convert) &&
|
|
422
|
+
onlyLayoutAndComments(source.slice(i + 1))) return i;
|
|
422
423
|
}
|
|
423
424
|
return -1;
|
|
424
425
|
}
|
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:
|
|
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": "+(
|
|
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": "+(
|
|
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
|
|
5224
|
+
"output": "1 is _A",
|
|
5225
5225
|
"variables": "[]"
|
|
5226
5226
|
}
|
|
5227
5227
|
]
|
package/test/run-regression.mjs
CHANGED
|
@@ -1410,6 +1410,27 @@ c4 ?- call((!;1)).
|
|
|
1410
1410
|
assertEqual(result.stdout, 'ok', 'DCG hand-off benchmark result');
|
|
1411
1411
|
},
|
|
1412
1412
|
},
|
|
1413
|
+
{
|
|
1414
|
+
name: 'DCG state hand-off reaches the next non-terminal at 8192 cells (issue #49 comment 5347991607)',
|
|
1415
|
+
run: () => {
|
|
1416
|
+
const filename = path.join(tmp, `issue49-small-handoff-${tmpCounter++}.pl`);
|
|
1417
|
+
fs.writeFileSync(filename,
|
|
1418
|
+
':- set_prolog_flag(occurs_check, true).\na --> ..., epsilon.\nepsilon --> [].\n');
|
|
1419
|
+
const result = runCli([], {
|
|
1420
|
+
input:
|
|
1421
|
+
`[${sourceAtom(filename)}].\n` +
|
|
1422
|
+
'use_module(library(lists)).\n' +
|
|
1423
|
+
'\\+ \\+ (length(L,8192), phrase(a,L)).\n' +
|
|
1424
|
+
'halt.\n',
|
|
1425
|
+
timeout: 3000,
|
|
1426
|
+
});
|
|
1427
|
+
if (result.error) throw result.error;
|
|
1428
|
+
assertEqual(result.status, 0, `small DCG hand-off status; stderr=${result.stderr}`);
|
|
1429
|
+
assertNotIncludes(result.stdout, 'resource_error', 'small DCG hand-off resource error');
|
|
1430
|
+
assertNotIncludes(result.stdout, 'depth_limit_exceeded', 'small DCG hand-off depth error');
|
|
1431
|
+
assertEqual(result.stderr, '', 'small DCG hand-off stderr');
|
|
1432
|
+
},
|
|
1433
|
+
},
|
|
1413
1434
|
{
|
|
1414
1435
|
name: 'Trealla-style DCG hand-off reaches 65536 cells without the solver depth ceiling',
|
|
1415
1436
|
run: () => {
|
|
@@ -1839,7 +1860,7 @@ c4 ?- call((!;1)).
|
|
|
1839
1860
|
'check :- read(A), read(B), A \\== B, write_canonical(pair(A, B)), nl.\n',
|
|
1840
1861
|
{ goal: 'check', ioOptions: { input: 'V.\nV.\n' } },
|
|
1841
1862
|
);
|
|
1842
|
-
assertEqual(distinctReads.stdout, 'pair(
|
|
1863
|
+
assertEqual(distinctReads.stdout, 'pair(_A,_B)\ncheck.\n', 'separate read variable sets');
|
|
1843
1864
|
},
|
|
1844
1865
|
},
|
|
1845
1866
|
{
|
|
@@ -1910,6 +1931,19 @@ c4 ?- call((!;1)).
|
|
|
1910
1931
|
assertIncludes(result.stdout, '?- repeat, fail.', 'terminal query echo');
|
|
1911
1932
|
},
|
|
1912
1933
|
},
|
|
1934
|
+
{
|
|
1935
|
+
name: 'REPL stops at the end token before parsing unmatched brackets (issue #51)',
|
|
1936
|
+
run: () => {
|
|
1937
|
+
const result = runCli([], { input: '[l.\ntrue.\n{.\ntrue.\nhalt.\n' });
|
|
1938
|
+
assertEqual(result.status, 0, 'exit status');
|
|
1939
|
+
assertNotIncludes(result.stdout, '| ', 'no continuation prompt after malformed end token');
|
|
1940
|
+
assertEqual((result.stdout.match(/\?- true\./g) ?? []).length, 2,
|
|
1941
|
+
'following lines remain separate top-level queries');
|
|
1942
|
+
assertEqual((result.stdout.match(/parse line 1:/g) ?? []).length, 2,
|
|
1943
|
+
'both malformed bracketed queries report syntax errors');
|
|
1944
|
+
assertEqual(result.stderr, '', 'stderr');
|
|
1945
|
+
},
|
|
1946
|
+
},
|
|
1913
1947
|
{
|
|
1914
1948
|
name: 'REPL accepts multiline period-terminated queries',
|
|
1915
1949
|
run: () => {
|
|
@@ -2941,6 +2975,20 @@ child.stdin.write(\`consult(${consultedAtom}).\\n\`);
|
|
|
2941
2975
|
}
|
|
2942
2976
|
},
|
|
2943
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
|
+
},
|
|
2944
2992
|
{
|
|
2945
2993
|
name: 'write predicates and write_term options select distinct formats',
|
|
2946
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>'),
|
|
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
|
|