eyeprolog 1.3.40 → 1.3.41
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/examples/book/README.md +1 -0
- package/examples/book/chapter-40/02-program.pl +4 -4
- package/examples/book/chapter-40/03-program-2.pl +5 -0
- package/package.json +1 -1
- package/src/io.js +1 -1
- package/src/iso.js +12 -4
- package/src/quads.js +56 -16
- package/src/write.js +59 -6
- package/test/conformance/WG17-SYNTAX-STATUS.md +2 -2
- package/test/conformance/expected/iso/wg17_syntax_high_risk.pl +2 -2
- package/test/conformance/wg17-syntax-cases.json +99 -90
- package/test/run-regression.mjs +63 -1
- package/the-art-of-eyeprolog.md +29 -10
package/examples/book/README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
% From The Art of EyeProlog, Chapter 40.
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
?- read(X).
|
|
3
|
+
inputs("1."), X = 1, unexpected.
|
|
4
|
+
inputs("1."), peeks(" "), X = 1.
|
|
5
|
+
inputs("1. "), peeks(" "), X = 1, unexpected.
|
package/package.json
CHANGED
package/src/io.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Synchronous ISO stream state shared by a solver and all of its inner solvers.
|
|
2
2
|
import { BufferCtor, fs } from './platform.js';
|
|
3
3
|
|
|
4
|
-
const INVALID_UTF8_SENTINEL = '\udc00';
|
|
4
|
+
export const INVALID_UTF8_SENTINEL = '\udc00';
|
|
5
5
|
|
|
6
6
|
export class InvalidCharacterEncodingError extends Error {
|
|
7
7
|
constructor() {
|
package/src/iso.js
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
} from './parser.js';
|
|
13
13
|
import { formatTermForWrite } from './write.js';
|
|
14
14
|
import { emptyTerminalSequence, expandDcgBody, isListOrPartialList, validateDcgEmbeddedGoals } from './dcg.js';
|
|
15
|
+
import { INVALID_UTF8_SENTINEL } from './io.js';
|
|
15
16
|
import {
|
|
16
17
|
characterCodeConstantEnd, continuesGraphicToken, isTerminatingFullStop, quotedEscapeEnd,
|
|
17
18
|
} from './syntax-scan.js';
|
|
@@ -1089,6 +1090,13 @@ function* termTextCandidates(stream, solver) {
|
|
|
1089
1090
|
let quote = null, lineComment = false, blockComment = false;
|
|
1090
1091
|
for (let i = stream.position; i < source.length; i++) {
|
|
1091
1092
|
const ch = source[i], next = source[i + 1];
|
|
1093
|
+
// Text streams preserve invalid UTF-8 bytes as an impossible Unicode
|
|
1094
|
+
// sentinel. read/1-2 and read_term/2-3 must surface the same character
|
|
1095
|
+
// representation error as get_char/1-2 instead of misclassifying the
|
|
1096
|
+
// undecodable byte as malformed Prolog syntax (issue #64).
|
|
1097
|
+
if (stream.strictUtf8 && ch === INVALID_UTF8_SENTINEL) {
|
|
1098
|
+
throw new PrologError('representation_error(character)');
|
|
1099
|
+
}
|
|
1092
1100
|
if (lineComment) { if (ch === '\n') lineComment = false; continue; }
|
|
1093
1101
|
if (blockComment) { if (ch === '*' && next === '/') { blockComment = false; i++; } continue; }
|
|
1094
1102
|
if (quote) {
|
|
@@ -1305,10 +1313,10 @@ function* readTermBuiltin({ solver, goal, env }) {
|
|
|
1305
1313
|
yield next;
|
|
1306
1314
|
}
|
|
1307
1315
|
function defaultTermWriteOptions(mode) {
|
|
1308
|
-
if (mode === 'writeq') return { quoted: true, ignoreOps: false, numbervars: true, variableNames: new Map(), compact: true, operatorAtomsAsArgs: true, doubleQuotes: null };
|
|
1309
|
-
if (mode === 'canonical') return { quoted: true, ignoreOps: true, numbervars: false, variableNames: new Map(), compact: true, operatorAtomsAsArgs: true, doubleQuotes: null };
|
|
1310
|
-
if (mode === 'write_term') return { quoted: false, ignoreOps: false, numbervars: false, variableNames: new Map(), compact: true, operatorAtomsAsArgs: true, doubleQuotes: null };
|
|
1311
|
-
return { quoted: false, ignoreOps: false, numbervars: true, variableNames: new Map(), compact: true, operatorAtomsAsArgs: true, doubleQuotes: null };
|
|
1316
|
+
if (mode === 'writeq') return { quoted: true, ignoreOps: false, numbervars: true, variableNames: new Map(), compact: true, minimalOperatorSpacing: true, operatorAtomsAsArgs: true, doubleQuotes: null };
|
|
1317
|
+
if (mode === 'canonical') return { quoted: true, ignoreOps: true, numbervars: false, variableNames: new Map(), compact: true, minimalOperatorSpacing: true, operatorAtomsAsArgs: true, doubleQuotes: null };
|
|
1318
|
+
if (mode === 'write_term') return { quoted: false, ignoreOps: false, numbervars: false, variableNames: new Map(), compact: true, minimalOperatorSpacing: true, operatorAtomsAsArgs: true, doubleQuotes: null };
|
|
1319
|
+
return { quoted: false, ignoreOps: false, numbervars: true, variableNames: new Map(), compact: true, minimalOperatorSpacing: true, operatorAtomsAsArgs: true, doubleQuotes: null };
|
|
1312
1320
|
}
|
|
1313
1321
|
|
|
1314
1322
|
function writeOptionBoolean(value, env, option) {
|
package/src/quads.js
CHANGED
|
@@ -11,6 +11,7 @@ import { Program } from './program.js';
|
|
|
11
11
|
import { Solver } from './solver.js';
|
|
12
12
|
import { getEyePrologRegistry } from './standard-library.js';
|
|
13
13
|
import { formatTermForWrite } from './write.js';
|
|
14
|
+
import { INVALID_UTF8_SENTINEL } from './io.js';
|
|
14
15
|
|
|
15
16
|
const DEFAULT_QUAD_MAX_INFERENCES = 100000;
|
|
16
17
|
const DEFAULT_LOOP_MAX_INFERENCES = 10000;
|
|
@@ -93,18 +94,24 @@ function checkAlternative(program, quad, alternative, options, context) {
|
|
|
93
94
|
return { ok: false, kind: 'unsupported', expected: unsupported };
|
|
94
95
|
}
|
|
95
96
|
|
|
96
|
-
const
|
|
97
|
-
if (
|
|
98
|
-
|
|
99
|
-
|
|
97
|
+
const ioLeaves = leaves.filter((leaf) => leaf.input != null || leaf.peek != null);
|
|
98
|
+
if (ioLeaves.length > 1 || (ioLeaves.length > 0 && leaves.length !== 1)) {
|
|
99
|
+
return { ok: false, kind: 'malformed', expected: alternative };
|
|
100
|
+
}
|
|
101
|
+
const hasInputSpec = ioLeaves.length === 1;
|
|
102
|
+
const inputLeaf = ioLeaves[0] ?? null;
|
|
103
|
+
const input = inputLeaf?.input ?? '';
|
|
104
|
+
const peek = inputLeaf?.peek ?? null;
|
|
100
105
|
const moreAt = leaves.findIndex((leaf) => leaf.more);
|
|
101
106
|
const describedCount = moreAt < 0 ? leaves.length : moreAt + (leaves[moreAt].hasExpectation ? 1 : 0);
|
|
102
|
-
const maxSolutions =
|
|
107
|
+
const maxSolutions = hasInputSpec
|
|
103
108
|
? 1
|
|
104
109
|
: moreAt < 0 ? describedCount + 1 : Math.max(describedCount, 1);
|
|
105
110
|
const actual = executeQuery(program, quad.query, input, maxSolutions, {
|
|
106
111
|
...options,
|
|
107
112
|
detectLoops: leaves.some((leaf) => leaf.loops),
|
|
113
|
+
inputBoundary: hasInputSpec,
|
|
114
|
+
inputPeek: peek,
|
|
108
115
|
});
|
|
109
116
|
|
|
110
117
|
if (requiresSto) {
|
|
@@ -119,9 +126,12 @@ function checkAlternative(program, quad, alternative, options, context) {
|
|
|
119
126
|
return { ok: true };
|
|
120
127
|
}
|
|
121
128
|
|
|
122
|
-
if (
|
|
129
|
+
if (hasInputSpec) {
|
|
123
130
|
const leaf = leaves[0];
|
|
124
|
-
const
|
|
131
|
+
const exactConsumption = actual.inputPosition === input.length;
|
|
132
|
+
const expectedRemainder = `${peek ?? ''}${INVALID_UTF8_SENTINEL}`;
|
|
133
|
+
const boundaryPreserved = actual.inputRemainder === expectedRemainder;
|
|
134
|
+
const matches = exactConsumption && boundaryPreserved && matchLeaf(program, quad.query, leaf, actual, 0);
|
|
125
135
|
if (actual.undecided && !matches) return undecidedResult(actual, alternative);
|
|
126
136
|
return { ok: leaf.unexpected ? !matches : matches };
|
|
127
137
|
}
|
|
@@ -147,14 +157,14 @@ function checkAlternative(program, quad, alternative, options, context) {
|
|
|
147
157
|
// turn a successful negative match back into a failure.
|
|
148
158
|
if (leaf.unexpected && leaf.error != null) return { ok: true };
|
|
149
159
|
if (leaf.more) return { ok: true };
|
|
150
|
-
if (!leaf.unexpected && (leaf.false || leaf.error != null)) {
|
|
160
|
+
if (!leaf.unexpected && (leaf.false || leaf.loops || leaf.error != null)) {
|
|
151
161
|
if (actual.undecided) return undecidedResult(actual, alternative);
|
|
152
162
|
return { ok: position === leaves.length - 1 };
|
|
153
163
|
}
|
|
154
164
|
position++;
|
|
155
165
|
}
|
|
156
166
|
|
|
157
|
-
const ended = position >= actual.solutions.length && actual.error == null && !actual.undecided;
|
|
167
|
+
const ended = position >= actual.solutions.length && actual.error == null && !actual.undecided && !actual.loopObserved;
|
|
158
168
|
if (!ended && actual.undecided && position >= actual.solutions.length && actual.error == null) {
|
|
159
169
|
return undecidedResult(actual, alternative);
|
|
160
170
|
}
|
|
@@ -191,6 +201,7 @@ function describeLeaf(term) {
|
|
|
191
201
|
loops: false,
|
|
192
202
|
error: null,
|
|
193
203
|
input: null,
|
|
204
|
+
peek: null,
|
|
194
205
|
output: null,
|
|
195
206
|
unsupported: null,
|
|
196
207
|
malformed: null,
|
|
@@ -227,7 +238,9 @@ function describeLeaf(term) {
|
|
|
227
238
|
continue;
|
|
228
239
|
}
|
|
229
240
|
if (item.type === COMPOUND && item.name === 'peeks' && item.arity === 1) {
|
|
230
|
-
|
|
241
|
+
const text = characterText(item.args[0]);
|
|
242
|
+
if (text == null || Array.from(text).length !== 1 || leaf.peek != null) leaf.malformed ??= item;
|
|
243
|
+
else leaf.peek = text;
|
|
231
244
|
continue;
|
|
232
245
|
}
|
|
233
246
|
if (isErrorDescription(item)) leaf.error = item;
|
|
@@ -241,6 +254,9 @@ function describeLeaf(term) {
|
|
|
241
254
|
|
|
242
255
|
function executeQuery(program, query, input, maxSolutions, options) {
|
|
243
256
|
let pendingOutput = '';
|
|
257
|
+
const boundedInput = options.inputBoundary
|
|
258
|
+
? `${input}${options.inputPeek ?? ''}${INVALID_UTF8_SENTINEL}`
|
|
259
|
+
: input;
|
|
244
260
|
const solver = new Solver(program, {
|
|
245
261
|
...options,
|
|
246
262
|
registry: options.registry ?? getEyePrologRegistry(),
|
|
@@ -254,10 +270,18 @@ function executeQuery(program, query, input, maxSolutions, options) {
|
|
|
254
270
|
// allowance.
|
|
255
271
|
solutionLimit: Math.max(maxSolutions, options.solutionLimit ?? 10000000),
|
|
256
272
|
ioOptions: {
|
|
257
|
-
input,
|
|
273
|
+
input: boundedInput,
|
|
258
274
|
write: (text) => { pendingOutput += String(text); },
|
|
259
275
|
},
|
|
260
276
|
});
|
|
277
|
+
if (options.inputBoundary) {
|
|
278
|
+
// Quads need a boundary that is neither EOF nor a valid character. This
|
|
279
|
+
// mirrors Trealla's sentinel technique: inputs/1 says exactly what was
|
|
280
|
+
// consumed, while peeks/1 supplies one additional character that must
|
|
281
|
+
// remain unread. If the query asks for anything beyond that boundary it
|
|
282
|
+
// sees representation_error(character), not an artificial EOF.
|
|
283
|
+
solver.io.resolve('user_input').strictUtf8 = true;
|
|
284
|
+
}
|
|
261
285
|
// Undefined predicates are test failures rather than silent negative
|
|
262
286
|
// answers unless the source explicitly selected another unknown policy.
|
|
263
287
|
if (!(program.prologFlagDirectives ?? []).some(([flag]) => flag.type === ATOM && flag.name === 'unknown')) {
|
|
@@ -273,7 +297,15 @@ function executeQuery(program, query, input, maxSolutions, options) {
|
|
|
273
297
|
iterator = solver.solve([query], new Env(), 0);
|
|
274
298
|
while (solutions.length < maxSolutions) {
|
|
275
299
|
pendingOutput = '';
|
|
300
|
+
const cycleBefore = solver.recursionCycleDetected;
|
|
276
301
|
const result = iterator.next();
|
|
302
|
+
if (!cycleBefore && solver.recursionCycleDetected) {
|
|
303
|
+
// The recursion guard found an operational loop wall while advancing
|
|
304
|
+
// to this result. Any answer produced only after that guard pruned the
|
|
305
|
+
// looping branch is not reachable by ordinary Prolog search, so do not
|
|
306
|
+
// count it as a leaf answer (issue #58 comment 5381101420).
|
|
307
|
+
break;
|
|
308
|
+
}
|
|
277
309
|
if (result.done) {
|
|
278
310
|
tailOutput += pendingOutput;
|
|
279
311
|
complete = true;
|
|
@@ -289,22 +321,30 @@ function executeQuery(program, query, input, maxSolutions, options) {
|
|
|
289
321
|
} finally {
|
|
290
322
|
if (!complete) iterator?.return?.();
|
|
291
323
|
}
|
|
292
|
-
const
|
|
324
|
+
const inputStream = solver.io.resolve('user_input');
|
|
325
|
+
const inputPosition = inputStream?.position ?? 0;
|
|
326
|
+
const inputRemainder = String(inputStream?.content ?? '').slice(inputPosition);
|
|
293
327
|
const bounded = solver.depthLimitExceeded || solver.inferenceLimitExceeded;
|
|
294
|
-
const
|
|
328
|
+
const loopObserved = solver.recursionCycleDetected;
|
|
329
|
+
// A structural recursion-cycle witness is stronger than a resource limit:
|
|
330
|
+
// it establishes an operational loop wall and can therefore refute a finite
|
|
331
|
+
// answer description. Pure depth/inference exhaustion remains undecided.
|
|
332
|
+
const undecided = !options.detectLoops && !loopObserved && bounded;
|
|
295
333
|
return {
|
|
296
334
|
solutions,
|
|
297
335
|
error,
|
|
298
336
|
tailOutput,
|
|
299
337
|
inputPosition,
|
|
338
|
+
inputRemainder,
|
|
300
339
|
complete,
|
|
340
|
+
loopObserved,
|
|
301
341
|
stoObserved: solver.occursCheckObserved,
|
|
302
|
-
nstoObserved: complete && !solver.occursCheckObserved && !
|
|
342
|
+
nstoObserved: complete && !solver.occursCheckObserved && !loopObserved &&
|
|
303
343
|
!bounded && !resourceInterrupted,
|
|
304
344
|
// A loops expectation explicitly asks for bounded nontermination evidence.
|
|
305
345
|
// Other descriptions treat the same exhausted search budget as undecided:
|
|
306
346
|
// a timeout cannot establish finite failure or an exact answer sequence.
|
|
307
|
-
loops: options.detectLoops && (
|
|
347
|
+
loops: options.detectLoops && (loopObserved || bounded),
|
|
308
348
|
undecided,
|
|
309
349
|
undecidedReason: solver.inferenceLimitExceeded ? 'inference limit reached'
|
|
310
350
|
: solver.depthLimitExceeded ? 'depth limit reached'
|
|
@@ -316,7 +356,7 @@ function executeQuery(program, query, input, maxSolutions, options) {
|
|
|
316
356
|
function matchLeaf(program, query, leaf, actual, position) {
|
|
317
357
|
if (leaf.loops) return actual.loops;
|
|
318
358
|
if (leaf.false) {
|
|
319
|
-
return position >= actual.solutions.length && actual.error == null && !actual.undecided &&
|
|
359
|
+
return position >= actual.solutions.length && actual.error == null && !actual.undecided && !actual.loopObserved &&
|
|
320
360
|
outputMatches(program, leaf.output, actual.tailOutput);
|
|
321
361
|
}
|
|
322
362
|
if (leaf.error != null) {
|
package/src/write.js
CHANGED
|
@@ -58,6 +58,51 @@ function isDottedGraphicAtom(name) {
|
|
|
58
58
|
[...name].every((ch) => dottedGraphicAtomCharacters.has(ch));
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
function compactBoundaryNeedsSpace(left, right) {
|
|
62
|
+
const leftChars = Array.from(left);
|
|
63
|
+
const rightChars = Array.from(right);
|
|
64
|
+
const a = leftChars[leftChars.length - 1] ?? '';
|
|
65
|
+
const b = rightChars[0] ?? '';
|
|
66
|
+
if (!a || !b) return false;
|
|
67
|
+
// Adjacent quoted atoms need layout: `''` is part of quoted-atom syntax,
|
|
68
|
+
// so concatenating two quoted operator/argument tokens would change the
|
|
69
|
+
// tokenization (WG17 #169).
|
|
70
|
+
if (a === "'" && b === "'") return true;
|
|
71
|
+
// Adjacent graphic characters form one maximal graphic token. Keep them
|
|
72
|
+
// apart when an operator boundary would otherwise disappear (`a+ -b`,
|
|
73
|
+
// `a/ *b`, etc.).
|
|
74
|
+
if (graphicAtomCharacters.has(a) && graphicAtomCharacters.has(b)) return true;
|
|
75
|
+
// Alphanumeric operator names similarly need a lexical boundary from a
|
|
76
|
+
// neighbouring identifier/number token. Most predefined word operators
|
|
77
|
+
// are handled explicitly below; this also protects quoted/custom cases that
|
|
78
|
+
// render without punctuation.
|
|
79
|
+
if (/^[A-Za-z0-9_]$/.test(a) && /^[A-Za-z0-9_]$/.test(b)) return true;
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function isWordOperatorToken(token) {
|
|
84
|
+
return /^[a-z][A-Za-z0-9_]*$/.test(token);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function compactPrefixOperator(token, argument) {
|
|
88
|
+
if (isWordOperatorToken(token)) return `${token} ${argument}`;
|
|
89
|
+
return `${token}${compactBoundaryNeedsSpace(token, argument) ? ' ' : ''}${argument}`;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function compactPostfixOperator(argument, token) {
|
|
93
|
+
if (isWordOperatorToken(token)) return `${argument} ${token}`;
|
|
94
|
+
return `${argument}${compactBoundaryNeedsSpace(argument, token) ? ' ' : ''}${token}`;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function compactInfixOperator(left, token, right) {
|
|
98
|
+
// Solo punctuation operators already delimit themselves.
|
|
99
|
+
if (token === ',' || token === ';') return `${left}${token}${right}`;
|
|
100
|
+
if (isWordOperatorToken(token)) return `${left} ${token} ${right}`;
|
|
101
|
+
const before = compactBoundaryNeedsSpace(left, token) ? ' ' : '';
|
|
102
|
+
const after = compactBoundaryNeedsSpace(token, right) ? ' ' : '';
|
|
103
|
+
return `${left}${before}${token}${after}${right}`;
|
|
104
|
+
}
|
|
105
|
+
|
|
61
106
|
function legacyVariableToIso(name) {
|
|
62
107
|
if (name === '?') return '_';
|
|
63
108
|
const tail = name.slice(1);
|
|
@@ -313,9 +358,11 @@ function format(term, env, options, table, maxPriority = 1200, context = 'term')
|
|
|
313
358
|
// numeric-leading argument so writeq/write_term remain read-back safe
|
|
314
359
|
// (WG17 #135, #183, #215, #216, and #248).
|
|
315
360
|
if (resolved.name === '-' && startsWithUnsignedNumber(resolved.args[0], env, table, options)) {
|
|
316
|
-
|
|
361
|
+
const argument = format(resolved.args[0], env, options, table, 1200);
|
|
362
|
+
text = options.minimalOperatorSpacing ? `${token}(${argument})` : `${token} (${argument})`;
|
|
317
363
|
} else {
|
|
318
|
-
|
|
364
|
+
const argument = format(resolved.args[0], env, options, table, argumentPriority);
|
|
365
|
+
text = options.minimalOperatorSpacing ? compactPrefixOperator(token, argument) : `${token} ${argument}`;
|
|
319
366
|
}
|
|
320
367
|
} else if (specifier === 'xf' || specifier === 'yf') {
|
|
321
368
|
let argumentPriority = specifier === 'xf' ? priority - 1 : priority;
|
|
@@ -324,7 +371,8 @@ function format(term, env, options, table, maxPriority = 1200, context = 'term')
|
|
|
324
371
|
['fx', 'fy', 'xfx', 'xfy', 'yfx'].includes(childDefinition.specifier)) {
|
|
325
372
|
argumentPriority = priority - 1;
|
|
326
373
|
}
|
|
327
|
-
|
|
374
|
+
const argument = format(resolved.args[0], env, options, table, argumentPriority);
|
|
375
|
+
text = options.minimalOperatorSpacing ? compactPostfixOperator(argument, token) : `${argument} ${token}`;
|
|
328
376
|
} else {
|
|
329
377
|
let leftPriority = specifier === 'yfx' ? priority : priority - 1;
|
|
330
378
|
const rightPriority = specifier === 'xfy' ? priority : priority - 1;
|
|
@@ -334,9 +382,13 @@ function format(term, env, options, table, maxPriority = 1200, context = 'term')
|
|
|
334
382
|
}
|
|
335
383
|
const left = format(resolved.args[0], env, options, table, leftPriority);
|
|
336
384
|
const right = format(resolved.args[1], env, options, table, rightPriority);
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
385
|
+
if (options.minimalOperatorSpacing) {
|
|
386
|
+
text = resolved.name === ',' ? `${left},${right}` : compactInfixOperator(left, token, right);
|
|
387
|
+
} else if (resolved.name === ',') {
|
|
388
|
+
text = `${left}, ${right}`;
|
|
389
|
+
} else {
|
|
390
|
+
text = compactInfixOperators.has(resolved.name) ? `${left}${token}${right}` : `${left} ${token} ${right}`;
|
|
391
|
+
}
|
|
340
392
|
}
|
|
341
393
|
return priority > maxPriority ? `(${text})` : text;
|
|
342
394
|
}
|
|
@@ -358,6 +410,7 @@ export function formatTermForWrite(term, env = new Env(), options = {}) {
|
|
|
358
410
|
? printableGeneratedVariableNames(term, env, explicitVariableNames, options.variableNameState)
|
|
359
411
|
: printableReadVariableNames(term, env, explicitVariableNames),
|
|
360
412
|
compact: options.compact === true,
|
|
413
|
+
minimalOperatorSpacing: options.minimalOperatorSpacing === true,
|
|
361
414
|
operatorAtomsAsArgs: options.operatorAtomsAsArgs === true,
|
|
362
415
|
dottedGraphicAtoms: options.dottedGraphicAtoms === true,
|
|
363
416
|
};
|
|
@@ -21,8 +21,8 @@ upstream assertion.
|
|
|
21
21
|
The matrix runs in strict ISO stream-reader mode as part of `npm test`. The
|
|
22
22
|
3 upstream `waits` cases are checked through EyeProlog's interactive input
|
|
23
23
|
hook. All 366 executable cases are independently checked against the
|
|
24
|
-
upstream Codex expectation.
|
|
25
|
-
outcomes for stronger regression checking;
|
|
24
|
+
upstream Codex expectation. 366 cases additionally retain exact reviewed
|
|
25
|
+
outcomes for stronger regression checking; 0 cases currently rely on the upstream assertion alone.
|
|
26
26
|
|
|
27
27
|
## Traceable evidence
|
|
28
28
|
|
|
@@ -479,7 +479,7 @@
|
|
|
479
479
|
"type": "success",
|
|
480
480
|
"stages": [
|
|
481
481
|
{
|
|
482
|
-
"output": "(-)
|
|
482
|
+
"output": "(-)-(-)",
|
|
483
483
|
"variables": "[]"
|
|
484
484
|
}
|
|
485
485
|
]
|
|
@@ -495,7 +495,7 @@
|
|
|
495
495
|
"type": "success",
|
|
496
496
|
"stages": [
|
|
497
497
|
{
|
|
498
|
-
"output": "(:-)
|
|
498
|
+
"output": "(:-):-(:-)",
|
|
499
499
|
"variables": "[]"
|
|
500
500
|
}
|
|
501
501
|
]
|
|
@@ -511,7 +511,7 @@
|
|
|
511
511
|
"type": "success",
|
|
512
512
|
"stages": [
|
|
513
513
|
{
|
|
514
|
-
"output": "(*)
|
|
514
|
+
"output": "(*)=(*)",
|
|
515
515
|
"variables": "[]"
|
|
516
516
|
}
|
|
517
517
|
]
|
|
@@ -559,7 +559,7 @@
|
|
|
559
559
|
"type": "success",
|
|
560
560
|
"stages": [
|
|
561
561
|
{
|
|
562
|
-
"output": "a
|
|
562
|
+
"output": "a*(b+c)",
|
|
563
563
|
"variables": "[]"
|
|
564
564
|
}
|
|
565
565
|
]
|
|
@@ -607,7 +607,7 @@
|
|
|
607
607
|
"type": "success",
|
|
608
608
|
"stages": [
|
|
609
609
|
{
|
|
610
|
-
"output": "a
|
|
610
|
+
"output": "a:-b,c",
|
|
611
611
|
"variables": "[]"
|
|
612
612
|
}
|
|
613
613
|
]
|
|
@@ -862,7 +862,7 @@
|
|
|
862
862
|
},
|
|
863
863
|
{
|
|
864
864
|
"output": "",
|
|
865
|
-
"variables": "['F'
|
|
865
|
+
"variables": "['F'=('.'),'A'=2]"
|
|
866
866
|
}
|
|
867
867
|
]
|
|
868
868
|
}
|
|
@@ -1015,7 +1015,7 @@
|
|
|
1015
1015
|
},
|
|
1016
1016
|
{
|
|
1017
1017
|
"output": "",
|
|
1018
|
-
"variables": "['X'
|
|
1018
|
+
"variables": "['X'=1.2,'Y'=3]"
|
|
1019
1019
|
}
|
|
1020
1020
|
]
|
|
1021
1021
|
}
|
|
@@ -1308,7 +1308,7 @@
|
|
|
1308
1308
|
"type": "success",
|
|
1309
1309
|
"stages": [
|
|
1310
1310
|
{
|
|
1311
|
-
"output": "-
|
|
1311
|
+
"output": "-(1)",
|
|
1312
1312
|
"variables": "[]"
|
|
1313
1313
|
}
|
|
1314
1314
|
]
|
|
@@ -1340,7 +1340,7 @@
|
|
|
1340
1340
|
"type": "success",
|
|
1341
1341
|
"stages": [
|
|
1342
1342
|
{
|
|
1343
|
-
"output": "-
|
|
1343
|
+
"output": "-(1^2)",
|
|
1344
1344
|
"variables": "[]"
|
|
1345
1345
|
}
|
|
1346
1346
|
]
|
|
@@ -1356,7 +1356,7 @@
|
|
|
1356
1356
|
"type": "success",
|
|
1357
1357
|
"stages": [
|
|
1358
1358
|
{
|
|
1359
|
-
"output": "-
|
|
1359
|
+
"output": "-a^2",
|
|
1360
1360
|
"variables": "[]"
|
|
1361
1361
|
}
|
|
1362
1362
|
]
|
|
@@ -1372,7 +1372,7 @@
|
|
|
1372
1372
|
"type": "success",
|
|
1373
1373
|
"stages": [
|
|
1374
1374
|
{
|
|
1375
|
-
"output": "-
|
|
1375
|
+
"output": "-(a,b)",
|
|
1376
1376
|
"variables": "[]"
|
|
1377
1377
|
}
|
|
1378
1378
|
]
|
|
@@ -1388,7 +1388,7 @@
|
|
|
1388
1388
|
"type": "success",
|
|
1389
1389
|
"stages": [
|
|
1390
1390
|
{
|
|
1391
|
-
"output": "-
|
|
1391
|
+
"output": "-(1*2)",
|
|
1392
1392
|
"variables": "[]"
|
|
1393
1393
|
}
|
|
1394
1394
|
]
|
|
@@ -1404,7 +1404,7 @@
|
|
|
1404
1404
|
"type": "success",
|
|
1405
1405
|
"stages": [
|
|
1406
1406
|
{
|
|
1407
|
-
"output": "-
|
|
1407
|
+
"output": "-a",
|
|
1408
1408
|
"variables": "[]"
|
|
1409
1409
|
}
|
|
1410
1410
|
]
|
|
@@ -1420,7 +1420,7 @@
|
|
|
1420
1420
|
"type": "success",
|
|
1421
1421
|
"stages": [
|
|
1422
1422
|
{
|
|
1423
|
-
"output": "-
|
|
1423
|
+
"output": "-(-)",
|
|
1424
1424
|
"variables": "[]"
|
|
1425
1425
|
}
|
|
1426
1426
|
]
|
|
@@ -1436,7 +1436,7 @@
|
|
|
1436
1436
|
"type": "success",
|
|
1437
1437
|
"stages": [
|
|
1438
1438
|
{
|
|
1439
|
-
"output": "-
|
|
1439
|
+
"output": "-[-]",
|
|
1440
1440
|
"variables": "[]"
|
|
1441
1441
|
}
|
|
1442
1442
|
]
|
|
@@ -1452,7 +1452,7 @@
|
|
|
1452
1452
|
"type": "success",
|
|
1453
1453
|
"stages": [
|
|
1454
1454
|
{
|
|
1455
|
-
"output": "-
|
|
1455
|
+
"output": "-p(c)",
|
|
1456
1456
|
"variables": "[]"
|
|
1457
1457
|
}
|
|
1458
1458
|
]
|
|
@@ -1468,7 +1468,7 @@
|
|
|
1468
1468
|
"type": "success",
|
|
1469
1469
|
"stages": [
|
|
1470
1470
|
{
|
|
1471
|
-
"output": "-
|
|
1471
|
+
"output": "-{}",
|
|
1472
1472
|
"variables": "[]"
|
|
1473
1473
|
}
|
|
1474
1474
|
]
|
|
@@ -1484,7 +1484,7 @@
|
|
|
1484
1484
|
"type": "success",
|
|
1485
1485
|
"stages": [
|
|
1486
1486
|
{
|
|
1487
|
-
"output": "-
|
|
1487
|
+
"output": "-{a}",
|
|
1488
1488
|
"variables": "[]"
|
|
1489
1489
|
}
|
|
1490
1490
|
]
|
|
@@ -1500,7 +1500,7 @@
|
|
|
1500
1500
|
"type": "success",
|
|
1501
1501
|
"stages": [
|
|
1502
1502
|
{
|
|
1503
|
-
"output": "- -
|
|
1503
|
+
"output": "- -a",
|
|
1504
1504
|
"variables": "[]"
|
|
1505
1505
|
}
|
|
1506
1506
|
]
|
|
@@ -1516,7 +1516,7 @@
|
|
|
1516
1516
|
"type": "success",
|
|
1517
1517
|
"stages": [
|
|
1518
1518
|
{
|
|
1519
|
-
"output": "- - -
|
|
1519
|
+
"output": "- - -a",
|
|
1520
1520
|
"variables": "[]"
|
|
1521
1521
|
}
|
|
1522
1522
|
]
|
|
@@ -1532,7 +1532,7 @@
|
|
|
1532
1532
|
"type": "success",
|
|
1533
1533
|
"stages": [
|
|
1534
1534
|
{
|
|
1535
|
-
"output": "- -
|
|
1535
|
+
"output": "- -(1)",
|
|
1536
1536
|
"variables": "[]"
|
|
1537
1537
|
}
|
|
1538
1538
|
]
|
|
@@ -1552,7 +1552,7 @@
|
|
|
1552
1552
|
"variables": "[]"
|
|
1553
1553
|
},
|
|
1554
1554
|
{
|
|
1555
|
-
"output": "-
|
|
1555
|
+
"output": "-(1~2~3)",
|
|
1556
1556
|
"variables": "[]"
|
|
1557
1557
|
}
|
|
1558
1558
|
]
|
|
@@ -1572,7 +1572,7 @@
|
|
|
1572
1572
|
"variables": "[]"
|
|
1573
1573
|
},
|
|
1574
1574
|
{
|
|
1575
|
-
"output": "-
|
|
1575
|
+
"output": "-(1~2)",
|
|
1576
1576
|
"variables": "[]"
|
|
1577
1577
|
}
|
|
1578
1578
|
]
|
|
@@ -1592,7 +1592,7 @@
|
|
|
1592
1592
|
"variables": "[]"
|
|
1593
1593
|
},
|
|
1594
1594
|
{
|
|
1595
|
-
"output": "1
|
|
1595
|
+
"output": "1~2",
|
|
1596
1596
|
"variables": "[]"
|
|
1597
1597
|
}
|
|
1598
1598
|
]
|
|
@@ -1608,7 +1608,7 @@
|
|
|
1608
1608
|
"type": "success",
|
|
1609
1609
|
"stages": [
|
|
1610
1610
|
{
|
|
1611
|
-
"output": "-
|
|
1611
|
+
"output": "-[1]",
|
|
1612
1612
|
"variables": "[]"
|
|
1613
1613
|
}
|
|
1614
1614
|
]
|
|
@@ -1624,7 +1624,7 @@
|
|
|
1624
1624
|
"type": "success",
|
|
1625
1625
|
"stages": [
|
|
1626
1626
|
{
|
|
1627
|
-
"output": "-
|
|
1627
|
+
"output": "-A",
|
|
1628
1628
|
"variables": "[]"
|
|
1629
1629
|
}
|
|
1630
1630
|
]
|
|
@@ -1640,7 +1640,7 @@
|
|
|
1640
1640
|
"type": "success",
|
|
1641
1641
|
"stages": [
|
|
1642
1642
|
{
|
|
1643
|
-
"output": "-
|
|
1643
|
+
"output": "-A",
|
|
1644
1644
|
"variables": "[]"
|
|
1645
1645
|
},
|
|
1646
1646
|
{
|
|
@@ -1660,11 +1660,11 @@
|
|
|
1660
1660
|
"type": "success",
|
|
1661
1661
|
"stages": [
|
|
1662
1662
|
{
|
|
1663
|
-
"output": "-
|
|
1663
|
+
"output": "-A",
|
|
1664
1664
|
"variables": "[]"
|
|
1665
1665
|
},
|
|
1666
1666
|
{
|
|
1667
|
-
"output": "-1
|
|
1667
|
+
"output": "-1'$VAR'",
|
|
1668
1668
|
"variables": "[]"
|
|
1669
1669
|
}
|
|
1670
1670
|
]
|
|
@@ -1685,7 +1685,7 @@
|
|
|
1685
1685
|
},
|
|
1686
1686
|
{
|
|
1687
1687
|
"output": "",
|
|
1688
|
-
"variables": "['X'
|
|
1688
|
+
"variables": "['X'= -1]"
|
|
1689
1689
|
}
|
|
1690
1690
|
]
|
|
1691
1691
|
}
|
|
@@ -1732,7 +1732,7 @@
|
|
|
1732
1732
|
"type": "success",
|
|
1733
1733
|
"stages": [
|
|
1734
1734
|
{
|
|
1735
|
-
"output": "+
|
|
1735
|
+
"output": "+1^2",
|
|
1736
1736
|
"variables": "[]"
|
|
1737
1737
|
}
|
|
1738
1738
|
]
|
|
@@ -1759,7 +1759,7 @@
|
|
|
1759
1759
|
"type": "success",
|
|
1760
1760
|
"stages": [
|
|
1761
1761
|
{
|
|
1762
|
-
"output": "[+
|
|
1762
|
+
"output": "[+{a},+[]]",
|
|
1763
1763
|
"variables": "[]"
|
|
1764
1764
|
}
|
|
1765
1765
|
]
|
|
@@ -1840,7 +1840,7 @@
|
|
|
1840
1840
|
},
|
|
1841
1841
|
{
|
|
1842
1842
|
"output": "",
|
|
1843
|
-
"variables": "['X'
|
|
1843
|
+
"variables": "['X'=[a|b]]"
|
|
1844
1844
|
}
|
|
1845
1845
|
]
|
|
1846
1846
|
}
|
|
@@ -2165,7 +2165,7 @@
|
|
|
2165
2165
|
"stages": [
|
|
2166
2166
|
{
|
|
2167
2167
|
"output": "",
|
|
2168
|
-
"variables": "['X'
|
|
2168
|
+
"variables": "['X'=1]"
|
|
2169
2169
|
}
|
|
2170
2170
|
]
|
|
2171
2171
|
}
|
|
@@ -2246,7 +2246,7 @@
|
|
|
2246
2246
|
"stages": [
|
|
2247
2247
|
{
|
|
2248
2248
|
"output": "",
|
|
2249
|
-
"variables": "['X'
|
|
2249
|
+
"variables": "['X'=a141]"
|
|
2250
2250
|
}
|
|
2251
2251
|
]
|
|
2252
2252
|
}
|
|
@@ -2467,7 +2467,7 @@
|
|
|
2467
2467
|
},
|
|
2468
2468
|
{
|
|
2469
2469
|
"output": "",
|
|
2470
|
-
"variables": "['X'
|
|
2470
|
+
"variables": "['X'=0]"
|
|
2471
2471
|
}
|
|
2472
2472
|
]
|
|
2473
2473
|
}
|
|
@@ -2486,7 +2486,7 @@
|
|
|
2486
2486
|
"variables": "[]"
|
|
2487
2487
|
},
|
|
2488
2488
|
{
|
|
2489
|
-
"output": "0
|
|
2489
|
+
"output": "0''",
|
|
2490
2490
|
"variables": "[]"
|
|
2491
2491
|
}
|
|
2492
2492
|
]
|
|
@@ -2506,7 +2506,7 @@
|
|
|
2506
2506
|
"variables": "[]"
|
|
2507
2507
|
},
|
|
2508
2508
|
{
|
|
2509
|
-
"output": "0
|
|
2509
|
+
"output": "0''",
|
|
2510
2510
|
"variables": "[]"
|
|
2511
2511
|
}
|
|
2512
2512
|
]
|
|
@@ -2543,7 +2543,7 @@
|
|
|
2543
2543
|
},
|
|
2544
2544
|
{
|
|
2545
2545
|
"output": "",
|
|
2546
|
-
"variables": "['F'
|
|
2546
|
+
"variables": "['F'=(''),'A'=2]"
|
|
2547
2547
|
}
|
|
2548
2548
|
]
|
|
2549
2549
|
}
|
|
@@ -2563,7 +2563,7 @@
|
|
|
2563
2563
|
},
|
|
2564
2564
|
{
|
|
2565
2565
|
"output": "",
|
|
2566
|
-
"variables": "['F'
|
|
2566
|
+
"variables": "['F'=(''),'A'=2]"
|
|
2567
2567
|
}
|
|
2568
2568
|
]
|
|
2569
2569
|
}
|
|
@@ -2653,7 +2653,7 @@
|
|
|
2653
2653
|
"variables": "[]"
|
|
2654
2654
|
},
|
|
2655
2655
|
{
|
|
2656
|
-
"output": "0
|
|
2656
|
+
"output": "0'f '",
|
|
2657
2657
|
"variables": "[]"
|
|
2658
2658
|
}
|
|
2659
2659
|
]
|
|
@@ -2685,7 +2685,7 @@
|
|
|
2685
2685
|
},
|
|
2686
2686
|
{
|
|
2687
2687
|
"output": "",
|
|
2688
|
-
"variables": "['F'
|
|
2688
|
+
"variables": "['F'=('1'),'A'=2]"
|
|
2689
2689
|
}
|
|
2690
2690
|
]
|
|
2691
2691
|
}
|
|
@@ -2705,7 +2705,7 @@
|
|
|
2705
2705
|
},
|
|
2706
2706
|
{
|
|
2707
2707
|
"output": "",
|
|
2708
|
-
"variables": "['F'
|
|
2708
|
+
"variables": "['F'=('1'),'A'=2]"
|
|
2709
2709
|
}
|
|
2710
2710
|
]
|
|
2711
2711
|
}
|
|
@@ -2721,7 +2721,7 @@
|
|
|
2721
2721
|
"stages": [
|
|
2722
2722
|
{
|
|
2723
2723
|
"output": "",
|
|
2724
|
-
"variables": "['X'
|
|
2724
|
+
"variables": "['X'=65]"
|
|
2725
2725
|
}
|
|
2726
2726
|
]
|
|
2727
2727
|
}
|
|
@@ -2737,7 +2737,7 @@
|
|
|
2737
2737
|
"stages": [
|
|
2738
2738
|
{
|
|
2739
2739
|
"output": "",
|
|
2740
|
-
"variables": "['X'
|
|
2740
|
+
"variables": "['X'=65]"
|
|
2741
2741
|
}
|
|
2742
2742
|
]
|
|
2743
2743
|
}
|
|
@@ -2753,7 +2753,7 @@
|
|
|
2753
2753
|
"stages": [
|
|
2754
2754
|
{
|
|
2755
2755
|
"output": "",
|
|
2756
|
-
"variables": "['X'
|
|
2756
|
+
"variables": "['X'=1]"
|
|
2757
2757
|
}
|
|
2758
2758
|
]
|
|
2759
2759
|
}
|
|
@@ -2780,7 +2780,7 @@
|
|
|
2780
2780
|
"stages": [
|
|
2781
2781
|
{
|
|
2782
2782
|
"output": "",
|
|
2783
|
-
"variables": "['X'
|
|
2783
|
+
"variables": "['X'=0]"
|
|
2784
2784
|
}
|
|
2785
2785
|
]
|
|
2786
2786
|
}
|
|
@@ -2796,7 +2796,7 @@
|
|
|
2796
2796
|
"stages": [
|
|
2797
2797
|
{
|
|
2798
2798
|
"output": "",
|
|
2799
|
-
"variables": "['X'
|
|
2799
|
+
"variables": "['X'=1]"
|
|
2800
2800
|
}
|
|
2801
2801
|
]
|
|
2802
2802
|
}
|
|
@@ -2823,7 +2823,7 @@
|
|
|
2823
2823
|
"stages": [
|
|
2824
2824
|
{
|
|
2825
2825
|
"output": "",
|
|
2826
|
-
"variables": "['X'
|
|
2826
|
+
"variables": "['X'=2]"
|
|
2827
2827
|
}
|
|
2828
2828
|
]
|
|
2829
2829
|
}
|
|
@@ -2839,7 +2839,7 @@
|
|
|
2839
2839
|
"stages": [
|
|
2840
2840
|
{
|
|
2841
2841
|
"output": "",
|
|
2842
|
-
"variables": "['X'
|
|
2842
|
+
"variables": "['X'=2]"
|
|
2843
2843
|
}
|
|
2844
2844
|
]
|
|
2845
2845
|
}
|
|
@@ -2855,7 +2855,7 @@
|
|
|
2855
2855
|
"stages": [
|
|
2856
2856
|
{
|
|
2857
2857
|
"output": "",
|
|
2858
|
-
"variables": "['X'
|
|
2858
|
+
"variables": "['X'=1]"
|
|
2859
2859
|
}
|
|
2860
2860
|
]
|
|
2861
2861
|
}
|
|
@@ -2871,7 +2871,7 @@
|
|
|
2871
2871
|
"stages": [
|
|
2872
2872
|
{
|
|
2873
2873
|
"output": "",
|
|
2874
|
-
"variables": "['X'
|
|
2874
|
+
"variables": "['X'=0+1]"
|
|
2875
2875
|
}
|
|
2876
2876
|
]
|
|
2877
2877
|
}
|
|
@@ -2957,7 +2957,7 @@
|
|
|
2957
2957
|
"variables": "[]"
|
|
2958
2958
|
},
|
|
2959
2959
|
{
|
|
2960
|
-
"output": "' op'
|
|
2960
|
+
"output": "' op'[]",
|
|
2961
2961
|
"variables": "[]"
|
|
2962
2962
|
}
|
|
2963
2963
|
]
|
|
@@ -2984,7 +2984,7 @@
|
|
|
2984
2984
|
"type": "success",
|
|
2985
2985
|
"stages": [
|
|
2986
2986
|
{
|
|
2987
|
-
"output": "-
|
|
2987
|
+
"output": "-(a*b)",
|
|
2988
2988
|
"variables": "[]"
|
|
2989
2989
|
}
|
|
2990
2990
|
]
|
|
@@ -3000,7 +3000,7 @@
|
|
|
3000
3000
|
"type": "success",
|
|
3001
3001
|
"stages": [
|
|
3002
3002
|
{
|
|
3003
|
-
"output": "\\
|
|
3003
|
+
"output": "\\(a*b)",
|
|
3004
3004
|
"variables": "[]"
|
|
3005
3005
|
}
|
|
3006
3006
|
]
|
|
@@ -3086,7 +3086,7 @@
|
|
|
3086
3086
|
"variables": "[]"
|
|
3087
3087
|
},
|
|
3088
3088
|
{
|
|
3089
|
-
"output": "-
|
|
3089
|
+
"output": "-[1]",
|
|
3090
3090
|
"variables": "[]"
|
|
3091
3091
|
}
|
|
3092
3092
|
]
|
|
@@ -3107,7 +3107,7 @@
|
|
|
3107
3107
|
},
|
|
3108
3108
|
{
|
|
3109
3109
|
"output": "",
|
|
3110
|
-
"variables": "['X'
|
|
3110
|
+
"variables": "['X'=[1|e]]"
|
|
3111
3111
|
}
|
|
3112
3112
|
]
|
|
3113
3113
|
}
|
|
@@ -3131,7 +3131,7 @@
|
|
|
3131
3131
|
},
|
|
3132
3132
|
{
|
|
3133
3133
|
"output": "",
|
|
3134
|
-
"variables": "['X'
|
|
3134
|
+
"variables": "['X'=1]"
|
|
3135
3135
|
}
|
|
3136
3136
|
]
|
|
3137
3137
|
}
|
|
@@ -3711,7 +3711,7 @@
|
|
|
3711
3711
|
"type": "success",
|
|
3712
3712
|
"stages": [
|
|
3713
3713
|
{
|
|
3714
|
-
"output": "'.'
|
|
3714
|
+
"output": "'.'+'.'",
|
|
3715
3715
|
"variables": "[]"
|
|
3716
3716
|
}
|
|
3717
3717
|
]
|
|
@@ -3795,7 +3795,7 @@
|
|
|
3795
3795
|
"stages": [
|
|
3796
3796
|
{
|
|
3797
3797
|
"output": "9.8813129168249309e-324",
|
|
3798
|
-
"variables": "['X'
|
|
3798
|
+
"variables": "['X'=9.8813129168249309e-324]"
|
|
3799
3799
|
}
|
|
3800
3800
|
]
|
|
3801
3801
|
}
|
|
@@ -3843,7 +3843,7 @@
|
|
|
3843
3843
|
"stages": [
|
|
3844
3844
|
{
|
|
3845
3845
|
"output": "",
|
|
3846
|
-
"variables": "['T'
|
|
3846
|
+
"variables": "['T'=t(1,1,1)]"
|
|
3847
3847
|
}
|
|
3848
3848
|
]
|
|
3849
3849
|
}
|
|
@@ -3859,7 +3859,7 @@
|
|
|
3859
3859
|
"stages": [
|
|
3860
3860
|
{
|
|
3861
3861
|
"output": "",
|
|
3862
|
-
"variables": "['X'
|
|
3862
|
+
"variables": "['X'=1]"
|
|
3863
3863
|
}
|
|
3864
3864
|
]
|
|
3865
3865
|
}
|
|
@@ -3894,7 +3894,7 @@
|
|
|
3894
3894
|
"variables": "[]"
|
|
3895
3895
|
},
|
|
3896
3896
|
{
|
|
3897
|
-
"output": "a
|
|
3897
|
+
"output": "a-->b,c'|'d",
|
|
3898
3898
|
"variables": "[]"
|
|
3899
3899
|
}
|
|
3900
3900
|
]
|
|
@@ -3965,7 +3965,7 @@
|
|
|
3965
3965
|
"variables": "[]"
|
|
3966
3966
|
},
|
|
3967
3967
|
{
|
|
3968
|
-
"output": "[(a
|
|
3968
|
+
"output": "[(a'|'b)]",
|
|
3969
3969
|
"variables": "[]"
|
|
3970
3970
|
}
|
|
3971
3971
|
]
|
|
@@ -3985,7 +3985,7 @@
|
|
|
3985
3985
|
"variables": "[]"
|
|
3986
3986
|
},
|
|
3987
3987
|
{
|
|
3988
|
-
"output": "[a,(b,
|
|
3988
|
+
"output": "[a,(b,c)]",
|
|
3989
3989
|
"variables": "[]"
|
|
3990
3990
|
}
|
|
3991
3991
|
]
|
|
@@ -4002,7 +4002,7 @@
|
|
|
4002
4002
|
"stages": [
|
|
4003
4003
|
{
|
|
4004
4004
|
"output": "",
|
|
4005
|
-
"variables": "['X'
|
|
4005
|
+
"variables": "['X'=7]"
|
|
4006
4006
|
}
|
|
4007
4007
|
]
|
|
4008
4008
|
}
|
|
@@ -4018,7 +4018,7 @@
|
|
|
4018
4018
|
"stages": [
|
|
4019
4019
|
{
|
|
4020
4020
|
"output": "",
|
|
4021
|
-
"variables": "['X'
|
|
4021
|
+
"variables": "['X'=7]"
|
|
4022
4022
|
}
|
|
4023
4023
|
]
|
|
4024
4024
|
}
|
|
@@ -4097,7 +4097,7 @@
|
|
|
4097
4097
|
"stages": [
|
|
4098
4098
|
{
|
|
4099
4099
|
"output": "'\\0\\'",
|
|
4100
|
-
"variables": "['C'
|
|
4100
|
+
"variables": "['C'='\\0\\']"
|
|
4101
4101
|
}
|
|
4102
4102
|
]
|
|
4103
4103
|
}
|
|
@@ -4145,7 +4145,7 @@
|
|
|
4145
4145
|
"stages": [
|
|
4146
4146
|
{
|
|
4147
4147
|
"output": "+(_A,_A)",
|
|
4148
|
-
"variables": "['B'
|
|
4148
|
+
"variables": "['B'=B]"
|
|
4149
4149
|
}
|
|
4150
4150
|
]
|
|
4151
4151
|
}
|
|
@@ -4219,7 +4219,7 @@
|
|
|
4219
4219
|
"variables": "[]"
|
|
4220
4220
|
},
|
|
4221
4221
|
{
|
|
4222
|
-
"output": "f (1,
|
|
4222
|
+
"output": "f (1,2)",
|
|
4223
4223
|
"variables": "[]"
|
|
4224
4224
|
}
|
|
4225
4225
|
]
|
|
@@ -4282,7 +4282,7 @@
|
|
|
4282
4282
|
"variables": "[]"
|
|
4283
4283
|
},
|
|
4284
4284
|
{
|
|
4285
|
-
"output": "a
|
|
4285
|
+
"output": "a>. >b",
|
|
4286
4286
|
"variables": "[]"
|
|
4287
4287
|
}
|
|
4288
4288
|
]
|
|
@@ -4393,7 +4393,7 @@
|
|
|
4393
4393
|
"variables": "[]"
|
|
4394
4394
|
},
|
|
4395
4395
|
{
|
|
4396
|
-
"output": ">(a)
|
|
4396
|
+
"output": ">(a)>b",
|
|
4397
4397
|
"variables": "[]"
|
|
4398
4398
|
}
|
|
4399
4399
|
]
|
|
@@ -4693,7 +4693,7 @@
|
|
|
4693
4693
|
"stages": [
|
|
4694
4694
|
{
|
|
4695
4695
|
"output": "",
|
|
4696
|
-
"variables": "['C'
|
|
4696
|
+
"variables": "['C'=' ']"
|
|
4697
4697
|
}
|
|
4698
4698
|
]
|
|
4699
4699
|
}
|
|
@@ -4709,7 +4709,7 @@
|
|
|
4709
4709
|
"stages": [
|
|
4710
4710
|
{
|
|
4711
4711
|
"output": "",
|
|
4712
|
-
"variables": "['C'
|
|
4712
|
+
"variables": "['C'='%']"
|
|
4713
4713
|
}
|
|
4714
4714
|
]
|
|
4715
4715
|
}
|
|
@@ -4735,7 +4735,7 @@
|
|
|
4735
4735
|
"type": "success",
|
|
4736
4736
|
"stages": [
|
|
4737
4737
|
{
|
|
4738
|
-
"output": "--
|
|
4738
|
+
"output": "--a",
|
|
4739
4739
|
"variables": "[]"
|
|
4740
4740
|
}
|
|
4741
4741
|
]
|
|
@@ -4751,7 +4751,7 @@
|
|
|
4751
4751
|
"type": "success",
|
|
4752
4752
|
"stages": [
|
|
4753
4753
|
{
|
|
4754
|
-
"output": "--
|
|
4754
|
+
"output": "--a",
|
|
4755
4755
|
"variables": "[]"
|
|
4756
4756
|
},
|
|
4757
4757
|
{
|
|
@@ -4803,7 +4803,7 @@
|
|
|
4803
4803
|
"type": "success",
|
|
4804
4804
|
"stages": [
|
|
4805
4805
|
{
|
|
4806
|
-
"output": "0
|
|
4806
|
+
"output": "0+1",
|
|
4807
4807
|
"variables": "[]"
|
|
4808
4808
|
}
|
|
4809
4809
|
]
|
|
@@ -4841,7 +4841,7 @@
|
|
|
4841
4841
|
"type": "success",
|
|
4842
4842
|
"stages": [
|
|
4843
4843
|
{
|
|
4844
|
-
"output": "[(a,
|
|
4844
|
+
"output": "[(a,b)]",
|
|
4845
4845
|
"variables": "[]"
|
|
4846
4846
|
}
|
|
4847
4847
|
]
|
|
@@ -4857,7 +4857,7 @@
|
|
|
4857
4857
|
"type": "success",
|
|
4858
4858
|
"stages": [
|
|
4859
4859
|
{
|
|
4860
|
-
"output": "1
|
|
4860
|
+
"output": "1= \\\\",
|
|
4861
4861
|
"variables": "[]"
|
|
4862
4862
|
}
|
|
4863
4863
|
]
|
|
@@ -4923,7 +4923,7 @@
|
|
|
4923
4923
|
"stages": [
|
|
4924
4924
|
{
|
|
4925
4925
|
"output": "",
|
|
4926
|
-
"variables": "['T'
|
|
4926
|
+
"variables": "['T'=(a,b)]"
|
|
4927
4927
|
}
|
|
4928
4928
|
]
|
|
4929
4929
|
}
|
|
@@ -4958,7 +4958,7 @@
|
|
|
4958
4958
|
"variables": "[]"
|
|
4959
4959
|
},
|
|
4960
4960
|
{
|
|
4961
|
-
"output": "~
|
|
4961
|
+
"output": "~(a=b)",
|
|
4962
4962
|
"variables": "[]"
|
|
4963
4963
|
}
|
|
4964
4964
|
]
|
|
@@ -4974,7 +4974,7 @@
|
|
|
4974
4974
|
"type": "success",
|
|
4975
4975
|
"stages": [
|
|
4976
4976
|
{
|
|
4977
|
-
"output": "\\
|
|
4977
|
+
"output": "\\(a=b)",
|
|
4978
4978
|
"variables": "[]"
|
|
4979
4979
|
}
|
|
4980
4980
|
]
|
|
@@ -4990,7 +4990,7 @@
|
|
|
4990
4990
|
"type": "success",
|
|
4991
4991
|
"stages": [
|
|
4992
4992
|
{
|
|
4993
|
-
"output": "+
|
|
4993
|
+
"output": "+(a=b)",
|
|
4994
4994
|
"variables": "[]"
|
|
4995
4995
|
}
|
|
4996
4996
|
]
|
|
@@ -5038,7 +5038,7 @@
|
|
|
5038
5038
|
"type": "success",
|
|
5039
5039
|
"stages": [
|
|
5040
5040
|
{
|
|
5041
|
-
"output": "{a,
|
|
5041
|
+
"output": "{a,b}",
|
|
5042
5042
|
"variables": "[]"
|
|
5043
5043
|
}
|
|
5044
5044
|
]
|
|
@@ -5076,7 +5076,7 @@
|
|
|
5076
5076
|
"type": "success",
|
|
5077
5077
|
"stages": [
|
|
5078
5078
|
{
|
|
5079
|
-
"output": "+
|
|
5079
|
+
"output": "+(1*2)^3",
|
|
5080
5080
|
"variables": "[]"
|
|
5081
5081
|
}
|
|
5082
5082
|
]
|
|
@@ -5092,7 +5092,7 @@
|
|
|
5092
5092
|
"type": "success",
|
|
5093
5093
|
"stages": [
|
|
5094
5094
|
{
|
|
5095
|
-
"output": "-
|
|
5095
|
+
"output": "-((1*2)^3)",
|
|
5096
5096
|
"variables": "[]"
|
|
5097
5097
|
}
|
|
5098
5098
|
]
|
|
@@ -5108,7 +5108,7 @@
|
|
|
5108
5108
|
"type": "success",
|
|
5109
5109
|
"stages": [
|
|
5110
5110
|
{
|
|
5111
|
-
"output": "[a|\\+
|
|
5111
|
+
"output": "[a|\\+2]",
|
|
5112
5112
|
"variables": "[]"
|
|
5113
5113
|
}
|
|
5114
5114
|
]
|
|
@@ -5293,7 +5293,7 @@
|
|
|
5293
5293
|
"variables": "[]"
|
|
5294
5294
|
},
|
|
5295
5295
|
{
|
|
5296
|
-
"output": "a
|
|
5296
|
+
"output": "a.> .>",
|
|
5297
5297
|
"variables": "[]"
|
|
5298
5298
|
}
|
|
5299
5299
|
]
|
|
@@ -5451,7 +5451,7 @@
|
|
|
5451
5451
|
"type": "success",
|
|
5452
5452
|
"stages": [
|
|
5453
5453
|
{
|
|
5454
|
-
"output": "{a
|
|
5454
|
+
"output": "{a:-b}",
|
|
5455
5455
|
"variables": "[]"
|
|
5456
5456
|
}
|
|
5457
5457
|
]
|
|
@@ -5555,7 +5555,16 @@
|
|
|
5555
5555
|
"input": "writeq(?).",
|
|
5556
5556
|
"readCount": 1,
|
|
5557
5557
|
"expected": "?",
|
|
5558
|
-
"assertion": "upstream"
|
|
5558
|
+
"assertion": "upstream",
|
|
5559
|
+
"outcome": {
|
|
5560
|
+
"type": "success",
|
|
5561
|
+
"stages": [
|
|
5562
|
+
{
|
|
5563
|
+
"output": "?",
|
|
5564
|
+
"variables": "[]"
|
|
5565
|
+
}
|
|
5566
|
+
]
|
|
5567
|
+
}
|
|
5559
5568
|
}
|
|
5560
5569
|
],
|
|
5561
5570
|
"sourceRevision": "1.300",
|
package/test/run-regression.mjs
CHANGED
|
@@ -1333,6 +1333,24 @@ c4 ?- call((!;1)).
|
|
|
1333
1333
|
assertEqual(result.stdout, 'quads: 1 run, 1 passed, 0 failed.\n', 'quad report');
|
|
1334
1334
|
},
|
|
1335
1335
|
},
|
|
1336
|
+
{
|
|
1337
|
+
name: 'quad recursion-cycle evidence consistently refutes finite failure (issue #58 comment 5381101420)',
|
|
1338
|
+
run: () => {
|
|
1339
|
+
const result = publicApi.runQuads(`inf :- inf, inf.
|
|
1340
|
+
|
|
1341
|
+
23
|
|
1342
|
+
?- inf.
|
|
1343
|
+
loops.
|
|
1344
|
+
false.
|
|
1345
|
+
`);
|
|
1346
|
+
assertEqual(result.total, 2, 'quad total');
|
|
1347
|
+
assertEqual(result.passed, 1, 'loops passed');
|
|
1348
|
+
assertEqual(result.failed, 1, 'false failed');
|
|
1349
|
+
assertEqual(result.undecided, 0, 'no undecided result');
|
|
1350
|
+
assertIncludes(result.stdout, 'expected: false.', 'finite failure diagnostic');
|
|
1351
|
+
assertNotIncludes(result.stdout, 'undecided: recursion cycle encountered.', 'cycle is decisive');
|
|
1352
|
+
},
|
|
1353
|
+
},
|
|
1336
1354
|
{
|
|
1337
1355
|
name: 'quad search-budget exhaustion is undecided rather than loops or failure (issue #58)',
|
|
1338
1356
|
run: () => {
|
|
@@ -1383,6 +1401,21 @@ c4 ?- call((!;1)).
|
|
|
1383
1401
|
assertIncludes(nsto.stdout, 'quads: FAILED 34, <input>:1', 'NSTO diagnostic');
|
|
1384
1402
|
},
|
|
1385
1403
|
},
|
|
1404
|
+
{
|
|
1405
|
+
name: 'quads peeks/1 supplies one unconsumed look-ahead character (issue #62)',
|
|
1406
|
+
run: () => {
|
|
1407
|
+
const result = publicApi.runQuads(`29
|
|
1408
|
+
?- read(X).
|
|
1409
|
+
inputs("1."), X = 1, unexpected.
|
|
1410
|
+
inputs("1."), peeks(" "), X = 1.
|
|
1411
|
+
inputs("1. "), peeks(" "), X = 1, unexpected.
|
|
1412
|
+
`);
|
|
1413
|
+
assertEqual(result.total, 3, 'quad total');
|
|
1414
|
+
assertEqual(result.passed, 3, 'quad passed');
|
|
1415
|
+
assertEqual(result.failed, 0, 'quad failed');
|
|
1416
|
+
assertEqual(result.stdout, 'quads: 3 run, 3 passed, 0 failed.\n', 'quad report');
|
|
1417
|
+
},
|
|
1418
|
+
},
|
|
1386
1419
|
{
|
|
1387
1420
|
name: 'outputs/1 accepts DCG bodies over captured characters (issue #59)',
|
|
1388
1421
|
run: () => {
|
|
@@ -3282,6 +3315,28 @@ child.stdin.write(\`consult(${consultedAtom}).\\n\`);
|
|
|
3282
3315
|
}
|
|
3283
3316
|
},
|
|
3284
3317
|
},
|
|
3318
|
+
{
|
|
3319
|
+
name: 'read and read_term report invalid UTF-8 as representation_error(character) (issue #64)',
|
|
3320
|
+
run: () => {
|
|
3321
|
+
const invalidPath = path.join(tmp, `read-invalid-utf8-${++tmpCounter}.bin`);
|
|
3322
|
+
fs.writeFileSync(invalidPath, Buffer.from([0xff]));
|
|
3323
|
+
const quotedPath = sourceAtom(invalidPath);
|
|
3324
|
+
for (const goal of [
|
|
3325
|
+
`open(${quotedPath}, read, S, []), read(S, C)`,
|
|
3326
|
+
`open(${quotedPath}, read, S, []), read_term(S, C, [])`,
|
|
3327
|
+
`open(${quotedPath}, read, S, []), set_input(S), read(C)`,
|
|
3328
|
+
`open(${quotedPath}, read, S, []), set_input(S), read_term(C, [])`,
|
|
3329
|
+
]) {
|
|
3330
|
+
let caught = null;
|
|
3331
|
+
try {
|
|
3332
|
+
run('', { goal });
|
|
3333
|
+
} catch (error) {
|
|
3334
|
+
caught = error;
|
|
3335
|
+
}
|
|
3336
|
+
assertEqual(caught?.formal, 'representation_error(character)', `${goal} invalid UTF-8`);
|
|
3337
|
+
}
|
|
3338
|
+
},
|
|
3339
|
+
},
|
|
3285
3340
|
{
|
|
3286
3341
|
name: 'writeq gives unnamed variables underscore-prefixed names (issue #53)',
|
|
3287
3342
|
run: () => {
|
|
@@ -3310,6 +3365,13 @@ child.stdin.write(\`consult(${consultedAtom}).\\n\`);
|
|
|
3310
3365
|
);
|
|
3311
3366
|
},
|
|
3312
3367
|
},
|
|
3368
|
+
{
|
|
3369
|
+
name: 'writeq separates operators only where lexical ambiguity requires it (issue #63)',
|
|
3370
|
+
run: () => {
|
|
3371
|
+
const source = "emit :- writeq(1+2), put_char('|'), writeq(a+ -b), put_char('|'), writeq(a+b*c), nl.\n";
|
|
3372
|
+
assertEqual(run(source, { goal: 'emit' }).stdout, '1+2|a+ -b|a+b*c\nemit.\n', 'minimal operator spacing');
|
|
3373
|
+
},
|
|
3374
|
+
},
|
|
3313
3375
|
{
|
|
3314
3376
|
name: 'write predicates and write_term options select distinct formats',
|
|
3315
3377
|
run: () => {
|
|
@@ -3332,7 +3394,7 @@ child.stdin.write(\`consult(${consultedAtom}).\\n\`);
|
|
|
3332
3394
|
].join('\n');
|
|
3333
3395
|
assertEqual(
|
|
3334
3396
|
run(source, { goal: 'emit' }).stdout,
|
|
3335
|
-
"hello world|'hello world'|a
|
|
3397
|
+
"hello world|'hello world'|a+b*c|+(a,*(b,c))|hello world|'hello world'|+(a,b)|a+b|A|$VAR(0)|pair(Left,Right)|\"ab\"|[a,b]emit.\n",
|
|
3336
3398
|
'stdout',
|
|
3337
3399
|
);
|
|
3338
3400
|
},
|
package/the-art-of-eyeprolog.md
CHANGED
|
@@ -5412,8 +5412,11 @@ where needed, and `write_canonical/1-2` exposes canonical structure. Dotted
|
|
|
5412
5412
|
graphic atoms do not need quotes merely because they contain a period:
|
|
5413
5413
|
`writeq(./*)`, `writeq(.*)`, and `writeq(...*)` output `./*`, `.*`, and `...*`
|
|
5414
5414
|
respectively. ISO term output uses only the separator characters needed by the
|
|
5415
|
-
syntax, so functional arguments
|
|
5416
|
-
|
|
5415
|
+
syntax, so functional arguments, list elements, and operator applications are
|
|
5416
|
+
emitted compactly when no lexical ambiguity would arise. For example,
|
|
5417
|
+
`writeq([a,b])` outputs `[a,b]` and `writeq(1+2)` outputs `1+2`; a separator is
|
|
5418
|
+
still retained where adjacent graphic tokens would otherwise merge, as in
|
|
5419
|
+
`a+ -b`.
|
|
5417
5420
|
`write_term/2-3` supports `quoted/1`, `ignore_ops/1`, `numbervars/1`, and
|
|
5418
5421
|
`variable_names/1`.
|
|
5419
5422
|
|
|
@@ -6891,13 +6894,26 @@ variable in the renamed exception term. `...` and `ad_infinitum` accept further
|
|
|
6891
6894
|
indented descriptions after one query are independent checks: each re-runs the
|
|
6892
6895
|
query, each is counted in the `quads:` summary, and a failing description does
|
|
6893
6896
|
not suppress later descriptions for that query. `inputs/1` supplies and checks
|
|
6894
|
-
consumed
|
|
6895
|
-
|
|
6896
|
-
|
|
6897
|
-
|
|
6898
|
-
|
|
6899
|
-
|
|
6900
|
-
|
|
6897
|
+
exactly the characters consumed by the query. `peeks/1` may add one character
|
|
6898
|
+
that is available for look-ahead but must remain unconsumed. The runner puts an
|
|
6899
|
+
invalid-character sentinel immediately after the declared input boundary, so a
|
|
6900
|
+
reader cannot accidentally use an artificial end-of-file to decide that a full
|
|
6901
|
+
stop terminates the term. For example:
|
|
6902
|
+
|
|
6903
|
+
```eyeprolog
|
|
6904
|
+
?- read(X).
|
|
6905
|
+
inputs("1."), X = 1, unexpected.
|
|
6906
|
+
inputs("1."), peeks(" "), X = 1.
|
|
6907
|
+
inputs("1. "), peeks(" "), X = 1, unexpected.
|
|
6908
|
+
```
|
|
6909
|
+
|
|
6910
|
+
`outputs/1` checks characters emitted while reaching the described answer or
|
|
6911
|
+
error, including output produced before a later exception. Its argument may be
|
|
6912
|
+
an exact character list/string or a DCG body: terminal sequences,
|
|
6913
|
+
conjunction/disjunction, `...`/`ad_infinitum` sequence wildcards, and
|
|
6914
|
+
user-defined DCG nonterminals are matched against the captured characters.
|
|
6915
|
+
The `waits` and unordered `other_answer_sequence` annotations are not executed
|
|
6916
|
+
by the current runner.
|
|
6901
6917
|
|
|
6902
6918
|
#### STO, loops, and undecided quad results
|
|
6903
6919
|
|
|
@@ -6933,7 +6949,10 @@ does not guess.
|
|
|
6933
6949
|
|
|
6934
6950
|
`loops` is kept distinct from merely exhausting the quad runner's resources.
|
|
6935
6951
|
EyeProlog accepts structural nontermination evidence such as an active-variant
|
|
6936
|
-
recursion cycle, with the loop depth/inference bounds as a bounded fallback
|
|
6952
|
+
recursion cycle, with the loop depth/inference bounds as a bounded fallback. A
|
|
6953
|
+
structural cycle is also strong enough to refute a finite `false` description;
|
|
6954
|
+
it is not reported as undecided merely because the same query was checked by a
|
|
6955
|
+
different answer description:
|
|
6937
6956
|
|
|
6938
6957
|
```eyeprolog
|
|
6939
6958
|
inf :- inf, inf.
|