eyeprolog 1.5.75 → 1.5.77
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 +22 -8
- package/test/regression/cases-regression.mjs +33 -0
package/package.json
CHANGED
package/src/iso.js
CHANGED
|
@@ -1153,24 +1153,38 @@ function streamHandle(id) {
|
|
|
1153
1153
|
return compound('$stream', [numberTerm(id)]);
|
|
1154
1154
|
}
|
|
1155
1155
|
|
|
1156
|
+
function streamHandleId(value, env) {
|
|
1157
|
+
// A `$stream(Id)` term is an ordinary compound, not an opaque blob, so
|
|
1158
|
+
// general term-construction predicates such as functor/3 and arg/3 can
|
|
1159
|
+
// rebuild one whose argument is a variable that only later gets unified
|
|
1160
|
+
// with the real stream number (issue #109). Deref that argument, the same
|
|
1161
|
+
// as any other compound argument, instead of inspecting the raw arg term
|
|
1162
|
+
// and rejecting an equally valid stream reference as malformed.
|
|
1163
|
+
if (value.type !== COMPOUND || value.name !== '$stream' || value.arity !== 1) return null;
|
|
1164
|
+
const id = deref(value.args[0], env);
|
|
1165
|
+
// The shape is right, but the argument that would identify the stream is
|
|
1166
|
+
// still unbound: whether this term is a valid stream reference cannot be
|
|
1167
|
+
// decided yet, so that is an instantiation error, not a domain error (see
|
|
1168
|
+
// issue #109's stc#72 follow-up) — unlike a wrong functor/arity above,
|
|
1169
|
+
// which can never become valid no matter how any variable gets bound.
|
|
1170
|
+
if (id.type === VAR) throw new PrologError('instantiation_error');
|
|
1171
|
+
return id.type === NUMBER && isDecimalInteger(id.name) ? Number(id.name) : null;
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1156
1174
|
function streamReference(term, env) {
|
|
1157
1175
|
const value = deref(term, env);
|
|
1158
1176
|
if (value.type === VAR) throw new PrologError('instantiation_error');
|
|
1159
1177
|
if (value.type === ATOM) return value.name;
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
return Number(value.args[0].name);
|
|
1163
|
-
}
|
|
1178
|
+
const id = streamHandleId(value, env);
|
|
1179
|
+
if (id != null) return id;
|
|
1164
1180
|
throw new PrologError('domain_error(stream_or_alias)', value);
|
|
1165
1181
|
}
|
|
1166
1182
|
|
|
1167
1183
|
function streamTermReference(term, env) {
|
|
1168
1184
|
const value = deref(term, env);
|
|
1169
1185
|
if (value.type === VAR) return null;
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
return Number(value.args[0].name);
|
|
1173
|
-
}
|
|
1186
|
+
const id = streamHandleId(value, env);
|
|
1187
|
+
if (id != null) return id;
|
|
1174
1188
|
throw new PrologError('domain_error(stream)', value);
|
|
1175
1189
|
}
|
|
1176
1190
|
|
|
@@ -28,6 +28,39 @@ import {
|
|
|
28
28
|
|
|
29
29
|
export function regressionCases() {
|
|
30
30
|
return [
|
|
31
|
+
{
|
|
32
|
+
name: 'close/1 accepts a $stream/1 term rebuilt via functor/3 and arg/3 that is structurally == to the real handle (issue #109)',
|
|
33
|
+
run: () => {
|
|
34
|
+
const file = sourceAtom(path.join(temp.dir, `stream-109-${++temp.counter}.txt`));
|
|
35
|
+
const result = runCli([], { input:
|
|
36
|
+
`open(${file},write,S),functor(S,Fn,A),functor(S2,Fn,A),arg(1,S,A1),arg(1,S2,A1),S==S2,close(S2).\n` +
|
|
37
|
+
'halt.\n',
|
|
38
|
+
});
|
|
39
|
+
assertEqual(result.status, 0, result.stderr);
|
|
40
|
+
// S2's argument only becomes the real stream number through
|
|
41
|
+
// unification rather than being built in place by open/3, so
|
|
42
|
+
// close/1 must deref it like any other compound argument instead of
|
|
43
|
+
// rejecting an equally valid, structurally-== stream reference as
|
|
44
|
+
// malformed.
|
|
45
|
+
assertNotIncludes(result.stdout + result.stderr, 'error(', 'no domain_error(stream_or_alias, ...) from close/1');
|
|
46
|
+
assertIncludes(result.stdout, 'A1 = ', 'query succeeds and reports the shared stream number');
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
name: 'close/1 raises instantiation_error, not domain_error(stream_or_alias), for a $stream/1 term whose argument is unbound (issue #109 follow-up)',
|
|
51
|
+
run: () => {
|
|
52
|
+
const result = runCli([], { input:
|
|
53
|
+
"S='$stream'(X),close(S).\nhalt.\n",
|
|
54
|
+
});
|
|
55
|
+
assertEqual(result.status, 0, result.stderr);
|
|
56
|
+
// The argument that would identify the stream is still unbound, so
|
|
57
|
+
// whether this term is a valid stream reference cannot be decided
|
|
58
|
+
// yet — that calls for instantiation_error, not a domain_error
|
|
59
|
+
// claiming the term itself is already known to be invalid.
|
|
60
|
+
assertIncludes(result.stdout, 'error(instantiation_error,', 'unbound $stream/1 argument reports instantiation_error');
|
|
61
|
+
assertNotIncludes(result.stdout, 'domain_error(stream_or_alias', 'no domain_error(stream_or_alias, ...) once the argument is still unbound');
|
|
62
|
+
},
|
|
63
|
+
},
|
|
31
64
|
{
|
|
32
65
|
name: 'top level never mints a generated variable name that collides with a query variable\'s own name (issue #108)',
|
|
33
66
|
run: () => {
|