1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 package io.github.prolobjectlink.prolog;
27
28 import static io.github.prolobjectlink.prolog.PrologTermType.ATOM_TYPE;
29 import static io.github.prolobjectlink.prolog.PrologTermType.CLASS_TYPE;
30 import static io.github.prolobjectlink.prolog.PrologTermType.CUT_TYPE;
31 import static io.github.prolobjectlink.prolog.PrologTermType.DOUBLE_TYPE;
32 import static io.github.prolobjectlink.prolog.PrologTermType.FAIL_TYPE;
33 import static io.github.prolobjectlink.prolog.PrologTermType.FALSE_TYPE;
34 import static io.github.prolobjectlink.prolog.PrologTermType.FIELD_TYPE;
35 import static io.github.prolobjectlink.prolog.PrologTermType.FLOAT_TYPE;
36 import static io.github.prolobjectlink.prolog.PrologTermType.INTEGER_TYPE;
37 import static io.github.prolobjectlink.prolog.PrologTermType.LIST_TYPE;
38 import static io.github.prolobjectlink.prolog.PrologTermType.LONG_TYPE;
39 import static io.github.prolobjectlink.prolog.PrologTermType.MAP_ENTRY_TYPE;
40 import static io.github.prolobjectlink.prolog.PrologTermType.MAP_TYPE;
41 import static io.github.prolobjectlink.prolog.PrologTermType.MIXIN_TYPE;
42 import static io.github.prolobjectlink.prolog.PrologTermType.NIL_TYPE;
43 import static io.github.prolobjectlink.prolog.PrologTermType.OBJECT_TYPE;
44 import static io.github.prolobjectlink.prolog.PrologTermType.PARAMETER_TYPE;
45 import static io.github.prolobjectlink.prolog.PrologTermType.RESULT_TYPE;
46 import static io.github.prolobjectlink.prolog.PrologTermType.STRUCTURE_TYPE;
47 import static io.github.prolobjectlink.prolog.PrologTermType.TRUE_TYPE;
48 import static io.github.prolobjectlink.prolog.PrologTermType.VARIABLE_TYPE;
49
50 import java.util.ArrayDeque;
51 import java.util.Deque;
52 import java.util.HashMap;
53 import java.util.Map;
54
55
56
57
58
59
60
61 public abstract class AbstractTerm implements PrologTerm {
62
63 protected int type;
64 protected final PrologProvider provider;
65
66 protected AbstractTerm(int type, PrologProvider provider) {
67 this.type = type;
68 this.provider = provider;
69 }
70
71 protected final void checkIndex(int index) {
72 if (index < 0) {
73 throw new ArrayIndexOutOfBoundsException(index);
74 }
75 }
76
77 protected final void checkIndex(int index, int max) {
78 if (index < 0 || index > max) {
79 throw new ArrayIndexOutOfBoundsException(index);
80 }
81 }
82
83 protected final String removeQuoted(String functor) {
84 if (functor != null && functor.startsWith("\'") && functor.endsWith("\'")) {
85 return functor.substring(1, functor.length() - 1);
86 }
87 return functor;
88 }
89
90 protected final <K extends PrologTerm> K toTerm(Object o, Class<K> from) {
91 return provider.toTerm(o, from);
92 }
93
94 protected final <K extends PrologTerm> K[] toTermArray(Object[] os, Class<K[]> from) {
95 return provider.toTermArray(os, from);
96 }
97
98 protected final <K> K fromTerm(PrologTerm term, Class<K> to) {
99 return provider.fromTerm(term, to);
100 }
101
102 protected final <K> K[] fromTermArray(PrologTerm[] terms, Class<K[]> to) {
103 return provider.fromTermArray(terms, to);
104 }
105
106 protected final PrologLogger getLogger() {
107 return provider.getLogger();
108 }
109
110 public PrologTerm getArgument(int index) {
111 PrologTerm[] array = getArguments();
112 checkIndex(index, array.length);
113 return array[index];
114 }
115
116 public final String getIndicator() {
117 return getFunctor() + "/" + getArity();
118 }
119
120 public final boolean hasIndicator(String functor, int arity) {
121 return getFunctor().equals(functor) && getArity() == arity;
122 }
123
124 public PrologTerm getTerm() {
125 return this;
126 }
127
128 public final int getType() {
129 return type;
130 }
131
132 public final PrologProvider getProvider() {
133 return provider;
134 }
135
136
137
138
139
140
141
142
143
144
145
146
147
148 protected final <T extends PrologTerm> T cast(PrologTerm term, Class<T> type) {
149 return type.cast(term);
150 }
151
152
153
154
155
156
157
158
159
160
161
162
163 protected final <T extends PrologTerm> T cast(PrologTerm term) {
164 return (T) term;
165 }
166
167 public final <T extends PrologTerm> T cast() {
168 return cast(this);
169 }
170
171 public Object getObject() {
172 PrologTerm term = this;
173 switch (term.getType()) {
174 case NIL_TYPE:
175 return null;
176 case CUT_TYPE:
177 return "!";
178 case FAIL_TYPE:
179 return "fail";
180 case TRUE_TYPE:
181 return true;
182 case FALSE_TYPE:
183 return false;
184 case ATOM_TYPE:
185 return term.getFunctor();
186 case FLOAT_TYPE:
187 return ((PrologNumber) term).getFloatValue();
188 case INTEGER_TYPE:
189 return ((PrologNumber) term).getIntegerValue();
190 case DOUBLE_TYPE:
191 return ((PrologNumber) term).getDoubleValue();
192 case LONG_TYPE:
193 return ((PrologNumber) term).getLongValue();
194 case VARIABLE_TYPE:
195 return ((PrologVariable) term).getName();
196 case LIST_TYPE:
197 return fromTermArray(term.getArguments(), Object[].class);
198 case STRUCTURE_TYPE:
199 return term;
200 case OBJECT_TYPE:
201 return term.getObject();
202 case FIELD_TYPE:
203 PrologVariable field = term.cast();
204 return "field " + field.getName();
205 case RESULT_TYPE:
206 PrologVariable result = term.cast();
207 return "result " + result.getName();
208 case PARAMETER_TYPE:
209 PrologVariable parameter = term.cast();
210 return "parameter " + parameter.getName();
211 case CLASS_TYPE:
212 case MIXIN_TYPE:
213 return "class " + term.getFunctor();
214 default:
215 return null;
216 }
217 }
218
219 public final boolean isEntry() {
220 return getType() == MAP_ENTRY_TYPE;
221 }
222
223 public final boolean isMap() {
224 return getType() == MAP_TYPE;
225 }
226
227 public boolean isField() {
228 return getType() == FIELD_TYPE;
229 }
230
231 public boolean isResult() {
232 return getType() == RESULT_TYPE;
233 }
234
235 public boolean isParameter() {
236 return getType() == PARAMETER_TYPE;
237 }
238
239 public final boolean isMixin() {
240 return getType() == MIXIN_TYPE;
241 }
242
243 public final boolean isClass() {
244 return getType() == CLASS_TYPE;
245 }
246
247 public boolean isVariableBound() {
248 return isVariable() && getTerm() != this;
249 }
250
251 public boolean isVariableNotBound() {
252 return isVariable() && getTerm() == this;
253 }
254
255 public final boolean isClause() {
256 return false;
257 }
258
259 public final boolean isTerm() {
260 return true;
261 }
262
263
264
265
266
267
268
269 public final Map<String, PrologTerm> match(PrologTerm term) {
270 Deque<PrologTerm> stack = new ArrayDeque<PrologTerm>();
271 if (unify(term, stack)) {
272 int size = stack.size();
273 HashMap<String, PrologTerm> substitution = new HashMap<String, PrologTerm>(size);
274 while (size > 0) {
275 PrologVariable variable = (PrologVariable) stack.pop();
276 substitution.put(variable.getName(), variable.getTerm());
277
278 size--;
279 }
280 return substitution;
281 }
282 return new HashMap<String, PrologTerm>();
283 }
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305 private boolean unify(PrologTerm term, Deque<PrologTerm> stack) throws PrologError {
306
307 PrologTerm thisTerm = this;
308 PrologTerm otherTerm = term;
309
310 if (thisTerm.isVariableBound()) {
311 return ((AbstractTerm) thisTerm.getTerm()).unify(otherTerm, stack);
312 }
313
314 else if (otherTerm.isVariableBound()) {
315 return ((AbstractTerm) otherTerm.getTerm()).unify(thisTerm, stack);
316 }
317
318
319 else if (thisTerm.isVariableNotBound()) {
320
321
322 stack.push(thisTerm);
323 return true;
324
325 }
326
327
328 else if (otherTerm.isVariableNotBound()) {
329
330
331 stack.push(otherTerm);
332 return true;
333
334 }
335
336
337 else if (thisTerm.isNumber() || otherTerm.isNumber()) {
338 if ((thisTerm.isInteger() || thisTerm.isLong()) && (otherTerm.isInteger() || otherTerm.isLong())) {
339 int thisInt = ((PrologNumber) thisTerm).getIntegerValue();
340 int otherInt = ((PrologNumber) otherTerm).getIntegerValue();
341 return thisInt == otherInt;
342 }
343 return thisTerm.equals(otherTerm);
344 }
345
346 else {
347
348 int thisArity = thisTerm.getArity();
349 int otherArity = otherTerm.getArity();
350 String thisFunctor = thisTerm.getFunctor();
351 String otherFunctor = otherTerm.getFunctor();
352
353 if (thisFunctor.equals(otherFunctor) && thisArity == otherArity) {
354 for (int i = 0; i < thisArity; i++) {
355 if (thisTerm.getArgument(i) != null && otherTerm.getArgument(i) != null) {
356 if (!((AbstractTerm) thisTerm.getArgument(i)).unify(otherTerm.getArgument(i), stack)) {
357 return false;
358 }
359 }
360 }
361 return true;
362 }
363 }
364 return false;
365 }
366
367 }