eyeprolog 1.3.81 → 1.3.82

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.81",
6
+ "version": "1.3.82",
7
7
  "description": "EyeProlog turns facts and rules into answers and proofs.",
8
8
  "type": "module",
9
9
  "main": "./index.js",
@@ -111,18 +111,88 @@ export function runRegression(reporter = new TestReporter(), requestedSection =
111
111
  function regressionCases() {
112
112
  return [
113
113
  {
114
- name: 'dif/2 keeps a delayed disequality across later unification (issue #68)',
115
- run: () => {
116
- assertEqual(run('', { goal: 'dif(1,Y),Y=1' }).stats.completed_goal_lists, 0,
117
- 'binding a constrained variable to the forbidden value fails');
118
- assertEqual(run('', { goal: 'dif(1,Y),Y=2' }).stats.completed_goal_lists, 1,
119
- 'binding a constrained variable to a different value succeeds');
120
- assertEqual(run('', { goal: 'dif(X,Y),X=Y' }).stats.completed_goal_lists, 0,
121
- 'aliasing two constrained variables fails');
122
- assertEqual(run('', { goal: 'dif(X-Y,1-2),X=Y,Y=1' }).stats.completed_goal_lists, 1,
123
- 'a specialization that makes the terms non-unifiable discharges the constraint');
124
- assertEqual(run('', { goal: 'dif(X-Y,1-2),X=Y,X=2' }).stats.completed_goal_lists, 1,
125
- 'a second specialization discharges the same structural constraint');
114
+ name: 'dif/2 passes the WG17 finite-tree comparison cases (issue #68)',
115
+ run: () => {
116
+ // Comparison cases from
117
+ // https://www.complang.tuwien.ac.at/ulrich/iso-prolog/dif
118
+ const comparisonCases = [
119
+ ['1', true, 'dif(1,2)'],
120
+ ['2', false, 'dif(1,Y),Y=1'],
121
+ ['3', true, 'dif(1,Y),Y=2'],
122
+ ['4', false, 'dif(X,-Y),X= -Y'],
123
+ ['5', false, 'dif(X,Y),X=Y'],
124
+ ['6', false, 'dif(X,Y),X=Y,X=1'],
125
+ ['7', false, 'dif(-X,-Y),X=Y'],
126
+ ['8', false, 'dif(-X,-Y),X=Y,X=1'],
127
+ ['9', true, 'dif(-X,X)'],
128
+ ['10', true, 'dif(-X,Y),X=Y'],
129
+ ['11', true, 'X=Y,dif(X-Y,1-2)'],
130
+ ['12', true, 'dif(X-Y,1-2),X=Y'],
131
+ ['13', true, 'X=Y,Y=1,dif(X-Y,1-2)'],
132
+ ['14', true, 'dif(X-Y,1-2),X=Y,Y=1'],
133
+ ['15', true, 'dif(X-Y,1-2),X=Y,X=2'],
134
+ ['16', true, 'dif(A-C,B-D),C-D=z-z,A-B=1-2'],
135
+ ['17', true, 'A-B=1-2,C-D=z-z,dif(A-C,B-D)'],
136
+ ['18', true, 'dif(A,[C|B]),A=[[]|_],A=[B]'],
137
+ ['19', true, 'dif([E],[/]),E=1'],
138
+ ['20', true, 'dif([a],B),B=[_|_],B=[b]'],
139
+ ['21', true, 'dif([],A),A=[_]'],
140
+ ['22', true, 'A=[_],dif([],A)'],
141
+ // Cases 23-26 are implementation-defined in the comparison. These
142
+ // assertions record EyeProlog's term-copying and collector
143
+ // choices so changes remain deliberate.
144
+ ['23', true, 'dif(X,a),copy_term(X,a)'],
145
+ ['24', true, 'findall(X,dif(X,a),[a])'],
146
+ ['25', true, 'setof(t,dif(X,a),_),X=a'],
147
+ ['26', true, 'setof(t,(dif(X,a);dif(X,b)),_),X=a'],
148
+ ];
149
+ for (const [id, succeeds, query] of comparisonCases) {
150
+ const result = run(`check :- ${query}.`, { goal: 'check' });
151
+ assertEqual(result.stdout, succeeds ? 'check.\n' : '', `WG17 dif/2 case ${id}`);
152
+ }
153
+
154
+ // EyeProlog is a finite-tree processor. The comparison's rational-tree
155
+ // probes must terminate as failures instead of constructing cycles.
156
+ const rationalTreeCases = [
157
+ ['t1', '\\+ \\+ -X=X'],
158
+ ['t2', '-X=X,-Y=Y,X\\=Y'],
159
+ ['t3', '-X=X,dif(X,1)'],
160
+ ['t4', '-X=X,-Y=Y,dif(X,Y)'],
161
+ ['t5', 'dif(X,Y),-X=X,-Y=Y'],
162
+ ['t6', 'A=[[]|A],dif(A,B),B=[[]|A]'],
163
+ ['t7', 'dif(-X,X),-Y=Y,X=Y'],
164
+ ['t8', '-X=X,dif(X,Y),X=Y'],
165
+ ];
166
+ for (const [id, query] of rationalTreeCases) {
167
+ assertEqual(run(`check :- ${query}.`, { goal: 'check' }).stdout, '',
168
+ `WG17 dif/2 ${id} terminates under finite-tree unification`);
169
+ }
170
+
171
+ for (const [id, query, succeeds] of [
172
+ ['o1', '-X=X', false],
173
+ ['o2', 'dif(-X,X)', true],
174
+ ['o3', 'dif(-X,Y),X=Y', true],
175
+ ]) {
176
+ assertEqual(run(`check :- ${query}.`, { goal: 'check' }).stdout,
177
+ succeeds ? 'check.\n' : '', `WG17 dif/2 occurs-check case ${id}`);
178
+ }
179
+
180
+ const residuals = runCli([], {
181
+ input:
182
+ 'dif(A-C,B-D),C-D=z-z.\n' +
183
+ 'dif(A,[C|B]),A=[[]|_],A=[B].\n' +
184
+ 'dif(X-Y,1-2),X=Y.\n' +
185
+ 'halt.\n',
186
+ });
187
+ assertEqual(residuals.status, 0, 'dif/2 residual display status');
188
+ assertEqual(residuals.stdout,
189
+ '?- C = z, D = z, dif(A - z, B - z).\n' +
190
+ '?- A = [[]], B = [], dif([[]], [C]).\n' +
191
+ '?- X = Y.\n' +
192
+ '?- ',
193
+ 'dif/2 residual constraints are retained and discharged');
194
+ assertEqual(residuals.stderr, '', 'dif/2 residual display stderr');
195
+
126
196
  assertEqual(run('p(a).', { goal: 'dif(X,a),p(X)' }).stats.completed_goal_lists, 0,
127
197
  'scalar-fact fast matching still validates annotated variables');
128
198
  assertEqual(run('p(b).', { goal: 'dif(X,a),p(X)' }).stats.completed_goal_lists, 1,