View Javadoc

1   /*
2    * #%L
3    * prolobjectlink-jpi-jtrolog
4    * %%
5    * Copyright (C) 2019 Prolobjectlink Project
6    * %%
7    * This program is free software: you can redistribute it and/or modify
8    * it under the terms of the GNU Lesser General Public License as
9    * published by the Free Software Foundation, either version 2.1 of the
10   * License, or (at your option) any later version.
11   * 
12   * This program is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   * GNU General Lesser Public License for more details.
16   * 
17   * You should have received a copy of the GNU General Lesser Public
18   * License along with this program.  If not, see
19   * <http://www.gnu.org/licenses/lgpl-2.1.html>.
20   * #L%
21   */
22  package io.github.prolobjectlink.prolog.jtrolog;
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.NIL_TYPE;
34  import static io.github.prolobjectlink.prolog.PrologTermType.OBJECT_TYPE;
35  import static io.github.prolobjectlink.prolog.PrologTermType.STRUCTURE_TYPE;
36  import static io.github.prolobjectlink.prolog.PrologTermType.TRUE_TYPE;
37  import static io.github.prolobjectlink.prolog.PrologTermType.VARIABLE_TYPE;
38  
39  import java.util.Iterator;
40  
41  import io.github.prolobjectlink.prolog.AbstractTerm;
42  import io.github.prolobjectlink.prolog.PrologNumber;
43  import io.github.prolobjectlink.prolog.PrologProvider;
44  import io.github.prolobjectlink.prolog.PrologTerm;
45  import jTrolog.engine.Prolog;
46  import jTrolog.terms.Double;
47  import jTrolog.terms.Float;
48  import jTrolog.terms.Int;
49  import jTrolog.terms.Long;
50  import jTrolog.terms.Number;
51  import jTrolog.terms.Struct;
52  import jTrolog.terms.StructAtom;
53  import jTrolog.terms.Term;
54  import jTrolog.terms.Var;
55  
56  /**
57   * 
58   * @author Jose Zalacain
59   * @since 1.0
60   */
61  abstract class JTrologTerm extends AbstractTerm implements PrologTerm {
62  
63  	// variable index
64  	protected int vIndex;
65  	protected Term value;
66  
67  	static final JTrologOperatorSet ops = new JTrologOperatorSet();
68  
69  	protected JTrologTerm(int type, PrologProvider provider) {
70  		super(type, provider);
71  	}
72  
73  	protected JTrologTerm(int type, PrologProvider provider, Term value) {
74  		super(type, provider);
75  		this.value = value;
76  	}
77  
78  	/**
79  	 * Variable constructor
80  	 * 
81  	 * @param type
82  	 * @param provider
83  	 * @param n
84  	 */
85  	protected JTrologTerm(int type, PrologProvider provider, String name, int n) {
86  		this(type, provider, new Var(name, n));
87  		this.vIndex = n;
88  	}
89  
90  	public final boolean isAtom() {
91  		return value instanceof StructAtom;
92  	}
93  
94  	public final boolean isNumber() {
95  		return value instanceof Number;
96  	}
97  
98  	public final boolean isFloat() {
99  		return value instanceof Float && !isDouble();
100 	}
101 
102 	public final boolean isDouble() {
103 		return value instanceof Double;
104 	}
105 
106 	public final boolean isInteger() {
107 		return value instanceof Int && !isLong();
108 	}
109 
110 	public final boolean isLong() {
111 		return value instanceof Long;
112 	}
113 
114 	public final boolean isVariable() {
115 		return value instanceof Var;
116 	}
117 
118 	public final boolean isList() {
119 		if (value == Term.emptyList) {
120 			return true;
121 		} else if (value instanceof Struct) {
122 			Struct s = (Struct) value;
123 			return (s.name.equals(".") && s.arity == 2);
124 		}
125 		return false;
126 	}
127 
128 	public final boolean isStructure() {
129 		if (!isAtom() && !isList()) {
130 			return value instanceof Struct;
131 		}
132 		return false;
133 	}
134 
135 	public final boolean isNil() {
136 		if (!isVariable() && !isNumber()) {
137 			return hasIndicator("nil", 0);
138 		}
139 		return false;
140 	}
141 
142 	public final boolean isEmptyList() {
143 		return value == Term.emptyList;
144 	}
145 
146 	public final boolean isEvaluable() {
147 		Prolog prolog = new Prolog();
148 		Iterator<?> i = prolog.getCurrentOperators();
149 		while (i.hasNext()) {
150 			Object object = i.next();
151 			boolean valueIsStrct = (value instanceof Struct);
152 			boolean objectIsStrct = (object instanceof Struct);
153 			if (valueIsStrct && objectIsStrct) {
154 				Struct op = (Struct) object;
155 				Struct vop = (Struct) value;
156 				if (op.arity == 3 && ((StructAtom) op.getArg(2)).name.equals(vop.name)) {
157 					return true;
158 				}
159 			}
160 		}
161 		return false;
162 	}
163 
164 	public final boolean isAtomic() {
165 		return !isCompound();
166 	}
167 
168 	public final boolean isCompound() {
169 		return !(isEmptyList()) && (isList() || isStructure());
170 	}
171 
172 	public final boolean isTrueType() {
173 		return getObject().equals(true);
174 	}
175 
176 	public final boolean isFalseType() {
177 		return getObject().equals(false);
178 	}
179 
180 	public final boolean isNullType() {
181 		return getObject() == null;
182 	}
183 
184 	public final boolean isVoidType() {
185 		return getObject() == void.class;
186 	}
187 
188 	public final boolean isObjectType() {
189 		return getType() == OBJECT_TYPE;
190 	}
191 
192 	public final boolean isReference() {
193 		return isObjectType();
194 	}
195 
196 	public PrologTerm getTerm() {
197 		return this;
198 	}
199 
200 	public final boolean unify(PrologTerm term) {
201 		Term otherTerm = fromTerm(term, Term.class);
202 		return Prolog.match(value, otherTerm);
203 	}
204 
205 	public final int compareTo(PrologTerm term) {
206 		int termType = term.getType();
207 
208 		if ((type >> 8) < (termType >> 8)) {
209 			return -1;
210 		} else if ((type >> 8) > (termType >> 8)) {
211 			return 1;
212 		}
213 
214 		switch (type) {
215 		case NIL_TYPE:
216 		case CUT_TYPE:
217 		case FAIL_TYPE:
218 		case TRUE_TYPE:
219 		case FALSE_TYPE:
220 		case ATOM_TYPE:
221 
222 			// alphabetic functor comparison
223 			StructAtom atom = (StructAtom) value;
224 			int result = atom.name.compareTo(term.getFunctor());
225 			if (result < 0) {
226 				return -1;
227 			} else if (result > 0) {
228 				return 1;
229 			}
230 			break;
231 
232 		case FLOAT_TYPE:
233 
234 			float thisFloatValue = ((Number) value).floatValue();
235 			float otherFloatValue = ((PrologNumber) term).getFloatValue();
236 
237 			if (thisFloatValue < otherFloatValue) {
238 				return -1;
239 			} else if (thisFloatValue > otherFloatValue) {
240 				return 1;
241 			}
242 
243 			break;
244 
245 		case LONG_TYPE:
246 
247 			long thisLongValue = ((Number) value).longValue();
248 			long otherLongValue = ((PrologNumber) term).getLongValue();
249 
250 			if (thisLongValue < otherLongValue) {
251 				return -1;
252 			} else if (thisLongValue > otherLongValue) {
253 				return 1;
254 			}
255 
256 			break;
257 
258 		case DOUBLE_TYPE:
259 
260 			double thisDoubleValue = ((Number) value).doubleValue();
261 			double otherDoubleValue = ((PrologNumber) term).getDoubleValue();
262 
263 			if (thisDoubleValue < otherDoubleValue) {
264 				return -1;
265 			} else if (thisDoubleValue > otherDoubleValue) {
266 				return 1;
267 			}
268 
269 			break;
270 
271 		case INTEGER_TYPE:
272 
273 			int thisIntegerValue = ((Number) value).intValue();
274 			int otherIntegerValue = ((PrologNumber) term).getIntegerValue();
275 
276 			if (thisIntegerValue < otherIntegerValue) {
277 				return -1;
278 			} else if (thisIntegerValue > otherIntegerValue) {
279 				return 1;
280 			}
281 
282 			break;
283 
284 		case LIST_TYPE:
285 		case STRUCTURE_TYPE:
286 
287 			PrologTerm thisCompound = this;
288 			PrologTerm otherCompound = term;
289 
290 			// comparison by arity
291 			if (thisCompound.getArity() < otherCompound.getArity()) {
292 				return -1;
293 			} else if (thisCompound.getArity() > otherCompound.getArity()) {
294 				return 1;
295 			}
296 
297 			// alphabetic functor comparison
298 			result = thisCompound.getFunctor().compareTo(otherCompound.getFunctor());
299 			if (result < 0) {
300 				return -1;
301 			} else if (result > 0) {
302 				return 1;
303 			}
304 
305 			// arguments comparison
306 			PrologTerm[] thisArguments = thisCompound.getArguments();
307 			PrologTerm[] otherArguments = otherCompound.getArguments();
308 
309 			for (int i = 0; i < thisArguments.length; i++) {
310 				PrologTerm thisArgument = thisArguments[i];
311 				PrologTerm otherArgument = otherArguments[i];
312 				if (thisArgument != null && otherArgument != null) {
313 					result = thisArgument.compareTo(otherArgument);
314 					if (result != 0) {
315 						return result;
316 					}
317 				}
318 			}
319 			break;
320 
321 		case VARIABLE_TYPE:
322 
323 			PrologTerm thisVariable = this;
324 			PrologTerm otherVariable = term;
325 			if (thisVariable.hashCode() < otherVariable.hashCode()) {
326 				return -1;
327 			} else if (thisVariable.hashCode() > otherVariable.hashCode()) {
328 				return 1;
329 			}
330 			break;
331 
332 		default:
333 			return 0;
334 
335 		}
336 
337 		return 0;
338 	}
339 
340 	public int hashCode() {
341 		final int prime = 31;
342 		int result = 1;
343 		result = prime * result + type;
344 		result = prime * result + ((value == null) ? 0 : value.toString().hashCode());
345 		return result;
346 	}
347 
348 	public boolean equals(Object obj) {
349 		if (this == obj)
350 			return true;
351 		if (obj == null)
352 			return false;
353 		if (!(obj instanceof JTrologTerm))
354 			return false;
355 		JTrologTerm other = (JTrologTerm) obj;
356 		if (value == null) {
357 			if (other.value != null)
358 				return false;
359 		} else if (value.toString().equals(other.value.toString())) {
360 			return true;
361 		} else if (!Prolog.match(value, other.value)) {
362 			return false;
363 		}
364 		return true;
365 	}
366 
367 	public String toString() {
368 		return value.toStringSmall();
369 	}
370 
371 }