eyeprolog 1.2.39 → 1.2.40
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 +19 -3
- package/test/run-regression.mjs +31 -0
package/package.json
CHANGED
package/src/iso.js
CHANGED
|
@@ -1076,6 +1076,7 @@ function* nlBuiltin({ solver, goal, env }) {
|
|
|
1076
1076
|
|
|
1077
1077
|
function* termTextCandidates(stream) {
|
|
1078
1078
|
const source = String(stream.content);
|
|
1079
|
+
const lastBufferedNonLayout = lastNonLayoutIndex(source, stream.position);
|
|
1079
1080
|
let quote = null, lineComment = false, blockComment = false;
|
|
1080
1081
|
for (let i = stream.position; i < source.length; i++) {
|
|
1081
1082
|
const ch = source[i], next = source[i + 1];
|
|
@@ -1106,14 +1107,29 @@ function* termTextCandidates(stream) {
|
|
|
1106
1107
|
}
|
|
1107
1108
|
if (ch === "'" || ch === '"') { quote = ch; continue; }
|
|
1108
1109
|
if (ch === '.' && isTerminatingFullStop(source, i)) {
|
|
1110
|
+
// A buffered stream exposes what follows the layout after this dot. If
|
|
1111
|
+
// the dot continues a graphic token and later non-layout input exists,
|
|
1112
|
+
// it is part of that maximal token rather than an early end char. The
|
|
1113
|
+
// interactive reader makes the corresponding decision incrementally.
|
|
1114
|
+
if (continuesGraphicToken(source, i) && lastBufferedNonLayout > i) continue;
|
|
1109
1115
|
yield { text: source.slice(stream.position, i + 1), end: i + 1 };
|
|
1110
1116
|
}
|
|
1111
1117
|
}
|
|
1112
1118
|
}
|
|
1113
1119
|
function hasNonLayoutRemainder(source, start) {
|
|
1114
|
-
return source
|
|
1115
|
-
|
|
1116
|
-
|
|
1120
|
+
return lastNonLayoutIndex(source, start) >= start;
|
|
1121
|
+
}
|
|
1122
|
+
function lastNonLayoutIndex(source, start = 0) {
|
|
1123
|
+
const ignored = /[\u0009-\u000d\u0020]+|%[^\n]*(?:\n|$)|\/\*[\s\S]*?\*\//g;
|
|
1124
|
+
ignored.lastIndex = start;
|
|
1125
|
+
let cursor = start;
|
|
1126
|
+
let last = -1;
|
|
1127
|
+
for (let match = ignored.exec(source); match != null; match = ignored.exec(source)) {
|
|
1128
|
+
if (match.index > cursor) last = match.index - 1;
|
|
1129
|
+
cursor = match.index + match[0].length;
|
|
1130
|
+
}
|
|
1131
|
+
if (cursor < source.length) last = source.length - 1;
|
|
1132
|
+
return last;
|
|
1117
1133
|
}
|
|
1118
1134
|
function convertedTermText(text, solver) {
|
|
1119
1135
|
if (solver.prologFlags.get('char_conversion')?.value?.name !== 'on' || solver.charConversions.size === 0) return text;
|
package/test/run-regression.mjs
CHANGED
|
@@ -777,6 +777,37 @@ c4 ?- call((!;1)).
|
|
|
777
777
|
assertEqual(term.args[1].name, `${name}.`, `graphic operator atom for ${name}`);
|
|
778
778
|
}
|
|
779
779
|
|
|
780
|
+
// Unlike an interactive reader waiting at a line boundary, a buffered
|
|
781
|
+
// stream can see later non-layout input. Its first dot therefore
|
|
782
|
+
// remains in the maximal graphic token, making the adjacent ! invalid
|
|
783
|
+
// rather than prematurely returning the shorter atom.
|
|
784
|
+
for (const name of [...graphicOperators, '?', '#', '@', './*', '//*']) {
|
|
785
|
+
let bufferedError = null;
|
|
786
|
+
try {
|
|
787
|
+
runEyeProlog('', {
|
|
788
|
+
goal: 'read_term(T, [])',
|
|
789
|
+
ioOptions: { input: `${name}.\n!\n.` },
|
|
790
|
+
});
|
|
791
|
+
} catch (caught) {
|
|
792
|
+
bufferedError = caught;
|
|
793
|
+
}
|
|
794
|
+
assertEqual(
|
|
795
|
+
bufferedError?.message,
|
|
796
|
+
'error(syntax_error(read_term))',
|
|
797
|
+
`buffered graphic atom boundary for ${name}`,
|
|
798
|
+
);
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
const bufferedPath = path.join(tmp, 'graphic-atom-boundary.pl');
|
|
802
|
+
fs.writeFileSync(bufferedPath, '*.\n!\n.');
|
|
803
|
+
const namedStream = runEyeProlog([
|
|
804
|
+
`caught(ok) :- open(${sourceAtom(bufferedPath)}, read, S),`,
|
|
805
|
+
' catch(read_term(S, _, []), error(syntax_error(read_term), _), true),',
|
|
806
|
+
' close(S).',
|
|
807
|
+
'',
|
|
808
|
+
].join('\n'), { goal: 'caught(ok)' });
|
|
809
|
+
assertEqual(namedStream.stdout, 'caught(ok).\n', 'named buffered stream syntax error');
|
|
810
|
+
|
|
780
811
|
let error = null;
|
|
781
812
|
try {
|
|
782
813
|
runEyeProlog('', { goal: 'read(T)', ioOptions: { input: '!.!.' } });
|