1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package io.github.prolobjectlink.prolog.jlog;
23
24 import static io.github.prolobjectlink.prolog.PrologTermType.ATOM_TYPE;
25 import static io.github.prolobjectlink.prolog.PrologTermType.CUT_TYPE;
26 import static io.github.prolobjectlink.prolog.PrologTermType.DOUBLE_TYPE;
27 import static io.github.prolobjectlink.prolog.PrologTermType.FAIL_TYPE;
28 import static io.github.prolobjectlink.prolog.PrologTermType.FALSE_TYPE;
29 import static io.github.prolobjectlink.prolog.PrologTermType.FLOAT_TYPE;
30 import static io.github.prolobjectlink.prolog.PrologTermType.INTEGER_TYPE;
31 import static io.github.prolobjectlink.prolog.PrologTermType.LIST_TYPE;
32 import static io.github.prolobjectlink.prolog.PrologTermType.LONG_TYPE;
33 import static io.github.prolobjectlink.prolog.PrologTermType.MAP_ENTRY_TYPE;
34 import static io.github.prolobjectlink.prolog.PrologTermType.MAP_TYPE;
35 import static io.github.prolobjectlink.prolog.PrologTermType.NIL_TYPE;
36 import static io.github.prolobjectlink.prolog.PrologTermType.OBJECT_TYPE;
37 import static io.github.prolobjectlink.prolog.PrologTermType.STRUCTURE_TYPE;
38 import static io.github.prolobjectlink.prolog.PrologTermType.TRUE_TYPE;
39 import static io.github.prolobjectlink.prolog.PrologTermType.VARIABLE_TYPE;
40 import static ubc.cs.JLog.Foundation.iType.TYPE_LIST;
41 import static ubc.cs.JLog.Foundation.iType.TYPE_PREDICATE;
42
43 import java.io.IOException;
44 import java.util.ArrayDeque;
45 import java.util.Deque;
46 import java.util.Enumeration;
47
48 import io.github.prolobjectlink.prolog.AbstractTerm;
49 import io.github.prolobjectlink.prolog.PrologLogger;
50 import io.github.prolobjectlink.prolog.PrologNumber;
51 import io.github.prolobjectlink.prolog.PrologProvider;
52 import io.github.prolobjectlink.prolog.PrologTerm;
53 import ubc.cs.JLog.Foundation.jEquivalenceMapping;
54 import ubc.cs.JLog.Foundation.jKnowledgeBase;
55 import ubc.cs.JLog.Foundation.jPrologFileServices;
56 import ubc.cs.JLog.Foundation.jPrologServices;
57 import ubc.cs.JLog.Parser.pOperatorEntry;
58 import ubc.cs.JLog.Parser.pOperatorRegistry;
59 import ubc.cs.JLog.Parser.pPredicateRegistry;
60 import ubc.cs.JLog.Terms.jCompoundTerm;
61 import ubc.cs.JLog.Terms.jInteger;
62 import ubc.cs.JLog.Terms.jList;
63 import ubc.cs.JLog.Terms.jListPair;
64 import ubc.cs.JLog.Terms.jNullList;
65 import ubc.cs.JLog.Terms.jTerm;
66 import ubc.cs.JLog.Terms.jVariable;
67
68
69
70
71
72 abstract class JLogTerm extends AbstractTerm implements PrologTerm {
73
74 protected int vIndex;
75 protected jTerm value;
76 private PrologTerm vValue;
77 protected static int vIdexer = 0;
78
79 private final jEquivalenceMapping equivalence = new jEquivalenceMapping();
80
81 protected final jList adaptList(PrologTerm[] arguments) {
82 jList pList = jNullList.NULL_LIST;
83 for (int i = arguments.length - 1; i >= 0; --i) {
84 pList = new jListPair(fromTerm(arguments[i], jTerm.class), pList);
85 }
86 return pList;
87 }
88
89 protected final jCompoundTerm adaptCompound(PrologTerm[] arguments) {
90 jCompoundTerm compound = new jCompoundTerm(arguments.length);
91 for (PrologTerm iPrologTerm : arguments) {
92 compound.addTerm(fromTerm(iPrologTerm, jTerm.class));
93 }
94 return compound;
95 }
96
97 protected JLogTerm(int type, PrologProvider provider) {
98 super(type, provider);
99 }
100
101 protected JLogTerm(int type, PrologProvider provider, jTerm value) {
102 super(type, provider);
103 this.value = value;
104 }
105
106 protected JLogTerm(int type, PrologProvider provider, int vIndex) {
107 this(type, provider, new jVariable());
108 this.vIndex = vIndex;
109 }
110
111 protected JLogTerm(int type, PrologProvider provider, String name, int vIndex) {
112 this(type, provider, new jVariable(name));
113 this.vIndex = vIndex;
114 }
115
116 public final boolean isAtom() {
117 return type == ATOM_TYPE || type == FAIL_TYPE || type == FALSE_TYPE || type == TRUE_TYPE || type == CUT_TYPE
118 || type == NIL_TYPE;
119 }
120
121 public final boolean isNumber() {
122 return isDouble() || isFloat() || isInteger() || isLong();
123 }
124
125 public final boolean isFloat() {
126 return type == FLOAT_TYPE;
127 }
128
129 public final boolean isDouble() {
130 return type == DOUBLE_TYPE;
131 }
132
133 public final boolean isInteger() {
134 return type == INTEGER_TYPE;
135 }
136
137 public final boolean isLong() {
138 return type == LONG_TYPE;
139 }
140
141 public final boolean isVariable() {
142 return type == VARIABLE_TYPE;
143 }
144
145 public final boolean isList() {
146 return (this instanceof JLogList)
147
148 ||
149
150 (this instanceof JLogEmpty)
151
152 ||
153
154 (this instanceof JLogMap);
155 }
156
157 public final boolean isStructure() {
158 return (this instanceof JLogStructure) || (this instanceof JLogEntry);
159 }
160
161 public final boolean isNil() {
162 return this instanceof JLogNil;
163 }
164
165 public final boolean isEmptyList() {
166 return (this instanceof JLogEmpty)
167
168 ||
169
170 (this instanceof JLogMap
171
172 &&
173
174 ((JLogMap) this).size() == 0);
175 }
176
177 public boolean isEvaluable() {
178 if (isStructure()) {
179 String builtins = "builtins";
180 jKnowledgeBase kb = new jKnowledgeBase();
181 pOperatorRegistry or = new pOperatorRegistry();
182 pPredicateRegistry pr = new pPredicateRegistry();
183 jPrologServices engine = new jPrologServices(kb, pr, or);
184 engine.setFileServices(new jPrologFileServices());
185 try {
186 engine.loadLibrary(builtins);
187 } catch (IOException e) {
188 getLogger().error(getClass(), PrologLogger.ERROR_LOADING_BUILT_INS, e);
189 }
190 Enumeration<?> e = engine.getOperatorRegistry().enumOperators();
191 while (e.hasMoreElements()) {
192 Object object = e.nextElement();
193 if (object instanceof pOperatorEntry) {
194 pOperatorEntry entry = (pOperatorEntry) object;
195 String operator = entry.getName();
196 String functor = getFunctor();
197 if (functor.startsWith("'") && functor.endsWith("'")) {
198 functor = functor.substring(1, functor.length() - 1);
199 }
200 if (operator.equals(functor)) {
201 return true;
202 }
203 }
204 }
205 }
206 return false;
207 }
208
209 public final boolean isAtomic() {
210 return !isCompound();
211 }
212
213 public boolean isCompound() {
214 return (value != null)
215
216 && (value.type == TYPE_PREDICATE
217
218 || value.type == TYPE_LIST
219
220 );
221 }
222
223 public final boolean isTrueType() {
224 Object object = getObject();
225 return object != null && object.equals(true);
226 }
227
228 public final boolean isFalseType() {
229 Object object = getObject();
230 return object != null && object.equals(false);
231 }
232
233 public final boolean isNullType() {
234 return isObjectType() && getObject() == null;
235 }
236
237 public final boolean isVoidType() {
238 return getObject() == void.class;
239 }
240
241 public final boolean isObjectType() {
242 return getType() == OBJECT_TYPE;
243 }
244
245 public final boolean isReference() {
246 return isObjectType();
247 }
248
249 public PrologTerm getTerm() {
250 return toTerm(value.getTerm(), PrologTerm.class);
251 }
252
253 public final boolean unify(PrologTerm term) {
254 Deque<PrologTerm> stack = new ArrayDeque<PrologTerm>();
255 boolean match = unify(term, stack);
256 for (PrologTerm prologTerm : stack) {
257 ((JLogTerm) prologTerm).unbind();
258 }
259 stack.clear();
260 return match;
261 }
262
263 private final boolean unify(PrologTerm term, Deque<PrologTerm> stack) {
264 return unify((JLogTerm) term, stack);
265 }
266
267 private final boolean unify(JLogTerm otherTerm, Deque<PrologTerm> stack) {
268
269 JLogTerm thisTerm = this;
270
271 if (thisTerm == otherTerm) {
272 if (thisTerm.isVariableNotBound()) {
273 thisTerm.bind(otherTerm);
274 otherTerm.bind(thisTerm);
275 stack.push(thisTerm);
276 }
277 return true;
278 }
279
280 else if (thisTerm.isVariableBound()) {
281 return ((JLogTerm) thisTerm.vValue).unify(otherTerm, stack);
282 }
283
284 else if (otherTerm.isVariableBound()) {
285 return ((JLogTerm) otherTerm.vValue).unify(thisTerm, stack);
286 }
287
288
289 else if (thisTerm.isVariableNotBound()) {
290 thisTerm.bind(otherTerm);
291 stack.push(thisTerm);
292 return true;
293 }
294
295
296 else if (otherTerm.isVariableNotBound()) {
297 otherTerm.bind(thisTerm);
298 stack.push(otherTerm);
299 return true;
300 }
301
302
303 else if (thisTerm.isNumber() || otherTerm.isNumber()) {
304 if ((thisTerm.isInteger() || thisTerm.isLong()) && (otherTerm.isInteger() || otherTerm.isLong())) {
305 int thisInt = fromTerm(thisTerm, jInteger.class).getIntegerValue();
306 int otherInt = fromTerm(otherTerm, jInteger.class).getIntegerValue();
307 return thisInt == otherInt;
308 }
309 return thisTerm.equals(otherTerm);
310 }
311
312 else {
313
314 int thisArity = thisTerm.getArity();
315 int otherArity = otherTerm.getArity();
316 String thisFunctor = thisTerm.getFunctor();
317 String otherFunctor = otherTerm.getFunctor();
318 if (thisFunctor.equals(otherFunctor) && thisArity == otherArity) {
319 PrologTerm[] thisArguments = thisTerm.getArguments();
320 PrologTerm[] otherArguments = otherTerm.getArguments();
321 if (thisArguments.length == otherArguments.length) {
322 for (int i = 0; i < thisArguments.length; i++) {
323 if (thisArguments[i] != null && otherArguments[i] != null) {
324 JLogTerm thisJLogTerm = (JLogTerm) thisArguments[i];
325 JLogTerm otherJLogTerm = (JLogTerm) otherArguments[i];
326 if (!thisJLogTerm.unify(otherJLogTerm, stack)) {
327 return false;
328 }
329 }
330 }
331 }
332 return true;
333 }
334 }
335 return false;
336
337 }
338
339
340
341
342
343
344
345 public final boolean isVariableBound() {
346 return isVariable() && vValue != null;
347 }
348
349
350
351
352
353
354
355 public final boolean isVariableNotBound() {
356 return isVariable() && vValue == null;
357 }
358
359
360
361
362
363
364 private final void bind(JLogTerm term) {
365 vValue = term;
366 }
367
368
369 private final void unbind() {
370 vValue = null;
371 }
372
373 public final int compareTo(PrologTerm term) {
374
375 int termType = term.getType();
376
377 if ((type >> 8) < (termType >> 8)) {
378 return -1;
379 } else if ((type >> 8) > (termType >> 8)) {
380 return 1;
381 }
382
383 switch (type) {
384 case NIL_TYPE:
385 case CUT_TYPE:
386 case FAIL_TYPE:
387 case TRUE_TYPE:
388 case FALSE_TYPE:
389 case ATOM_TYPE:
390
391
392 int result = value.getName().compareTo(term.getFunctor());
393 if (result < 0) {
394 return -1;
395 } else if (result > 0) {
396 return 1;
397 }
398 break;
399
400 case FLOAT_TYPE:
401
402 float thisFloatValue = ((jFloat) value).getRealValue();
403 float otherFloatValue = ((PrologNumber) term).getFloatValue();
404
405 if (thisFloatValue < otherFloatValue) {
406 return -1;
407 } else if (thisFloatValue > otherFloatValue) {
408 return 1;
409 }
410
411 break;
412
413 case LONG_TYPE:
414
415 long thisValue = ((jInteger) value).getIntegerValue();
416 long otherValue = ((PrologNumber) term).getLongValue();
417
418 if (thisValue < otherValue) {
419 return -1;
420 } else if (thisValue > otherValue) {
421 return 1;
422 }
423
424 break;
425
426 case DOUBLE_TYPE:
427
428 double thisDoubleValue = ((jDouble) value).getRealValue();
429 double otherDoubleValue = ((PrologNumber) term).getDoubleValue();
430
431 if (thisDoubleValue < otherDoubleValue) {
432 return -1;
433 } else if (thisDoubleValue > otherDoubleValue) {
434 return 1;
435 }
436
437 break;
438
439 case INTEGER_TYPE:
440
441 int thisIntergerValue = ((jInteger) value).getIntegerValue();
442 int otherIntegerValue = ((PrologNumber) term).getIntegerValue();
443
444 if (thisIntergerValue < otherIntegerValue) {
445 return -1;
446 } else if (thisIntergerValue > otherIntegerValue) {
447 return 1;
448 }
449
450 break;
451
452 case MAP_TYPE:
453 case LIST_TYPE:
454 case STRUCTURE_TYPE:
455 case MAP_ENTRY_TYPE:
456
457 PrologTerm thisCompound = this;
458 PrologTerm otherCompound = term;
459
460 if (thisCompound.isEmptyList() && otherCompound.isEmptyList()) {
461 return 0;
462 }
463
464
465 if (thisCompound.getArity() < otherCompound.getArity()) {
466 return -1;
467 } else if (thisCompound.getArity() > otherCompound.getArity()) {
468 return 1;
469 }
470
471
472 result = thisCompound.getFunctor().compareTo(otherCompound.getFunctor());
473 if (result < 0) {
474 return -1;
475 } else if (result > 0) {
476 return 1;
477 }
478
479
480 PrologTerm[] thisArguments = thisCompound.getArguments();
481 PrologTerm[] otherArguments = otherCompound.getArguments();
482
483 for (int i = 0; i < thisArguments.length; i++) {
484 PrologTerm thisArgument = thisArguments[i];
485 PrologTerm otherArgument = otherArguments[i];
486 if (thisArgument != null && otherArgument != null) {
487 result = thisArgument.compareTo(otherArgument);
488 if (result != 0) {
489 return result;
490 }
491 }
492 }
493 break;
494
495 case VARIABLE_TYPE:
496
497 JLogTerm thisVariable = this;
498 JLogTerm otherVariable = ((JLogTerm) term);
499 if (thisVariable.vIndex < otherVariable.vIndex) {
500 return -1;
501 } else if (thisVariable.vIndex > otherVariable.vIndex) {
502 return 1;
503 }
504 break;
505
506 default:
507 return 0;
508
509 }
510
511 return 0;
512 }
513
514 @Override
515 public int hashCode() {
516 final int prime = 31;
517 int result = 1;
518 result = prime * result + type;
519 result = prime * result + ((value == null) ? 0 : value.toString().hashCode());
520 return result;
521 }
522
523 @Override
524 public boolean equals(Object obj) {
525 if (this == obj)
526 return true;
527 if (obj == null)
528 return false;
529 if (getClass() != obj.getClass())
530 return false;
531 JLogTerm other = (JLogTerm) obj;
532 if (type != other.type)
533 return false;
534 if (value == null) {
535 if (other.value != null)
536 return false;
537 } else if (!value.equivalence(other.value, equivalence)) {
538 return false;
539 }
540 return true;
541 }
542
543 @Override
544 public String toString() {
545 return value.toString(true);
546 }
547
548 }